继续创造,加快生长!这是我参加「日新计划 6 月更文挑战」的第32天,点击检查活动详情
在这篇文章中,准备用 Python 从头开始完成一个全衔接的神经网络。你或许会问,为什么需求自己完成梯度洗脱,有许多库和框架可认为咱们做这件事,比方 Tensorflow、Pytorch 等。这儿只想说只有自己亲手完成了,才是自己的。
想到今日自己从接触到从事与神经网络相梯度下降法原理关工作现已多少 2、3 年了,其间也尝试用 tensorflow 或 pytorch 框架去完成一些经典网络。不过关于反向传达背后机制仍是比较模糊。
梯度
梯度是函数上升最快方向,最快的方向也便是说这个方向函数形状很陡峭,那么也是函数下降最快的方向。
虽然关于一些理论、梯度消失和结点饱满可以输出一个 1、2、3 但是深究仍是没有底气,毕竟没有自己动手去完成过一个反向传达和完整练习进程。所以感觉仍是浮在外梯度下降法的目标是表,知其所以然而。
由于最近有一段空闲时刻、所以使神经网络英文用这段休息时刻将要把这部分知识收拾一下、深入了解了解
类型 | 符号 | 阐明 | 表达式 | 维度 |
---|---|---|---|---|
标量 | nLn^L | 表明python123第 L 层神经元的数量 | ||
向量 | BLB^L | 表明第 L 层偏置 | nL1n^L times 1 | |
矩阵 | WL变量W^L | 表明第 L 层的权重 | nLnLn梯度下降^神经网络英文L times n^L | |
向量 | ZLZ^L | 表明第 L 层输入到激梯度下降活函数的值 | ZL=WLA(L−1)+BLZ^L=W^LA^{(L-1)} + B^L | nL1n^L times 1 |
向量 | ALA^L | 表明第 L 层输出值 | AL=(ZL)A^L =梯度下降 sigma(Z^L) | nL1n^L times 1 |
咱们大家或许都了解练习神经网络的进程,便是更新网络参数,更新的方向是下降丢失函数值。也便是将学习问python123题转化为了一个优化的问题。那么怎么更新参数呢?咱们需求核算参加练习参数相关于丢失函数的导数,然后求解梯度,然后使用梯度下变量值降法来更新参数,迭代这个进程,可以找到一个最佳的解决方案变量名来最小化丢失函数。
咱们知道反向传达首要便是用来结算丢失函数相关于权重和偏置的导数
或许现已听到或读到了,许多关于在网络经过反向传达来传递差错的信息。然后根据神经元的 wpython语言 和 b 对偏差奉献变量是什么意思的大小。也便是将差错分配到每一个神经元上。
但这儿的差错(error)是什么python编程意思呢?这个差错的确切的定义又是什么?答案是这些差错是由每一层神经网络所奉献的,而且某一层的差错是后继层差错基础上分摊的,网络中第 ll 层的差神经网络引擎错用 ldelta^l 来表明。
反向传达是根据 4 个根本方程的,经过这些方程来核算差错 Ldelta^L 和丢失函数,这儿将这 4 个方程逐个列出
关于怎么解读这个 4 个方程,随后想用一期共享来阐明。
class NeuralNetwork(object):
def __init__(self):
pass
def forward(self,x):
# 回来前向传达的 Z 也便是 w 和 b 线性组合,输入激活函数前的值
# 回来激活函数输出值 A
# z_s , a_s
pass
def backward(self,y,z_s,a_s):
#回来前向传达中学习参数的导数 dw db
pass
def train(self,x,y,batch_size=10,epochs=100,lr=0.001):
pass
咱们都是神经网络学习进程,也便是练习进程。首要分为两个阶段前向传达和后向传梯度怎么求达
- 在前向传达函数中,首要核算传达的 Z 和 A,关于 Z 和 A 详细是什么请参见前面表格
- 在反向传达中核算神经网络是什么可学习变量 w 和 b 的导数
def __init__(self,layers = [2 , 10, 1], activations=['sigmoid', 'sigmoid']):
assert(len(layers) == len(activations)+1)
self.layers = layers
self.activations = activations
self.weights = []
self.biases = []
for i in range(len(layers)-1):
self.weights.append(np.random.randn(layers[i+1], layers[i]))
self.biases.append(np.random.randn(layers[i+1], 1))
- layers 参数用于指定每一层神经元的个数
- activations 为每一层指定激活函数,也便是梯度稀释的目的(wx+b) sig梯度稀释ma(wx + b)
来简略读解一下代码 assert(len(la神经网络对信息的存储依赖什么yers) == len(activationspython保留字)+1)
for i in range(len(layers)-1):
self.weights.append(np.random.randn(layers[i+1], layers[i]))
self.biases.append(np.random.randn(layers[i+1], 1))
由于python123平台登录权重衔接每一个层神经元的 w 和 b ,也就两两层之间的方程,上面代码是对
前向传达
在前向传达中,将python基础教程输入 X 输入到 a_s 中,z=wx+bz = wx + b 然后对输出再核算 a=(z)a=sigma(z),
def feedforward(self, x):
# 回来前向传达的值
a = np.copy(x)
z_s = []
a_s = [a]
for i in range(len(self.weights)):
activation_function = self.getActivationFunction(self.activations[i])
z_s.append(self.weights[i].dot(a) + self.biases[i])
a = activation_function(z_s[-1])
a_s.append(a)
return (z_s, a_s)
这儿激活函数,这个函数回来值是一个函数,在 py梯度下降算法的正确步骤thon 用 la梯度下降mbda
来回来一个函数,这儿简答留下一个伏笔,随后会对其进行修正。
@staticmethod
def getActivationFunction(name):
if(name == 'sigmoid'):
return lambda x : np.exp(x)/(1+np.exp(x))
elif(name == 'linear'):
return lambda x : x
elif(name == 'relu'):
def relu(x):
y = np.copy(x)
y[y<0] = 0
return y
return relu
else:
print('Unknown activation function. linear is used')
return lambda x: x
[@staticmethod]
def getDerivitiveActivationFunction(name):
if(name == 'sigmoid'):
sig = lambda x : np.exp(x)/(1+np.exp(x))
return lambda x :sig(x)*(1-sig(x))
elif(name == 'linear'):
return lambda x: 1
elif(name == 'relu'):
def relu_diff(x):
y = np.copy(x)
y[y>=0] = 1
y[y<0] = 0
return y
return relu_diff
else:
print('Unknown activation function. linear is used')
return lambda x: 1
反向传达
这是本次共享重点
def backpropagation(self,y, z_s, a_s):
dw = [] # dC/dW
db = [] # dC/dB
deltas = [None] * len(self.weights) # delta = dC/dZ 核算每一层的差错
# 最终一层差错
deltas[-1] = ((y-a_s[-1])*(self.getDerivitiveActivationFunction(self.activations[-1]))(z_s[-1]))
# 反向传达
for i in reversed(range(len(deltas)-1)):
deltas[i] = self.weights[i+1].T.dot(deltas[i+1])*(self.getDerivitiveActivationFunction(self.activations[i])(z_s[i]))
#a= [print(d.shape) for d in deltas]
batch_size = y.shape[1]
db = [d.dot(np.ones((batch_size,1)))/float(batch_size) for d in deltas]
dw = [d.dot(a_s[i].T)/float(batch_size) for i,d in enumerate(deltas)]
# 回来权重(weight)矩阵 and 偏置向量(biases)
return dw, db
首先核算最终一层差错根据 BP1 等式可以得到下面的式子
deltas[-1] = ((y-a_s[-1])*(self.getDerivitiveActivationFunction(self.activations[-1]))(z_s[-1]))
接下来根据上一层的 l+1delta^{l+1} 差错来核算当前层 ldelta^l
batch_size = y.shape[1]
db = [d.dot(np.ones((batch_size,1)))/float(batch_size) for d in deltas]
dw = [d.dot(a_s[i].T)/float(batch_size) for i,d in enumerate(deltas)]
开始练习
def train(self, x, y, batch_size=10, epochs=100, lr = 0.01):
# update weights and biases based on the output
for e in range(epochs):
i=0
while(i<len(y)):
x_batch = x[i:i+batch_size]
y_batch = y[i:i+batch_size]
i = i+batch_size
z_s, a_s = self.feedforward(x_batch)
dw, db = self.backpropagation(y_batch, z_s, a_s)
self.weights = [w+lr*dweight for w,dweight in zip(self.weights, dw)]
self.biases = [w+lr*dbias for w,dbias in zip(self.biases, db)]
# print("loss = {}".format(np.linalg.norm(a_s[-1]-y_batch) ))