李宏毅《机器学习》总结 - 2022 HW2(分类) Strong Baseline
目前做的最好的是 private 0.758 / public 0.756
感觉 HW 2 就是随便调调参 + 网络结构改成 BN + Dropout 啊
代码: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,))
训练过程跟之前没啥区别,唯一不同之处在于 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 最小