01神经网络的理论及实现

感知机的缺点就是需要设置合适的权重,而权重的设置都是人工操作的。

1、从感知机到神经网络

重新画出感知机的模型,在图上加上偏置,由于偏置始终为1,所以颜色加深。

01神经网络的理论及实现_第1张图片

图1-1 感知机模型

  引入新函数(激活函数):

h(x)=\left\{\begin{matrix} 0 (x\leqslant 0)\\ 1(x>0) \end{matrix}\right.                                                        (1-1)

将感知机表达式改为:

y=h(b+w_{1}x_{1}+w_{2}x_{2})                                                (1-2)

也可以分开写为:

a=b+w_{1}x_{1}+w_{2}x_{2}                                                  (1-3)

y=h(a)                                                             (1-4)

根据公式(1-3)和(1-4)可以将图1-1更改为图1-2模型。

01神经网络的理论及实现_第2张图片

图1-2 加入激活函数的感知机图

2、激活函数

激活函数会将输入信号的总和转换为输出信号。

激活函数如果使用阶跃函数,就是感知机。

如果使用其它激活函数,就是神经网络。

2.1 阶跃函数

公式(1-1)就是阶跃函数。

实现代码:

import numpy as np
import matplotlib.pylab as plt

def step_function(x):
    return np.array(x>0,dtype=int)

x=np.arange(-5,5,0.1)
y=step_function(x)
plt.plot(x,y)
plt.ylim(-0.1,1.1)
plt.show()

运行结果:

01神经网络的理论及实现_第3张图片

原来的程序运行出错:

AttributeError: module 'numpy' has no attribute 'int'

解决办法:是因为版本的问题,将dtype=np.int更改为dtype=int即可。

2.2 sigmoid函数

   Sigmoid型函数是一类S型曲线函数,为两端饱和函数,常见的有Logistic函数和Tanh函数。

饱和:

      对于函数f(x),若x \to -\infty时,导数\frac{\mathrm{d} f(x)}{\mathrm{d} x}n \to 0,称为左饱和,当x \to +\infty时,导数\frac{\mathrm{d} f(x)}{\mathrm{d} x} \to 0,称为右饱和。两个都满足的情况下称为两端饱和。

2.2.1 Logistic函数

表达式:

h(x)=\frac{1}{1+e^{-x}}                                                                   (1-5)

实现代码:

def sigmoid(x):
    return 1/(1+np.exp(-x))

x=np.arange(-5,5,0.1)
y=sigmoid(x)
plt.plot(x,y)
plt.ylim(-0.1,1.1)
plt.show()

输出:

01神经网络的理论及实现_第4张图片

2.2.2 Tanh函数

表达式:

tanh(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}                                                       (1-6)

实现代码:

def tanh(x):
    return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))

x=np.arange(-5,5,0.1)
y1=tanh(x)
plt.plot(x,y1)
plt.ylim(-1.1,1.1)

plt.show()

输出:

01神经网络的理论及实现_第5张图片

Tanh函数的输出是零中心化的,而Logistic函数的输出恒大于0。非中心化的输出会使得其后一层的神经元的输入发生偏置偏移,并进一步使得梯度下降的收敛速度变慢

2.3 ReLU函数

ReLU(Rectified Linear Unit)函数,表达式为:

h(x)=\left\{\begin{matrix} x (x>0)\\ 0 (x\leqslant 0) \end{matrix}\right.                                                       (1-7)

实现代码:

def relu(x):
    return np.maximum(0,x)

x=np.arange(-6,6,0.1)
y=relu(x)
plt.plot(x,y)
plt.ylim(-1,5)
plt.show()

输出:

01神经网络的理论及实现_第6张图片

优点:

1、只需要进行加、乘和比较的操作,计算更高效。

2、具有很好的稀疏性,大约50%的神经元处于激活状态。

3、具有左饱和函数,在一定程度上缓解了梯度消失问题,加速梯度下降的收敛速度。

缺点:

1、非零中心化,影响梯度下降的效率;

2、死亡ReLU问题,即一次不恰当的更新后,ReLU神经元都不能被激活,永远可能都会是0.

2.3.1 带泄露的ReLU(Leaky ReLU)

在x<0时,可以保持一个很小的梯度\gamma,避免死亡ReLU的问题。

表达式:

\gamma一般选择为0.01.

LeakyReLU(x)=\left\{\begin{matrix} x &if x>0 \\ \\0.01 x & if x\leqslant 0 \end{matrix}\right.                                          (1-8)

代码实现:

import numpy as np
import matplotlib.pyplot as plt
def Leaky_relu(x):
    return np.maximum(0.01*x,x)

x=np.arange(-5.0,5.0,0.1)
y=Leaky_relu(x)
plt.plot(x,y)
plt.show()

输出:

01神经网络的理论及实现_第7张图片

和ReLU相比,负方向有个很小的弧度。

2.3.2 带参数的ReLU

带参数的ReLU(parametric ReLU,PReLU),PReLU是一个参数可变的函数。

表达式:

PReLU_{i}(x)=\left\{\begin{matrix} x&if x>0 \\ \gamma _{i} x&if x\leq 0 \end{matrix}\right.                                        (1-9)

2.3.3 ELU函数

ELU(Exponential Linear Unit,指数线性单元)

定义:

ELU(x)=\left\{\begin{matrix} x & if x>0\\ \gamma (e^{x}-1) & if x\leq 0 \end{matrix}\right.                                       (1-10)

代码实现:

import numpy as np
import matplotlib.pyplot as plt
import math
def elu(x,alpha=1):
    a = x[x>0]
    b = alpha*(math.e**(x[x<0])-1)
    result=np.concatenate((b,a),axis=0)
    return result

x=np.arange(-5.0,5.0,0.1)
y=elu(x)
plt.plot(x,y)
plt.show()

输出:

01神经网络的理论及实现_第8张图片

3、3层神经网络的实现

01神经网络的理论及实现_第9张图片

代码实现:

def init_network():#初始化权重和偏置
    network={}
    network['W1']=np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
    network['b1']=np.array([0.1,0.2,0.3])
    network['W2']=np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
    network['b2']=np.array([0.1,0.2])
    network['W3']=np.array([[0.1,0.3],[0.2,0.4]])
    network['b3']=np.array([0.1,0.2])
    
    return network

def forward(network,x):#前向传递,封装将输入信号转换为输出信号的处理过程
    W1,W2,W3=network['W1'],network['W2'],network['W3']
    b1,b2,b3=network['b1'],network['b2'],network['b3']
    
    a1=np.dot(x,W1)+b1
    z1=sigmoid(a1)
    a2=np.dot(z1,W2)+b2
    z2=sigmoid(a2)
    a3=np.dot(z2,W3)+b3
    y=identity_function(a3)
    
    return y

network=init_network()
x=np.array([1,0.5])
y=forward(network,x)
y

输出:

array([0.31682708, 0.69627909])

4、softmax函数

表达式:

y_{k}=\frac{e^{a_{k}}}{\sum_{i=1}^{n}e^{a_{i}}}                                                          (1-11)

由于会出现溢出情况,所以将公式(1-11)变换。

y_{k}=\frac{e^{a_{k}}}{\sum_{i=1}^{n}e^{a_{i}}}=\frac{Ce^{a_{k}}}{C\sum_{i=1}^{n}e^{a_{i}}}=\frac{e^{(a_{k}+logC)}}{\sum_{n}^{i=1}e^{(a_{i}+logC)}}=\frac{e^{(a_{k}+C{}')}}{\sum_{n}^{i=1}e^{(a_{i}+C{}')}}                 (1-12)

为了防止溢出,增加C{}'为任何值,一般会使用输入信号中的最大值。

实现代码:

def softmax(a):
    c=np.max(a)
    exp_a=np.exp(a-c)
    sum_exp_a=np.sum(exp_a)
    y=exp_a/sum_exp_a
    
    return y

softmax函数的输出是0~1.0之间的实数,总和为1。所以才把softmax函数的输出解释为“概率”。

举例:

a=np.array([0.3,2.9,4])
y=softmax(a)
y

输出:

array([0.01821127, 0.24519181, 0.73659691])

可以解释为y[0]概率0.018(1.8%),y[1]概率为0.245(24.5%),y[2]概率为0.737(73.7%)。

从概率结果可以看出,有74%概率是第2个类别。

由于指数函数的运算需要一定的计算机运算量,因此输出层的softmax函数一般会被省略。

5、手写数字识别实例

和机器学习步骤一样,分为学习和推理两个阶段。学习就是首先使用训练数据进行权重参数的学习;然后进行推理,使用刚才学习到的参数,对输入参数进行分类。

minist 显示代码

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image


def img_show(img):
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)

img = x_train[0]
label = t_train[0]
print(label)  # 5

print(img.shape)  # (784,)
img = img.reshape(28, 28)  # 把图像的形状变为原来的尺寸
print(img.shape)  # (28, 28)

img_show(img)

输出第1个图片:

01神经网络的理论及实现_第10张图片

计算精度的程序:

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax


def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test


def init_network():
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network


def predict(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)

    return y


x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
    y = predict(network, x[i])
    p= np.argmax(y) # 获取概率最高的元素的索引
    if p == t[i]:
        accuracy_cnt += 1

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))

输出精度为:93.51%。

5.1 批处理

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax


def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test


def init_network():
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network


def predict(network, x):
    w1, w2, w3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, w1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, w2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, w3) + b3
    y = softmax(a3)

    return y


x, t = get_data()
network = init_network()

batch_size = 100 # 批数量
accuracy_cnt = 0

for i in range(0, len(x), batch_size):
    x_batch = x[i:i+batch_size]
    y_batch = predict(network, x_batch)
    p = np.argmax(y_batch, axis=1)
    accuracy_cnt += np.sum(p == t[i:i+batch_size])

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))

参考资料:

1、深度学习入门:基于python的理论与实现 

2、神经网络与深度学习 邱锡鹏。

你可能感兴趣的:(神经网络,人工智能,算法)