import torch
import numpy as np
import matplotlib.pyplot as plt
torch.manual_seed(1100)
# ========================= example 1-1 =======================
"""
torch.autograd.backward()
1.功能:自动求取梯度
2.参数
tensors,通常是求导张量,如loss;
retain_graph,保存图;
create_graph,创建图,用于高阶求导
grad_tensors,多梯度权重
"""
# 使用retain_graph保存图
flag = False
# flag = True
if flag:
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
a = torch.add(w, x)
# 如果想保存a的张量梯度
b = torch.add(w, 1)
y = torch.mul(a, b) # y0 = (x+w) * (w+1)
y.backward(retain_graph=True)
print(w.grad)
# ========================= example 1-2 =======================
# grad_tensors
flag = False
# flag = True
if flag:
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
a = torch.add(w, x)
# 如果想保存a的张量梯度
b = torch.add(w, 1)
y0 = torch.mul(a, b) # y0 = (x+w) * (w+1)
y1 = torch.add(a,b) # y1 = (x+w) + (w+1) dy1/dw = 2
loss = torch.cat([y0,y1],dim=0)
grad_tensors = torch.tensor([1.,2.]) # 设置权重
# w.grad = w1*y0+w2*y1=1*5+2*2=9
loss.backward(gradient=grad_tensors)
print(w.grad)
# ========================= example 1-3 =======================
"""
torch.autograd.grad()
1.功能:求取梯度
2.参数
outputs,通常是求导张量,如loss;
inputs,需要求梯度张量
retain_graph,保存图;
create_graph,创建图,用于高阶求导
grad_tensors,多梯度权重
"""
# autograd.grad实现二阶导的求导过程
flag = False
# flag = True
if flag:
x = torch.tensor([3.],requires_grad=True)
y = torch.pow(x,2) # y = x**2
grad_1 = torch.autograd.grad(outputs=y,inputs=x,create_graph=True)
# y是output x是input create_graph一定要变成True才能实现高阶求导
# grad_1 = dy / dx = 2x = 2 * 3 = 6
print(grad_1)
grad_2 = torch.autograd.grad(grad_1[0],x)
# grad_2 = d(dy/dx)/dx = d(2x)/dx = 2
print(grad_2)
# ========================= tips:1 =======================
# 为什么有时候要导数清零
flag = False
# flag = True
if flag:
w = torch.tensor([1.],requires_grad=True)
x = torch.tensor([2.],requires_grad=True)
for i in range(4):
a = torch.add(w,x)
b = torch.add(w,1)
y = torch.mul(a,b)
y.backward()
print(w.grad)
"""
不清零
tensor([5.])
tensor([10.])
tensor([15.])
tensor([20.])
"""
w.grad.zero_()
# _下划线的意思:原味操作
"""
清零
tensor([5.])
tensor([5.])
tensor([5.])
tensor([5.])
"""
# ========================= tips:2 =======================
# 依赖于叶子节点的节点,requires_grad 默认 True
flag = False
# flag = True
if flag:
w = torch.tensor([1.],requires_grad=True)
x = torch.tensor([2.],requires_grad=True)
a = torch.add(w,x)
b = torch.add(w,1)
y = torch.mul(a,b)
print(a.requires_grad,b.requires_grad,y.requires_grad)
# ========================= tips:3 =======================
# 叶子节点不可执行in-place
flag = False
# flag = True
if flag:
w = torch.tensor([1.],requires_grad=True)
x = torch.tensor([2.],requires_grad=True)
a = torch.add(w,x)
b = torch.add(w,1)
y = torch.mul(a,b)
w.add_(1) # 在反向传播前,改变w的值
"""
会报错:如下
RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.
"""
y.backward()
# what is in-place操作:在原始内存当中,去改变这个数据
flag = False
# flag = True
if flag:
a = torch.ones((1,))
print(id(a),a)
a = a + torch.ones((1,)) # 表明分配了新的一个内存给a,即非in-place操作
print(id(a),a)
a += torch.ones((1,)) # += 操作后,地址没改变,即原位操作,in-palce操作
print(id(a),a)
"""
2443338884264 tensor([1.])
2443561213288 tensor([2.])
2443561213288 tensor([3.])
"""
# ========================= 实践案例:logistics regression =======================
# y = f(wx+b)
# f(x) = sigmoid(y)
# 线性2分类模型 0 0.5>y| 1 0.5<=y
# 训练步骤:【获取数据+模型+损失函数+优化器】-迭代训练
import torch.nn as nn
# ----------------------------- setp 1/5 生成数据 ----------------------------------------
sample_nums = 100
mean_value = 1.7
bias = 1
n_data = torch.ones(sample_nums,2)
x0 = torch.normal(mean_value*n_data,1) + bias
y0 = torch.zeros(sample_nums)
x1 = torch.normal(-mean_value*n_data,1) + bias
y1 = torch.ones(sample_nums)
train_x = torch.cat((x0,x1),0)
train_y = torch.cat((y0,y1),0)
# ----------------------------- setp 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() # 实例化逻辑回归模型
# ----------------------------- setp 3/5 损失函数 ----------------------------------------
loss_fn = nn.BCELoss()
# ----------------------------- setp 4/5 选择优化器 ----------------------------------------
lr = 0.01 # learning rate
optimizer = torch.optim.SGD(lr_net.parameters(),lr=lr,momentum=0.9)
# ----------------------------- setp 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 % 200 == 0:
mask = y_pred.ge(0.5).float().squeeze() # 以0.5位阈值分类
correct = (mask == train_y).sum() # 计算预测正确的个数
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:{:.2%}'.format(iteration,w0,w1,plot_b,acc))
plt.legend()
plt.show()
plt.pause(0.5)
if acc > 0.99:
break