李宏毅《机器学习》总结 - 2022 HW2(分类) Strong Baseline

目前做的最好的是 private 0.758 / public 0.756
image

感觉 HW 2 就是随便调调参 + 网络结构改成 BN + Dropout 啊
image
代码:https://colab.research.google.com/drive/19uQsG-kjgMZsw1wSIkZz-M8JSLIxu1Rw?usp=sharing

题目分析

关于要 concat 几个 frames 的问题,对原数据计算一下求个加权平均就行。。
代码如下:

import pandas as pd

data = pd.read_csv("./train_labels.csv")
buc = [0] * 100005
mx = 0
for i in data:
    cnt = 0
    all = i.split(' ')
    for nowj in all:
        cnt += 1
        if(cnt == 1):
            continue
        j = eval(nowj)
        if(j != 0):
            buc[j] += 1
            mx = max(mx, j)

wsum = sum = 0
for j in range(42):
    wsum += buc[j] * j
    sum += buc[j]
print(wsum / sum)

最后求的加权平均约为 21,因此concat_nframes = 21

前面那些和背景有关的初始化先不用管,先考虑 add layers,一开始是 1 层,在中间的隐藏层的 neuron 是 256 个,我直接改成 \(3\times 1024\) 大力出奇迹
这样直接跑完是 0.70+,直接过了 medium
然后改改架构,加了个 batchnorm 层和 dropout 层(其中 bn 层是将数据规范化一下,dropout 是忽略一部分数据)
适当开大一点 batch_size,这样变快了,但是训练会不太充分,因此同时开大了 epoch 数目
然后改完就过 strong 了,666

代码分析

前面的初始化不用看,看看 classfier 的部分。
这里采用了 DNN 的想法,把普通的小网络当成“积木”开始搭。
关于“积木”的构建:同上,linear+relu+BN+dropout

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

class BasicBlock(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(BasicBlock, self).__init__()

        self.block = nn.Sequential(
            nn.Linear(input_dim, output_dim),
            nn.ReLU(),
            nn.BatchNorm1d(output_dim),
            nn.Dropout(0.35)
        )

    def forward(self, x):
        x = self.block(x)
        return x


class Classifier(nn.Module):
    def __init__(self, input_dim, output_dim=41, hidden_layers=1, hidden_dim=256):
        super(Classifier, self).__init__()

        self.fc = nn.Sequential(
            BasicBlock(input_dim, hidden_dim),
            *[BasicBlock(hidden_dim, hidden_dim) for _ in range(hidden_layers)],
            nn.Linear(hidden_dim, output_dim)
        )

    def forward(self, x):
        x = self.fc(x)
        return x

利用 torchsummary 观察一下网络的结构:

import torchsummary
torchsummary.summary(model, input_size=(input_dim,))

image

训练过程跟之前没啥区别,唯一不同之处在于 classfier 的 criterion(计算 loss 的函数)应该设为 cross entropy 而非 MSE

关于 nn.CrossEntropyLoss() 的理解

再调用时,和传统讲的真实值是一个 one-hot vector 有所不同,真实值应直接为对应的类别
而且,由模型得到的一个代表概率的 vector (即 logits)不需要预先 softmax,因为已经包含在 crossentropy 中了
一个验证程序:

import torch
import torch.nn as nn
a1 = torch.tensor([[ 7.6791e-02,  6.1730e-03, -5.0974e-02, -1.3983e-02, -7.2176e-03,
          6.3506e-02, -4.1189e-02,  1.4947e-01, -1.9007e-01,  4.4429e-02,
          7.5406e-02]])
a2 = torch.tensor([7])
device = "cpu"
criterion = nn.CrossEntropyLoss()
loss = criterion(a1, a2.to(device))
print(loss)

发现当 a2 取 7 的时候,得到的 loss 最小

posted @ 2024-01-26 00:21  SkyRainWind  阅读(60)  评论(0编辑  收藏  举报