激活函数
为神经网络引入非线性因素,将输入信号的加权总和转换为输出信号,起到‘激活神经元’的作用
激活函数种类
1.阶跃函数
判断是否超过阈值,从而输出1或0
代码演示
import numpy as np
def step_function(x):
return np.array(x>0,dtype=int)
x=np.array([0,1,2,3,-1,-2,-3])
print(step_function(x))
2.Sigmoid函数
可看作对阶跃函数的改进,光滑、可微,可将输入映射到(0,1)区间。

代码演示
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
x=np.array([0,1,2,3,-1,-2,-3])
print(sigmoid(x))
3.Tanh函数
将Sigmoid函数进行平移缩放,使得输出有正有负

Sigmoid与Tanh的局限
由各自图像可知,在低于或高于某一阈值时,函数变化接近于0,从而造成梯度消失的问题
4.ReLU函数
将小于等于0的输出为0,大于零的输入保持不变

代码演示
import numpy as np
def relu(x):
return np.maximum(0,x)
x=np.array([0,1,2,3,-1,-2,-3])
print(relu(x))
ReLU函数作为激活函数不存在梯度消失的问题,但若输入持续为负数,会出现‘神经元死亡’,从而影响模型的学习能力,为解决此类问题,可通过Leaky ReLU,引入一个很小的常数来解决‘神经元死亡’的问题

5.Softmax函数
将输入映射到(0,1)区间,并可以输出多个类的概率,常用于多分类问题

代码演示
import numpy as np
def softmax(x):
if x.ndim==2:
x=x.T
x=x-np.max(x,axis=0)
y=np.array(np.exp(x)/np.sum(np.exp(x),axis=0))
return y.T
x=x-np.max(x,axis=0)
return np.exp(x)/np.sum(np.exp(x))
x=np.array([[0,1,2],[3,4,5],[6,7,8],[-1,-2,-3]])
print(softmax(x))
由于指数函数的性质,为了防止数据过大而溢出,可以将指数调小,具体做法如下:
对每个Xi减X中的最大值,相当于式中分子分母同除exp(Xmax),比例不变的同时,使得每个指数Xi变成负数。
x=x-np.max(x,axis=0) x=x-np.max(x,axis=0)
对于二维矩阵,代码中X为4×3矩阵,由于广播机制,拿出来的X中的最大值为4×1的向量,要使矩阵的列数等于后面向量的维度,所以要对X矩阵进行转置,最后的输出y在转置回来。
神经网络的简单实现
深度神经网络由多个层组成,称为模型,模型接受输入,生成输出,并包含一些参数。从输入到输出,即为前向传播,如下图所示


代码演示
import numpy as np
from functions.Identity import identity
from functions.function import sigmoid
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(a3)
return y
#定义模型和数据
network=init_network()
x=np.array([1.0,0.5])
#前向传播
y=forward(network,x)
print(y)
损失函数
通过损失函数可以寻找最优权重参数
1.均方误差(MSE)
MSE常用于回归问题

n为系数,不影响模型训练,故可以设为1/2,求导后可将2进行化简掉

由于MSE为平方项,对异常值敏感,遇到异常值可能出现梯度爆炸。
代码演示
def mean_squared_error(y,t):
return 0.5*np.sum((y-t)**2)
2.交叉熵误差
常用于分类问题,用于评估我们预估的概率分布和真实概率分布的差异

数值微分
1.梯度计算
为了使损失函数最小,需求出梯度对权重参数进行更新,即参数优化



代码演示
import numpy as np
#传入的x是向量
def _numerical_grad(f,x):
h=1e-4
grad=np.zeros_like(x)
for i in range(x.size):
temp=x[i]
x[i]=temp+h
fxh1=f(x)
x[i]=temp-h
fxh2=f(x)
grad[i]=(fxh1-fxh2)/(2*h)
x[i]=temp
return grad
#传入的X是矩阵
def numerical_grad(f,X):
if X.ndim==1:
return _numerical_grad(f,X)
else:
grad=np.zeros_like(X)
for i,x in enumerate(X):
grad[i]=_numerical_grad(f,x)
return grad
2.神经网络的梯度计算
神经网络十分复杂,利用数值微分的方法,只需要知道X发生的微小改变与对应的Y发生了怎么样的改变即可计算梯度,用前向传播即可计算,不需要知道整体的函数表达式
定义神经网络类
让代码模块化
代码演示
import numpy as np
from functions.sofmax import softmax
from sklearn.metrics import log_loss
from grad import numerical_grad
#定义一个神经网络类
class simple_net:
#初始化
def __init__(self):
self.W=np.random.randn(2,3)
def forward(self,x):
a=x@self.W
y=softmax(a)
return y
def loss(self,x,t):
y=self.forward(x)
loss=log_loss(t,y)
return loss
神经网络梯度计算
代码演示
import numpy as np
from functions.sofmax import softmax
from sklearn.metrics import log_loss
from grad import numerical_grad
#定义一个神经网络类
class simple_net:
#初始化
def __init__(self):
self.W=np.random.randn(2,3)
#前向传播
def forward(self,x):
a=x@self.W
y=softmax(a)
return y
#交叉熵损失函数
def loss(self,x,t):
y=self.forward(x)
loss=log_loss(t,y)
return loss
if __name__=='__main__':
# 定义数据和模型
x=np.array([0.6,0.9])
t=np.array([0,0,1])
net=simple_net()
f = lambda w:net.loss(x,t)
#计算梯度
gradw=numerical_grad(f,net.W)
print(gradw)





