torch入门笔记3:用torch实现多层感知器

来源:互联网 发布:sai软件下载官网 编辑:程序博客网 时间:2024/05/25 19:57

转自:http://www.aichengxu.com/view/2464033

代码地址:https://github.com/vic-w/torch-practice/tree/master/multilayer-perceptron

上一次我们使用了输出节点和输入节点直接相连的网络。网络里只有两个可变参数。这种网络只能表示一条直线,不能适应复杂的曲线。我们将把它改造为一个多层网络。一个输入节点,然后是两个隐藏层,每个隐藏层有3个节点,每个隐藏节点后面都跟一个非线性的Sigmoid函数。如图所示,这次我们使用的网络是有2个隐藏层,每层有3个节点的多层神经网络。



那么这样的结构用代码如何表示呢?我们来直接在上一次的代码上修改。
这个网络结构是一层一层的叠加起来的,nn库里有一个类型叫做Sequential序列,正好适合我们。这个Sequential是一个容器类,我们可以在它里面添加一些基本的模块。

[plain] view plain copy
  1. model = nn.Sequential()  

第一个我们要添加的是输入节点和第一个隐藏层的连接,它是一个Linear线性的类型,它的输入是1个节点,输出是3个节点。
[plain] view plain copy
  1. model:add(nn.Linear(1,3))  

然后我们在他后面添加一个Sigmoid层,它的节点个数会自动和前一层的输出个数保持一致。
[plain] view plain copy
  1. model:add(nn.Sigmoid())  

接下来我们添加第一和第二隐藏层中间的线性连接,输入是3,输出也是3。
[plain] view plain copy
  1. model:add(nn.Linear(3,3))  

再添加一个Sigmoid层。
[plain] view plain copy
  1. model:add(nn.Sigmoid())  

最后是第二隐藏层和输出节点之间的线性连接,输入是3,输出是1。
[plain] view plain copy
  1. model:add(nn.Linear(3,1))  

所以完整的建立模型的代码看起来是这样的
[plain] view plain copy
  1. model = nn.Sequential()   --define a sequential model
  2. model:add(nn.Linear(1,3))  --add linear model function with one input three output
  3. model:add(nn.Sigmoid())  --add the sigmoid(activated) function
  4. model:add(nn.Linear(3,3))  
  5. model:add(nn.Sigmoid())  
  6. model:add(nn.Linear(3,1))  

好,理论上讲我们已经改造完了网络,可以开始训练了。我们运行一下,看一下结果。我们会很意外的发现这个结果还不如我们上一次的结果。

其实这里面存在两个问题:
一个是我们的训练数据,输入的月份取值范围从1到10,输出的价格取值范围是几万。这样开始训练的时候后面几层的梯度会受到输出值的影响,变得非常大,迅速的把前面几层的参数推到一个很大的数值。而Sigmoid函数在远离零点的位置几乎梯度为零,所以就一直固定在一个位置不动了。

解决的方法是把输入和输出的取值范围调整到合适的区间,我这里把输入除以10,输出除以50000。预测时再把50000乘回去。在代码里面体现,就是在开头和结尾加两个辅助层,nn.MulConstant,这种类型的模块是对网络中的每个元素乘上一个常数。在输入进入之前先乘以0.1,在输入之后乘以50000。(and also try to figure out the batch normalization)
这样一来,建立模型的代码就变成了这样:
[plain] view plain copy
  1. model = nn.Sequential()  
  2. model:add(nn.MulConstant(0.1)) --在输入进入之前先乘以0.1  
  3. model:add(nn.Linear(1,3))  
  4. model:add(nn.Sigmoid())  
  5. model:add(nn.Linear(3,3))  
  6. model:add(nn.Sigmoid())  
  7. model:add(nn.Linear(3,1))  
  8. model:add(nn.MulConstant(50000)) --在输入之后乘以50000  


数据预处理问题现在解决了,还有一个问题是训练的速度很慢。因为我们现在的优化方法用的是最原始梯度下降法。
其实Torch已经给我们提供了各种先进的优化算法,都放在optim这个库里。我们在文件的头部添加包含optim库:
[plain] view plain copy
  1. require 'optim'  

另外,还需要把model里面的参数找出来方便随时调用。
[plain] view plain copy
  1. w, dl_dw = model:getParameters()  
w是model里面所有可调参数的集合,dl_dw是每个参数对loss的偏导数。需要注意的是这里的w和dl_dw都相当于C++里面的“引用”,一旦你对他们进行了操作,模型里的参数也会跟着改变。

优化函数的调用方法有一点特殊,需要你先提供一个目标函数,这个函数相当于C++里的回调函数,他的输入是一组网络权重参数w,输出有两个,第一个是网络使用参数w时,其输出结果与实际结果之间的差别,也可以叫loss损失,另一个是w中每个参数对于loss的偏导数。
[plain] view plain copy
  1. feval = function(w_new)  
  2.    if w ~= w_new then w:copy(w_new) end  
  3.    dl_dw:zero()  -- set loss to zero 
  4.   
  5.    price_predict = model:forward(month_train)  
  6.    loss = criterion:forward(price_predict, price_train)  -- calculate the loss between predict and train by MSE
  7.    model:backward(month_train, criterion:backward(price_predict, price_train))  -- backward input (predict / loss)
  8.    return loss, dl_dw  
  9. end  

这个回调函数可以参照这个例子来写,同样是“例行公事”,调用一下反向传播的算法。

有了这个目标函数,优化迭代的过程就简单多了。只需要一句optim.rprop(feval, w, params)。 rprop是一种改进的梯度下降法,它只看梯度的方向,不管大小,只要方向不变,它会无限的增大步长,所以他速度非常快。迭代的代码如下:
[plain] view plain copy
  1. params = {  
  2.    learningRate = 1e-2  
  3. }  
  4.   
  5. for i=1,3000 do  
  6.    optim.rprop(feval, w, params)  
  7.   
  8.    if i%10==0 then  
  9.       gnuplot.plot({month, price}, {month_train:reshape(10), price_predict:reshape(10)})  
  10.    end  
  11. end  

其中每10次迭代会把结果用gnuplot画出来。

我们来运行一下。
在命令行键入
[plain] view plain copy
  1. th mlp.lua  



看一下结果,这次的结果看起来就好多了。绿线(预测值)几乎和蓝线(实际值)重合在一起了。

下一节,我们将介绍如何用卷积神经网络识别MNIST手写数字图像。

本节的完整代码:
[plain] view plain copy
  1. require 'torch'  
  2. require 'nn'  
  3. require 'optim'  
  4. require 'gnuplot'  
  5.   
  6. month = torch.range(1,10)  
  7. price = torch.Tensor{28993,29110,29436,30791,33384,36762,39900,39972,40230,40146}  
  8.   
  9. model = nn.Sequential()  
  10. model:add(nn.MulConstant(0.1))  
  11. model:add(nn.Linear(1,3))  
  12. model:add(nn.Sigmoid())  
  13. model:add(nn.Linear(3,3))  
  14. model:add(nn.Sigmoid())  
  15. model:add(nn.Linear(3,1))  
  16. model:add(nn.MulConstant(50000))  
  17. criterion = nn.MSECriterion()  
  18.   
  19. month_train = month:reshape(10,1)  
  20. price_train = price:reshape(10,1)  
  21.   
  22. gnuplot.figure()  
  23.   
  24. w, dl_dw = model:getParameters()  
  25.   
  26. feval = function(w_new)  
  27.    if w ~= w_new then w:copy(w_new) end  
  28.     dl_dw:zero()  
  29.   
  30.     price_predict = model:forward(month_train)  
  31.     loss = criterion:forward(price_predict, price_train)  
  32.     model:backward(month_train, criterion:backward(price_predict, price_train))  
  33.     return loss, dl_dw  
  34. end  
  35.       
  36. params = {  
  37.    learningRate = 1e-2  
  38. }  
  39.   
  40. for i=1,3000 do  
  41.    optim.rprop(feval, w, params)  
  42.   
  43.    if i%10==0 then  
  44.       gnuplot.plot({month, price}, {month_train:reshape(10), price_predict:reshape(10)})  
  45.    end  
  46. end  
  47.   
  48. month_predict = torch.range(1,12)  
  49. local price_predict = model:forward(month_predict:reshape(12,1))  
  50. print(price_predict)  
  51.   
  52. gnuplot.pngfigure('plot.png')  
  53. gnuplot.plot({month, price}, {month_predict, price_predict})  
  54. gnuplot.plotflush()  

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子学习成绩差家长该怎么办 孩子一年级语文成绩不好怎么办 孩子上网成瘾不听父母话怎么办 10岁数学不开窍怎么办 孩子五年级数学不好怎么办 一岁宝宝难断奶怎么办 2岁宝宝断不了奶怎么办 快2岁宝宝不听话怎么办 2岁半的宝宝不听话怎么办 3岁宝宝哭闹不止怎么办 2岁宝宝爱打人怎么办 两周岁宝宝吃东西就吐怎么办 两周岁宝宝不爱吃饭怎么办 两周岁宝宝反复发烧怎么办 两周岁宝宝咳嗽厉害怎么办 2岁宝宝体内有火怎么办 4岁宝宝数都不会怎么办 两岁宝宝太撅怎么办 儿童晚上发烧白天不发烧怎么办 宝宝晚上睡觉认人怎么办 两岁宝宝尿裤子怎么办 分手了想和好怎么办说 2岁半宝宝胆小怎么办 1岁半宝宝胆小怎么办 分手了还是想他怎么办 两岁宝宝夜惊怎么办 孩子误吃了牙膏怎么办 孩子跳舞脸上的妆卸不掉怎么办 4周岁还不会说话怎么办 宝贝2岁多还不会说话怎么办 孩子20个月离婚怎么办 两个月宝宝闹夜怎么办 两个月宝宝闹瞌睡怎么办 2岁宝宝话特别多怎么办 宝宝3岁还不会说话怎么办 小儿3岁说话晚怎么办 1岁半了不会说话怎么办 宝宝2岁还说话晚怎么办 一岁宝宝不愿意学说话怎么办 2周岁宝宝不愿意学说话怎么办 三岁宝宝不爱说话应该怎么办