Pytorch简介
Pytorch是一个基于Python的深度学习框架,可以代替Numpy在GPU上进行科学计算。
什么是Tensor
Tensor即张量,类似于Numpy的ndarrays,tensor可以在GPU上使用以加速计算。
Pytorch创建张量的常用方法
- 创建一个未初始化的张量,其值不确定:
# 初始化值不确定,由所分配内存的当前值决定
x = torch.empty(5, 3)
print(x)
运行后结果如下,可以看到元素的值是随机的,再次运行元素的值也会发生变化。
- 创建一个随机初始化的张量,元素值在0到1之间:
# 随机初始化矩阵,各元素的值在0到1之间
x = torch.rand(5, 3)
print(x)
运行结果如下。
3. 用0初始化创建张量,并设置元素类型为long:
# 用0初始化创建一个矩阵,并设置元素类型为long
x = torch.zeros((5, 3), dtype=torch.long)
print(x)
运行结果如下。
4. 直接用数据构建张量:
# 直接从数据构造张量
x = torch.tensor([[5.5, 3], [1.2, 3.99]])
print(x)
运行结果如下。
5. 利用已有张量创建新张量,若未指定新的dtype,则dtype与已有张量相同:
# 利用已有张量创建新张量
x = x.new_ones((5, 3), dtype=torch.double) # new_ 方法会改变对象大小
print(x)
x = torch.randn_like(x, dtype=torch.float)
print(x)
这里的x是已经创建过的张量,即一个实例化的对象,对象的new_方法会重置对象大小。运行结果如下。
查看Tensor的size
查看张量维度可以使用张量对象的size()方法:
# 查看张量维度
print(x.size())
结果如下。
Note:torch.Size类型实际是一个元组类型,因此它支持各种元组操作。
基本运算操作
加法操作要求两个张量的维度相同。
## 加法
y = torch.rand((5, 3))
print(x + y) # 方法一
print(torch.add(x, y)) # 方法二
result = torch.empty((5, 3))
torch.add(x, y, out=result) # 方法三,用out参数指定输出存储位置
print(result)
y.add_(x) # 方法四,将x加到y上
print(y)
Note:当对象需要就地更改时,使用对象的_方法,如y.add_()将直接把结果保存至y。
索引操作类似Numpy,可以使用所有附加的功能。
## 索引操作
print(x)
print(x[:, 1]) # 取第二列
当Tensor只有一个元素时,可用item()方法取出元素。
## 取单个元素
x = torch.randn(1)
print(x)
print(x.item()) # 取元素
张量对象的view()方法可以重置张量维度。
## resize操作
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # 当设置-1时,该维度的值由其余维度的值来确定
print(x.size(), y.size(), z.size())
执行结果如下。
Tensor与Numpy的转换
tensor转换numpy可以调用.numpy()方法,但应当注意的是,torch tensor和numpy数组将共享基础内存位置(如果torch tensor在CPU上),并且当一个发生改时,另一个也会发生改变。
## tensor转换numpy
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
a.add_(1)
print(a)
print(b)
运行结果如下。
除了CharTensor之外,CPU上的所有Tensor都支持转换为NumPy并返回。
## numpy转换tensor
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
运行结果如下。
Note:Numpy数组默认类型是float64,而Tensor数据的默认类型是float64,采用from_numpy()方法或torch.tensor()方法得到的tensor数据类型与numpy一致,即原先的numpy是float64,则得到的tensor也是float64;若采用torch.Tensor()方法(注意这里的T是大写),则得到的tensor为float32。此外,使用from_numpy()方法会共享内存;使用torch.tensor()方法只复制数据,不共享内存;使用torch.Tensor()方法当数据类型一致时,共享内存,不一致时,复制数据,不共享内存。测试代码如下:
当使用默认数据类型时:
# 测试数据类型
a = np.zeros(5)
b = torch.Tensor(a)
c = torch.tensor(a)
d = torch.from_numpy(a)
print("a:" + str(a.dtype), "\nb:" + str(b.dtype), "\nc:" + str(c.dtype), "\nd:" + str(d.dtype))
# 测试是否共享内存
a[2] = 100
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
执行结果:
当修改numpy数据类型为float32后:
a = np.zeros(5, dtype=np.float32) # 修改numpy数据类型为float32
b = torch.Tensor(a)
c = torch.tensor(a)
d = torch.from_numpy(a)
print("a:" + str(a.dtype), "\nb:" + str(b.dtype), "\nc:" + str(c.dtype), "\nd:" + str(d.dtype))
# 测试是否共享内存
a[2] = 100
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
执行结果:
总结如下表:
方法 | 是否保持数据类型 | 是否共享内存 |
from_numpy() | 是 | 是 |
torch.tensor() | 是 | 否 |
torch.Tensor() | 否 | 仅数据类型一致时共享内存 |
在GPU上使用Tensor
如果存在可用的CUDA,使用.to()方法可以让Tensor在指定设备上进行计算。
# 在GPU上使用tensor
if torch.cuda.is_available():
device = torch.device("cuda") # 一个CUDA设备对象
y = torch.ones_like(x, device=device) # 直接在GPU上创建tensor
x = x.to(device) # 或者使用 x = x.to("cuda")
z = x + y
print(z)
print(z.to("cpu", torch.double)) # .to 方法也可以同时改变dtype
运行结果如下。