import torch
import numpy as np
张量的运算规则、切片索引规则与numpy类似,运算中遵循广播原则和同形状同位置元素对齐运算原则
t1 = torch.randn(2,3)
t2 = torch.ones(2,3)
print('t1=',t1)
print('t1+3=',t1+3)
print('t1+t2=',t1+t2) #同位置元素相加
print('t1.add(t2)=',t1.add(t2)) #等价t1+t2
print('t1=',t1)
t1.add_(t2) # add_方法表示就地改变原值,不需要存放在其它变量内
print('t1.add_(t2)=',t1)
输出:
t1= tensor([[-1.1872, 1.4624, 0.1379],
[ 1.0701, -2.6139, -1.2106]])
t1+3= tensor([[1.8128, 4.4624, 3.1379],
[4.0701, 0.3861, 1.7894]])
t1+t2= tensor([[-0.1872, 2.4624, 1.1379],
[ 2.0701, -1.6139, -0.2106]])
t1.add(t2)= tensor([[-0.1872, 2.4624, 1.1379],
[ 2.0701, -1.6139, -0.2106]])
t1= tensor([[-1.1872, 1.4624, 0.1379],
[ 1.0701, -2.6139, -1.2106]])
t1.add_(t2)= tensor([[-0.1872, 2.4624, 1.1379],
[ 2.0701, -1.6139, -0.2106]])
张量的算数运算包括:abs(绝对值)、cunsum(累加)、divide(除)、floor_divide(整除)、mean(均值)、min(最小值)、max(最大值)、multiply(乘)等,矩阵转置常用(tensor.T)和矩阵乘法用(matmul或@)
print('t1.matmul(t2.T)=',t1.matmul(t2.T))
print('t1 @ (t2.T)=',t1 @ (t2.T))
输出:
t1.matmul(t2.T)= tensor([[3.4131, 3.4131],
[0.2456, 0.2456]])
t1 @ (t2.T)= tensor([[3.4131, 3.4131],
[0.2456, 0.2456]])
t3 = t1.sum()
print('t3=',t3,type(t3))
print('t3.item()=', t3.item(),type(t3.item()))
输出:
t3= tensor(3.6586)
t3.item()= 3.658644914627075
使用torch.from_numpy()方法将ndarray转成张量,使用tensor.numpy()方法得到对应的ndarray数组,它们共用相同内存
a = np.random.randn(2,3)
print('a= ', a)
t = torch.from_numpy(a)
print('t= ', t)
print('t.numpy()=',t.numpy())
输出:
a= [[-0.17144614 0.03711562 -0.40770295]
[ 0.64600264 -1.39858095 0.41699902]]
t= tensor([[-0.1714, 0.0371, -0.4077],
[ 0.6460, -1.3986, 0.4170]], dtype=torch.float64)
t.numpy()= [[-0.17144614 0.03711562 -0.40770295]
[ 0.64600264 -1.39858095 0.41699902]]
tensor.size()方法和tensor.shape属性返回张量的形状。
改变张量的形状用tensor.view()方法,相当于numpy中的reshape方法
t = torch.randn(4,6)
print('shape返回张量的形状: t.shape=',t.shape)
t1 = t.view(3,8)
print('view改变形状: t1.shape=',t1.shape)
# 将tensor矩阵展平,-1表示长度自动计算
t1 = t.view(-1,1)
print('view展平: t1.shape=',t1.shape)
# 使用view增加维度,总元素个数不变
t1 = t.view(1,4,6)
print('view增加维度: t1.shape=',t1.shape)
# 当维度为1时,使用torch.squeeze()去掉长度为1的维度,相应的torch.unsqueeze()增加长度为1的维度
print('t1.shape=',t1.shape)
t2 = torch.squeeze(t1) # 去掉长度为1的维度
print('squeeze去掉1维度: t2.shape=',t2.shape)
t3 = torch.unsqueeze(t2,0)
print('unsqueeze增加1维度: t2.shape=',t3.shape)
输出;
shape返回张量的形状: t.shape= torch.Size([4, 6])
view改变形状: t1.shape= torch.Size([3, 8])
view展平: t1.shape= torch.Size([24, 1])
view增加维度: t1.shape= torch.Size([1, 4, 6])
t1.shape= torch.Size([1, 4, 6])
squeeze去掉1维度: t2.shape= torch.Size([4, 6])
unsqueeze增加1维度: t2.shape= torch.Size([1, 4, 6])
requires_grad属性设置为True时,Pytorch会跟踪此张量所有计算,并可调用backward() 计算所有梯度,梯度将累加到grad属性中。
grad_fn属性指向运算生成此张量的方法。
t = torch.ones(2,2,requires_grad= True)
print('是否跟踪计算梯度:', t.requires_grad)
print('输出梯度:', t.grad)
print('生成此张量的方法:', t.grad_fn)
y = t + 5
print('y= ', y)
print('y.grad_fn=',y.grad_fn)
z = y * 2
out = z.mean()
print('out=',out)
# 对out微分:d(out)/d(t)
out.backward()
print('t.grad=',t.grad)
输出:
是否跟踪计算梯度: True
输出梯度: None
生成此张量的方法: None
y= tensor([[6., 6.],
[6., 6.]], grad_fn=)
y.grad_fn=
out= tensor(12., grad_fn=)
t.grad= tensor([[0.5000, 0.5000],
[0.5000, 0.5000]])
print('是否跟踪计算梯度:', t.requires_grad)
print('是否跟踪计算梯度:', (t+2).requires_grad)
with torch.no_grad():
print('是否跟踪计算梯度:', (t+2).requires_grad)
输出:
是否跟踪计算梯度: True
是否跟踪计算梯度: True
是否跟踪计算梯度: False
print('是否跟踪计算梯度:', out.requires_grad)
# s1 = out.data() #获取值
s = out.detach()
print('是否跟踪计算梯度:',s.requires_grad)
输出:
是否跟踪计算梯度: True
是否跟踪计算梯度: False
print('是否跟踪计算梯度:', t.requires_grad)
t.requires_grad_(False)
print('是否跟踪计算梯度:', t.requires_grad)
输出:
是否跟踪计算梯度: True
是否跟踪计算梯度: False