# 【深度之眼】【Pytorch打卡第2天】：张量、计算图、线性回归、逻辑回归

## 一、张量的操作

### 拼接

• torch.cat(): 将张量按维度dim进行拼接
• torch.stack()：在新建的维度dim上进行拼接
``````t = torch.ones((2, 3))

t_0 = torch.cat([t, t], dim=0)
t_1 = torch.stack([t, t], dim=0)

print(t_0)
print(t_0.shape)
print(t_1)
print(t_1.shape)
``````

``````tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
torch.Size([4, 3])
tensor([[[1., 1., 1.],
[1., 1., 1.]],

[[1., 1., 1.],
[1., 1., 1.]]])
torch.Size([2, 2, 3])
``````

### 切分

• torch.chunk(input, chunks, dim): 将张量按维度dim进行平均切分
``````t = torch.ones((2, 7))
print(t)

list_of_tensor = torch.chunk(t, dim=1, chunks=3)
print(list_of_tensor)
``````

``````tensor([[1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1.]])
(tensor([[1., 1., 1.],
[1., 1., 1.]]), tensor([[1., 1., 1.],
[1., 1., 1.]]), tensor([[1.],
[1.]]))
``````
• torch.split(): 将张量按维度dim进行切分
``````t = torch.ones((2, 7))
print(t)
list_of_tensor_2 = torch.split(t, 3, dim=1)
print(list_of_tensor_2)

list_of_tensor_3 = torch.split(t, [2, 2, 3], dim=1)
print(list_of_tensor_3)
``````

``````tensor([[1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1.]])
(tensor([[1., 1., 1.],
[1., 1., 1.]]), tensor([[1., 1., 1.],
[1., 1., 1.]]), tensor([[1.],
[1.]]))
(tensor([[1., 1.],
[1., 1.]]), tensor([[1., 1.],
[1., 1.]]), tensor([[1., 1., 1.],
[1., 1., 1.]]))
``````

### 索引

• torch.index_select(): 在维度dim上，按index索引数据
``````t = torch.randint(0, 9, (3, 3))
print(t)

# index_select
idx=torch.tensor([0,2],dtype=torch.long)
t_index_select=torch.index_select(t,index=idx,dim=0)
print(t_index_select)
``````

``````tensor([[8, 7, 5],
[0, 0, 5],
[1, 0, 7]])
tensor([[8, 7, 5],
[1, 0, 7]])
``````
``````t = torch.randint(0, 9, (3, 3))
print(t)

mask = t.ge(5) # ge means greater than or equal to,gt means greater than

``````

``````tensor([[0, 6, 8],
[5, 2, 8],
[2, 4, 5]])
tensor([[False,  True,  True],
[ True, False,  True],
[False, False,  True]])
tensor([6, 8, 5, 8, 5])
``````

### 变换

• torch.reshape: 变换张量形状
notice: 注意事项:当张量在内存中是连续时，新张 量与input共享数据内存
``````# torch.reshape
t = torch.randperm(8)
print(t)
t_reshape = torch.reshape(t, (2, 4))  # -1代表不关心
print(t_reshape)
``````

``````tensor([2, 1, 6, 4, 3, 7, 0, 5])
tensor([[2, 1, 6, 4],
[3, 7, 0, 5]])
``````
• torch.transpose(): 交换张量的两个维度
``````# torch.transpose
t = torch.rand((2, 3, 4))
print(t)
t_transpose = torch.transpose(t, dim0=1, dim1=2)
print(t_transpose)
``````

``````tensor([[[0.8289, 0.5771, 0.4477, 0.0689],
[0.1176, 0.8692, 0.0684, 0.8340],
[0.2765, 0.2561, 0.7809, 0.9669]],

[[0.1702, 0.8590, 0.1033, 0.3139],
[0.5455, 0.9026, 0.0666, 0.7125],
[0.8124, 0.4118, 0.0077, 0.9554]]])
tensor([[[0.8289, 0.1176, 0.2765],
[0.5771, 0.8692, 0.2561],
[0.4477, 0.0684, 0.7809],
[0.0689, 0.8340, 0.9669]],

[[0.1702, 0.5455, 0.8124],
[0.8590, 0.9026, 0.4118],
[0.1033, 0.0666, 0.0077],
[0.3139, 0.7125, 0.9554]]])
``````
• torch.t(): 2维张量转置，对矩阵而言，等价于 torch.transpose(input, 0, 1)

• torch.squeeze(): 压缩长度为1的维度(轴)

``````# torch.squeeze
t=torch.rand((1,2,3,1))

t1=torch.squeeze(t)
print(t1.shape)

t2=torch.squeeze(t,dim=2)
print(t2.shape)
``````

``````torch.Size([2, 3])
torch.Size([1, 2, 3, 1])
``````
• torch.unsqueeze(): 依据dim扩展维度

## 二、张量的数学运算

``````# torch.add
t0=torch.rand((3,3))
t1=torch.ones_like(t0)
print(t0)
print(t1)
``````

``````tensor([[0.9255, 0.6299, 0.0767],
[0.4752, 0.1457, 0.6222],
[0.1632, 0.7180, 0.2238]])
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
tensor([[10.9255, 10.6299, 10.0767],
[10.4752, 10.1457, 10.6222],
[10.1632, 10.7180, 10.2238]])
``````

## 三、线性回归

``````import torch
import numpy as np
import matplotlib.pyplot as plt
torch.manual_seed(10)

lr = 0.1   # 学习率

# 创建训练数据
x = torch.rand(20, 1) * 10
# print(x)
y = 2 * x + (5 + torch.randn(20, 1))

# 构建回归参数

for iteration in range(1000):
# 前向传播
wx = torch.mul(w, x)

# 计算MSE loss
loss = (0.5 * (y - y_pred) ** 2).mean()

# 后向传播,得到梯度
loss.backward()

# 更新参数

# 绘图
if iteration%20==0:

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(iteration,w.data.numpy(),b.data.numpy()))
plt.pause(0.5)

if loss.data.numpy()<1:
break

``````

## 四、计算图

### 叶子结点很重要

• is_leaf(): 查看是否为 叶子结点，返回：True / False
``````import torch
import numpy as np
import matplotlib.pyplot as plt

y = torch.mul(a, b)

y.backward()

# 查看叶子结点
print(a.is_leaf, b.is_leaf, w.is_leaf)

# 查看梯度

``````

``````tensor([5.])
False False True
tensor([5.]) tensor([2.]) None
``````

## 五、动态图

• tensors: 用于求导的张量，如 loss

• retain_graph : 保存计算图

• create_graph : 创建导数计算图，用于高阶求导

``````import torch
import numpy as np
import matplotlib.pyplot as plt

y0 = torch.mul(a, b)

loss = torch.cat([y0, y1], dim=0)
print(loss)

# 权重的设置

``````

``````tensor([6.], grad_fn=<MulBackward0>) tensor([5.], grad_fn=<AddBackward0>)
tensor([7.])

Process finished with exit code 0
``````

• outputs: 用于求导的张量，如 loss
• inputs : 需要梯度的张量
• create_graph : 创建导数计算图，用于高阶求导
• retain_graph : 保存计算图
``````import torch
import numpy as np
import matplotlib.pyplot as plt

y = torch.pow(x, 2)

# 一次求导
print(gard_1)

# 二次求导
``````

``````(tensor([6.], grad_fn=<MulBackward0>),)
(tensor([2.]),)
``````

1. 梯度不自动清零，会叠加
3. 叶子结点不可执行in-place

``````import torch

a = torch.ones((1,))
print(id(a), a)

# a=a+torch.ones((1,))   # 开辟新的内存地址
# print(id(a),a)

a += torch.ones((1,))    # 原位操作
print(id(a), a)
``````

``````2093022703432 tensor([1.])
2093022703432 tensor([2.])
``````

## 七、逻辑回归

### 机器学习的五大步：

• 数据
• 模型
• 损失函数
• 优化器
• 迭代训练
``````import torch
import torch.nn as nn

import numpy as np
import matplotlib.pyplot as plt

torch.manual_seed(10)

# ********************** step 1/5: 生成数据 **********************
sample_nums = 100
mean_value = 1.7
bias = 1
n_data = torch.ones(sample_nums, 2)  # dim = 100x2

x0 = torch.normal(mean_value * n_data, 1) + bias  # 类别0 数据 shape=(100,2)
y0 = torch.zeros(sample_nums)                     # 类别0 标签 shape=(100,1)

x1 = torch.normal(-mean_value * n_data, 1) + bias # 类别1 数据 shape=(100,2)
y1 = torch.ones(sample_nums)                      # 类别2 标签 shape=(100,1)

train_x = torch.cat((x0, x1), 0)
train_y = torch.cat((y0, y1), 0)

# ********************** step 2/5: 选择模型 **********************

class LR(nn.Module):
def __init__(self):
super(LR, self).__init__()
self.features = nn.Linear(2, 1)
self.sigmoid = nn.Sigmoid()

def forward(self, x):
x = self.features(x)
x = self.sigmoid(x)
return x

# 实例化逻辑回归模型
lr_net = LR()

# ********************** step 3/5: 选择损失函数 **********************
loss_fn = nn.BCELoss()

# ********************** step 4/5: 选择优化器 **********************
lr = 0.01  # 学习率
optimizer = torch.optim.SGD(lr_net.parameters(), lr=lr, momentum=0.9)

# ********************** step 5/5:模型训练 **********************

for iteration in range(1000):
# 向前传播
y_pred = lr_net(train_x)

# 计算loss
loss = loss_fn(y_pred.squeeze(), train_y)

# 反向传播
loss.backward()

# 更新参数
optimizer.step()

# 绘图
if iteration % 20 == 0:
# 以0.5为阈值进行分类

# 计算正确预测的样本数

# 计算准确率
acc = correct.item() / train_y.size(0)
plt.scatter(x0.data.numpy()[:,0],x0.data.numpy()[:,1],c='r',label='class 0')
plt.scatter(x1.data.numpy()[:, 0], x1.data.numpy()[:, 1], c='b', label='class 1')

w0,w1=lr_net.features.weight[0]
w0,w1=float(w0.item()),float(w1.item())
plot_b=float(lr_net.features.bias[0].item())
plot_x=np.arange(-6,6,0.1)
plot_y=(-w0*plot_x-plot_b)/w1

plt.xlim(-5,7)
plt.ylim(-7,7)
plt.plot(plot_x,plot_y)

plt.text(-5,5,'loss=%.4f'%loss.data.numpy(),fontdict={'size':20,'color':'red'})
plt.title('Iteration:{}\nw0:{:.2f} w1:{:.2f} b:{:.2f} accuracy:{:.2f}'.format(iteration,w0,w1,plot_b,acc))
plt.legend()

plt.show()
plt.pause(0.5)

if acc>0.99:
break

``````