hw2
代码
任务描述:
Multiclass Classification,让你判断给定的向量是属于哪一个phoneme,由于一个phoneme可能包含好多个向量,所以要对数据进行处理,对向量进行拼接。
不同baseline 要求
方法分析
先给出我最终使用的过boss baseline的方法,后面再介绍我一步步的思考过程。
助教提示过boss baseline要使用RNN模型,所以我们直接使用BiLSTM模型,在pytorch里面实现也非常方便。模型结构如下:只需要将经过BiLSTM后的中间向量再经过一个预测层就可以得到结果。
import torch
import torch.nn as nn
import torch.nn.functional asFclassClassifier(nn.Module):
def __init__(self, batch_size, num_layers=3, hidden_dim=356, seq_length=concat_nframes): #inputsize: batch_size * concat_nframes *39super(Classifier, self).__init__()
self.batch_size = batch_size
self.num_layers = num_layers
self.hidden_dim = hidden_dim
self.seq_length = seq_length
self.lstm = nn.LSTM(input_size=39, hidden_size=hidden_dim, num_layers= num_layers, batch_first=True, dropout=0.4, bidirectional=True)
# self.h0 = torch.zeros(num_layers *2, batch_size, hidden_dim).to(device)
# self.c0 = torch.zeros(num_layers *2, batch_size, hidden_dim).to(device)
self.fc = nn.Sequential(
nn.LeakyReLU(0.1),
nn.BatchNorm1d(2* hidden_dim),
nn.Dropout(0.4),
nn.Linear(2* hidden_dim, hidden_dim),
nn.LeakyReLU(0.1),
nn.BatchNorm1d(hidden_dim),
nn.Dropout(0.4),
nn.Linear(hidden_dim,41))
def forward(self, x):
x, _ = self.lstm(x)
x = x[:,self.seq_length//2]
x = self.fc(x)return x
Hyper-parameters****optimizer 和 scheduler设置如下:
optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate *200)
scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer,T_0=2, T_mult=4, eta_min=0)
# data prarameters
concat_nframes =51 # the number of frames to concat with, n must be odd(total 2k+1= n frames)
train_ratio =0.99 # the ratio of data used for training, the rest will be used for validation
# training parameters
seed =0 # random seed
batch_size =2048 # batch size
num_epoch =30 # the number of training epoch
learning_rate =1e-5 # learning rate
model_path ='./model.ckpt' # the path where the checkpoint will be saved
最终只训练了16个epoch,使用Tesla P100 花费了大约九个小时。
提交结果
双榜均过 boss baseline!
过程总结
上面的技巧你可能五分钟以内就可以看完并实现,但是我却花费了一周。过程极其曲折,走了很多弯路。
首先看到这个任务,我没兴趣在它原来的线性层构建的网络结构上调参,我知道线性网络再调参它也是有上限的,我直接就尝试了LSTM模型,初步写了一个跑了一下,正确率大概在0.75左右,之后就是调参了,包括网络参数(hidden_dim,num_layers,bidirectional等等),网络结构(直接取中间向量的输出,还是所有向量的输出)加上batchnorm,LeakyReLU,dropout设置等等。
这些慢慢尝试,调了两三天最后得到的结果是0.785,此时我感觉已经把能尝试的都尝试了,心里感觉非常的毛躁,安慰自己说过了strong baseline已经很棒了,这个差不多了,写下一个任务吧。但是看看自己的排名,0.785不是有手就行,肯定有人会这样说,于是就又开始尝试看有没有更加强力的模型。通过看其他人的经验分享我知道了BiLSTM–CRF 模型,这个是序列标注任务常用的模型,通过在BiLSTM模型后面加一个CRF模型,从而让它学到关于序列间的某些约束,从而可以更好的进行预测,刚好我的这个也是个序列,不过我只需要预测中间的向量即可,但也可以用,又看了一天原理及实现,成功将其应用,最后跑出来正确率0.77左右,进行调参0.78左右,还是不行啊,加个CRF模型没啥用啊。
基于BiLSTM–CRF模型我实现了两个版本,一个是直接使用经过CRF层得到的输出计算loss,另一个是经过使用BiLSTM的输出计算loss1和经过CRF的输出计算的loss2按一定比例相加得到总的loss。
l
o
s
s
=
(
1
−
α
)
l
o
s
s
1
+
α
l
o
s
s
2
loss =(1-\alpha) loss1 + \alpha loss2
loss=(1−α)loss1+αloss2
α
\alpha
α 随
e
p
o
c
h
epoch
epoch从0增长到1,我设计这个loss函数的意义是训练初期强调loss1注重BiLSTM的正确率,等到中后期BiLSTM训练的差不多了再着重训练CRF,使用CRF来优化BiLSTM的输出。
想法非常的好,loss函数的设计也是之后的任务会经常使用的技巧,可惜对于这个任务来说并没有卵用,但是也算是一种尝试吧,只有失败了你才知道不行。
尝试过CRF之后我又开始回归到我之前的模型上,感觉还是只取中间层的向量更加靠谱,因为我最终也只需要中间向量的结果。然后还是使用双向的LSTM。加大hidden_dim和num_layers,同时要提高dropout,(因为模型变得更复杂了)这里说明一点,之前我的hidden_dim一直不敢加太多,我尝试了39 和 78,但发现问题的关键就在于这里,hidden_dim勇敢加,发现模型的正确率也在稳步提升,最终一直加到了356,如果你想要继续提高正确率的话可以继续调大hidden_dim,不过训练时间也会变得更加长。同时数据方面,为了能够有更多的训练数据,提高train_ratio。
总结一下,我发现正确率提高不了,不是其他参数没有调好,而是我的模型复杂度不够,hidden_dim太小,就这一点!
版权归原作者 失败人生自救指南 所有, 如有侵权,请联系我们删除。