Pytorch一小时入门教程
前言
机器学习的门槛并没有想象中那么高,我会陆续把我在学习过程中看过的一些文章和写过的代码以博客的形式分享给大家,和大家一起交流,这个是本系列的第一篇,pytoch入门教程,翻译自pytoch官方文档:Pytorch一小时入门教程。
pytorch是什么
它是一个基于python的科学计算库,致力于为两类用户提供服务:
- 一些想要找到Numpy搭建神经网络替代品的用户;
- 寻找一个可提供极强的可拓展性和运行速度的深度学习研究平台;
让我们开始干活吧!
1. 张量的概念和生成
张量和Numpy中ndarrays的概念很相似,有了这个作为基础,张量也可以被运行在GPU上来加速计算,下面介绍如何创建张量。
from __future__ import print_function
import torch
# 这个是用来生成一个为未初始化的5*3的张量,切记不是全零
x = torch.empty(5, 3)
print(x)
"""
tensor([[2.7712e+35, 4.5886e-41, 7.2927e-04],
[3.0780e-41, 3.8725e+35, 4.5886e-41],
[4.4446e-17, 4.5886e-41, 3.9665e+35],
[4.5886e-41, 3.9648e+35, 4.5886e-41],
[3.8722e+35, 4.5886e-41, 4.4446e-17]])
"""
# 这个是生成一个均匀分布的初始化的,每个元素从0~1的张量,与第一个要区别开,另外,还有其它的随机张量生成函数,如torch.randn()、torch.normal()、torch.linespace(),分别是标准正态分布,离散正态分布,线性间距向量
x = torch.rand(5, 3)
print(x)
"""
tensor([[0.9600, 0.0110, 0.9917],
[0.9549, 0.1732, 0.7781],
[0.8098, 0.5300, 0.5747],
[0.5976, 0.1412, 0.9444],
[0.6023, 0.7750, 0.5772]])
"""
# 这个是初始化一个全零张量,可以指定每个元素的类型。
x = torch.zeros(5, 3, dtype=torch.long)
print(x)
"""tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])"""
#从已有矩阵转化为张量
x = torch.tensor([5.5, 3])
print(x)
"""
tensor([5.5000, 3.0000])
"""
# 从已有张量中创造一个张量,新的张量将会重用已有张量的属性。如:若不提供新的值,那么每个值的类型将会被重用。
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
"""
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
tensor([[ 0.3327, -0.2405, -1.3764],
[-0.1040, -0.9072, 0.0069],
[-0.2622, 1.8072, 0.0175],
[ 0.0572, -0.6766, 1.6201],
[-0.7197, -1.1166, 1.7308]])
"""
# 最后我们学习如何获取张量的形状,一个小Tip,torch.Size是一个元组,所以支持元组的操作。
print(x.size())
"""torch.Size([5, 3])"""
2. 张量的操作
实际上有很多语法来操作张量,现在我们来看一看加法。
y = torch.rand(5, 3)
# 加法方式1
print(x + y)
"""
tensor([[ 1.2461, 0.6067, -0.9796],
[ 0.0663, -0.9046, 0.8010],
[ 0.4199, 1.8893, 0.7887],
[ 0.6264, -0.2058, 1.8550],
[ 0.0445, -0.8441, 2.2513]])
"""
# 加法方式2
print(torch.add(x, y))
"""
tensor([[ 1.2461, 0.6067, -0.9796],
[ 0.0663, -0.9046, 0.8010],
[ 0.4199, 1.8893, 0.7887],
[ 0.6264, -0.2058, 1.8550],
[ 0.0445, -0.8441, 2.2513]])
"""
# 还可以加参数
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)
"""
tensor([[ 1.2461, 0.6067, -0.9796],
[ 0.0663, -0.9046, 0.8010],
[ 0.4199, 1.8893, 0.7887],
[ 0.6264, -0.2058, 1.8550],
[ 0.0445, -0.8441, 2.2513]])
"""
# 方法二的一种变式,注意有一个‘_’,这个符号在所有替换自身操作符的末尾都有,另外,输出的方式还可以象python一样。
y.add_(x)
print(y)
"""
tensor([[ 1.2461, 0.6067, -0.9796],
[ 0.0663, -0.9046, 0.8010],
[ 0.4199, 1.8893, 0.7887],
[ 0.6264, -0.2058, 1.8550],
[ 0.0445, -0.8441, 2.2513]])
"""
print(x[:, 1])
"""
tensor([-0.2405, -0.9072, 1.8072, -0.6766, -1.1166])
"""
我们现在看一看如何调整张量的形状。
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())
"""
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
"""
我们现在看一看如何查看张量的大小。
x = torch.randn(1)
print(x)
print(x.item())
"""
tensor([-1.4743])
-1.4742881059646606
"""
到这里,基本的操作知识就已经讲完了,如果了解更详细的部分,请点击这个链接.
3. 张量和Numpy的相互转换
张量和Numpy数组之间的转换十分容易。
- Tensor到Nump,在使用Cpu的情况下,张量和array将共享他们的物理位置,改变其中一个的值,另一个也会随之变化。
a = torch.ones(5)
print(a)
"""
tensor([1., 1., 1., 1., 1.])
"""
b = a.numpy()
print(b)
"""
[1. 1. 1. 1. 1.]
"""
a.add_(1)
print(a)
print(b)
"""
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
"""
- Numpy到Tensor ,在使用Cpu的情况下,张量和array将共享他们的物理位置,改变其中一个的值,另一个也会随之变化。
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
"""
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
"""
- Gpu下的转换。
# 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!
"""
tensor([-0.4743], device='cuda:0')
tensor([-0.4743], dtype=torch.float64)
"""
自动微分
在pytorch中,神经网络的核心是自动微分,在本节中我们会初探这个部分,也会训练一个小型的神经网络。自动微分包会提供自动微分的操作,它是一个取决于每一轮的运行的库,你的下一次的结果会和你上一轮运行的代码有关,因此,每一轮的结果,有可能都不一样。接下来,让我们来看一些例子。
1. 张量
torch.Tensor是这个包的核心类,如果你设置了它的参数 ‘.requires_grad=true’ 的话,它将会开始去追踪所有的在这个张量上面的运算。当你完成你得计算的时候,你可以调用’backwward()来计算所有的微分。这个向量的梯度将会自动被保存在’grad’这个属性里面。
如果想要阻止张量跟踪历史数据,你可以调用’detach()'来将它从计算历史中分离出来,当然未来所有计算的数据也将不会被保存。或者你可以使用’with
torch.no_grad()‘来调用代码块,不光会阻止梯度计算,还会避免使用储存空间,这个在计算模型的时候将会有很大的用处,因为模型梯度计算的这个属性默认是开启的,而我们可能并不需要。
第二个非常重要的类是Function,Tensor和Function,他们两个是相互联系的并且可以搭建一个非循环的运算图。每一个张量都有一个’grad_fn’的属性,它可以调用Function来创建Tensor,当然,如果用户自己创建了Tensor的话,那这个属性自动设置为None。
如果你想要计算引出量的话,你可以调用’.backward()'在Tensor上面,如果Tensor是一个纯数的话,那么你将不必要指明任何参数;如果它不是纯数的话,你需要指明一个和张量形状匹配的梯度的参数。下面来看一些例程。
import torch
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>)
"""
print(y.grad_fn)
"""
<AddBackward0 object at 0x7fc6bd199ac8>
"""
z = y * y * 3
out = z.mean()
print(z, out)
"""
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
"""
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 0x7fc6bd1b02e8>
"""
2. 梯度
现在我们将进行反向梯度传播。因为输出包含一个纯数,那么out.backward()等于out.backward(torch.tensor(1.));梯度的计算如下(分为数量和向量)
- 数量的梯度,即各个方向的导数的集合
print(x.grad)
"""
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
"""
- 1
- 2
- 3
- 4
- 5
- 向量的全微分,即雅可比行列式。
J = ( ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n )J