PyTorch 入坑五 autograd与逻辑回归

torch.autograd

      深度学习模型的训练就是不断更新权值,权值的更新需要求解梯度,梯度在模型训练中是至关重要的。
      然而求解梯度十分繁琐,pytorch提供自动求导系统。我们不需要手动计算梯度,只需要搭建好前向传播的计算图,然后根据pytorch中的autograd方法就可以得到所有张量的梯度。

torch.autograd.backward

  • 功能:自动求取计算图所有节点变量的梯度
  • tensor:用于求导的张量,如loss
  • grad_tensors:多梯度权重;当有多个loss需要去计算梯度的时候,就要设计各个loss之间的权重比例
  • retain_graph:保存计算图;由于pytorch采用动态图机制,在每一次反向传播结束之后,计算图都会释放掉。如果想继续使用计算图,就需要设置参数retain_graph为True
  • create_graph:创建导数计算图,用于高阶求导,例如二阶导数、三阶导数等等
torch.autograd.backward(tensors, grad_tensors=None,\
retain_graph=None, create_graph=False, grad_variables=None)

使用示例

import torch
torch.manual_seed(10)  #用于设置随机数

flag = True
# flag = False

if flag:
    w = torch.tensor([1.], requires_grad=True)    #创建叶子张量,并设定requires_grad为True,因为需要计算梯度;
    x = torch.tensor([2.], requires_grad=True)    #创建叶子张量,并设定requires_grad为True,因为需要计算梯度;

    a = torch.add(w, x)    #执行运算并搭建动态计算图
    b = torch.add(w, 1)
    y = torch.mul(a, b)

    y.backward()   #对y执行backward方法就可以得到x和w两个叶子节点
    print(w.grad)   #输出为tensor([5.])
    '''
backward()中有一个retain_graph参数,它是用来保存计算图的,如果还想执行一次反向传播 ,必须将retain_graph参数设置为True,否则代码会报错。因为如果没有设置为True,每进行一次backward之后,计算图都会被清空,没法再进行一次backward()操作
因此,如果执行
	y.backward(retain_graph=True)
	y.backward(retain_graph=True)
	输出为:tensor([10.])
    '''

从代码中可以发现对y求导使用的是y.backward()方法,也就是张量中的类方法。我们上面介绍的是torch.autograd中的backward()。这两个方法之间有什么联系呢?
通过pycharm中的断点调试,可以发现y.backward()是Tensor.py中的一个类方法的函数。这个函数只有一行代码,就是调用torch.autograd.backward()

def backward(self, gradient=None, retain_graph=None, create_graph=False):
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  • grad_tensors,用于设置多个梯度之间的权重,具体的使用可以参考一下下面的代码
import numpy as np
import tensor
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)
    y0 = torch.mul(a, b)  # y0 = (x+w) * (w+1)
    y1 = torch.add(a, b)  # y1 = (x+w) + (w+1)
    loss = torch.cat([y0, y1], dim=0)  # [y0, y1],损失函数由两部分组成
    grad_tensors = torch.tensor([1.,2.])  #设置两部分损失函数的权重
    loss.backward(gradient=grad_tensors)  # gradient 传入 torch.autograd.backward()中的grad_tensors 
    print(w.grad)    # w = 1*5 + 2*2 = 9,输出为9

torch.autograd.grad

  • 功能:求取梯度
  • outputs:用于求导的张量,如loss;
  • inputs:需要梯度的张量,如上面代码中的w;
  • create_graph:创建导数计算图,用于高阶求导;
  • retain_graph:保存计算图
  • grad_outputs:多梯度权重
import numpy as np
import torch
flag = True
if flag:
    x = torch.tensor([3.], requires_grad=True)
    y = torch.pow(x, 3)  # y = x**2
    grad_1 = torch.autograd.grad(y, x, create_graph = True) #求y关于x的一阶梯度
    print(grad_1)   #输出为(tensor([6.], grad_fn=<MulBackward0>),)
    grad_2 = torch.autograd.grad(grad_1[0], x) #y关于x的二阶梯度
    print(grad_2)   #输出为(tensor([2.]),)

梯度不自动清零与grad.zero_()

比较下面两段代码

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.])

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)
        w.grad.zero_()
tensor([5.])
tensor([5.])
tensor([5.])
tensor([5.])

依赖于叶子结点的结点,requires_grad默认为True

待定

叶子结点不可执行in-place

待定

Logistic 算法(逻辑回归算法)

逻辑回归与线性回归的区别

逻辑回归模型表达式:
在这里插入图片描述
线性回归模型表达式:
在这里插入图片描述

  • 逻辑回归是在线性回归的基础上加了一个激活函数sigmoid()
  • 为了更好地描述分类置信度,所以采用sigmoid函数将输出映射到0-1,符合一个概率取值

机器学习的一般步骤

数据 -> 模型 -> 损失函数 -> 优化器

数据

数据的采集、清洗、划分和预处理

模型

根据任务的难易程度选择简单的线性模型或者复杂的神经网络模型

损失函数

根据不同的任务选择不同的损失函数,比如在线性回归模型中采用均方差损失函数,如果是分类任务,可以用交叉熵
有了损失函数,就可以求Loss关于参数的梯度

优化器

得到梯度之后,可以选择某一种优化方式,更新我们的权值。
针对非线性局部最优、鞍点、病态网络等问题,最新优化器在SGD的基础上做过很多优化工作。这是一个很大的课题,后续有时间的话,会开一个专栏进行总结。

@本代码来源于深度之眼《pytorch框架班》
@作者:课程讲师:余老师
@如有侵权,请联系我

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
torch.manual_seed(10)
from math import *


# ============================ step 1/5 生成数据 ============================
sample_nums = 100
mean_value = 1.7
bias = 1.5
n_data = torch.ones(sample_nums, 2)
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)                          # 类别1 标签 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()

    # 清空梯度
    optimizer.zero_grad()

    # 绘图
    if iteration % 20 == 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(-5, 7)
        plt.plot(plot_x, plot_y)

        plt.text(-8, 1, '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:
            plt.show()
            break

结果:
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值