1. 张量操作
- dim : 表示张量的维度, 例如2维张量,dim=0或者1, 当dim=0表示对行方向处理; dim=1表示对列方向处理;
- 对于多维张量,dim从小到大取值表示具体某一维度.
实例:
a = torch.ones([1,3])
dim=0,表示对a的行方向(1)进行处理,包括拼接,切片等;
dim=1,表示对a的列方向(3)进行处理,包括拼接,切片等;
1.1 张量拼接
# 1. torch.cat()张量拼接,将张量按维度dim进行拼接
a=torch.randn([1,3]) # 形状(1,3)
b = torch.cat([a,a],dim=0) # 在dim=0维度上拼接,大小(2,3)
b = torch.cat([a,a],dim=1) # 在dim=1维度上拼接,大小(1,6)
# 2. torch.stack()张量拼接, 在新创建的维度上进行拼接
a = torch.randn([1,3]) # 形状(1,3)
# 仅改变dim
b = torch.stack([a,a],dim=0) # 在dim=0维度上拼接,大小(2,1,3)
b = torch.stack([a,a],dim=1) # 在dim=1维度上拼接,大小(1,2,3)
b = torch.stack([a,a],dim=2) # 在dim=2维度上拼接,大小(1,3,2)
# 改变拼接张量数量
b = torch.stack([a,a,a],dim=0) # 在dim=0维度上拼接,大小(3,1,3)
b = torch.stack([a,a,a],dim=1) # 在dim=1维度上拼接,大小(1,3,3)
1.2 张量切分
# 1. torch.chunk()张量切分,将张量按维度dim进行切分
# 参数: input:待切分的张量, chunks:切的份数,dim:要切分的维度
# 切片后的张量是元祖的形式
a = torch.randn([3,5]) # 形状(3,5)
b = torch.chunk(input=a, chunks=3,dim=0) # 在dim=0维度上切片,将a切成3份
# 2. torch.split()张量切分
# 第一个参数: 待切分的张量,
# 第二参数:为int数时,表示每一份的长度,为list时,按照list切分,且list之和要与将切分的维度相等.
a = torch.randn([3,5]) # 形状(3,5)
b = torch.split(a,1,dim=0) # 在dim=0维度上切分
b = torch.stack(a,1,dim=1) # 在dim=1维度上切分
b = torch.stack(a,[1,2,2],dim=1) # 在dim=1维度上切分,按照lis切分
1.3 张量索引
a = torch.randn([3,5]) # 形状(3,5)
# index_select中的index参数必须是整型数据张量的形式,dim表示索引的维度
torch.index_select(a,index=torch.tensor([0,2]),dim=1)
1.4 张量变换
张量进行形状重组后,其将变为数据共享内存,因此重组后不能改变数据.
# 1. torch.reshape() 变换张量形状
a = torch.randn([3,5]) # 形状(3,5)
b = torch.reshape(a,[5,3]) # 形状(5,3),注意重组前后维度之积不改变
b = torch.reshape(a,[5,-1]) # -1表示系统根据已知条件自己推测维度值
# 2. torch.transpose(), 交换张量的两个维度
# 参数: 要交换的张量, 交换的维度(0,1,2,3等), 交换的维度(0,1,2,3等)
a = torch.rand([2,1,3]) # 形状(2,1,3)
b = torch.transpose(a,0,2) # 交换0,2维度,得到形状(3,1,2)
b = torch.transpose(a,1,2) # 交换1,2维度,得到形状(2,3,1)
# 3. torch.squeeze(), 压缩长度为1的维度(轴)
# 参数dim: 如果不指定dim,则将原始张量维度为1的都删除压缩,如果指定dim,则仅在该维度为1时进行压缩
a = torch.randn([1,2,3,1]) #形状(1,2,3,1)
b = torch.squeeze(a) # 全压缩,压缩后形状[2,3]
b = torch.squeeze(a,dim=3) # 仅压缩维度为3上,形状变为(1,2,3)
b = torch.squeeze(a,dim=1) # 压缩维度为1上,由于其其不为1形状不变(1,2,3,1)
# 4. torch.unsqueeze() 扩展dim维度
a = torch.zeros([2,3]) # 形状(2,3)
b = torch.unsqueeze(a,dim=0) # 扩展为(1,2,3)
b = torch.unsqueeze(a,dim=1) # 扩展为(2,1,3)
b = torch.unsqueeze(a,dim=2) # 扩展为(2,3,1)
2. 张量运算
- 实例展示
a = torch.ones([1,3]) # (1,3)全为1的张量
b = torch.normal(2,0.02,[1,3]) # (1,3)正态分布张量
c = torch.add(b,a,alpha=10) # c = b+10*a, 相加,带乘项因子10
3. 线性回归实例
问题: y=wx+b, 通过已知真值的x,y(有噪声),反向传播的方式求解w,b
import torch
import matplotlib.pyplot as plt
torch.manual_seed(10) # 设置随机初始化种子
lr = 0.05 # 学习率
# 创建训练数据
x = torch.rand([1,20])*10 # 均匀分布[0-1],扩大10倍
y = 8*x + (6 + torch.randn([1,20])) # y=8*x+6+正态分布噪声(0,1)
# 构建线性函数
w = torch.randn([1,1], requires_grad=True) # 需要计算梯度
b = torch.zeros([1,1], requires_grad=True)
for iter in range(1000):
# 前向传播
y_pred = w*x + b # 与下面式子等价,都是torch张量形式
# y_pred = torch.add( torch.mul(w, x), b )
# 损失函数
loss = ( 0.5* (y-y_pred)**2 ).mean()
# 反向传播
loss.backward()
# 更新参数
w.data.sub_( lr*w.grad ) # sub添加_(下划线) 会改变调用对象的值,即改变w的值
b.data.sub_( lr*b.grad )
# 每次迭代都清空张量的维度
w.grad.zero_()
b.grad.zero_()
# 绘图
if iter % 100 == 0:
print('Loss=%.4f' % loss.data.numpy()) # 打印损失函数
# 画出损失函数图
"""
plt.scatter(x.data.numpy(), y.data.numpy())
plt.plot(x.data.numpy(), y_pred.data.numpy(), 'r-', lw=5)
plt.text(2, 20, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
plt.xlim(1.5, 10)
plt.ylim(8, 28)
plt.title("Iteration: {}\nw: {} b: {}".format(iter, w.data.numpy(), b.data.numpy()))
plt.pause(0.1)
"""
print(w,b)