Torch手札1:安装及基础使用(以XOR问题为例)

Posted by Kriz on 2017-04-11

之前一直耽于勾搭唱见小哥哥小姐姐学习不能自拔,导致手里的坑越攒越多,深感有必要填一发了。这个系列其实是今年初就想写出来的,一方面自己掌握得还不太扎实,另一方面网上的资料有点老了,发出来也算是个可行的参考。

和目前比较主流的其他深度学习框架比起来,torch相对比较小型,做小规模的运算已经足够使用了。再加上安装便捷,文档丰富,用来上手是很合适的。一个问题在于torch基于Lua语言,根本没人用稍微有些冷门,不过年初它被移植到了python生态圈中,框架名为PyTorch(点我进入官网),嗯,火前留名。

大型计算或者抖M建议选择巨坑Caffe/TensorFlow,前者请留出三个工作日时间并做好心理准备来配置它,后者则上手有点麻烦。不过效果当然是值得的。


那么惯例从安装开始

本文基于macOS 10.12.4系统,其他的请参考官网教程

安装过程非常简单,在终端里输入:

1
2
3
git clone https://github.com/torch/distro.git ~/torch --recursive
cd ~/torch; bash install-deps;
./install.sh

安装过程中需要选择PATH的添加位置,根据自己的情况选择~/.bashrc(使用bash)、~/.zshrc(使用zsh)或~/.profile(这两种都不用)即可。

安装完毕后,键入

1
th

如果成功看到了torch的字符画,则安装完成(两次ctrl+C退出)。

LuaRocks是之后最常用到的Lua包管理工具,在这个过程中也已经被安装好了。

为了方便调试,可以考虑安装iTorch

遇到问题需要卸载torch的话,直接移除就可以了:

1
rm -rf ~/torch

Lua语言入门

因为感觉接触torch之前了解Lua的人应该不多,所以这一部分也稍微提及一点。

Lua作为单独的开发语言很少见,一般用于嵌入C/C++应用程序提供扩展。个人觉得是很简洁干净的语言,如果有其他脚本语言的基础,应该很快就能上手。

我最喜欢的一篇基础教程是《Lua for Programmers》,不拖泥带水,阅读起来非常舒服。一共分为四篇,每篇都不长,半小时左右就可以全部阅读完毕。

Part 1: Language Essentials

Part 2: Data and Standard Libraries

Part 3: More Advanced Concepts

Part 4: Tips and Tricks

需要了解的内容也不是很多,个人觉得这些就足够了。


Torch实现XOR问题

接下来就是简单的上手了,来,祭出notebook吧。

XOR是个非常简单又经典的问题,它使用一个含单隐层的双输入单输出网络实现异或问题(异或是非线性可分的,所以需要隐藏层),刚好适合做热身。如果对神经网络的概念不熟悉,比较简单粗暴的理论知识请参考这里

先把用到的库包含进来:

1
2
require 'torch' --torch本体
require 'nn' --神经网络

nn库中有一个容器类Sequential,它可以容纳我们需要的网络结构的基本模块。我们使用Sequential序列初始化构建多层感知器mlp(Multi-Layer Perceptron)。

1
mlp = nn.Sequential();

接下来建立神经网络。两个输入一个输出,三层网络,设定隐藏层包含20个神经元:

1
2
3
4
inputs = 2; outputs = 1; HUs = 20;
mlp.add(nn.Linear(inputs, HUs))
mlp:add(nn.Tanh())
mlp:add(nn.Linear(HUs, outputs))

确定损失函数,这里使用MSECriterion(均方误差标准):

1
criterion = nn.MSECriterion()

接下来就是训练部分了。确定循环次数(此处为5000次),接下来的语句都在循环体内执行。

首先生成训练样本:

1
2
3
4
5
6
7
local input = torch.randn(2); --生成两个正负随机的数值
local output = torch.Tensor(1); --初始化输出
if input[1] * input[2] > 0 then
output[1] = -1
else
output[1] = 1
end

进行前馈:

1
criterion:forward(mlp:forward(input), output)

接下来要把mlp内部的偏导数清零,不清零的话,其值会进行累积。

1
mlp:zeroGradParameters()

反向传播计算偏导数:

1
mlp:backward(input, criterion:backward(mlp.output, output))

更新参数,并反向推导出每个可调参数的偏导数:

1
mlp:updateParameters(0.01)

到这里循环结束。

进行输出测试:

1
2
3
4
5
x = torch.Tensor(2)
x[1] = 0.5; x[2] = 0.5; print(mlp:forward(x))
x[1] = 0.5; x[2] = -0.5; print(mlp:forward(x))
x[1] = -0.5; x[2] = 0.5; print(mlp:forward(x))
x[1] = -0.5; x[2] = -0.5; print(mlp:forward(x))

输出结果为

1
2
3
4
5
6
7
8
9
10
11
-1.0832
[torch.DoubleTensor of size 1]
0.8681
[torch.DoubleTensor of size 1]
0.2170
[torch.DoubleTensor of size 1]
-0.7896
[torch.DoubleTensor of size 1]

可以看出是没有问题的。


参考文献

https://github.com/torch/nn

http://blog.csdn.net/u011534057/article/details/52758818

http://blog.csdn.net/liyaohhh/article/details/50633527