这篇博客是官方Tutorial的翻译(加一丢丢自己的见解吧),原文链接为https://github.com/soumith/cvpr2015/blob/master/Deep%20Learning%20with%20Torch.ipynb

什么是Torch?

Torch是一个基于Lua [JIT]的科学计算框架,具有强大的CPU和CUDA后端。

Torch的优点:

•高效的Tensor库(如NumPy),具有高效的CUDA后端

•神经网络包 - 构建具有自动区分的任意非循环计算图

•还有快速的CUDA和CPU后端

•良好的社区和行业支持 - 数百个社区建立和维护的包。

•易于使用多GPU支持和并行化神经网络

开始之前再说一句

•基于Lua并运行Lua-JIT(即时编译器),速度很快

•Lua非常接近javascript。

•默认情况下,变量是全局变量,除非使用local关键字。全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。

•只有一个内置的数据结构,表,用{}表示。表为哈希表和数组。

•索引从1开始。(啊,好清新脱俗的设定啊)

•foo:bar()与foo.bar(foo)相同

顺便讲下lua的一丢丢语法吧~

-- 单行注释
--[[多行注释多行注释
--]]..  连接两个字符串 如a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。
#   一元运算符,返回字符串或表的长度。    #"Hello" 返回 5

开始

在Torch中,x=torch.funcname(...)与x:funcname(...)是等价的。

字符串,数字,表格

a = 'hello'
print(a)
b = {}
b[1] = a
print(b)
b[2] = 30
for i=1,#b do -- Lua中#操作符表示表的长度print(b[i])
end

Tensor乘法

a = torch.Tensor(5,3) -- 构建一个未初始化的5x3矩阵
a = torch.rand(5,3)
print(a)
b=torch.rand(3,4)
-- 矩阵 - 矩阵乘法:语法1
a*b
-- 矩阵 - 矩阵乘法:语法2
torch.mm(a,b)
-- 矩阵 - 矩阵乘法:语法3
c=torch.Tensor(5,4)
c:mm(a,b) -- 将结果存储在c中

CUDA Tensors
可以使用:cuda函数将tensor移动到GPU上

require 'cutorch';
a = a:cuda()
b = b:cuda()
c = c:cuda()
c:mm(a,b) -- done on GPU

Tensor加法:元素的数量必须匹配,但维度和样式可以不相同。

x = torch.Tensor(2, 2):fill(2) -- 用2填充2*2的矩阵
y = torch.Tensor(4):fill(3)
-- 矩阵加法语法1:将tensor1添加到tensor2并将结果放入res。 元素的数量必须匹配,但维度和样式可以不同
-- torch.add([res], tensor1, tensor2)
x:add(y) -- 将y加到x中,结果存储在x中
-- 矩阵加法语法2:将tensor2的元素乘以标量值并将其添加到tensor1。 元素的数量必须匹配,但维度和样式可以不同
-- torch.add([res,] tensor1, value, tensor2)
x:add(2, y)输出:
> x5  55  5
[torch.DoubleTensor of size 2x2]
> x8  88  8
[torch.DoubleTensor of size 2x2]

神经网络

Torch中的神经网络可以使用nn包构建。

require 'nn';

模块用于构建神经网络。 每个模块都是神经网络,但可以与其他网络使用容器(containers)组合来创建复杂的神经网络。

例如,看看这个分类数字图像的网络:

它是一个简单的前馈网络。
它接受输入,一个接一个地通过几个层输入,然后最终给出输出。

这样的网络容器是nn.Sequential,输入通过几层模块产生输出。

net = nn.Sequential()
net:add(nn.SpatialConvolution(1, 6, 5, 5)) -- 1个输入图像通道,6个输出通道,5x5卷积内核
net:add(nn.ReLU())                       -- 添加非线性激励函数
net:add(nn.SpatialMaxPooling(2,2,2,2))     -- max-pooling操作,寻找2x2窗口中的最大值
net:add(nn.SpatialConvolution(6, 16, 5, 5))
net:add(nn.ReLU())
net:add(nn.SpatialMaxPooling(2,2,2,2))
net:add(nn.View(16*5*5))                    -- 从16x5x5的3维矩阵重塑为16*5*5的1维矩阵
net:add(nn.Linear(16*5*5, 120))             -- 完全连接层(输入和权重之间的矩阵乘法)
net:add(nn.ReLU())
net:add(nn.Linear(120, 84))
net:add(nn.ReLU())
net:add(nn.Linear(84, 10))                   -- 在这个例子中,网络的输出数量是10
net:add(nn.LogSoftMax())                     -- 将输出转换为对数概率,以助于分类
print('Lenet5\n' .. net:__tostring());

nn容器的其他示例如下图所示:

torch中的每个神经网络模块都具有一个前向和后向函数。forward(输入)函数,用于计算给定输入的输出,使输入通过网络流动。 backward(输入,梯度)函数,它将根据传入的梯度区分网络中的每个神经元。这是通过链规则完成的。

input = torch.rand(1,32,32) -- 传递随机矩阵作为网络的输入
output = net:forward(input)
print(output)
net:zeroGradParameters() -- 使网络的内部梯度缓冲区归零(稍后会介绍)
gradInput = net:backward(input, torch.rand(10))
print(#gradInput)

损失函数

当你在训练让一个模型时,你会通过反馈知道它做得如何。客观度量模型性能的函数称为损失函数。

典型的损失函数接受模型的输出和分类准确性,并计算一个量化模型性能的值。

然后,该模型纠正自己以使得损失变小。

在torch中,损失函数就像神经网络模块一样实现,它们有两个功能 - 前向(输入,目标),后向(输入,目标)

例如:

criterion = nn.ClassNLLCriterion() -- 多分类的负对数似然准则
criterion:forward(output, 3) -- 实际分类的编号:3
gradients = criterion:backward(output, 3)
gradInput = net:backward(input, gradients)

回顾一下目前说过的内容

•网络可以有多层
•网络在正向传播中接收输入并产生输出
•损失函数,也即torch的评价模块(criterion)计算网络的损失及与输出有关的梯度。
•网络在其反向传递中采用(输入,梯度)对,并计算关于网络中每个层(和神经元)的梯度。

细节补充——神经网络层可以具有可学习的参数。

卷积层通过学习来适应输入数据和要解决的问题。
最大池层没有可学习的参数。 它只是寻找本地窗口中的最大值。

torch中具有可学习的权重通常包含.weight(以及可选的.bias)

m = nn.SpatialConvolution(1,3,2,2) -- 3个2x2内核
print(m.weight) -- 权重是随机初始化的
print(m.bias) -- 卷积层中的操作是:输出=卷积层(输入,权重)+偏差

学习层中还有另外两个重要字段, gradWeight和gradBias。 gradWeight积累每个权重的梯度,gradBias记录每个偏差。

培训网络

为了让网络自行调整,随机梯度下降通常会执行以下操作:

weight = weight + learningRate * gradWeight [等式1]

随着时间的推移,这种更新将调整网络权重,使损失函数变少。

好的,现在是时候讨论一个问题:是谁访问神经网络中的每一层并根据公式1更新权重?

这个问题有多个答案,但我们将使用最简单的答案。
我们将使用神经网络模块附带的简单SGD训练器:nn.StochasticGradient。

它有一个功能:在给定数据集数据集上进行训练网络,并显示数据集的不同样本是如何影响网络的变化。

关于数据

通常,当您必须处理图像,文本,音频或视频数据时,您可以通过使用标准函数(如image.load或audio.load)方便地将数据加载到torch.Tensor或Lua表中。

现在让我们使用一些简单的数据来训练我们的网络。

我们将使用CIFAR-10数据集,它的标签种类有以下几种:'飞机','汽车','鸟','猫','鹿','狗','青蛙','马','船', '卡车'。
CIFAR-10中的图像尺寸为3×32×32,即尺寸为32×32像素的3通道彩色图像。

该数据集共有50,000个训练图像和10,000个测试图像。

我们现在需要5个步骤来训练我们第一个torch神经网络

1、加载和规范化数据
2、定义神经网络
3、定义损失函数
4、训练网络
5、测试网络

1、加载和标准化数据

今天,为了节省时间,我们事先准备好数据到4D torch ByteTensor,大小为50000x3x32x32(训练数据)和10000x3x32x32(测试数据)。让我们加载数据并进行检查。(不知道是官方数据写错了还是咋的,我两个数据集大小都是10000)

require 'paths'
if (not paths.filep("cifar10torchsmall.zip")) thenos.execute('wget -c https://s3.amazonaws.com/torch7/data/cifar10torchsmall.zip')os.execute('unzip cifar10torchsmall.zip')
end
trainset = torch.load('cifar10-train.t7')
testset = torch.load('cifar10-test.t7')
classes = {'airplane', 'automobile', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck'}
print(trainset)
print(#trainset.data)

让我们显示一个图像:

itorch.image(trainset.data[100]) -- 显示数据集中的第100个图像
print(classes[trainset.label[100]])

在这里本人踩了一大个坑(悲惨过程),原本我是在sublime上运行的,跑的这步的时候说没有itorch,按官网装了itorch又说没image。最后搜了以下有大大说这个得在notebook上运行,在jupyter上配lua的环境即可(配置教程)。

要在nn.StochasticGradient中使用数据集,必须根据其文档对数据集进行一番处理。

1、数据集必须具有:函数size()
2、数据集必须具有[i]索引,以便通过dataset[i]来操作datset中的第i个样本。
两者都可以快速完成:

-- 可以暂且忽略setmetatable,它是超出本教程范围的功能。 setmetatable的功能是设置索引运算符。
setmetatable(trainset, {__index = function(t, i) return {t.data[i], t.label[i]} end}
);
trainset.data = trainset.data:double() -- 将数据从ByteTensor转换为DoubleTensor。
function trainset:size() return self.data:size(1)
end
print(trainset:size()) -- 小小测试一下
print(trainset[33]) -- 加载样本号33
itorch.image(trainset[33][1])

在处理数据(通常在数据科学或机器学习)中,我们可以做的最重要的事情之一是使数据的平均值为0.0,标准偏差为1.0。

在我们数据处理的最后一步也来这么做吧。

为此,我们通过下面例子进行向您具体介绍tensor索引运算符:

redChannel = trainset.data[{ {}, {1}, {}, {}  }] -- 因为traindata.set是四维大小分别是{10000,3,32,32}的tensor
-- 因此该索引对应的内容是{所有图像,第一个通道,所有垂直像素,所有水平像素}
print(#redChannel)

在索引运算符中,以[{}]开头可以对tensor各维的元素进行分开操作。 您可以使用{}选择维度中的所有元素,或使用{i}选择特定元素,其中i是元素索引。 还可以使用{i1,i2}选择一区间的元素,例如{3,5}选择第3,4,5个元素。

练习:选择第150~300的数据

sel = trainset.data[{ {150,300}, {}, {}, {}  }]
-- 输出图像
for i=1,151,1 doitorch.image(sel[i])
end

回到标准化处理,使用我们在上面学到的索引操作符来完成此操作很简单。

mean = {} -- 存储均值,以便将来测试集标准化
stdv  = {} -- 存储偏差
for i=1,3 do -- 在每个图像颜色通道上mean[i] = trainset.data[{ {}, {i}, {}, {}  }]:mean() -- 均值print('Channel ' .. i .. ', Mean: ' .. mean[i])trainset.data[{ {}, {i}, {}, {}  }]:add(-mean[i]) -- 减去均值stdv[i] = trainset.data[{ {}, {i}, {}, {}  }]:std() -- 标准差print('Channel ' .. i .. ', Standard Deviation: ' .. stdv[i])trainset.data[{ {}, {i}, {}, {}  }]:div(stdv[i]) -- 除以标准差
end

现在训练数据已归一化并可随时使用。

2.定义神经网络

修改上文的神经网络使它可以接收3通道图像(而不是定义的1通道图像)。

net = nn.Sequential()
net:add(nn.SpatialConvolution(3, 6, 5, 5)) -- 3个图像输入通道,6个输出通道, 5x5卷积核
net:add(nn.ReLU())                       -- 添加非线性激励函数
net:add(nn.SpatialMaxPooling(2,2,2,2))     -- max-pooling操作,寻找2x2窗口中的最大值
net:add(nn.SpatialConvolution(6, 16, 5, 5))
net:add(nn.ReLU())
net:add(nn.SpatialMaxPooling(2,2,2,2))
net:add(nn.View(16*5*5))                    -- 从16x5x5的3维矩阵重塑为16*5*5的1维矩阵
net:add(nn.Linear(16*5*5, 120))             -- 完全连接层(输入和权重之间的矩阵乘法)
net:add(nn.ReLU())
net:add(nn.Linear(120, 84))
net:add(nn.ReLU())
net:add(nn.Linear(84, 10))                   -- 在这个例子中,网络的输出数量是10
net:add(nn.LogSoftMax())                     -- 将输出转换为对数概率,以助于分类

3.定义损失函数

让我们使用对数似然分类损失函数,这适合大多数分类问题。

criterion = nn.ClassNLLCriterion()

4.训练神经网络

事情现在开始变得有趣了。
我们首先定义一个nn.StochasticGradient对象。 然后我们将数据集提供给这个对象的函数:train(),这将使训练自动开始。

trainer = nn.StochasticGradient(net, criterion)
trainer.learningRate = 0.001
trainer.maxIteration = 5 -- 只做5轮训练
trainer:train(trainset)

5.测试网络,输出准确性

我们已经在训练数据集上训练了5轮,但我们需要检查网络是否已经学到了什么。我们将通过神经网络分类的情况与实际标签进行检查。 如果预测正确,我们将样本添加到正确预测列表中。

好的,第一步, 让我们从测试集中显示一个图像开始。

print(classes[testset.label[100]])
itorch.image(testset.data[100])

现在让我们使用训练数据的均值和标准偏差来规范化测试数据。

testset.data = testset.data:double()   -- 将数据从ByteTensor转换为DoubleTensor。
for i=1,3 do -- over each image channeltestset.data[{ {}, {i}, {}, {}  }]:add(-mean[i]) -- 减去均值   testset.data[{ {}, {i}, {}, {}  }]:div(stdv[i]) -- 除以标准差
end
-- 输出第100个样本的均值和标准差
horse = testset.data[100]
print(horse:mean(), horse:std())

好的,现在让我们看看神经网络的分类结果:

print(classes[testset.label[100]])
itorch.image(testset.data[100])
predicted = net:forward(testset.data[100])
-- 网络的输出是概率的对数, 要将它们转换为概率,必须采用e^x
print(predicted:exp())

您可以看到网络预测。 在给定图像的情况下,网络为每个类分配概率。

为了更清楚显示,让我们用其类名标记每个概率:

for i=1,predicted:size(1) doprint(classes[i], predicted[i])
end

一个样本可能很糟糕,让我们看看一个测试集中总共有多少是正确的?

correct = 0
for i=1,10000 dolocal groundtruth = testset.label[i]local prediction = net:forward(testset.data[i])local confidences, indices = torch.sort(prediction, true)  -- true表示按降序排序if groundtruth == indices[1] thencorrect = correct + 1end
end
print(correct, 100*correct/10000 .. ' % ')

看起来这大大好于随机,毕竟随机是10%的准确性(从10个类中随机挑选一个类)。 神经网络似乎学到了一些东西。

嗯,让我们看看10个类中哪些表现好,哪些表现差:

class_performance = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
for i=1,10000 dolocal groundtruth = testset.label[i]local prediction = net:forward(testset.data[i])local confidences, indices = torch.sort(prediction, true)  -- true表示按降序排序if groundtruth == indices[1] thenclass_performance[groundtruth] = class_performance[groundtruth] + 1end
end
for i=1,#classes doprint(classes[i], 100*class_performance[i]/1000 .. ' %')
end

好的,接下来呢? 我们如何在GPU上运行这个神经网络?

cunn:使用CUDA的GPU上的神经网络

require 'cunn';

这个想法非常简单。 使用神经网络,并将其转移到GPU:

net = net:cuda()

此外,将损失函数转移到GPU:

criterion = criterion:cuda()

接下来是数据:

trainset.data = trainset.data:cuda()
trainset.label = trainset.label:cuda()

好吧,让我们在GPU上训练。

trainer = nn.StochasticGradient(net, criterion)
trainer.learningRate = 0.001
trainer.maxIteration = 5 -- 只训练5轮
trainer:train(trainset)

因为目前示例的网络很小,所以不考虑与CPU相比的MASSIVE加速。

Torch深度学习的60分钟教程(翻译)相关推荐

  1. PyTorch深度学习:60分钟闪电战

    使用PYTORCH进行深度学习:60分钟的闪电战 本教程的目标: 全面了解PyTorch的Tensor库和神经网络. 训练一个小型神经网络对图像进行分类 请确保您有 torch 和 torchvisi ...

  2. PyTorch深度学习:60分钟入门(Translation)

    这是https://zhuanlan.zhihu.com/p/25572330的学习笔记. Tensors Tensors和numpy中的ndarrays较为相似, 因此Tensor也能够使用GPU来 ...

  3. Torch7系列教程之Torch深度学习库教程(一)

    Torch7深度学习库教程 写在前面的话 torch库 1 Tensor库 1.1 Tensor数据使用简介 1.2 Tensor构造函数 1.3 作用于Torch上的一些操作函数 2 Storage ...

  4. 什么是深度学习?45分钟理解深度神经网络和深度学习 刘利刚教授

    什么是深度学习? - 45分钟理解深度神经网络和深度学习 刘利刚 中国科学技术大学图形与几何计算实验室 http://staff.ustc.edu.cn/~lgliu [绪言] 近年来,人工智能(Ar ...

  5. torch 深度学习(3)

    torch 深度学习(3) 损失函数,模型训练 前面我们已经完成对数据的预处理和模型的构建,那么接下来为了训练模型应该定义模型的损失函数,然后使用BP算法对模型参数进行调整 损失函数 Criterio ...

  6. 深度学习与自然语言处理教程(8) - NLP中的卷积神经网络(NLP通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://www.showmeai.tech/article-d ...

  7. 深度学习与自然语言处理教程(4) - 句法分析与依存解析(NLP通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://www.showmeai.tech/article-d ...

  8. 深度学习与自然语言处理教程(5) - 语言模型、RNN、GRU与LSTM(NLP通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://www.showmeai.tech/article-d ...

  9. 深度学习与自然语言处理教程(3) - 神经网络与反向传播(NLP通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/36 本文地址:https://www.showmeai.tech/article-d ...

最新文章

  1. ajax技术运用案例,第12篇:Ajax技术与项目案例
  2. 【计算机网络】计算机网络概述 : 总结 ( 概念 | 组成 | 功能 | 分类 | 性能指标 | OSI 七层参考模型 | TCP/IP 模型 | 五层参考模型 )★★★
  3. 《JAVA与模式》之建造模式
  4. stm32 无符号整形_STM32中“unsigned short”和“unsigned int”的区别是什么?
  5. c++ memset 语言_C++中memset函数用法详解
  6. 小米功能机支持java吗_小米竟然卖功能机了!2.8吋/15天超长待机
  7. 面向对象的程序开发技术C++教学课件系列之二
  8. Laravel源码解析之Console内核
  9. 【数据结构和算法笔记】:广义表
  10. Redis入门到高可用(十一)—— 慢查询
  11. java中PrepareStatement使用的一点小问题
  12. ​知者见于未萌:百度CTO王海峰与中国 AI 三十年
  13. 百度商业推广php,百度“知心搜索”,背后商业协议
  14. Java Http请求工具类
  15. NIVIDIA Xavier联网问题
  16. DEA数据包络分析----(投入、中间变量及产出)分期望与非期望讨论第一篇
  17. java自行车DH32,中国国际自行车嘉年华之Enduro、DH装备篇
  18. LLC谐振变换器学习 一
  19. Halcon示例程序Circle 解析
  20. H3C SE 教程笔记——构建安全优化的广域网(上)

热门文章

  1. java如何开发webservice接口
  2. 我们这一代人的困惑 - 转载
  3. 如何实现分库分表?怎么配置?
  4. 【CodeForces 1260E --- Tournament】
  5. 《Java语言程序设计与数据结构》编程练习答案(第四章)(一)
  6. asp.net ajax1.0基础回顾(三):UpdatePanel的基本用法
  7. PS Suite Studio Android 调试方法
  8. 全国青少年软件编程等级考试内容,知识点思维导图(Scratch编程四级)
  9. 华为音乐APP提示网络忙无法连接
  10. 关于时间戳和标准时间、国际标准时间的一些方法