PyTorch入门实战教程笔记(十四):神经网络与全连接层1

PyTorch入门实战教程笔记(十四):神经网络与全连接层1

交叉熵Cross Entropy Loss

在介绍交叉熵之前,先介绍一下信息熵,表达式如下:
在这里插入图片描述
信息熵表达了信息出现的概率或者不确定性,如果uncertainty比较高,Entropy比较低,说明信息量很大,很惊喜。熵越高,代表越稳定,没有惊喜度。对于cross entropy一般指的是p,q 两个分布H(p, q) = Σp(x) logq(x), 可以推导成H(p,q) = H§ +DKL(p|q), DKL(p|q)是KL Divergence,KL散度,两个分布重合度越高,KL散度值越低,完全重合KL散度为0. 如果P=Q时,H(p,q) = H§, 对于one-hot encoding,它的Entropy = 1log1 = 0, 那么H(p,q) = DKL(p|q), 而P,Q的Divergence就是衡量两个的重叠程度,对于网路模型预测的Pθ(p,q), 和真实的Pr(p,q),如果两者相等,那么H(p|q)=0,就是我们的优化目标。
在这里插入图片描述
针对于二分类问题,参考下图,非cat即dog,设真实值为y,预测值为p,那么可以简化成H(y,p) = -( ylog§ + (1-y)log(1-p) ), 如果y=1的话,那么后一项等于零,意味着要最小值 -log§, 那也就是要最大化log§, 即使p最大化, 而p = P(y = 1 | x), 故优化是合理的,刚好让y=1的概率最大,与目标y=1,是一致的。 如果y=0的话,那么前一项等于零,意味着要最小值 -log(1-p), 那也就是要最大化log(1-p), 即使p最小化, 而p = P(y = 1 | x),也就是最大化y=0的概率,与目标y=0,是一致的,, 故优化是合理的。
在这里插入图片描述
下面举实例来看一下,五类假设top1为dog,可以对比,上面的Q1和下面的Q1算出来的H,上面的H大,下面的H小,说明下面的效果好,与我们实际观测到的下面的Q1比上面的Q1好是一致的,说明通过交叉熵来优化也是可行的。对比于mse,0.4到0.98,优化了0.3~0.4,而cross entropy优化了0.9左右,梯度更大了,优化更快了。
在这里插入图片描述
对比于Sigmoid+MSE,Sigmoid可能出现梯度弥散的情况,且比cross entropy收敛要慢。不过凡事都不是绝对的,有时候cross entropy性能不行,可以用mse试一下,mse的性能比交叉熵要好。
注意对于下面的神经网络:
在这里插入图片描述
对于pytorch来说,里面的cross_entropy,已经包含了softmax+log+null_loss(交叉熵运算),即上图的灰色部分已经包装了, 所以在传入参数时,要传入logits,这样才正确。如果真的要自己一步一步计算,先计算softmax,在计算log,可以调用nll_loss函数,传入参数为经过log运算后的预测值。具体如下图代码:
在这里插入图片描述

多分类问题实战

首先 我们初始化w1 ~ 3,b1 ~ 3,要注意对于pytorch,使用torch.randn来定义w时,第一个维度为ch-out,第二个维度为ch-in,所以第一层输入维度为784,输出为200,要注意一定要设置requires_grad = True,第二层维度没有降维,最后10分类,所以最终的输出为10。
在这里插入图片描述
下面利用SGD优化器,来优化参数w,b,其中nn.CrossEntropyLoss()和前面的F.cross_entropy功能是一样的。然后通过前面定义的函数forward来计算logits,注意criteon(logits, target), 是logits。具体代码如下:
在这里插入图片描述
在实战中会发现,损失一直减不下去,也没出现梯度为零的情况,是因为初始化不合理,影响了最终的结果,所以初始化参数在实战中也是非常重要的,我们做以下调整。
在这里插入图片描述
多分类问题的详细代码:

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)



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

经过10个epoch,实验的精度达到了96%:
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值