Deep Learning with PyTorch pdf 下载
可以直接下载
也分享到了 PyTorch 交流群群文件
群号:518428276
PyTorch 入门教程
Deep Learning with PyTorch pdf 下载
可以直接下载
也分享到了 PyTorch 交流群群文件
群号:518428276
为了更加方便深度学习爱好者进行学习,磐创AI 推出了视频教程,视频教程首先覆盖了 60 分钟快速入门部分,方便快速的上手,视频教程的定位是简洁清晰,以下是视频内容的介绍。点击开始学习!
https://study.163.com/course/introduction/1209483828.htm
手机版网页,限时 5元优惠券。
https://m.study.163.com/m/provider/480000001931488/index.htm
PyTorch 中文版官方教程来了。
PyTorch 是近年来较为火爆的深度学习框架,然而其中文版官方教程久久不来。近日,一款完整的 PyTorch 中文版官方教程出炉,读者朋友可以更好的学习了解 PyTorch 的相关细节了。教程作者来自 pytorchchina.com。
教程网站:http://pytorch123.com
教程里有什么
教程根据 PyTorch 官方版本目录,完整地还原了所有的内容。包括简单的环境搭建、快速入门相关 API、高级操作、图像处理实战、文本处理实战、GAN 和强化学习等,基本涵盖了目前所有深度学习相关的知识点。
教程的一部分内容,使用 torch.view 改变 tensor 的大小或形状
用教程设计一个聊天机器人,以上为部分对话。
教程目录
PyTorch 之简介与下载
原文链接:https://www.jiqizhixin.com/articles/2019-09-02-8
官方教程包含了 PyTorch 介绍,安装教程; 60 分钟快速入门教程,可以迅速从小白阶段完成一个分类器模型;计算机视觉常用模型,方便基于自己的数据进行调整,不再需要从头开始写;自然语言处理模型,聊天机器人,文本生成等生动有趣的项目。
总而言之: 如果你想了解一下 PyTorch,可以看介绍部分。
如果你想快速入门 PyTorch,可以看 60 分钟快速入门。
如果你想解决计算机视觉问题,可以看计算机视觉部分。
如果你想解决自然语言处理问题,可以看 NLP 部分。
后续会更新强化学习和生成对抗网络部分内容。
作者:磐创 AI pytorch 翻译小组: News & Panchuang
PyTorch 入门教程:http://pytorch123.com/
第一章:PyTorch 之简介与下载
1.PyTorch 简介
2.PyTorch 环境搭建
第二章:PyTorch 之 60min 入门
1.PyTorch 入门
2.PyTorch 自动微分
3.PyTorch 神经网络
4.PyTorch 图像分类器
5.PyTorch 数据并行处理
第三章:PyTorch 之入门强化
1.数据加载和处理
2.PyTorch 小试牛刀
3.迁移学习
4.混合前端的 seq2seq 模型部署
5.保存和加载模型
第四章:PyTorch 之图像篇
1.微调基于 torchvision 0.3 的目标检测模型
2.微调 TorchVision 模型
3.空间变换器网络
4.使用 PyTorch 进行 Neural-Transfer
5.生成对抗示例
6.使用 ONNX 将模型转移至 Caffe2 和移动端
第五章:PyTorch 之文本篇
1.聊天机器人教程
2.使用字符级 RNN 生成名字
3.使用字符级 RNN 进行名字分类
4.在深度学习和 NLP 中使用 Pytorch
5.使用 Sequence2Sequence 网络和注意力进行翻译
第六章:PyTorch 之生成对抗网络
第七章:PyTorch 之强化学习
GitHub 仓库,欢迎 Star,Fork
https://github.com/fendouai/PyTorchDocs
相较于目前Tensorflow类型的书籍已经烂大街的状况,PyTorch类的书籍目前已出版的并没有那么多,笔者给大家推荐我认为还不错的四本PyTorch书籍。
前言:译者实测 PyTorch 代码非常简洁易懂,只需要将中文分词的数据集预处理成作者提到的格式,即可很快的就迁移了这个代码到中文分词中,相关的代码后续将会分享。
Pytorch是一个动态神经网络工具包。 动态工具包的另一个例子是Dynet(我之所以提到这一点,因为与Pytorch和Dynet的工作方式类似。如果你在Dynet中看到一个例子,它可能会帮助你在Pytorch中实现它)。 相反的是静态工具包,包括Theano,Keras,TensorFlow等。核心区别如下:
动态工具包还有一个优点,那就是更容易调试,代码更像主机语言(我的意思是pytorch和dynet看起来更像实际的python代码,而不是keras或theano)。
对于本节,我们将看到用于命名实体识别的Bi-LSTM条件随机场的完整复杂示例。 上面的LSTM标记符通常足以用于词性标注,但是像CRF这样的序列模型对于NER上的强大性能非常重要。 假设熟悉CRF。 虽然这个名字听起来很可怕,但所有模型都是CRF,但是LSTM提供了特征。 这是一个高级模型,比本教程中的任何早期模型复杂得多。
下面的例子在 log 空间中实现了计算微分函数的正向算法,以及要解码的维特比算法。反向传播将自动为我们计算梯度。我们不必用手做任何事。
这个算法用来演示,没有优化。如果您了解正在发生的事情,您可能会很快看到,在转发算法中迭代下一个标记可能是在一个大型操作中完成的。我想用代码来提高可读性。如果你想做相关的改变,你可以用这个标记器来完成真正的任务。
# Author: Robert Guthrie import torch import torch.autograd as autograd import torch.nn as nn import torch.optim as optim torch.manual_seed(1)
帮助程序函数,使代码更具可读性。
def argmax(vec): # return the argmax as a python int _, idx = torch.max(vec, 1) return idx.item() def prepare_sequence(seq, to_ix): idxs = [to_ix[w] for w in seq] return torch.tensor(idxs, dtype=torch.long) # Compute log sum exp in a numerically stable way for the forward algorithm def log_sum_exp(vec): max_score = vec[0, argmax(vec)] max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1]) return max_score + \ torch.log(torch.sum(torch.exp(vec - max_score_broadcast)))
创建模型
class BiLSTM_CRF(nn.Module): def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim): super(BiLSTM_CRF, self).__init__() self.embedding_dim = embedding_dim self.hidden_dim = hidden_dim self.vocab_size = vocab_size self.tag_to_ix = tag_to_ix self.tagset_size = len(tag_to_ix) self.word_embeds = nn.Embedding(vocab_size, embedding_dim) self.lstm = nn.LSTM(embedding_dim, hidden_dim // 2, num_layers=1, bidirectional=True) # Maps the output of the LSTM into tag space. self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size) # Matrix of transition parameters. Entry i,j is the score of # transitioning *to* i *from* j. self.transitions = nn.Parameter( torch.randn(self.tagset_size, self.tagset_size)) # These two statements enforce the constraint that we never transfer # to the start tag and we never transfer from the stop tag self.transitions.data[tag_to_ix[START_TAG], :] = -10000 self.transitions.data[:, tag_to_ix[STOP_TAG]] = -10000 self.hidden = self.init_hidden() def init_hidden(self): return (torch.randn(2, 1, self.hidden_dim // 2), torch.randn(2, 1, self.hidden_dim // 2)) def _forward_alg(self, feats): # Do the forward algorithm to compute the partition function init_alphas = torch.full((1, self.tagset_size), -10000.) # START_TAG has all of the score. init_alphas[0][self.tag_to_ix[START_TAG]] = 0. # Wrap in a variable so that we will get automatic backprop forward_var = init_alphas # Iterate through the sentence for feat in feats: alphas_t = [] # The forward tensors at this timestep for next_tag in range(self.tagset_size): # broadcast the emission score: it is the same regardless of # the previous tag emit_score = feat[next_tag].view( 1, -1).expand(1, self.tagset_size) # the ith entry of trans_score is the score of transitioning to # next_tag from i trans_score = self.transitions[next_tag].view(1, -1) # The ith entry of next_tag_var is the value for the # edge (i -> next_tag) before we do log-sum-exp next_tag_var = forward_var + trans_score + emit_score # The forward variable for this tag is log-sum-exp of all the # scores. alphas_t.append(log_sum_exp(next_tag_var).view(1)) forward_var = torch.cat(alphas_t).view(1, -1) terminal_var = forward_var + self.transitions[self.tag_to_ix[STOP_TAG]] alpha = log_sum_exp(terminal_var) return alpha def _get_lstm_features(self, sentence): self.hidden = self.init_hidden() embeds = self.word_embeds(sentence).view(len(sentence), 1, -1) lstm_out, self.hidden = self.lstm(embeds, self.hidden) lstm_out = lstm_out.view(len(sentence), self.hidden_dim) lstm_feats = self.hidden2tag(lstm_out) return lstm_feats def _score_sentence(self, feats, tags): # Gives the score of a provided tag sequence score = torch.zeros(1) tags = torch.cat([torch.tensor([self.tag_to_ix[START_TAG]], dtype=torch.long), tags]) for i, feat in enumerate(feats): score = score + \ self.transitions[tags[i + 1], tags[i]] + feat[tags[i + 1]] score = score + self.transitions[self.tag_to_ix[STOP_TAG], tags[-1]] return score def _viterbi_decode(self, feats): backpointers = [] # Initialize the viterbi variables in log space init_vvars = torch.full((1, self.tagset_size), -10000.) init_vvars[0][self.tag_to_ix[START_TAG]] = 0 # forward_var at step i holds the viterbi variables for step i-1 forward_var = init_vvars for feat in feats: bptrs_t = [] # holds the backpointers for this step viterbivars_t = [] # holds the viterbi variables for this step for next_tag in range(self.tagset_size): # next_tag_var[i] holds the viterbi variable for tag i at the # previous step, plus the score of transitioning # from tag i to next_tag. # We don't include the emission scores here because the max # does not depend on them (we add them in below) next_tag_var = forward_var + self.transitions[next_tag] best_tag_id = argmax(next_tag_var) bptrs_t.append(best_tag_id) viterbivars_t.append(next_tag_var[0][best_tag_id].view(1)) # Now add in the emission scores, and assign forward_var to the set # of viterbi variables we just computed forward_var = (torch.cat(viterbivars_t) + feat).view(1, -1) backpointers.append(bptrs_t) # Transition to STOP_TAG terminal_var = forward_var + self.transitions[self.tag_to_ix[STOP_TAG]] best_tag_id = argmax(terminal_var) path_score = terminal_var[0][best_tag_id] # Follow the back pointers to decode the best path. best_path = [best_tag_id] for bptrs_t in reversed(backpointers): best_tag_id = bptrs_t[best_tag_id] best_path.append(best_tag_id) # Pop off the start tag (we dont want to return that to the caller) start = best_path.pop() assert start == self.tag_to_ix[START_TAG] # Sanity check best_path.reverse() return path_score, best_path def neg_log_likelihood(self, sentence, tags): feats = self._get_lstm_features(sentence) forward_score = self._forward_alg(feats) gold_score = self._score_sentence(feats, tags) return forward_score - gold_score def forward(self, sentence): # dont confuse this with _forward_alg above. # Get the emission scores from the BiLSTM lstm_feats = self._get_lstm_features(sentence) # Find the best path, given the features. score, tag_seq = self._viterbi_decode(lstm_feats) return score, tag_seq
开始训练
START_TAG = "<START>" STOP_TAG = "<STOP>" EMBEDDING_DIM = 5 HIDDEN_DIM = 4 # Make up some training data training_data = [( "the wall street journal reported today that apple corporation made money".split(), "B I I I O O O B I O O".split() ), ( "georgia tech is a university in georgia".split(), "B I O O O O B".split() )] word_to_ix = {} for sentence, tags in training_data: for word in sentence: if word not in word_to_ix: word_to_ix[word] = len(word_to_ix) tag_to_ix = {"B": 0, "I": 1, "O": 2, START_TAG: 3, STOP_TAG: 4} model = BiLSTM_CRF(len(word_to_ix), tag_to_ix, EMBEDDING_DIM, HIDDEN_DIM) optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4) # Check predictions before training with torch.no_grad(): precheck_sent = prepare_sequence(training_data[0][0], word_to_ix) precheck_tags = torch.tensor([tag_to_ix[t] for t in training_data[0][1]], dtype=torch.long) print(model(precheck_sent)) # Make sure prepare_sequence from earlier in the LSTM section is loaded for epoch in range( 300): # again, normally you would NOT do 300 epochs, it is toy data for sentence, tags in training_data: # Step 1. Remember that Pytorch accumulates gradients. # We need to clear them out before each instance model.zero_grad() # Step 2. Get our inputs ready for the network, that is, # turn them into Tensors of word indices. sentence_in = prepare_sequence(sentence, word_to_ix) targets = torch.tensor([tag_to_ix[t] for t in tags], dtype=torch.long) # Step 3. Run our forward pass. loss = model.neg_log_likelihood(sentence_in, targets) # Step 4. Compute the loss, gradients, and update the parameters by # calling optimizer.step() loss.backward() optimizer.step() # Check predictions after training with torch.no_grad(): precheck_sent = prepare_sequence(training_data[0][0], word_to_ix) print(model(precheck_sent)) # We got it!
输出
(tensor(2.6907), [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1]) (tensor(20.4906), [0, 1, 1, 1, 2, 2, 2, 0, 1, 2, 2])
我们没有必要在进行解码时创建计算图,因为我们不会从维特比路径得分反向传播。 因为无论如何我们都有它,尝试训练标记器,其中损失函数是维特比路径得分和测试标准路径得分之间的差异。 应该清楚的是,当预测的标签序列是正确的标签序列时,该功能是非负的和0。 这基本上是结构感知器。
由于已经实现了 Viterbi 和score_sentence ,因此这种修改应该很短。 这是取决于训练实例的计算图形的示例。 虽然我没有尝试在静态工具包中实现它,但我想它可能但不那么直截了当。
拿起一些真实数据并进行比较!
原文链接:https://pytorch.org/tutorials/beginner/nlp/advanced_tutorial.html#advanced-making-dynamic-decisions-and-the-bi-lstm-crf
概述
PyText 是一个基于 PyTorch 实现的 NLP 框架。PyText 解决了实现快速实验和在规模部署服务模型的冲突。它通过为模型组件提供简单和可扩展的接口和抽象,以及使用通过 PyTorch 优化的 Caffe2 执行引擎可以导出用于推断的模型的能力,来实现这一点。我们使用 Facebook 中的 PyText 来快速迭代新的建模思想,然后无缝地将它们弹性发布。
PyText 核心特性:
各种生产就绪模型的 NLP/NLU 任务:
文本分类器
Yoon Kim (2014): Convolutional Neural Networks for Sentence Classification
Lin et al. (2017): A Structured Self-attentive Sentence Embedding
序列标记符
Lample et al. (2016): Neural Architectures for Named Entity Recognition
联合意图时隙模型
Zhang et al. (2016): A Joint Model of Intent Determination and Slot Filling for Spoken Language Understanding
上下文意图槽模型
支持建立在 PyTorch 1.0 上新的 C10d 后端分布式训练
可扩展组件,允许轻松创建新模型和任务
参考实现和论文的预训练模型:Gupta et al. (2018): Semantic Parsing for Task Oriented Dialog using Hierarchical Representations
增强培训支持
安装 PyText
要开始使用云虚拟机,请查看我们的指南:https://pytext-pytext.readthedocs-hosted.com/en/latest/installation.html#cloud-vm-setup
我们建议使用 virtualenv:
$ python3 -m venv pytext_venv
$ source pytext_venv/bin/activate
(pytext_venv) $ pip install pytext-nlp
详细说明和更多的安装选项可以在我们的文档(https://pytext-pytext.readthedocs-hosted.com/en/latest/installation.html)中找到。如果在安装过程中遇到缺少依赖项的问题,请参考OS(https://pytext-pytext.readthedocs-hosted.com/en/latest/installation.html#os-dependencies)依赖项。
训练第一个文本分类器
对于第一个例子,我们将使用基于 CNN 的文本分类器,我们将使用 tests/data/train_data_tiny.tsv。可以通过克隆存储库或通过从GitHub手动下载文件来获得数据和配置文件。
(venv)$pytext.
神经网络
神经网络可以通过 torch.nn 包来构建。
现在对于自动梯度(autograd)有一些了解,神经网络是基于自动梯度 (autograd)来定义一些模型。一个 nn.Module 包括层和一个方法 forward(input) 它会返回输出(output)。
例如,看一下数字图片识别的网络:
这是一个简单的前馈神经网络,它接收输入,让输入一个接着一个的通过一些层,最后给出输出。
一个典型的神经网络训练过程包括以下几点:
1.定义一个包含可训练参数的神经网络
2.迭代整个输入
3.通过神经网络处理输入
4.计算损失(loss)
5.反向传播梯度到神经网络的参数
6.更新网络的参数,典型的用一个简单的更新方法:weight = weight – learning_rate *gradient
定义神经网络
import torch import torch.nn as nn import torch.nn.functional as F class Net(nn.Module): def __init__(self): super(Net, self).__init__() # 1 input image channel, 6 output channels, 5x5 square convolution # kernel self.conv1 = nn.Conv2d(1, 6, 5) self.conv2 = nn.Conv2d(6, 16, 5) # an affine operation: y = Wx + b self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): # Max pooling over a (2, 2) window x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # If the size is a square you can only specify a single number x = F.max_pool2d(F.relu(self.conv2(x)), 2) x = x.view(-1, self.num_flat_features(x)) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x def num_flat_features(self, x): size = x.size()[1:] # all dimensions except the batch dimension num_features = 1 for s in size: num_features *= s return num_features net = Net() print(net)
输出:
Net( (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1)) (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1)) (fc1): Linear(in_features=400, out_features=120, bias=True) (fc2): Linear(in_features=120, out_features=84, bias=True) (fc3): Linear(in_features=84, out_features=10, bias=True) )
你刚定义了一个前馈函数,然后反向传播函数被自动通过 autograd 定义了。你可以使用任何张量操作在前馈函数上。
一个模型可训练的参数可以通过调用 net.parameters() 返回:
params = list(net.parameters()) print(len(params)) print(params[0].size()) # conv1's .weight
输出:
10 torch.Size([6, 1, 5, 5])
让我们尝试随机生成一个 32×32 的输入。注意:期望的输入维度是 32×32 。为了使用这个网络在 MNIST 数据及上,你需要把数据集中的图片维度修改为 32×32。
input = torch.randn(1, 1, 32, 32) out = net(input) print(out)
输出:
tensor([[-0.0233, 0.0159, -0.0249, 0.1413, 0.0663, 0.0297, -0.0940, -0.0135, 0.1003, -0.0559]], grad_fn=<AddmmBackward>)
把所有参数梯度缓存器置零,用随机的梯度来反向传播
net.zero_grad() out.backward(torch.randn(1, 10))
在继续之前,让我们复习一下所有见过的类。
torch.Tensor – A multi-dimensional array with support for autograd operations like backward(). Also holds the gradient w.r.t. the tensor.
nn.Module – Neural network module. Convenient way of encapsulating parameters, with helpers for moving them to GPU, exporting, loading, etc.
nn.Parameter – A kind of Tensor, that is automatically registered as a parameter when assigned as an attribute to a Module.
autograd.Function – Implements forward and backward definitions of an autograd operation. Every Tensor operation, creates at least a single Function node, that connects to functions that created a Tensor and encodes its history.
在此,我们完成了:
1.定义一个神经网络
2.处理输入以及调用反向传播
还剩下:
1.计算损失值
2.更新网络中的权重
损失函数
一个损失函数需要一对输入:模型输出和目标,然后计算一个值来评估输出距离目标有多远。
有一些不同的损失函数在 nn 包中。一个简单的损失函数就是 nn.MSELoss ,这计算了均方误差。
例如:
output = net(input) target = torch.randn(10) # a dummy target, for example target = target.view(1, -1) # make it the same shape as output criterion = nn.MSELoss() loss = criterion(output, target) print(loss)
输出:
tensor(1.3389, grad_fn=<MseLossBackward>)
现在,如果你跟随损失到反向传播路径,可以使用它的 .grad_fn 属性,你将会看到一个这样的计算图:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d -> view -> linear -> relu -> linear -> relu -> linear -> MSELoss -> loss
所以,当我们调用 loss.backward(),整个图都会微分,而且所有的在图中的requires_grad=True 的张量将会让他们的 grad 张量累计梯度。
为了演示,我们将跟随以下步骤来反向传播。
print(loss.grad_fn) # MSELoss print(loss.grad_fn.next_functions[0][0]) # Linear print(loss.grad_fn.next_functions[0][0].next_functions[0][0]) # ReLU
输出:
<MseLossBackward object at 0x7fab77615278> <AddmmBackward object at 0x7fab77615940> <AccumulateGrad object at 0x7fab77615940>
反向传播
为了实现反向传播损失,我们所有需要做的事情仅仅是使用 loss.backward()。你需要清空现存的梯度,要不然帝都将会和现存的梯度累计到一起。
现在我们调用 loss.backward() ,然后看一下 con1 的偏置项在反向传播之前和之后的变化。
net.zero_grad() # zeroes the gradient buffers of all parameters print('conv1.bias.grad before backward') print(net.conv1.bias.grad) loss.backward() print('conv1.bias.grad after backward') print(net.conv1.bias.grad)
输出:
conv1.bias.grad before backward tensor([0., 0., 0., 0., 0., 0.]) conv1.bias.grad after backward tensor([-0.0054, 0.0011, 0.0012, 0.0148, -0.0186, 0.0087])
现在我们看到了,如何使用损失函数。
唯一剩下的事情就是更新神经网络的参数。
更新神经网络参数:
最简单的更新规则就是随机梯度下降。
weight = weight - learning_rate * gradient
我们可以使用 python 来实现这个规则:
learning_rate = 0.01 for f in net.parameters(): f.data.sub_(f.grad.data * learning_rate)
尽管如此,如果你是用神经网络,你想使用不同的更新规则,类似于 SGD, Nesterov-SGD, Adam, RMSProp, 等。为了让这可行,我们建立了一个小包:torch.optim 实现了所有的方法。使用它非常的简单。
import torch.optim as optim # create your optimizer optimizer = optim.SGD(net.parameters(), lr=0.01) # in your training loop: optimizer.zero_grad() # zero the gradient buffers output = net(input) loss = criterion(output, target) loss.backward() optimizer.step() # Does the update
下载 Python 源代码:
下载 Jupyter 源代码:
你已经了解了如何定义神经网络,计算损失值和网络里权重的更新。
通常来说,当你处理图像,文本,语音或者视频数据时,你可以使用标准 python 包将数据加载成 numpy 数组格式,然后将这个数组转换成 torch.*Tensor
特别是对于视觉,我们已经创建了一个叫做 totchvision 的包,该包含有支持加载类似Imagenet,CIFAR10,MNIST 等公共数据集的数据加载模块 torchvision.datasets 和支持加载图像数据数据转换模块 torch.utils.data.DataLoader。
这提供了极大的便利,并且避免了编写“样板代码”。
对于本教程,我们将使用CIFAR10数据集,它包含十个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10 中的图像尺寸为3*32*32,也就是RGB的3层颜色通道,每层通道内的尺寸为32*32。
我们将按次序的做如下几步:
加载并归一化 CIFAR10
使用 torchvision ,用它来加载 CIFAR10 数据非常简单。
import torch import torchvision import torchvision.transforms as transforms
torchvision 数据集的输出是范围在[0,1]之间的 PILImage,我们将他们转换成归一化范围为[-1,1]之间的张量 Tensors。
transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2) testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2) classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
输出:
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz Files already downloaded and verified
让我们来展示其中的一些训练图片。
import matplotlib.pyplot as plt import numpy as np # functions to show an image def imshow(img): img = img / 2 + 0.5 # unnormalize npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) plt.show() # get some random training images dataiter = iter(trainloader) images, labels = dataiter.next() # show images imshow(torchvision.utils.make_grid(images)) # print labels print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
输出:
cat plane ship frog
import torch.nn as nn import torch.nn.functional as F class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 16 * 5 * 5) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x net = Net()
import torch.optim as optim criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch in range(2): # loop over the dataset multiple times running_loss = 0.0 for i, data in enumerate(trainloader, 0): # get the inputs inputs, labels = data # zero the parameter gradients optimizer.zero_grad() # forward + backward + optimize outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() # print statistics running_loss += loss.item() if i % 2000 == 1999: # print every 2000 mini-batches print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0 print('Finished Training')
[1, 2000] loss: 2.187 [1, 4000] loss: 1.852 [1, 6000] loss: 1.672 [1, 8000] loss: 1.566 [1, 10000] loss: 1.490 [1, 12000] loss: 1.461 [2, 2000] loss: 1.389 [2, 4000] loss: 1.364 [2, 6000] loss: 1.343 [2, 8000] loss: 1.318 [2, 10000] loss: 1.282 [2, 12000] loss: 1.286 Finished Training
在测试集上测试网络
我们已经通过训练数据集对网络进行了2次训练,但是我们需要检查网络是否已经学到了东西。
我们将用神经网络的输出作为预测的类标来检查网络的预测性能,用样本的真实类标来校对。如果预测是正确的,我们将样本添加到正确预测的列表里。
好的,第一步,让我们从测试集中显示一张图像来熟悉它。
输出:
GroundTruth: cat ship ship plane
现在让我们看看 神经网络认为这些样本应该预测成什么:
outputs = net(images)
输出是预测与十个类的近似程度,与某一个类的近似程度越高,网络就越认为图像是属于这一类别。所以让我们打印其中最相似类别类标:
_, predicted = torch.max(outputs, 1) print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
输出:
Predicted: cat ship car ship
结果看起开非常好,让我们看看网络在整个数据集上的表现。
correct = 0 total = 0 with torch.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy of the network on the 10000 test images: %d %%' % ( 100 * correct / total))
输出:
Accuracy of the network on the 10000 test images: 54 %
这看起来比随机预测要好,随机预测的准确率为10%(随机预测出为10类中的哪一类)。看来网络学到了东西。
class_correct = list(0. for i in range(10)) class_total = list(0. for i in range(10)) with torch.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = torch.max(outputs, 1) c = (predicted == labels).squeeze() for i in range(4): label = labels[i] class_correct[label] += c[i].item() class_total[label] += 1 for i in range(10): print('Accuracy of %5s : %2d %%' % ( classes[i], 100 * class_correct[i] / class_total[i]))
输出:
Accuracy of plane : 57 % Accuracy of car : 73 % Accuracy of bird : 49 % Accuracy of cat : 54 % Accuracy of deer : 18 % Accuracy of dog : 20 % Accuracy of frog : 58 % Accuracy of horse : 74 % Accuracy of ship : 70 % Accuracy of truck : 66 %
所以接下来呢?
我们怎么在GPU上跑这些神经网络?
在GPU上训练
就像你怎么把一个张量转移到GPU上一样,你要将神经网络转到GPU上。
如果CUDA可以用,让我们首先定义下我们的设备为第一个可见的cuda设备。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # Assume that we are on a CUDA machine, then this should print a CUDA device: print(device)
输出:
cuda:0
本节剩余部分都会假定设备就是台CUDA设备。
接着这些方法会递归地遍历所有模块,并将它们的参数和缓冲器转换为CUDA张量。
net.to(device)
记住你也必须在每一个步骤向GPU发送输入和目标:
inputs, labels = inputs.to(device), labels.to(device)
为什么没有注意到与CPU相比巨大的加速?因为你的网络非常小。
练习:尝试增加你的网络宽度(首个 nn.Conv2d 参数设定为 2,第二个nn.Conv2d参数设定为1–它们需要有相同的个数),看看会得到怎么的速度提升。
目标:
在多个GPU上训练
如果你想要来看到大规模加速,使用你的所有GPU,请查看:数据并行性(https://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.html)。PyTorch 60 分钟入门教程:数据并行处理
下载 Python 源代码:
下载 Jupyter 源代码:
autograd 包是 PyTorch 中所有神经网络的核心。首先让我们简要地介绍它,然后我们将会去训练我们的第一个神经网络。该 autograd 软件包为 Tensors 上的所有操作提供自动微分。它是一个由运行定义的框架,这意味着以代码运行方式定义你的后向传播,并且每次迭代都可以不同。我们从 tensor 和 gradients 来举一些例子。
1、TENSOR
torch.Tensor 是包的核心类。如果将其属性 .requires_grad 设置为 True,则会开始跟踪针对 tensor 的所有操作。完成计算后,您可以调用 .backward() 来自动计算所有梯度。该张量的梯度将累积到 .grad 属性中。
要停止 tensor 历史记录的跟踪,您可以调用 .detach(),它将其与计算历史记录分离,并防止将来的计算被跟踪。
要停止跟踪历史记录(和使用内存),您还可以将代码块使用 with torch.no_grad(): 包装起来。在评估模型时,这是特别有用,因为模型在训练阶段具有 requires_grad = True 的可训练参数有利于调参,但在评估阶段我们不需要梯度。
还有一个类对于 autograd 实现非常重要那就是 Function。Tensor 和 Function 互相连接并构建一个非循环图,它保存整个完整的计算过程的历史信息。每个张量都有一个 .grad_fn 属性保存着创建了张量的 Function 的引用,(如果用户自己创建张量,则g rad_fn 是 None )。
如果你想计算导数,你可以调用 Tensor.backward()。如果 Tensor 是标量(即它包含一个元素数据),则不需要指定任何参数backward(),但是如果它有更多元素,则需要指定一个gradient 参数来指定张量的形状。
import torch
创建一个张量,设置 requires_grad=True 来跟踪与它相关的计算
x = torch.ones(2, 2, requires_grad=True) print(x)
输出:
tensor([[1., 1.], [1., 1.]], requires_grad=True)
针对张量做一个操作
y = x + 2 print(y)
输出:
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
y 作为操作的结果被创建,所以它有 grad_fn
print(y.grad_fn)
输出:
<AddBackward0 object at 0x7fe1db427470>
针对 y 做更多的操作:
z = y * y * 3 out = z.mean() print(z, out)
输出:
tensor([[27., 27.], [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
.requires_grad_( ... )
会改变张量的 requires_grad
标记。输入的标记默认为 False
,如果没有提供相应的参数。
a = torch.randn(2, 2) a = ((a * 3) / (a - 1)) print(a.requires_grad) a.requires_grad_(True) print(a.requires_grad) b = (a * a).sum() print(b.grad_fn)
输出:
False True <SumBackward0 object at 0x7fe1db427dd8>
梯度:
我们现在后向传播,因为输出包含了一个标量,out.backward()
等同于out.backward(torch.tensor(1.))
。
out.backward()
打印梯度 d(out)/dx
print(x.grad)
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
原理解释:
现在让我们看一个雅可比向量积的例子:
x = torch.randn(3, requires_grad=True) y = x * 2 while y.data.norm() < 1000: y = y * 2 print(y)
输出:
tensor([ -444.6791, 762.9810, -1690.0941], grad_fn=<MulBackward0>)
现在在这种情况下,y 不再是一个标量。torch.autograd 不能够直接计算整个雅可比,但是如果我们只想要雅可比向量积,只需要简单的传递向量给 backward 作为参数。
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float) y.backward(v) print(x.grad)
输出:
tensor([1.0240e+02, 1.0240e+03, 1.0240e-01])
你可以通过将代码包裹在 with torch.no_grad(),来停止对从跟踪历史中 的 .requires_grad=True 的张量自动求导。
print(x.requires_grad) print((x ** 2).requires_grad) with torch.no_grad(): print((x ** 2).requires_grad)
输出:
True True False
稍后可以阅读:
autograd
和 Function
的文档在: https://pytorch.org/docs/autograd
下载 Python 源代码:
下载 Jupyter 源代码: