自己动手写深度学习框架(优化深度学习框架)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
用过tensorflow、pytorch的同学都知道,这些框架是可以任意选择激励函数、任意选择优化方法的。要做到这一点,其实并不复杂,只需要把我们之前写的代码流程更新一下。也就是说基本上所有的函数,都要写成class的形式,在这个函数里面再添加forward函数和backward函数。这样推导的时候,就可以使用forward函数,如果是训练的时候,就使用backward函数。

1、激励函数的forward化、backward化
目前遇到的激励函数主要是relu和sigmoid,可以先把这两个函数转换成class,
'''
about Relu
'''
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
dout[self.mask] = 0
dx = dout
return dx
'''
about Sigmoid
'''
class Sigmoid:
def __init__(self):
self.out = None
def forward(self, x):
out = 1 / (1 + np.exp(-x))
self.out = out
return self.out
def backward(self, dout):
dx = dout * (1-self.out) * self.out
return dx
2、全连接函数的forward化、backward化
对于全连接函数,forward是比较容易理解的。但是backward是稍微复杂一点的,如果有兴趣,可以去找一点资料,看下全连接函数backward的证明过程。暂时,我们可以先使用,先把神经网络用起来。
'''
about Affine
'''
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
self.x = None
self.dW = None
self.db = None
def forward(self, x):
self.x = x
out = np.dot(x, self.W) + self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
return dx
3、输出函数和残差函数forward化、backward化
就推理来说,接下来就是输出函数和残差函数的forward、backward处理。输出函数一般就是softmax,而残差方程则是cross_entropy_error。现在要做的,就是把这两个函数放在一起做推导,至于训练,暂时只记住结论就可以了。
'''
about SoftmaxWithLoss
'''
class SoftmaxWithLoss:
def __init__(self):
self.loss = None
self.y = None
self.t = None
def forward(self, x, t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
batch_size = self.t.shape[0]
dx = (self.y - self.t) / batch_size
return dx
4、推理方法的改进
既然所有的函数都转成class的形式,那么至此整个推导就比较容易了,
def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)
return x
5、网络的创建
和之前创建网络不同,现在我们创建网络,理论上可以创建无限层次了,只要训练得过来即可。
# construct layer here
self.layers = OrderedDict()
self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
self.layers['Relu1'] = Relu()
self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])
self.lastLayer = SoftmaxWithLoss()
6、网络的训练
解决了推导的问题,下面就是网络的训练问题。如果推导是forward,那么训练就是backward的过程。这个时候,backward走一遍,那么不同网络层的梯度就会计算一遍了。
def gradient(self, x, t):
#forward
self.loss(x,t)
#backward
dout = 1
dout = self.lastLayer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
# about grads
grads = {}
grads['W1'] = self.layers['Affine1'].dW
grads['b1'] = self.layers['Affine1'].db
grads['W2'] = self.layers['Affine2'].dW
grads['b2'] = self.layers['Affine2'].db
return grads
7、更新网络层参数
训练得到的梯度,那么下面就可以开始更新网络参数了。因为更新的方法很多,所以通常我们也是写成class的形式来处理,这样可以灵活切换优化方法,比如像这样,
class SGD:
def __init__(self,lr=0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
有了SGD这个class之后,更新参数就比较容易了,首先肯定是创建SGD,
optimizer=SGD()
后期,每次更新的时候,直接输入params和grads就好了,
params = network.params
optimizer.update(params, grads)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)