上一个博客中讲解了用python实现一个简单的两层神经网络,我们是把所有的网络层都直接写在了类中。但是作为一个神经网络框架,网络的结构应该是可以由使用者自定义的,这样一来也就不用为每个网络结构都重写所有代码,我们把每一层模块化,在神经网络的类中定义结构时使用这些模块化的层堆叠形成一个完整的神经网络。每一种层,分别实现forward和password两个函数,用来正向计算和反向传播。

这里我们实现的网络层和功能有:全连层、激活层、计算loss、自动训练

1、全连层

全连层的正向计算很简单,f(W,x)=xW+b。

反向传播分别求x,W,b的梯度,dx=f(W,x)·W.T,dW=x·f(W,x),db=f(W,x)。

1 defaffine_forward(x, w, b):2 #######################################

3 #x: input shape (N, d_1, ..., d_k)

4 #w: Weights shape (D, M)

5 #b: bias shape (M)

6 #7 #Returns :

8 #out: output,shape (N, M)

9 #cache: (x, w, b)

10 ########################################

11 x1=x.reshape(x.shape[0],-1)12 out=np.dot(x1,w)+b13 cache=(x,w)14 returnout,cache15

16 defaffine_backward(dout, cache):17 ##################################################

18 #dout: Upstream derivative, of shape (N, M)

19 #cache: Tuple of:

20 #x: Input shape (N, d_1, ... d_k)

21 #w: Weights shape (D, M)

22 #23 #Returns a tuple of:

24 #dx: shape (N, d1, ..., d_k)

25 #dw: shape (D, M)

26 #db: shape (M,)

27 ##################################################

28 x,w=cache29 N=x.shape[0]30 x1=x.reshape(N,-1)31 dx=np.dot(dout,w.T).reshape(*x.shape)32 dw=np.dot(x1.T,dout)33 db=np.sum(dout,axis=0)34 return dx,dw,db

View Code

2、激活层

激活层只实现常用的relu激活函数。f(x)=max(0,x)。

反向传播也很简单,被激活的继承上一级的梯度,没有激活的梯度为0。这里不涉及到参数的梯度计算,只涉及到梯度的传播。

1 defrelu_forward(x):2 out =np.maximum(0,x)3 cache =x4 returnout, cache5

6

7 defrelu_backward(dout, cache):8 x =cache9 dx = dout * (x>0)10 return dx

View Code

实际使用过程中,一般全连接层后面都会接激活层,为了方便起见,可以合并两层。这里的合并跟之后的整个神经网络的堆叠思想一致。

1 defaffine_relu_forward(x, w, b):2 """

3 全连接层和激活层的合并4

5 Inputs:6 - x: 全连接层的输入7 - w, b: 全连接层的权重参数8

9 Returns a tuple of:10 - out: 被激活的全连接层的输出11 - cache: 用于反向传播12 """

13 a,fc_cache=affine_forward(x,w,b)14 out,relu_cache=relu_forward(a)15 returnout, (fc_cache,relu_cache)16

17

18 defaffine_relu_backward(dout, cache):19 fc_cache, relu_cache =cache20 da=relu_backward(dout,relu_cache)21 dx,dw,db=affine_backward(da,fc_cache)22 return dx, dw, db

View Code

3、loss层

严格上讲这不算神经网络的一个层,只是为了训练而必须进行的一个计算,但是这里我们就把它也当作一个层好了。

loss函数在上一个博客中已经详细介绍过了。https://www.cnblogs.com/super-JJboom/p/9748468.html

1 defsvm_loss(x, y):2

3 N,C=x.shape4 correct_class_scores=x[range(N),y].reshape(-1,1)5 margins=np.maximum(0,x-correct_class_scores+1)6 loss=np.sum(margins)/N7 dx =np.zeros_like(x)8 dx[margins>0]=1

9 num_pos = np.sum(margins > 0, axis=1)10 dx[range(N),y]-=num_pos11 dx/=N12

13 returnloss, dx14

15

16 defsoftmax_loss(x, y):17

18 N,C=x.shape19 shift_x=x-np.max(x,axis=1,keepdims=True).reshape(-1,1)20 Z=np.sum(np.exp(shift_x),axis=1,keepdims=True)21 log_pro=-shift_x+np.log(Z)22 loss=np.sum(log_pro[range(N),y])/N23 probs=np.exp(-log_pro)24 probs[range(N),y]-=1

25 dx=probs26 dx/=N

View Code

到此为止,之前我们实现两层神经网络需要的层已经都实现了。先重构一下之前的实现吧。

1 #2层神经网络

2 classTwoLayerNet(object):3 #The architecure : affine - relu - affine - softmax.

4 def __init__(self, input_dim=3*32*32,hidden_dim=100,num_classes=10,weight_scale=1e-3,reg=0.0):5 ################################

6 #input_dim 输入维度

7 #hidden_dims 隐藏层神经元个数

8 #num_classes 输出个数

9 #weight_scale 初始化权重

10 #reg 正则项系数

11 ################################

12 self.params={}13 self.reg=reg14 self.params['W1']=weight_scale*np.random.randn(input_dim,hidden_dim)15 self.params['b1']=np.zeros(hidden_dim)16 self.params['W2']=weight_scale*np.random.randn(hidden_dim,num_classes)17 self.params['b2']=np.zeros(num_classes)18

19 def loss(self,X,y=None):20 #返回loss和grad

21

22 #前向计算

23 ar1_out,ar1_cache=affine_relu_forward(X,self.params['W1'],self.params['b1'])24 a2_out,a2_cache=affine_forward(ar1_out,self.params['W2'],self.params['b2'])25 scores=a2_out26

27 if y isNone:28 returnscores29

30 loss,grads=0,{}31 loss,dscores=softmax_loss(scores,y)32 loss=loss+0.5*self.reg*(np.sum(self.params['W1']**2)+np.sum(self.params['W2']**2))33 dx2,dw2,db2=affine_backward(dscores,a2_cache)34 grads['W2']=dw2+self.reg*self.params['W2']35 grads['b2']=db236

37 dx1,dw1,db1=affine_relu_backward(dx2,ar1_cache)38 grads['W1']=dw1+self.reg*self.params['W1']39 grads['b1']=db140

41 return loss,grads

View Code

看起来比之前的实现并没有简单多少。。。这是因为2层神经网络的结构过于简单,仅从代码量上来看并没有减少,但是对于后面要实现的更复杂的神经网络来说,就发挥了巨大的作用。

哦,对比之前的实现,发现少了自动化训练的实现。因为训练有很多参数可以选择和调节,之前没有实现,如果全部放入神经网络的类中的话会显得过于臃肿,所以把训练过程的实现单独拿出来作为一个类。

4、自动化训练

相比与之前的自动训练过程,这里增加了更多的可选项。可以选择优化方法,如:SGD,带动量的SGD,adam。每一轮数据迭代完之后显示数据。

1 importnumpy as np2 from cs231n importoptim3

4 classSolver(object):5 def __init__(self,model,data,**kwargs):6 '''

7 初始化对象8 inputs:9 - model:网络结构对象10 - data:字典,包含带标签的训练集和验证集11 - kwargs:可选参数,详细见下面提取时候的注释12 '''

13

14 self.model=model15 self.X_train=data['X_train']16 self.y_train=data['y_train']17 self.X_val=data['X_val']18 self.y_val=data['y_val']19

20 #解读kwargs

21 self.update_rule=kwargs.pop('update_rule','sgd') #优化方法的选择,默认为随机梯度下降

22 self.optim_config=kwargs.pop('optim_config',{}) #优化的参数,学习率是必须有的选项。其他可以有动量因子之类的参数

23 self.lr_decay=kwargs.pop('lr_decay',1.0) #学习率衰减因子,默认不衰减

24 self.batch_size=kwargs.pop('batch_size',128) #批大小,默认128

25 self.num_epochs=kwargs.pop('num_epochs',10) #训练全部数据的轮次,默认为10轮

26 self.print_every=kwargs.pop('print_every',10) #多少轮显示一次进度

27 self.verbose=kwargs.pop('verbose',True) #是否显示进度,为false的情况下上一个参数无效

28

29 #含有不支持的参数

30 if len(kwargs)>0:31 extra=','.join('"%s"' % k for k inkwargs.keys())32 raise ValueError('Unrecongnized arguments %s' %extra)33

34 #检查优化方法是否支持

35 if nothasattr(optim,self.update_rule):36 raise ValueError('invalid update_rule "%s"' %self.update_rule)37

38 self.update_rule=getattr(optim,self.update_rule)39

40 self._reset()41

42 def_reset(self):43 #初始化参数

44 self.epoch=045 self.best_val_acc=046 self.best_params={}47 self.loss_history=[]48 self.train_acc_history=[]49 self.val_acc_history=[]50

51 #给给个参数矩阵复制一个优化参数,因为之后每个权重的参数不相同,需要自己保存

52 self.optim_configs={}53 for p inself.model.params:54 d={k:v for k,v inself.optim_config.items()}55 self.optim_configs[p]=d56

57 def_step(self):58 #单步更新

59

60 #随机取出batchsize个数据

61 num_train=self.X_train.shape[0]62 batch_mask=np.random.choice(num_train,self.batch_size)63 X_batch=self.X_train[batch_mask]64 y_batch=self.y_train[batch_mask]65

66 #计算loss

67 loss,grads=self.model.loss(X_batch,y_batch)68 self.loss_history.append(loss)69

70 #更新参数

71 for p,w inself.model.params.items():72 dw=grads[p]73 config=self.optim_configs[p]74 next_w,next_config=self.update_rule(w,dw,config)75 self.model.params[p]=next_w76 self.optim_configs[p]=next_config77

78 #计算正确率

79 def check_accuracy(self,X,y,num_samples=None,batch_size=128):80 N=X.shape[0]81

82 #如果num_sample不为空 则只从全部数据中选则num_sample个数据计算

83 if num_samples is not None and N>num_samples:84 mask=np.random.choice(N,num_samples)85 N=num_samples86 X=X[mask]87 y=y[mask]88

89 num_batches=N//batch_size90 if N%batch_size!=0:91 num_batches+=1

92 y_pred=[]93 for i inrange(num_batches):94 start=i*batch_size95 end=(i+1)*batch_size96 scores=self.model.loss(X[start:end])97 y_pred.append(np.argmax(scores,axis=1))98 y_pred=np.concatenate(y_pred,axis=0)99 acc=np.mean(y_pred==y)100

101 returnacc102

103 deftrain(self):104 num_train=self.X_train.shape[0]105 iterations_per_epoch=max(num_train//self.batch_size,1)106 num_iterations=self.num_epochs*iterations_per_epoch107

108 for t inrange(num_iterations):109 self._step()110

111 if self.verbose and t%self.print_every==0:112 print('Iteration %d /%d loss: %f' %(t+1,num_iterations,self.loss_history[-1]) )113

114 #每个epoch执行相应操作

115 epoch_end=(t+1)%iterations_per_epoch==0116 ifepoch_end:117 self.epoch+=1

118 for k inself.optim_configs:119 self.optim_configs[k]['learning_rate']*=self.lr_decay120

121 first_it=(t==0)122 last_it=(t==num_iterations-1)123 if first_it or last_it orepoch_end:124 train_acc=self.check_accuracy(self.X_train,self.y_train,num_samples=1280)125 val_acc=self.check_accuracy(self.X_val ,self.y_val)126 self.train_acc_history.append(train_acc)127 self.val_acc_history.append(val_acc)128

129 #可视化进度

130 ifself.verbose:131 print ('(Epoch %d / %d) train acc: %f; val_acc: %f' %(132 self.epoch, self.num_epochs, train_acc, val_acc))133

134 #检查、保存模型

135 if val_acc>self.best_val_acc:136 self.best_val_acc=val_acc137 self.best_params={}138 for k,v inself.model.params.items():139 self.best_params[k]=v.copy()140

141 self.model.params=self.best_params

View Code

实现到这里,已经可以重新训练之前的两层神经网络了,训练代码全部整合带最后的测试代码里面了。

5、实现全连层神经网络框架

实现跟两层神经网络区别不大,只是网络层的堆叠使用了循环。这里还没有实现的批归一化和dropout操作后面会讲到。

1 classFullyConnectedNet(object):2 #archtecture: {affine - [batch norm] - relu - [dropout]} x (L - 1) - affine - softmax

3 def __init__(self,hidden_dims,input_dim=3*32*32,num_classes=10,dropout=0,4 use_batchnorm=False,reg=0.0,weight_scale=1e-3,dtype=np.float32,seed=None):5

6 '''

7 inputs:8 - hidden_dims:list,存储了有多少个中间层,每一层有多少个神经元9 - input_dim: 输入数据的维度大小10 - num_classes:类别的个数,也就是最后一层的神经元个数11 - dropout:失活率12 - use_batchnorm:是否在每一层之间使用批归一化操作13 - reg:正则权重14 - weight_scale:权重矩阵的初始数量级15 - seed:失活率随机16 '''

17

18 self.use_batchnorm=use_batchnorm19 self.use_dropout=(dropout>0)20 self.reg=reg21 self.num_layers=1+len(hidden_dims)22 self.dtype=dtype23 self.params={}24

25 #初始化每层的参数w,b [gamma,beta,dropout](如果有的话)

26 layer_input=input_dim27 for i,hd inenumerate(hidden_dims):28 self.params['W%d'%(i+1)]=weight_scale*np.random.randn(layer_input,hd)29 self.params['b%d'%(i+1)]=weight_scale*np.zeros(hd)30 ifself.use_batchnorm:31 self.params['gamma%d'%(i+1)]=np.ones(hd)32 self.params['beta%d'%(i+1)]=np.zeros(hd)33 layer_input=hd34 self.params['W%d'%(self.num_layers)]=weight_scale*np.random.randn(layer_input,num_classes)35 self.params['b%d'%(self.num_layers)]=weight_scale*np.zeros(num_classes)36 for k,v inself.params.items():37 self.params[k]=v.astype(dtype)38

39 self.dropout_param={}40 ifself.use_dropout:41 self.dropout_param={'mode':'train','p':dropout}42 if seed is notNone:43 self.dropout_param['seed']=seed44

45 self.bn_params=[]46 ifself.use_batchnorm:47 self.bn_params=[{'mode':'train'} for i in range(self.num_layers-1)]48

49 def loss(self,X,y=None):50

51 #跟之前一样,y=None时表示测试过程,直接返回最后一层的输出即可。否则表示训练过程,还要计算loss和gradient。

52

53 X=X.astype(self.dtype)54 mode='test' if y is None else 'train'

55

56 if self.dropout_param is notNone:57 self.dropout_param['mode'] =mode58 ifself.use_batchnorm:59 for bn_param inself.bn_params:60 bn_param['mode'] =mode61

62

63 #forward pass

64 layer_input=X65 ar_cache={}66 dp_cache={}67

68 for lay in range(self.num_layers-1):69 ifself.use_batchnorm:70 layer_input, ar_cache[lay] =affine_bn_relu_forward(layer_input,71 self.params['W%d'%(lay+1)], self.params['b%d'%(lay+1)],72 self.params['gamma%d'%(lay+1)], self.params['beta%d'%(lay+1)], self.bn_params[lay])73 else:74 layer_input,ar_cache[lay]=affine_relu_forward(layer_input,self.params['W%d'%(lay+1)],self.params['b%d'%(lay+1)])75

76 ifself.use_dropout:77 layer_input, dp_cache[lay] =dropout_forward(layer_input, self.dropout_param)78

79 ar_out,ar_cache[self.num_layers]=affine_forward(layer_input,self.params['W%d'%(self.num_layers)],self.params['b%d'%(self.num_layers)])80 scores=ar_out81

82 #预测时直接返回scores即可

83 if mode=='test':84 returnscores85

86 #训练时还要计算loss和gradient

87 grads={}88 loss,dscores=softmax_loss(scores,y)89 dhout=dscores90 loss+=0.5*self.reg*np.sum(self.params['W%d'%(self.num_layers)]**2)91 dx,dw,db=affine_backward(dhout,ar_cache[self.num_layers])92 grads['W%d'%(self.num_layers)]=dw+self.reg*self.params['W%d'%(self.num_layers)]93 grads['b%d'%(self.num_layers)]=db94 dhout=dx95 for lay in range(self.num_layers-1):96 lay=self.num_layers-1-lay-1

97 loss+=0.5*self.reg*np.sum(self.params['W%d'%(lay+1)]**2)98 ifself.use_dropout:99 dout=dropout_backward(dhout,dp_cache[lay])100 ifself.use_batchnorm:101 dx,dw,db,dgamma,dbeta=affine_bn_relu_backward(dhout,ar_cache[lay])102 grads['gamma%d'%(lay+1)] =dgamma103 grads['beta%d'%(lay+1)] =dbeta104 else:105 dx,dw,db=affine_relu_backward(dhout,ar_cache[lay])106 grads['W%d'%(lay+1)]=dw+self.reg*self.params['W%d'%(lay+1)]107 grads['b%d'%(lay+1)]=db108 dhout=dx109

110 return loss,grads

View Code

python神经网络调节参数_神经网络进阶-用python实现一个完整的神经网络框架并在CIFAR10数据集上调参...相关推荐

  1. python获取命令行参数_【整理】Python中如何获得并处理命令行参数

    运行Python脚本时,时常需要从命令行中传递一些参数到Python程序中,但是如何获得相应的传递进来的参数,以及如何解析这些参数,是很多人,包括最开始的我,所遇到的问题. 下面,就对此总结一下: 先 ...

  2. python多进程传递参数_急急急, Python 多进程,如何传递 epoll?

    10 2019-06-16 15:39:41 +08:00 @NoAnyLove 好的好的,我查了下,说 IPC 或向 worker 参数传递的东西必须要能 pickle,不然就报错,那就是 sele ...

  3. keras中lstm参数_如何使用Keras为自定义NER构建深度神经网络

    在这篇文章中,我们将学习如何使用Keras创建一个简单的神经网络来从非结构化文本数据中提取信息(NER). 模型架构 在这里,我们将使用BILSTM + CRF层.LSTM层用于过滤不需要的信息,将仅 ...

  4. python训练模型函数参数_一步步亲手用python实现Logistic Regression

    前面的[DL笔记1]Logistic回归:最基础的神经网络和[DL笔记2]神经网络编程原则&Logistic Regression的算法解析讲解了Logistic regression的基本原 ...

  5. python传中文参数_解决Python传递中文参数的问题

    今天有个需要需要传递中文参数给URL 但是在GBK环境下的脚本传递GBK的参数老是给我报UNICODE的解码错误.烦的很. 所以我们果断选择用urlencode来处理中文, 由于国内外网站编码不同,国 ...

  6. python 函数调用 不允许关键字参数_你所不知道的Python|函数参数的演进之路

    原标题:你所不知道的Python|函数参数的演进之路 函数参数处理机制是Python中一个非常重要的知识点,随着Python的演进,参数处理机制的灵活性和丰富性也在不断增加,使得我们不仅可以写出简化的 ...

  7. python函数装饰器参数 参数_【转】python 装饰器功能以及函数参数使用

    之前学习编程语言大多也就是学的很浅很浅,基本上也是很少涉及到装饰器这些的类似的内容.总是觉得是一样很神奇的东西,舍不得学(嘿嘿).今天看了一下书籍.发现道理还是很简单的. 简单的说:装饰器主要作用就是 ...

  8. python数据参数_零基础学习python数据分析——函数的参数

    原标题:零基础学习python数据分析--函数的参数 上一节课中我们讲了python的函数定义,Python的函数定义非常简单,但灵活度却非常大.除了正常定义的必选参数外,还可以使用默认参数.可变参数 ...

  9. url没有参数名怎么直接带参数_用30行Python爬虫带你看PLMM(划掉,喵星人)

    偶尔写写爬虫也算是打磨无聊生活的一种方式了. 之前写了一个用100多行Python爬虫看世界的帖子,有兴趣的朋友可以看一下. 带你用100多行Python爬虫看看今天的世界(上) 带你用100多行Py ...

最新文章

  1. WebCore中的渲染机制(二):块和内嵌(Blocks and Inlines)
  2. java并发-内存模型与volatile
  3. [Ext JS 7]基于NPM的开发
  4. 基于Spark的电影推荐系统(电影网站)
  5. linux中安装yum简单方法
  6. 帐号 快速看图cad_CAD快速看图
  7. WinDbg、Symbol Packages、SRVINSTW、DebugView下载地址
  8. ps怎么撤销参考线_干货技巧 | Photoshop10大奇技淫巧(肯定有你不知道的!)
  9. vs2017优雅配色
  10. 消息推送实现方法、移动终端及消息推送系统
  11. Docker配置远程访问
  12. 【VBA研究】输出PDF文件合并时出错
  13. ccd摄像机基础知识
  14. [NL系列] RNN LSTM 网络结构及应用
  15. refreshed 问题
  16. 快递查询单号查询物流实用攻略
  17. fpga配置过程(转载)
  18. S32K SDK使用详解之S32 SDK软件架构详解
  19. css 颤动_颤动-微光效果
  20. 制作FLV格式Flash视频

热门文章

  1. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 20丨查询球队积分【难度中等】​
  2. ARM 汇编语言入门
  3. Linux 动态库和静态库
  4. matlab读取时间数据,Matlab有关数据库读取及时间项的设定
  5. Guice之Servlet基础
  6. URLDecoder: Illegal hex characters in escape (%) pattern ...
  7. CoreAnimation编程指南(九)图层布局
  8. 找第一个只出现一次的字符_剑指offer 字符流中第一个只出现一次的字符
  9. Android studio的UI组件
  10. golang商城_Golang——简单是终极的成熟