Pytorch基础使用介绍 Pytorch是什么? Pytorch是一个基于python的科学计算包,主要面向两部分受众: 一个为了充分发挥GPU能力而设计的Numpy的GPU版本替代方案 一个提供更大灵活性和速度的深度学习研究平台 本节将会介绍Pytorch的一些基本使用和操作,帮助你熟悉和上手Pytorch,让我们开始吧~ 1.Tensors Tensors(张量)的概念可以类比Numpy中的ndarrays,本质上就是一个多维数组,是任何运算和操作间数据流动的最基础形式。
Pytorch是什么?
Pytorch是一个基于python的科学计算包,主要面向两部分受众:
一个为了充分发挥GPU能力而设计的Numpy的GPU版本替代方案
一个提供更大灵活性和速度的深度学习研究平台
本节将会介绍Pytorch的一些基本使用和操作,帮助你熟悉和上手Pytorch,让我们开始吧~
Tensors(张量)的概念可以类比Numpy中的ndarrays,本质上就是一个多维数组,是任何运算和操作间数据流动的最基础形式。
首先让我们加载torch库
import torch
首先让我们来看下如何生成一些简单的Tensor
构建一个未初始化的5*3的空矩阵(张量)的代码如下:
x = torch.empty(5, 3) print(type(x)) print(x)
输出:
<class 'torch.Tensor'> tensor([[7.7050e+31, 6.7415e+22, 1.2690e+31], [6.1186e-04, 4.6165e+24, 4.3701e+12], [7.5338e+28, 7.1774e+22, 3.7386e-14], [6.6532e-33, 1.8337e+31, 1.3556e-19], [1.8370e+25, 2.0616e-19, 4.7429e+30]])
注意,对于未初始化的张量,它的取值是不固定的,取决于它创建时分配的那块内存的取值。
torch.zeros 和 torch.ones也是非常常用的Tensor初始化函数:
tensor_ones = torch.ones(2,3) print(tensor_ones) tensor_zeros = torch.zeros(2,3) print(tensor_zeros)
输出:
tensor([[1., 1., 1.], [1., 1., 1.]]) tensor([[0., 0., 0.], [0., 0., 0.]])
可以通过dtype属性来指定tensor的数据类型
这里我们再次构建一个使用0填充的tensor,将dtype属性设置为长整型,并打印结果的数据类型,注意观察区别
print(tensor_zeros.dtype) tensor_zeros_int = torch.zeros(2, 3, dtype=torch.long) print(tensor_zeros_int.dtype)
输出:
torch.float32 torch.int64
和Numpy类似,除了常见的0/1取值的初始化,我们还可以进行随机初始化,或者直接用现有数据进行张量的初始化。
torch.rand 和 torch.randn 是两个常用的随机初始化函数
torch.rand用于生成服从区间[0,1)均匀分布的随机张量,示例:
x = torch.rand(5, 3) print(x)
输出:
tensor([[0.6544, 0.1733, 0.2569], [0.0680, 0.5781, 0.2667], [0.5051, 0.5366, 0.2776], [0.4903, 0.9934, 0.1181], [0.4497, 0.6201, 0.1952]])
torch.randn用于生成服从均值为0、方差为1正太分布的随机张量,示例:
x = torch.randn(4, 4) print(x)
输出:
tensor([[-1.2787, -1.8935, -0.1098, -0.5664], [ 1.2988, 0.5578, -1.7803, 0.9369], [ 0.7574, -0.4856, -1.5168, -0.5782], [ 0.9653, -1.0099, 0.4913, -0.1843]])
我们还可以直接用现有数据进行张量的初始化,例如python的列表List,例如:
x = torch.tensor([5.5, 3]) print(x)
输出:
tensor([5.5000, 3.0000])
也可以基于已有的tensor来创建新的tensor,通常是为了复用已有tensor的一些属性,包括shape和dtype。观察下面的示例:
x = torch.tensor([5.5, 3], dtype=torch.double) print(x.dtype) x = x.new_ones(5, 3) # new_* methods take in sizes print(x) x = torch.randn_like(x, dtype=torch.float) # override dtype! print(x) # result has the same size
输出:
torch.float64 tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], dtype=torch.float64) tensor([[-0.4643, -0.1942, -0.4497], [ 0.8090, 1.6753, -0.0678], [-1.1654, -0.3817, 0.3495], [ 2.3517, 1.7688, 0.0251], [-0.6314, -1.2776, 0.8398]])
可以看到,new_ones函数复用了x的dtype属性,randn_like函数复用了x的shape同时通过手动指定数据类型覆盖了原有的dtype属性
如果获取tensor的size?很简单
x_size = x.size() print(x_size) row, col = x_size print(row, col)
输出:
torch.Size([5, 3]) 5 3
torch.Size本质上是一个tuple,通过上面的例子也可以看出,它支持元组的操作。
最后介绍一个非常实用的函数torch.arange,用于生成一定范围内等间隔的一维数组。参数有三个,分别是范围的起始值、范围的结束值和步长,使用示例:
torch.arange(1, 10, 1)
输出:
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
Operations(操作)涉及的语法和函数很多,大多数都是相通的,下面我们列举一些常用操作及其用法示例。
首先来看下张量间的元素级的四则运算,加减乘除的用法
有多种不同的使用方法,以加法为例:语法1
y = torch.rand(5, 3) z1 = x + y print(z1)
输出:
tensor([[ 1.7110, -0.0545, 0.3557], [ 0.1074, 2.3876, 1.2455], [-0.1204, 1.1829, 0.6250], [ 0.0873, 1.3114, 1.0403], [-0.6172, 1.2261, -1.0718]])
加法:语法2
z2 = torch.add(x, y) print(z2)
输出:
tensor([[ 1.7110, -0.0545, 0.3557], [ 0.1074, 2.3876, 1.2455], [-0.1204, 1.1829, 0.6250], [ 0.0873, 1.3114, 1.0403], [-0.6172, 1.2261, -1.0718]])
加法:语法3,通过参数的形式进行输出tensor的保存
z3 = torch.empty(5, 3) torch.add(x, y, out=z3) print(z3)
输出:
tensor([[ 1.7110, -0.0545, 0.3557], [ 0.1074, 2.3876, 1.2455], [-0.1204, 1.1829, 0.6250], [ 0.0873, 1.3114, 1.0403], [-0.6172, 1.2261, -1.0718]])
加法:语法4,通过in-place操作直接将计算结果覆盖到y上
y.add_(x) print(y)
输出:
tensor([[ 1.7110, -0.0545, 0.3557], [ 0.1074, 2.3876, 1.2455], [-0.1204, 1.1829, 0.6250], [ 0.0873, 1.3114, 1.0403], [-0.6172, 1.2261, -1.0718]])
在Pytorch中,我们约定凡是会覆盖函数调用主体的in-place操作,都以后缀_结束,例如:x.copy_(y),x.t_(),都会改变x的取值。
张量之间的减法、点乘和点除的用法是类似的:
a =torch.randn(2,3) print(a) b =torch.randn(2,3) print(b) c =torch.sub(a, b) print(c) d =torch.mul(a, b) print(d) e =torch.div(a, b) print(e)
运行后,输出的内容如下:
tensor([[ 0.3580, -0.5780, -0.6883], [ 0.0883, -0.9064, 0.5411]]) tensor([[-1.7065, 0.7099, 0.6574], [-1.3688, 0.1767, 0.3669]]) tensor([[ 2.0645, -1.2880, -1.3457], [ 1.4571, -1.0831, 0.1742]]) tensor([[-0.6109, -0.4104, -0.4525], [-0.1209, -0.1602, 0.1986]]) tensor([[-0.2098, -0.8142, -1.0471], [-0.0645, -5.1292, 1.4748]])
当然,张量和常数间的基本运算也是支持的
a =torch.randn(2,3) print(a) b =torch.mul(a,10) print(b) c =torch.div(a,10) print(c)
运行后,输出的内容如下:
tensor([[-1.6306, 0.2616, 0.0606], [-0.4596, -1.3998, 0.9431]]) tensor([[-16.3055, 2.6162, 0.6061], [ -4.5963, -13.9981, 9.4307]]) tensor([[-0.1631, 0.0262, 0.0061], [-0.0460, -0.1400, 0.0943]])
上面介绍了torch.mul用来计算张量间的点乘,而进行矩阵乘法计算需要用到torch.mm函数
a =torch.randn(2, 3) print(a) b =torch.randn(3, 2) print(b) c =torch.mm(a, b) print(c)
输出的内容如下:
tensor([[-1.0442, 0.2439, 1.3658], [-1.0813, 0.3178, 0.4006]]) tensor([[ 0.4317, 0.3242], [-0.2085, 0.5584], [ 0.7991, 0.0926]]) tensor([[ 0.5898, -0.0759], [-0.2129, -0.1360]])
下面我们来看看其他的一些基础操作。
torch.abs函数可以用来计算张量的绝对值
a =torch.randn(2, 3) print(a) b =torch.abs(a) print(b)
输出:
tensor([[-0.8631, 0.3728, 1.0428], [ 0.5944, 0.5572, 0.6256]]) tensor([[0.8631, 0.3728, 1.0428], [0.5944, 0.5572, 0.6256]])
torch.pow函数用于进行求幂操作
import torch a = torch.randn(2, 3) print(a) b = torch.pow(a, 2) print(b)
输出:
tensor([[ 0.0115, 0.2041, -2.9827], [ 0.6467, 0.3175, -0.4201]]) tensor([[1.3127e-04, 4.1647e-02, 8.8963e+00], [4.1824e-01, 1.0082e-01, 1.7648e-01]])
在Pytorch中,我们可以使用标准的Numpy-like的索引操作,例如:
print(x[:, 1])
输出:
tensor([-0.0211, -1.4157, 0.1453, -1.3401, -0.8556])
resize操作:
如果你想要对tensor进行类似resize/reshape的操作,你可以使用torch.view
x = torch.randn(4, 4) y = x.view(16) z = x.view(-1, 8) # 使用-1时pytorch将会自动根据其他维度进行推导 print(x.size(), y.size(), z.size())
输出:
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
concate操作:
torch.cat函数用于将输入的tensor序列进行concate拼接操作
x = torch.randn(2, 3) print(x) x_cat_dim0 = torch.cat((x,x,x), dim=0) x_cat_dim1 = torch.cat((x,x,x), dim=1) print(x_cat_dim0) print(x_cat_dim1)
输出:
tensor([[ 0.6580, -1.0969, -0.4614], [-0.1034, -0.5790, 0.1497]]) tensor([[ 0.6580, -1.0969, -0.4614], [-0.1034, -0.5790, 0.1497], [ 0.6580, -1.0969, -0.4614], [-0.1034, -0.5790, 0.1497], [ 0.6580, -1.0969, -0.4614], [-0.1034, -0.5790, 0.1497]]) tensor([[ 0.6580, -1.0969, -0.4614, 0.6580, -1.0969, -0.4614, 0.6580, -1.0969, -0.4614], [-0.1034, -0.5790, 0.1497, -0.1034, -0.5790, 0.1497, -0.1034, -0.5790, 0.1497]])
如果有一个tensor,只包含一个元素,你可以使用.item()来获得它对应的Python形式的取值
x = torch.randn(1) print(x) print(x.size()) print(x.item()) print(type(x.item()))
输出:
tensor([0.4448]) torch.Size([1]) 0.4447539746761322 <class 'float'>
通常我们在需要控制张量的取值范围不越界时,需要用到torch.clamp函数,它可以对输入参数按照自定义的范围进行裁剪,最后将参数裁剪的结果作为输出。输入参数一共有三个,分别是需要进行裁剪的Tensor变量、裁剪的下边界和裁剪的上边界
import torch a =torch.randn(2,3) print(a) b =torch.clamp(a, -0.5, 0.5) print(b)
输出的内容如下:
tensor([[-0.1076, 1.4202, 1.5780], [-1.3722, -1.7166, -1.0581]]) tensor([[-0.1076, 0.5000, 0.5000], [-0.5000, -0.5000, -0.5000]])
想要学习更多?这里的官方教程有更多关于tensor操作的介绍,介绍了100多个Tensor运算,包括转置,索引,切片,数学运算,线性代数,随机数等。
Pytorch中可以很方便的将Torch的Tensor同Numpy的ndarray进行互相转换,相当于在Numpy和Pytorch间建立了一座沟通的桥梁,这将会让我们的想法实现起来变得非常方便。
注:Torch Tensor 和 Numpy ndarray 底层是分享内存空间的,也就是说改变其中之一会同时改变另一个(前提是你是在CPU上使用Torch Tensor)。
将一个Torch Tensor 转换为 Numpy Array
a = torch.ones(5) print(a) b = a.numpy() print(b)
输出:
tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
我们来验证下它们的取值是如何互相影响的
a.add_(1) print(a) print(b)
输出:
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
将一个 Numpy Array 转换为 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)
输出:
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
注:所有CPU上的Tensors,除了CharTensor均支持与Numpy的互相转换
1.1 深度学习环境配置一节,我们介绍了如何配置深度学习环境,以及如何安装GPU版本的pytorch,可以通过以下代码进行验证:
print(torch.cuda.is_available())
如果输出True,代表你安装了GPU版本的pytorch
True
Tensors可以通过.to函数移动到任何我们定义的设备device上,观察如下代码:
# 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.5906], device='cuda:0')
tensor([0.5906], dtype=torch.float64)
本文作者
初稿:安晟
第2版:游璐颖
校对:安晟
参考资料
《Pytorch深度学习》