PyTorch进行深度学习入门
一、PyTorch是什么?
这是一个基于Python的科学计算软件包,针对两组受众:
①、NumPy的替代品,可以使用GPU的强大功能
②、深入学习研究平台,提供最大的灵活性和速度
二、入门
①、张量(tensor):
张量与NumPy的ndarray类似,另外还有Tensors也可用于GPU以加速计算:
from __future__ import print_function
import torch
构造一个未初始化的5x3矩阵:
x = torch.empty(5, 3)
print(x)
构造一个随机初始化的矩阵:
x = torch.rand(5, 3)
print(x)
构造一个矩阵填充的零和dtype long:
x = torch.zeros(5, 3, dtype=torch.long)
print(x)
直接从数据构造张量:
x = torch.tensor([5.5, 3])
print(x)
根据现有的张量创建张量。除非用户提供新值,否则这些方法将重用输入张量的属性,例如dtype:
x = x.new_ones(5, 3, dtype=torch.double) # new_* methods take in sizes
print(x) x = torch.randn_like(x, dtype=torch.float) # override dtype!
print(x) # result has the same size
6 print(x.size()) #x的尺寸,torch.Size
实际上是一个元组,因此它支持所有元组操作。
②、操作
增加:语法1
y = torch.rand(5, 3)
print(x + y)
增加:语法2
print(torch.add(x, y))
增加:提供输出张量作为参数
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)
增加:就地。注意:任何使原位张量变形的操作都是用_
。后固定的。例如:x.copy_(y)
,x.t_()
,将改变x
。
# adds x to y
y.add_(x)
print(y)
使用标准的NumPy索引
print(x[:, 1])
调整大小:如果要调整张量/重塑张量,可以使用torch.view
:
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # the size -1 is inferred from other dimensions
print(x.size(), y.size(), z.size())
如果你有一个元素张量,用于.item()
获取值作为Python数字:
x = torch.randn(1)
print(x)
print(x.item())
③、NumPy Bridge:将Torch Tensor转换为NumPy阵列(反之亦然)是一件轻而易举的事。Torch Tensor和NumPy阵列将共享其底层内存位置,更改一个将改变另一个。
将Torch Tensor转换为NumPy数组:
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
了解numpy数组的值如何变化。
a.add_(1)
print(a)
print(b)
将NumPy数组转换为Torch Tensor:了解更改np阵列如何自动更改Torch Tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
除了CharTensor之外,CPU上的所有Tensors都支持转换为NumPy并返回。
④、CUDA Tensors
可以使用该.to方法将张量移动到任何设备上。
# let us run this cell only if CUDA is available
# We will use ``torch.device`` objects to move tensors in and out of GPU
if torch.cuda.is_available():
device = torch.device("cuda") # a CUDA device object
y = torch.ones_like(x, device=device) # directly create a tensor on GPU
x = x.to(device) # or just use strings ``.to("cuda")``
z = x + y
print(z)
print(z.to("cpu", torch.double)) # ``.to`` can also change dtype together!
⑤、AUTOGRAD:自动分化
autograd
包中是PyTorch中所有神经网络的核心。首先简要地访问它,然后将去训练第一个神经网络。该autograd
软件包为Tensors上的所有操作提供自动区分。它是一个逐个运行的框架,backprop由自己的代码运行方式定义,并且每个迭代都可以不同。
张量:torch.Tensor
是包的核心类。如果将其属性设置 .requires_grad
为True
,则会开始跟踪其上的所有操作。完成计算后,可以调用.backward()
并自动计算所有渐变。该张量的梯度将累积到.grad
属性中。要阻止张量跟踪历史记录,可以调用.detach()
它将其从计算历史记录中分离出来,并防止将来的计算被跟踪。
要防止跟踪历史记录(和使用内存),还可以将代码块包装在其中。这在评估模型时尤其有用,因为模型可能具有可训练的参数 ,但不需要梯度。with torch.no_grad():
requires_grad=True,还有一个类对于autograd实现非常重要 - a
Function,Tensor 和 function是否相互连接并建立一个非循环图,编码了完整的计算历史,每个张量都有一个.grad_fn属性,该属性引用一个创建了张量的函数(用户创建的张量除外——它们的grad_fn是None。如果你想去计算导数,可以在一个张量上调用.backward(),如果张量是标量(即它包含一个元素数据),不需要为.backward()指定任何参数,然而,如果它有更多的元素,需要指定一个梯度参数,这是一个匹配形状的张量。
import torch
创建一个张量,并设置requires_grad=True来跟踪计算:
x = torch.ones(2, 2, requires_grad=True)
print(x)
张量运算:
y = x + 2
print(y)
y是一个操作的结果,所以它有一个grad_fn。
print(y.grad_fn)
更多关于y的运算:
z = y * y * 3
out = z.mean()
print(z, out)
.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)
⑥、梯度下降
对于反向传播,因为out包含一个标量,out. backwards()等价于out. backwards(torch.tensor(1.))。
out.backward()
打印梯度d(out)/dx
print(x.grad)
在数学上,有一个向量值函数,y关于x的导数矩阵如下:
一般来说,torch.autograd用来计算雅可比行列式的工具,对于任意给定的矢量,计算。如果v恰好是标量函数梯度,那么,通过链规则,矢量雅可比产品将是梯度l关于
注意:给出一个行向量,可以转换为列向量
向量-雅可比矩阵乘积的这种特性使得将外部梯度输入具有非标量输出的模型非常方便。
一个向量雅可比矩阵乘积的例子:
x = torch.randn(3, requires_grad=True) y = x * 2
while y.data.norm() < 1000:
y = y * 2 print(y)
在这种情况下,y不再是标量。torch.autograd不能直接计算出整个雅可比矩阵,只需将向量作为参数传递给backward。
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v) print(x.grad)
可以使用.requires_grad=True来阻止autograd跟踪张量的历史,方法是使用torch.no_grad()将代码块封装起来:
print(x.requires_grad)
print((x ** 2).requires_grad) with torch.no_grad():
print((x ** 2).requires_grad)
三、搭建神经网络
①、可以使用torch.nn包来构造神经网络,nn取决于autograd,定义模块一个nn.Module包含层和一种方法forward(input),返回output。
②、卷积神经网络模型如下:
这是一个简单的前馈网络。它接受输入,一个接一个地通过几个层输入,然后最终给出输出。
③、神经网络的典型训练程序如下:
- 定义具有一些可学习参数(或权重)的神经网络
- 迭代输入数据集
- 通过网络处理输入
- 计算损失(输出距离正确多远)
- 将渐变传播回网络参数
- 通常使用简单的更新规则更新网络权重: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)
只需定义正向函数,然后使用autograd自动定义反向函数(其中计算梯度)。可以在正函数中使用任何张量运算。
模型的可学习参数由net.parameters()返回:
params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1's .weight
⑤、处理输入并向后调用
尝试一个随机的32x32输入。注意:此网络(LeNet)的预期输入大小为32x32。要在MNIST数据集上使用此网络,请将数据集中的图像大小调整为32x32。
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
使用随机梯度将所有参数和反向的梯度缓冲区归零:
net.zero_grad()
out.backward(torch.randn(1, 10))
注意: torch.nn仅支持小批量,整个torch.nn包仅支持输入是一小批样本,而不是单个样本:
例如:nn.Conv2d接收一个四维向量nSamples x nChannels x Height x Width,如果是单个样本,仅使用input.unsqueeze(0)添加伪批处理维度。
回顾一下到目前为止所见的所有类:
torch.Tensor
- 支持诸如backward()之类的autograd操作的多维数组,因此,包含梯度w.r.t这些向量。nn.Module
-神经网络模型,使用帮助程序将它们移动到GPU,导出,加载等。nn.Parameter
- 一种Tensor,在被指定为a的属性时自动注册为参数Module
。autograd.Function
- 实现自动编程操作的前向和后向定义。每个Tensor
操作至少创建一个Function
节点,该节点连接到创建Tensor
和编码其历史记录的函数。
⑥、损失函数
损失函数接受(输出,目标)输入对,并计算估计输出距目标的距离的值。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)
如果按照loss后向方向,使用它的.grad_fn属性,可以得到类似下面的计算步骤:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
因此,当要调用loss.backward()时,整个图像将被微分成w.r.t。这些损失,以及图中所有有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
⑦、反向传播
对于反向传播误差,需要求loss.backward()。不过,需要清除现有的梯度,否则梯度将累积为现有梯度。现在将调用loss. backwards (),看一下前后的conv1的偏置梯度。
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)
现在,我们已经学习了如何使用损失函数,神经网络包包含各种模块和损失函数,构成了深度神经网络的构建模块。唯一需要学习的是:更新网络的权重。
⑧、更新权重
实践中最简单的更新规则是随机梯度下降(SGD):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
注意:观察如何使用optimizer.zero_grad(),手动将梯度缓冲区设置为零。这是因为梯度是累积的。
⑨、训练分类器
通常,当需要处理图像,文本,音频或视频数据时,可以使用标准的python包将数据加载到numpy数组中。然后你可以将这个数组转换成一个torch.*Tensor
。
- 对于图像,Pillow,OpenCV等软件包很有用
- 对于音频,包括scipy和librosa
- 对于文本,无论是原始Python还是基于Cython的加载,还是NLTK和SpaCy都很有用
特别是对于视觉,我们创建了一个名为的包 torchvision
,它包含用于常见数据集的数据加载器,如Imagenet,CIFAR10,MNIST等,以及用于图像的数据转换器,即torchvision.datasets
和torch.utils.data.DataLoader
。
在本教程中,我们将使用CIFAR10数据集。它有类:'飞机','汽车','鸟','猫','鹿','狗','青蛙','马','船','卡车'。CIFAR-10中的图像尺寸为3x32x32,即尺寸为32x32像素的3通道彩色图像。
训练分类器执行以下步骤:
1、使用加载和标准化CIFAR10训练和测试数据集 torchvision
2、定义卷积神经网络
3、定义损失函数
4、在训练数据上训练网络
5、在测试数据上测试网络
加载和标准化CIFAR10
使用torchvision
,加载CIFAR10非常容易。
import torch
import torchvision
import torchvision.transforms as transforms
torchvision数据集的输出是范围[0,1]的PILImage图像。将它们转换为归一化范围的张量[-1,1]。
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')
展示一些训练图像,如下:
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)))
定义卷积神经网络:
从神经网络部分复制神经网络并修改它以获取3通道图像(而不是定义的1通道图像)
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()
定义Loss函数和优化器:
使用分类交叉熵损失和SGD动量:
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')
在测试数据上测试网络:
通过预测神经网络输出的类标签来检查网络是否已经学到了什么,并根据地面实况进行检查。如果预测正确,我们将样本添加到正确预测列表中。
第一步:从测试集中显示一个图像以熟悉:
dataiter = iter(testloader)
images, labels = dataiter.next() # print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
看看神经网络认为上面这些例子是什么:
outputs = net(images)
输出是10类的能量,一个类的能量越高,网络认为图像是特定类的越多。那么,让我们得到最高能量的指数:
_, predicted = torch.max(outputs, 1) print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
for j in range(4)))
⑩、如何在GPU上运行这些神经网络
如果有可用的CUDA,首先将设备定义为第一个可见的cuda设备:
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # Assuming that we are on a CUDA machine, this should print a CUDA device: print(device)
然后这些方法将递归遍历所有模块并将其参数和缓冲区转换为CUDA张量:
net.to(device)
还必须将每一步的输入和目标发送到GPU:
inputs, labels = inputs.to(device), labels.to(device)
PyTorch进行深度学习入门的更多相关文章
- Python学习(二)——深度学习入门介绍
课程二:深度学习入门 讲师:David (数据分析工程师) 这门课主要介绍了很多神经网络的基本原理,非常非常基础的了解. 零.思维导图预览: 一.深度神经网络 1.神经元 ...
- mnist手写数字识别——深度学习入门项目(tensorflow+keras+Sequential模型)
前言 今天记录一下深度学习的另外一个入门项目——<mnist数据集手写数字识别>,这是一个入门必备的学习案例,主要使用了tensorflow下的keras网络结构的Sequential模型 ...
- 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV
这次博客园的排版彻底残了..高清版请移步: https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程: 给深度学习入门者的Python快速教程 - 基础篇 给深度 ...
- 给深度学习入门者的Python快速教程 - numpy和Matplotlib篇
始终无法有效把word排版好的粘贴过来,排版更佳版本请见知乎文章: https://zhuanlan.zhihu.com/p/24309547 实在搞不定博客园的排版,排版更佳的版本在: 给深度学习入 ...
- 深度学习入门实战(二)-用TensorFlow训练线性回归
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者 :董超 上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能 ...
- 给深度学习入门者的Python快速教程
给深度学习入门者的Python快速教程 基础篇 numpy和Matplotlib篇 本篇部分代码的下载地址: https://github.com/frombeijingwithlove/dlcv_f ...
- 【PyTorch深度学习】学习笔记之PyTorch与深度学习
第1章 PyTorch与深度学习 深度学习的应用 接近人类水平的图像分类 接近人类水平的语音识别 机器翻译 自动驾驶汽车 Siri.Google语音和Alexa在最近几年更加准确 日本农民的黄瓜智能分 ...
- 学习《深度学习入门:基于Python的理论与实现》高清中文版PDF+源代码
入门神经网络深度学习,推荐学习<深度学习入门:基于Python的理论与实现>,这本书不来虚的,一上来就是手把手教你一步步搭建出一个神经网络,还能把每一步的出处讲明白.理解神经网络,很容易就 ...
- 深度学习入门者的Python快速教程 - 基础篇
5.1 Python简介 本章将介绍Python的最基本语法,以及一些和深度学习还有计算机视觉最相关的基本使用. 5.1.1 Python简史 Python是一门解释型的高级编程语言,特点是简单明 ...
随机推荐
- Tutorial中的Hello2代码
该hello2应用程序是一个Web模块,它使用Java Servlet技术来显示问候语和响应. 1.GreetingServlet.java源码文件: 1 @WebServlet("/gre ...
- springboot集成springsession利用redis来实现session共享
转:https://www.cnblogs.com/mengmeng89012/p/5519698.html 这次带来的是spring boot + redis 实现session共享的教程. 在sp ...
- CSS3_文本样式
1. 文字阴影 text-shadow 使用: text-shadow: 水平方向偏移量 垂直方向偏移量 模糊程度 颜色; #box { text-shadow: 10px 1 ...
- get与post请求问题
req.url可以获取请求路径: 为避免浏览器自身发送的'/favicon.ico'的影响,获取路径后可利用if(req.url=='/favicon.ico') return ;处理 url.pa ...
- dtIntersectSegmentPoly2D 2D上的线段与多边形相交计算 产生结果:是否相交,线段跨越的开始和结束百分比,相交的边
dtIntersectSegmentPoly2D(startPos, endPos, verts, nv, tmin, tmax, segMin, segMax): http://geomalgori ...
- 为什么局部变量必须以final修饰(或者有final实效:java8)才可以在内部类中使用?
为什么局部变量必须以final修饰(或者有final实效:java8)才可以在内部类中使用? public class Ace { public static void main(String[] a ...
- mac下git安装与使用
1.下载git客户端,下载地址为:https://git-scm.com/download/mac 2.打开安装包,可以看到此时的界面为: 我们需要把.pkg的安装包安装到系统当中.我双击了安装包 ...
- JAVA RPC (六) 之thrift反序列化RPC消息体
我们来看一下服务端的简单实现,直接上thrift代码,很直观的来看一看thrift的server到底干了些什么 public boolean process(TProtocol in, TProtoc ...
- 单元测试-unittest模块
1.简单的一个实例 import unittest def calc(a,b): return a+b class MyTest(unittest.TestCase): def testa(self) ...
- c++11 强类型枚举 enum class
在标准C++中,枚举类型不是类型安全的.枚举类型被视为整数,这使得两种不同的枚举类型之间可以进行比较.C++03 唯一提供的安全机制是一个整数或一个枚举型值不能隐式转换到另一个枚举别型. 此外,枚举所 ...