介绍
PyTorch是一个基于Torch的Python开源机器学习库,用于自然语言处理等应用程序。它主要由Facebookd的人工智能小组开发,不仅能够 实现强大的GPU加速,同时还支持动态神经网络,PyTorch提供了两个高级功能:
- 具有强大的GPU加速的张量计算(如Numpy)
- 包含自动求导系统的深度神经网络
除了Facebook之外,Twitter、GMU和Salesforce等机构都采用了PyTorch。
优势
- 支持GPU
- 灵活,支持动态神经网络
- 底层代码易于理解
- 命令式体验
- 自定义扩展
张量Tensor
from __future__ import print_function
import torchtorch.manual_seed(0) #为CPU设置种子用于生成随机数,以使得结果是确定的
torch.cuda.manual_seed(0)#为当前GPU设置随机种子;如果使用多个GPU,应该使用
#torch.cuda.manual_seed_all()为所有的GPU设置种子。
在开头加上
from __future__ import print_function
这句之后,即使在python2.X,使用print就得像python3.X那样加括号使用。python2.X中print不需要括号,而在python3.X中则需要。更广泛来说,如果某个版本中出现了某个新的功能特性,而且这个特性和当前版本中使用的不兼容,也就是它在该版本中不是语言标准,那么如果想要使用的话就需要从future模块导入。
- 构造一个5x3矩阵,不初始化
x = torch.empty(5, 3)
print(x)
输出为:
tensor([[1.6255e-43, 1.5554e-43, 1.5975e-43],[1.3873e-43, 1.4574e-43, 6.4460e-44],[1.4153e-43, 1.5274e-43, 1.5695e-43],[1.6255e-43, 1.6956e-43, 5.6052e-44],[7.4269e-44, 6.1657e-44, 4.4842e-44]])
- 构造一个随机初始化的矩阵
x = torch.rand(5, 3)
print(x)
输出为:
tensor([[0.3983, 0.0756, 0.3885],[0.5530, 0.0550, 0.0197],[0.7664, 0.1477, 0.9955],[0.2368, 0.3034, 0.8063],[0.3418, 0.6183, 0.1371]])
- 构造一个矩阵全为 0,而且数据类型是 long
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])
- 通过现有的
Tensor
来创建,此方法会默认重用输入Tensor
的一些属性,例如数据类型,除非自定义数据类型
x = x.new_ones(5, 3, dtype=torch.float64) # 返回的tensor默认具有相同的torch.dtype和torch.deviceprint(x)x = torch.randn_like(x, dtype=torch.float) # 指定新的数据类型print(x) 输出为:tensor([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]], dtype=torch.float64)tensor([[ 0.6035, 0.8110, -0.0451],[ 0.8797, 1.0482, -0.0445],[-0.7229, 2.8663, -0.5655],[ 0.1604, -0.0254, 1.0739],[ 2.2628, -0.9175, -0.2251]])
- 获取维度信息
print(x.size())
或
print(x.shape)
输出:
torch.Size([5, 3])
注意:返回的torch.Size其实就是一个tuple, 支持所有tuple的操作。
操作
算术操作
- 加法形式一
y = torch.rand(5, 3)
print(x + y)
输出为:
tensor([[1.9224, 1.8943, 1.7366],[1.9281, 1.8129, 1.3018],[1.4944, 1.0350, 1.6745],[1.1145, 1.0914, 1.0394],[1.5441, 1.6155, 1.3457]])
- 加法形式二
print(torch.add(x, y))
输出
tensor([[1.9224, 1.8943, 1.7366],[1.9281, 1.8129, 1.3018],[1.4944, 1.0350, 1.6745],[1.1145, 1.0914, 1.0394],[1.5441, 1.6155, 1.3457]])
或者另外提供一个 tensor 作为输出参数
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)
输出:
tensor([[1.9224, 1.8943, 1.7366],[1.9281, 1.8129, 1.3018],[1.4944, 1.0350, 1.6745],[1.1145, 1.0914, 1.0394],[1.5441, 1.6155, 1.3457]])
- 加法形式三:inplace
# adds x to y
y.add_(x)
print(y)
输出:
tensor([[1.9224, 1.8943, 1.7366],[1.9281, 1.8129, 1.3018],[1.4944, 1.0350, 1.6745],[1.1145, 1.0914, 1.0394],[1.5441, 1.6155, 1.3457]])
注意 任何使张量会发生变化的操作都有一个后缀 '_'。如x.copy_(y)
, x.t_()
, 将会改变 x
.
索引
可以使用类似NumPy的索引操作来访问Tensor
的一部分,需要注意的是:索引出来的结果与原数据共享内存,也即修改一个,另一个会跟着修改。
y = x[0, :]y += 1print(y)print(x[0, :]) # 源tensor也被改了输出为:tensor([1.6035, 1.8110, 0.9549])tensor([1.6035, 1.8110, 0.9549])
- 改变一个 tensor 的大小或者形状,可以使用
torch.view
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1所指的维度可以根据其他维度的值推出来
print(x.size(), y.size(), z.size())
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
注意view()
返回的新tensor与源tensor共享内存,也即更改其中的一个,另外一个也会跟着改变。
x += 1
print(x)
print(y) # 也加了1
输出为:
tensor([[2.6035, 2.8110, 1.9549],[1.8797, 2.0482, 0.9555],[0.2771, 3.8663, 0.4345],[1.1604, 0.9746, 2.0739],[3.2628, 0.0825, 0.7749]])
tensor([2.6035, 2.8110, 1.9549, 1.8797, 2.0482, 0.9555, 0.2771, 3.8663, 0.4345,1.1604, 0.9746, 2.0739, 3.2628, 0.0825, 0.7749])
如果不想共享内存,推荐先用clone
创造一个副本然后再使用view
x_cp = x.clone().view(15)
x -= 1
print(x)
print(x_cp)
输出为:
tensor([[ 1.6035, 1.8110, 0.9549],[ 0.8797, 1.0482, -0.0445],[-0.7229, 2.8663, -0.5655],[ 0.1604, -0.0254, 1.0739],[ 2.2628, -0.9175, -0.2251]])
tensor([2.6035, 2.8110, 1.9549, 1.8797, 2.0482, 0.9555, 0.2771, 3.8663, 0.4345,1.1604, 0.9746, 2.0739, 3.2628, 0.0825, 0.7749])
- 另外一个常用的函数就是
item()
, 它可以将一个标量Tensor
转换成一个Python number,获得Tensor的value
x = torch.randn(1)
print(x)
print(x.item())
输出:
tensor([-0.2508])
-0.25081250071525574
广播机制
x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
输出为:
tensor([[1, 2]])
tensor([[1],[2],[3]])
tensor([[2, 3],[3, 4],[4, 5]])
Tensor
和NumPy相互转换
numpy()
和from_numpy()
这两个函数产生的Tensor
和NumPy array实际是使用的相同的内存,改变其中一个时另一个也会改变
Tensor
转NumPy
a = torch.ones(5)
b = a.numpy()
print(a, b)a += 1
print(a, b)
b += 1
print(a, b)
输出为:
tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]
NumPy数组转Tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a, b)a += 1
print(a, b)
b += 1
print(a, b)
输出为;
[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
[3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
直接用torch.tensor()
将NumPy数组转换成Tensor
,该方法总是会进行数据拷贝,返回的Tensor
和原来的数据不再共享内存
# 用torch.tensor()转换时不会共享内存c = torch.tensor(a)a += 1print(a, c)输出为:[4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
Tensor
on GPU
# 以下代码只有在PyTorch GPU版本上才会执行
if torch.cuda.is_available():device = torch.device("cuda") # GPUy = torch.ones_like(x, device=device) # 直接创建一个在GPU上的Tensorx = x.to(device) # 等价于 .to("cuda")z = x + yprint(z)print(z.to("cpu", torch.double)) # to()还可以同时更改数据类型
输出:
tensor([0.7492], device='cuda:0')
tensor([0.7492], dtype=torch.float64)
torch.ones_like(input, dtype=None, layout=None, device=None, requires_grad=False) → Tensor
返回一个填充了标量值1的张量,其大小与之相同 input。
torch.ones_like(input)相当于 torch.ones(input.size(), dtype=input.dtype, layout=input.layout, device=input.device)
Parameters:
input (Tensor) – the size of input will determine size of the output tensor
dtype (torch.dtype, optional) – the desired data type of returned Tensor. Default: if None, defaults to the dtype of input.
layout (torch.layout, optional) – the desired layout of returned tensor. Default: if None, defaults to the layout of input.
device (torch.device, optional) – the desired device of returned tensor. Default: if None, defaults to the device of input.
requires_grad (bool, optional) – If autograd should record operations on the returned tensor. Default: False.