Know Your Wisdom

深度学习基础

2022-04-09

参考:https://zh-v2.d2l.ai/chapter_multilayer-perceptrons/mlp-scratch.html

首先给一个可以跑的起来的例子,然后对该例子进行解析:

import os, sys
import torch as tc
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from torch import nn
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, datasets


# download and load FashionMNIST dataset
def load_data(batch_size=64):
    train_dataset = datasets.FashionMNIST(
        root='~/.pytorch/F_MNIST_data',
        train=True,
        transform=transforms.ToTensor(),
        download=True
    )
    test_dataset = datasets.FashionMNIST(
        root='~/.pytorch/F_MNIST_data',
        train=False,
        transform=transforms.ToTensor(),
        download=True
    )

    # get iterator
    train_iter = DataLoader(
        dataset=train_dataset,
        batch_size=batch_size,
        shuffle=True,
    )
    test_iter = DataLoader(
        dataset=test_dataset,
        batch_size=batch_size,
        shuffle=True,
    )

    return train_iter, test_iter


def relu(X):
    return tc.max(input=X, other=tc.tensor(0.0))


def evaluate_accuracy(data_iter, net):
    acc_sum, n = 0.0, 0
    for X, y in data_iter:
        X = X.view(-1, num_inputs)
        acc_sum += (net(X).argmax(dim=1) == y).sum().item()
        n += y.shape[0]
    return acc_sum / n


if __name__ == '__main__':
    # create data loader
    batch_size = 64
    train_loader, test_loader = load_data(batch_size=batch_size)
    num_inputs, num_outputs, num_hiddens = 784, 10, 256

    # H(Hidden) = ReLU(XW1 + b1)
    W1 = nn.Parameter(tc.randn(
        num_inputs, num_hiddens, requires_grad=True) * 0.01)
    b1 = nn.Parameter(tc.zeros(num_hiddens, requires_grad=True))
    # O(Output) = HW2 + b2
    W2 = nn.Parameter(tc.randn(
        num_hiddens, num_outputs, requires_grad=True) * 0.01)
    b2 = nn.Parameter(tc.zeros(num_outputs, requires_grad=True))
    params = [W1, b1, W2, b2]

    def net(X):
        h = X@W1 + b1
        h = relu(h)
        o = h@W2 + b2
        return o

    loss = nn.CrossEntropyLoss(reduction='none')

    nums_epochs, lr = 20, 0.001
    updater = tc.optim.SGD(params, lr=lr)
    for epoch in range(nums_epochs):
        train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
        for X, y in train_loader:
            X = X.view(-1, num_inputs)
            y_hat = net(X)
            l = loss(y_hat, y).sum()
            updater.zero_grad()
            l.backward()
            updater.step()
            train_l_sum += l.item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()
            n += y.shape[0]
        test_acc = evaluate_accuracy(test_loader, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
              % (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))

最终的效果:

epoch 20, loss 0.2523, train acc 0.909, test acc 0.886

网络结构

参考:https://zh-v2.d2l.ai/chapter_multilayer-perceptrons/mlp.html

损失函数 - 交叉熵

assume we have got the y^ and y, so the cross entropy loss is -y*log(y^) , but why this formula happened?

损失函数 - SGD(随机梯度下降)

Official doc: https://pytorch.org/docs/stable/generated/torch.optim.SGD.html

My works before(including animation): https://mp.weixin.qq.com/s/_bAY0Oz9Oj8DJjnCyCUxcQ

经过 交叉熵反向传播后,网络中的参数都得到了对应自己的梯度。

SGD 就是在已知参数和参数梯度的情况下,优化网络参数。

权重衰减(L2正则化)

这里给出的前提假设是越小的网络权重越不容易过拟合。

权重衰减指的是在损失函数后面加上一个当前权重的 L2 值,由于梯度下降的目的就是将 loss 最小化,所以最终也会将权重L2最小化。最小化的程度可以由超参数控制。

暂退法

ChatGPT概括了下:

暂退法(Dropout)是一种用于神经网络中防止过拟合的技术。过拟合是指模型在训练数据上表现得很好,但在测试数据上表现较差的现象。暂退法通过在训练过程中随机地丢弃一些神经元的输出,从而减少模型对训练数据的过拟合。

在暂退法中,每个神经元的输出都有一定概率被设置为0。具体来说,对于每个训练样本,暂退法会独立地对每个神经元按照一定的概率进行丢弃操作。这个概率通常在0.2到0.5之间。在每次训练迭代中,丢弃的神经元都是随机选择的,因此每个迭代都相当于训练了一个不同的模型。在测试时,暂退法不再使用,而是使用所有神经元的输出。

暂退法的主要思想是防止神经网络中的神经元过度依赖特定的输入特征,从而提高模型的泛化能力。此外,暂退法还可以作为一种正则化方法,减少模型的复杂度,从而进一步防止过拟合。

虽然暂退法在神经网络中取得了广泛的应用,但也有一些缺点。例如,暂退法会增加训练时间,因为需要训练多个不同的模型。此外,在某些情况下,暂退法可能会影响模型的收敛速度和性能,因此需要谨慎使用。

疑问

  • 交叉熵损失函数的公式 -y*log(y^)怎么来的?