参照鱼书第四章写了一遍前向传播版的梯度下降训练神经网络权重的算法(不用ai就是收获颇丰啊)
以下贴出代码
发现先前的图片好像寄了所以代码直接传代码形式算了
针对二层(输入-单个隐藏层-输出层)网络写的求梯度方法 相当于造了遍轮子,不过造轮子确实学东西啊,而且不用ai了感觉写起来其实好麻烦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import sys,ossys.path.append(os.pardir) import numpy as numpyfrom common.functions import *from common.gradient import numerical_gradient""" 二层训练网络所需内容: Params 1、每一层之间的权重与偏置的存放 Grads 2、每一次之间的权重与偏置的梯度的计算与存储 人为输入:每一层的大小,一个人为设定权重初始化的标准差以减小权重分布 问ai学到,不乘这个标准差,直接获得权重分布的方法叫 朴素随机初始化 如果乘了这个人为固定的标准差,则叫 缩放初始化 除此之外还有较为高级的初始化方法(对weight_init_std进行函数处理) 如针对sigmoid/tanh函数的Xavier/Glorot初始化(理论最优) 或者针对ReLU激活函数的He初始化 类的编写思路: 1、初始化出权重和偏置 2、写正常的预测网络 3、通过预测网络求交叉熵(损失函数) 4、将交叉熵函数传进梯度计算 5、返回梯度 6、额外可加个计算预测的准确率的(不过有损失函数在了也可反应,加上了给人看更好) """ class two_layer_net : def __init__ (self,input_size,hide_size,out_size,weight_init_std = 0.01 ): self .params = {} self .params["w1" ] = np.random.randn(input_size,hide_size)*weight_init_std self .params["b1" ] = np.zeros(hide_size) self .params["w2" ] = weight_init_std * np.random.randn(hide_size,out_size) self .params["b2" ] = np.zeros(out_size) def prediction (self,x ): w1,w2 = self .params["w1" ], self .params["w2" ] b1,b2 = self .params["b1" ], self .params["b2" ] y1 = np.dot(x,w1) + b1 z1 = softmax(y1) y2 = np.dot(z1,w2) + b2 z2 = softmax(y2) return z2 def loss (self,x,t ): y = self .prediction(x) L = cross_entropy_error(y,t) return L def gradient_caculation (self,x,t ): tmp_f = lambda w: self .loss(x,t) grads = {} grads["w1" ] = numerical_gradient(tmp_f,self .params["w1" ]) grads["w2" ] = numerical_gradient(tmp_f,self .params["w2" ]) grads["b1" ] = numerical_gradient(tmp_f,self .params["b1" ]) grads["b2" ] = numerical_gradient(tmp_f,self .params["b2" ]) return grads def accuracy (self, x, t ): y = self .prediction(x) y = np.argmax(y, axis=1 ) t = np.argmax(t, axis=1 ) accuracy = np.sum (y == t) / float (x.shape[0 ]) return accuracy
针对上述工具和前向传播+梯度下降思路写的mnist的mini_batch训练函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import numpy as npimport sys,osfrom two_layer_net import two_layer_netimport matplotlib.pyplot as pltsys.path.append(os.pardir) from dataset.mnist import load_mnist(x_train,t_train),(x_test,t_test) = load_mnist(normalize=True ,one_hot_label=True ) train_lost_list = [] iters_num = 10000 train_size = x_train.shape[0 ] batch_size = 100 learning_rate = 0.1 net = two_layer_net(input_size=784 ,hide_size=50 ,out_size=10 ) for i_time in range (iters_num): batch_mask = np.random.choice(train_size,batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] grad = net.gradient_caculation(x_batch,t_batch) for key in ["b1" ,"b2" ,"w1" ,"w2" ]: net.params[key] -= grad[key]*learning_rate error = net.loss(x_batch,t_batch) train_lost_list.append(error) print ("训练次数:" ,i_time) xx = np.arange(0 ,np.size(train_lost_list)) plt.plot(xx,train_lost_list) plt.show()
评价这代码也就仅供学习用,我真试了跑了一遍训练,结果半天才训练一次,搞得我一度怀疑是自己写的有问题,询问ai后才知道基础的方法就这吊样,算的老多了,它说反向传播的梯度算法能比正向的快40000倍,这下来很期待了bushi,所以说真正训练看效果什么的还是等学完反向传播算法吧
由于没有系统学习python语法,直接来学的鱼书,因而对一些python特性不很熟悉,在实践过程中确实学到了许多有用的小技巧,比如字典这种东西就很舒服,比枚举好用很多,以及batch那里直接用下标取数据属实是把我这种就接触过C和一点点CPP的原始人看呆了,不得不说python真爽(你说能不能以后python写代码然后让ai给转成cpp)
PS:感觉读这种示例代码超多的书适合先把示例读一遍,然后不看示例复现一遍,先拿注释过思路也很舒服。