梯度的概念+激活函数及其梯度+loss(均方差)及其梯度+交叉熵+多分类实例+全连接网络实例+感知机及其梯度+链式反则+反向传播+l逻辑回归


一、梯度

1、什么是梯度?

导数——反映的是随着x的变化,y的变化趋势

偏微分——指定了自变量的方向上,因变量在某个自变量方向上的变化趋势
在这里插入图片描述

梯度——把所有的偏微分看做向量

在这里插入图片描述

容易出现的问题

(1)有可能会遇到局部最优解
只有当函数为凸函数的时候,才能从任意方向都找得到全局最优解
凸函数的性质
在这里插入图片描述
(2)saddle point出现鞍点,在一个自变量上的偏微分取得极大值,在另一个自变量上取极小值

优化梯度下降法来找到全局最优解的因素

(1)初始状态;

(2)学习率;

(3)momentum——如何逃离局部最小值

2、常见函数的梯度

在这里插入图片描述

二、激活函数及其梯度

神经网络原理:类似于神经元,当值达到一定范围才会激活下一个神经元
在这里插入图片描述
但是此时的激活值并不能求导
为了解决激活值不可导的情况,提出了sigmoid/logistic:光滑可导的函数,且把无穷的值域压缩到[0, 1]的范围内
在这里插入图片描述

sigmoid函数

sigmoid函数图像
但是会出现梯度离散的情况,参数无法得到更新,因为越往后,导数值与接近于0

sigmoid函数求导之后如下:
sigmoid函数求导

import torch
from torch.nn import functional as F

a = torch.linspace(-100, 100, 10).float()
print(a)
tensor([-100.0000,  -77.7778,  -55.5556,  -33.3333,  -11.1111,   11.1111,
          33.3333,   55.5555,   77.7778,  100.0000])


b = torch.sigmoid(a)
print(b)

tensor([0.0000e+00, 1.6655e-34, 7.4564e-25, 3.3382e-15, 1.4945e-05, 9.9999e-01,
    1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00])

Tanh函数,在RNN里用得比较多

在这里插入图片描述
求导:
在这里插入图片描述

a = torch.linspace(-10, 10, 10)
print(a)
tensor([-10.0000,  -7.7778,  -5.5556,  -3.3333,  -1.1111,   1.1111,   3.3333,
          5.5556,   7.7778,  10.0000])

b = torch.tanh(a)
print(b)

tensor([-1.0000, -1.0000, -1.0000, -0.9975, -0.8045,  0.8045,  0.9975,  1.0000,
         1.0000,  1.0000])

Relu是使用最多的激活函数

计算导数的时候非常简单,导数为1。不会放大也不会缩小,很大程度上减少了梯度爆炸和梯度离散发生的可能性
在这里插入图片描述

a = torch.linspace(-1, 1, 10)
print(a)

tensor([-1.0000, -0.7778, -0.5556, -0.3333, -0.1111,  0.1111,  0.3333,  0.5556,
     0.7778,  1.0000])


b = torch.relu(a)
print(b)

tensor([0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.1111, 0.3333, 0.5556, 0.7778,
        1.0000])

softmax

在这里插入图片描述
求导:
当i=j的时候求导结果为:
在这里插入图片描述
当i不等于j的时候求导结果为:
在这里插入图片描述

a = torch.rand(3, requires_grad=True)
p = F.softmax(a, dim=0)
#对a的3个数值分别进行softmax操作
#softmax之后会得到三个在【0-1】之间的数,这个结果分别对a的三个值进行求导


w1 = torch.autograd.grad(p[1], [a], retain_graph=True)

w2 = torch.autograd.grad(p[2], [a])
print(w1, w2)
#(tensor([-0.1053,  0.2178, -0.1125]),) (tensor([-0.1153, -0.1125,  0.2277]),)

在这里插入图片描述
当i=j的时候,值为正,i不等于1的时候值为负

三、loss及其梯度

典型的loss函数有:

(1)均方差

注意:MSE不同于二范数
二范数
在这里插入图片描述
在这里插入图片描述
求导:
在这里插入图片描述

#autograd.grad
x = torch.ones(1)
w = torch.full([1], 2, requires_grad=True)
mse = F.mse_loss(torch.ones(1), x * w)
#计算torch.ones(1)和xw的偏差
print(mse)
#(tensor([1.]),)

w0 = torch.autograd.grad(mse, [w])
#求mse对w的偏导数

print(w0)
#(tensor([2.]),)
#或者是通过loss的反向
x = torch.ones(1)
w = torch.full([1], 2, requires_grad=True)
mse = F.mse_loss(torch.ones(1), x * w)
loss = mse.backward()
w1 = w.grad
print(w1)
#tensor([2.])

(2)Cross Entropy Loss

可以用于二分类、多分类问题,经常使用softmax激活函数
Entropy——熵,指不确定性

熵大则信息量量比较小,越稳定,越没有惊喜度
在这里插入图片描述
Cross Entropy
在这里插入图片描述
P(x)表示通过网络学到的概率值;q(x)表示通过真实分布学到的概率值

import torch
from torch.nn import functional as F
'''
#熵
#1、每个事件发生的概率都相同
a = torch.full([4], 1/4)
print(a)
#tensor([0.2500, 0.2500, 0.2500, 0.2500])
b = -(a * torch.log2(a)).sum()
print(b)
#tensor(2.)

#当有一个事件发生的概率较大时
a = torch.tensor([0.1, 0.1, 0.1, 0.7])
c = -(a * torch.log2(a)).sum()
print(c)
#tensor(1.3568)


#比较极端的情况,一个事件发生的概率几乎等于1
a = torch.tensor([0.001, 0.001, 0.001, 0.999])
d = -(a * torch.log2(a)).sum()
print(d)
#tensor(0.0313)
'''

多分类问题:

在这里插入图片描述
这里的p值是最后的通过激活函数之后的概率值

y是0或1(one—hot编码)
在这里插入图片描述
交叉熵从0.916到0.02时,越接近于我们的目标:

是变好的过程

#Numerical Stability
#如果自己编写的话,需要三部——1、经过softmax激活层得到pred、2、计算log(pred),3、然后计算nll_loss
x = torch.randn(1, 784)
w = torch.randn(10, 784)

logits = x@w.t()

pred = F.softmax(logits, dim=1)

pre_log = torch.log(pred)

H = F.nll_loss(pre_log, torch.tensor([3]))
print(H)

#tensor(34.5468)

#或者一步到位
H = F.cross_entropy(logits, torch.tensor([3]))
print(H)
#tensor(34.5468)

利用minst数据实现多分类

import  torch
import  torch.nn as nn
import  torch.nn.functional as F
import  torch.optim as optim
from    torchvision import datasets, transforms


#设置一次训练所选取的样本数、学习率和最终的输出值
batch_size=200
learning_rate=0.01
epochs=10

train_loader = torch.utils.data.DataLoader(
    datasets.MNIST('../data', train=True, download=True,
                   transform=transforms.Compose([
                       transforms.ToTensor(),
                       transforms.Normalize((0.1307,), (0.3081,))
                   ])),
    batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
    datasets.MNIST('../data', train=False, transform=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))
    ])),
    batch_size=batch_size, shuffle=True)


#设置参数
#randn(out——输出的个数, in输入的个数)
w1, b1 = torch.randn(200, 784, requires_grad=True),\
         torch.zeros(200, requires_grad=True)
w2, b2 = torch.randn(200, 200, requires_grad=True),\
         torch.zeros(200, requires_grad=True)
w3, b3 = torch.randn(10, 200, requires_grad=True),\
         torch.zeros(10, requires_grad=True)

#利用凯明方法进行初始化参数值
torch.nn.init.kaiming_normal_(w1)
torch.nn.init.kaiming_normal_(w2)
torch.nn.init.kaiming_normal_(w3)

#前反馈
def forward(x):
    x = x@w1.t() + b1
    x = F.relu(x)
    x = x@w2.t() + b2
    x = F.relu(x)
    x = x@w3.t() + b3
    x = F.relu(x)
    return x


#优化参数
optimizer = optim.SGD([w1, b1, w2, b2, w3, b3], lr=learning_rate)
criteon = nn.CrossEntropyLoss()

for epoch in range(epochs):

    for batch_idx, (data, target) in enumerate(train_loader):
        data = data.view(-1, 28*28)

        logits = forward(data)
        loss = criteon(logits, target)

        optimizer.zero_grad()
        loss.backward()
        # print(w1.grad.norm(), w2.grad.norm())
        optimizer.step()

        if batch_idx % 100 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))

#计算准确率
    test_loss = 0
    correct = 0
    for data, target in test_loader:
        data = data.view(-1, 28 * 28)
        logits = forward(data)
        test_loss += criteon(logits, target).item()

        pred = logits.data.max(1)[1]
        correct += pred.eq(target.data).sum()

    test_loss /= len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))

torch.nn提供了一些高级API,可以直接定义隐藏层

import torch
from torch import nn
from torch.nn import functional as F


x = torch.randn(1, 784)
#print(x.shape)

#建立隐藏层
layer1 = nn.Linear(784, 200)
layer2 = nn.Linear(200, 200)
layer3 = nn.Linear(200, 10)


#经过隐藏层降维之后,经激活函数激活
x = layer1(x)
x = F.relu(x, inplace=True)
print(x.shape)
#torch.Size([1, 200])

x = layer2(x)
x = F.relu(x, inplace=True)
print(x.shape)
#torch.Size([1, 200])

x = layer3(x)
x = F.relu(x, inplace=True)
print(x.shape)
#torch.Size([1, 10])

全连接网络的实现

import  torch
import  torch.nn as nn
import  torch.nn.functional as F
import  torch.optim as optim
from    torchvision import datasets, transforms


batch_size=200
learning_rate=0.01
epochs=10

#加载数据集的代码省略了
#定义全连接网络
class MLP(nn.Module):

   #初始化
    def __init__(self):
        super(MLP, self).__init__()

       #定义隐藏层的输出值和输入值,linear本身有一套初始化参数值的方法,所以我们不需要自己初始化
        self.model = nn.Sequential(
            nn.Linear(784, 200),
            nn.ReLU(inplace=True),
            nn.Linear(200, 200),
            nn.ReLU(inplace=True),
            nn.Linear(200, 10),
            nn.ReLU(inplace=True),
        )

    def forward(self, x):
        x = self.model(x)

        return x
        
net = MLP()
#传入优化的参数,这里的参数是封装好的
optimizer = optim.SGD(net.parameters(), lr=learning_rate)
criteon = nn.CrossEntropyLoss()

for epoch in range(epochs):

    for batch_idx, (data, target) in enumerate(train_loader):
        data = data.view(-1, 28*28)

        logits = net(data)
        loss = criteon(logits, target)

        optimizer.zero_grad()
        loss.backward()
        # print(w1.grad.norm(), w2.grad.norm())
        optimizer.step()

        if batch_idx % 100 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))


    test_loss = 0
    correct = 0
    for data, target in test_loader:
        data = data.view(-1, 28 * 28)
        logits = net(data)
        test_loss += criteon(logits, target).item()

        pred = logits.data.max(1)[1]
        correct += pred.eq(target.data).sum()

    test_loss /= len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))

四、感知机的梯度推导

感知机单输出

在这里插入图片描述
这使用到的激活函数是sigmoid函数,对损失函数求wj0的导数过程如下:
在这里插入图片描述

#感知机单个输出值
x = torch.randn(1, 10)
w = torch.randn(1, 10, requires_grad=True)

o = torch.sigmoid(x@w.t())
print(o.shape)
#torch.Size([1, 1])

loss = F.mse_loss(torch.ones(1, 1), o)
print(loss.shape)

b = loss.backward()

w = w.grad

print(w)
'''
tensor([[-0.0325,  0.0405,  0.0269,  0.0008, -0.0052, -0.0281, -0.0428,  0.0342,
         -0.0511, -0.0165]])
'''

感知机多输出

在这里插入图片描述
求导
在这里插入图片描述

#感知机多个输出值
x = torch.randn(1, 10)
w = torch.randn(2, 10, requires_grad=True)

o = torch.sigmoid(x@w.t())
print(o.shape)
#torch.Size([1, 2])

loss = F.mse_loss(torch.randn(1, 2), o)

loss = loss.backward()

w = w.grad
print(w)
'''
tensor([[-2.1687e-04, -1.7179e-04, -1.4920e-04,  3.0565e-05,  5.2861e-04,
          3.3786e-04,  8.3089e-05, -2.8767e-05, -2.4070e-04,  6.7921e-04],
        [-7.5930e-02, -6.0148e-02, -5.2237e-02,  1.0702e-02,  1.8508e-01,
          1.1829e-01,  2.9091e-02, -1.0072e-02, -8.4274e-02,  2.3781e-01]])
'''

五、链式法则

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

print("*****************************************************")
#链式法则
x = torch.tensor(1.)
w1 = torch.tensor(2., requires_grad=True)
b1 = torch.tensor(1.)
w2 = torch.tensor(2., requires_grad=True)
b2 = torch.tensor(1.)

y1 = w1 * x + b1
y2 = w2 * y1 + b2

dy2_dy1 = torch.autograd.grad(y2, [y1], retain_graph=True)
print(dy2_dy1)
#(tensor(2.),)

dy1_dw1 = torch.autograd.grad(y1, [w1], retain_graph=True)
print(dy1_dw1)
#(tensor(1.),)

dy2_dw1 =torch.autograd.grad(y2, [w1], retain_graph=True)
print(dy2_dw1)
#(tensor(2.),)

#由于dy2_dw1 = dy2_dy1 * dy1_dw1 所以链式法则成立

六、反向传播

这里的激活函数统统是sigmoid
在这里插入图片描述
在这里插入图片描述

七、2D函数优化实例

找到函数式的极小值
在这里插入图片描述
在这里插入图片描述

import torch
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def himmelblau(x):
    return (x[0] ** 2 + x[1] - 11) ** 2 + (x[0] + x[1] ** 2 - 7) ** 2

x = np.arange(-6, 6, 0.1)
y = np.arange(-6, 6, 0.1)
X, Y = np.meshgrid(x, y)
Z = himmelblau([X, Y])

fig = plt.figure('himmelblau')
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z)
ax.view_init(60, -30)
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.show()

x = torch.tensor([0., 0.], requires_grad=True)
optimizer = torch.optim.Adam([x], lr=1e-3)
                           #对x求偏导, 学习率为lr
for step in range(20000):

    pred = himmelblau(x)

    optimizer.zero_grad()
    #初始化x的值为零
    pred.backward()
    optimizer.step()

    if step % 2000 == 0:
        print("step{}:x={}, y={}".format(step, x.tolist(), pred.item()))

八、逻辑回归

线性回归和逻辑归回/分类问题的区别:

1、函数式不同:

linear regression

y=wx+b;

ligistic regression——在线性回归的基础上加了一个激活函数
在这里插入图片描述

2、目标不同:

线性回顾的目标是预测值接近于真实值;

逻辑回归问题的目标是在x的条件下训练得到y值的概率和当自变量为x时,真实的等于y的概率之间差值最小

在这里插入图片描述

无法直接最大化准确率,原因有两个:(1)容易出现梯度为0的情况;(2)容易出现梯度爆炸的情况

准确率为:
在这里插入图片描述
分母为所有的y值,分子为预测值等于真实值的个数

(1)存在梯度为0的情况;

计算得到的p=0.4,调整权重之后得到0.45,虽然概率增加了,但是accuray没有发生变化

(2)也有可能存在梯度爆炸的情况

当p值从0.499变动到0.501时,准确的个数增加了一个,当y值(=5)数量较少是,准确个数从3变为4,那么准确率从0.6变动到0.8,准确率变化了0.2,而概率值变动了0.002,则会存在断层连续的情况,也就是梯度爆炸

总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值