文章目录
前言
只记录感兴趣的东西,详细参考如下。
参考:
http://tangshusen.me/Dive-into-DL-PyTorch/#/
《dive into deep learning》
pytorch文档:https://pytorch.org/docs/stable/torch.html
算数操作
pytorch算数运算+、-、*、/,除了最常见的表示方法,还有in-place(原地)形式
y.add_(x)
# 注:PyTorch操作in-place版本都有后缀_, 例如x.copy_(y), x.t_(), x.cos_
除此之外,但有torch.add(x, y)
虽然保存输出,但是可以添加out参数保存输出torch.add(x, y, out=result)
索引
之前在python中的numpy包提到过,如果使用数组子集选择(数组切片和数组下标索引,都是一回事)都是原数组的视图,所有的变化会返回到原数组上。
x = np.arange(24).reshape((2, 3, 4))
# 数组下标索引
a = x[0]
b = x[0]
a[:] = 12
print(x, a, b) # a[12,1,2,3] b[12,1,2,3],x也变化
# 数组的切片
c = x[0:1]
c[:1] = 13
print(x, a, b, c) # 都变了
上述这种赋值,相当于开辟一个内存空间a存放着指向x的地址,a只是一个指向,没有实际自己的数据空间。
Tensor和numpy一样,索引出来的结果和原数据共内存,一边改,另一边也会跟着改。
x = torch.rand(5, 3)
y = x[0, :]
y += 1
print(y)
print(x[0, :]) # 源tensor也被改了
还有view()也会共享内存,view()是用来改变Tensor形状的,但其实只是改变观察角度,内部数据并没有变化。
y = x.view(15)
z = x.view(-1, 5) # -1所指的维度可以根据其他维度的值推出来
print(x.size(), y.size(), z.size())
x += 1
print(x)
print(y) # 也加了1
如果不希望是视图,而是副本,可以使用clone(),或者先开辟空间再赋值
x_cp = x.clone().view(15)
# 使用clone还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源Tensor
选择函数
index_select(input, dim, index)
# 在指定维度dim上选取,比如选取某些行、某些列
Numpy、PIL、pytorch常用的类型转换
# PIL图片<->tensor
transforms.ToTensor()
transforms.ToPILImage()
# tensor<->numpy
x.numpy() # x开始是tensor,内存共享
torch.from_numpy(x) # x开始是array,内存共享
torch.tensor(x) # x开始是array,内存不共享
# PIL图片<->numpy
numpy.array(x) # x开始是pil图片
Image.fromarray(x.astype('uint8')).convert('RGB') # x开始是array
补充一点,
PIL读取图片是(H x W x C)数据在[0, 255];
Numpy数组最好是np.unit8;
tensor是(C x H x W)数据在[0.0, 1.0]。
广播机制
如果两个形状不同的tensor按照元素运算,会自己复制自己扩充到同样的大小,再做运算。
x = torch.arange(