一、tensor的创建
- 初始化一个随机的tensor,数值可能很大,也可能很小
- 利用
random
初始化tensor
= torch.rand(5, 3)
x = torch.randint(size=[3,4], low=0, high=3) # 数值位于[0, 3)的整数
x = torch.randn(2, 3) # 满足正态分布的 2*3 的 tensor
y = torch.rand_like(x) # 生成维度与x相同的tensor
- 初始化一个类型为long的全零tensor
= torch.zeros(5, 3, dtype=torch.long)
x = torch.zeros(5, 3).long()
- 生成全1的tensor
= torch.ones(3, 4)
x = torch.ones(2, 3, 4)
x = torch.ones(3, 4, dtype=int64) # 同时也可指定数据类型
- 根据数据构造tensor,这些方法会重用原来tensor的特征,例如数据类型,除非提供新的数据类型
= torch.tensor([5.5, 3]) # 根据数据构造tensor
y = x.new_ones(2, 3) # y.type沿用上面的数据类型,为torch.FloatTensor
z = x.new_ones(2, 3, dtype = torch.int32) # 指定新的数据类型
- 查看tensor的形状
print(x.shape)
print(x.shape[0]) # 返回第0维的大小
print(x.size())
print(x.size(0)) # 返回第0维的大小
- 获取维度
- 查看tensor的数据类型
- tensor的数据类型包括:torch.float64,torch.float32,torch.int64,torch.int32,torch.int16
= x.type(torch.float64) # y的数据与x相同,数据类型为float64
-
torch.Tensor()
和torch.tensor()
区别
- torch.Tensor()是Python类,是默认张量类型
torch.FloatTensor()
的别名。参数没有[]
时接收维度
作为参数生成张量,参数有[]
时接收数据
作为参数生成张量
>>> a=torch.Tensor([3,2]) # 生成数据为3,2的tensor
>>> a
tensor([3., 2.])
>>> a.type()
'torch.FloatTensor'
>>> b=torch.Tensor(3,2) # 生成3行2列的tensor
>>> b
tensor([[0.0000e+00, 0.0000e+00],
[2.8026e-45, 0.0000e+00],
[1.4013e-45, 0.0000e+00]])
- torch.tensor()的函数原型如下(直接
接收数据
作为参数生成张量):
torch.tensor(data, dtype=None, device=None, requires_grad=False)
其中data
可以是:list,tuple,ndarray,Python scalars等类型
torch.tensor()可以从data中的数据部分做拷贝(而不是直接引用),根据原始数据类型生成相应的torch.LongTensor
,torch.FloatTensor
,torch.DoubleTensor
。
>>> a = torch.tensor([1, 2])
>>> a.type()
'torch.LongTensor'
>>> a = torch.tensor([1., 2.])
>>> a.type()
'torch.FloatTensor'
>>> a = np.zeros(2, dtype=np.float64)
>>> a = torch.tensor(a)
>>> a.type()
'torch.DoubleTensor'
Reference: 【PyTorch】Tensor和tensor的区别
二、tensor的运算
- 对应元素相加
= torch.ones([5, 3]) # 初始化一个随机的tensor
y = torch.rand([5, 3]) # 初始化一个数字位于(0,1)的随机tensor
print(torch.add(x, y)) # 等价于x + y
res = torch.empty([5, 3])
torch.add(x, y, out = res) # 也就等价于res = x + y
in-place 操作
任何在原地改变张量的操作都有一个 _
后缀。例如x.copy_(y
), x.t_()
操作将改变x
- 广播
- 其他相关操作
.mean() # 求x所有元素的均值
x.sum() # 求x所有元素的和
x.max() # 获取最大值
x.min() # 获取最小值
x.transpose(0, 1) # 交换0维和1维的数据
x = x.permute(2,0,1) # 将原本0,1,2的顺序改为2,0,1
x.t() # 转置,无参方法,只能对一维和二维tensor进行转置
x.T # 转置
三、tensor的索引
可以使用所有的numpy索引操作
[:, 1:] # 留下所有的行,从第一列往后取
x[1:, 1:] # 从第一行以及第一列往后取
resize操作
用于重塑张量的形状,使用 torch.view
。相当于把tensor拉成一长条,然后根据所给的维度进行重塑
= torch.randn([4, 4])
y = x.view([16])
z = x.view([-1, 8]) # -1的意思是不指定维度,计算机自行计算
print(x.size(), y.size(), z.size())
当tensor为1*1时,可以用 item()
方法转成 python数值
= torch.rand(1)
x = x.item() # 此时x就是一个数值
关关于更多转置,索引,数学运算等操作参考:click
四、Torch张量与numpy数组相互转换
相互转换的tensor和ndarray 共享内存空间
,改变其中一个,另一个也改变
- 根据tensor创建ndarray
= torch.ones(5) # 创建全 1 tensor
b = a.numpy() # 根据tensor构造numpy,此时a和b共享内存空间
a[0] = 100 # 改变 a,b也会跟着改变
print(b) # [100. 1. 1. 1. 1.]
- 根据ndarray创建tensor
= np.ones(5)
b = torch.from_numpy(a) # 直接强制类型转换torch.tensor(a)
np.add(a, 1, out=a) # 等价于 a += 1,a内所有的值加1
print(a)
print(b)
五、张量的自动微分
- tensor的数据结构
-
data
: 表示tensor的数据值 -
grad
:保存了data的梯度,与data形状一致 -
grad_fn
:指向Function对象,用于反向传播的梯度计算之用
= torch.ones([2, 2], requires_grad=True)
y = x + 2
print(y.data)
print(y.grad_fn)
2. 反向传播求梯度
= torch.ones([2, 2], requires_grad=True)
y = x + 2
z = y ** 2 + 3
out = z.mean() # 到达输出层
out.backward() # 输出对输入求梯度,将梯度保存在输入的grad属性
print(x.grad)
最终会将输出对输入的梯度保存在输入的 grad
属性
然而我们要是查看输出值对中间的某个变量的梯度,就会报错
他说 正在访问非叶子Tensor的Tensor的属性,意思就是 grad
属性在非叶tensor上是不能访问的
- 不跟踪计算过程
包含在 with torch.no_grad()
上下文中时,计算不会被跟踪
with torch.no_grad():
is_trace = (x + 1).requires_grad # 返回False
detach()
方法也可以获得tensor不包含梯度的值
4. 改为跟踪计算过程
requires_grad_(bool)
方法原地改变tensor 的 requires_grad
属性
使用GPU运算
cuda
是NVIDIA推出的运算平台
可以使用 to()
方法将张量移动到别的设备上
if torch.cuda.is_available():
device = torch.device("cuda") # 获取GPU
y = torch.ones_like(x, device=device) # 利用GPU运算
x = x.to(device) # 将tensor搬到GPU上计算
z = x + y
print(z)
print(z.to("cpu", torch.double)) # 重新搬回CPU上运算,由于numpy的ndarray只能在cpu上运算