伯禹公益AI《动手学深度学习PyTorch版》Task 08 学习笔记
Task 08:文本分类;数据增强;模型微调
微信昵称:WarmIce
文本分类
前面一堆数据处理和对双向循环神经网络的讲解可以忽略了,之前都讲过,咱也都详细聊过。
这里主要说一下情感分类在使用双向循环神经网络时的一个细节。我们可以根据双向循环网络得到t个时刻的双向的经过concat的隐藏状态,那么如何利用这t个信息进行二分类呢(假设只进行正面与反面的二分类)。给的例子中,只使用了第1个时刻的concat后的隐藏状态与第t个时刻的concat后的隐藏状态,这样一来,最后的输出层的全连接权重参数就是(4*hidden_size, 2)。望周知。
另外一个永远不能忘记的就是,RNN这个吊东西就是要把seq_len作为第一维,为什么,因为它要一个字一个字送进去。
其实之前写到词嵌入的时候就有个问题,不过当时没有问,就是说,你给我预训练好的词向量,但是我建立的词典,对应下标的单词和你的这个预训练好的不一定匹配啊,因此,其实我们在使用这些预训练好的词向量的时候,还要进行一个匹配工作,在预训练的词向量里面找到我们的词典里面的每个单词对应的词向量,然后把找到的词向量拼接成一个矩阵赋给Embedding层,同时,还要注意,人家都给咱们训练好了,咱就别动了,因此还要让Embedding层不计算梯度。所有在预训练的词向量中查找不到的单词,都已oov论处。
一个小技巧:
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=lr)
可以使用filter函数配合匿名函数对需要更新的参数进行选择。
使用CNN来进行文本分类也挺简单的,用的是一维卷积,需要注意的是在整个过程中,channel是什么,最低维(feature维度)是什么,经过一维卷积后channel如何变化,feature维度如何变化,搞清楚这些,所谓的TextCNN就很简单。
感觉第一个想出来这么做的人就是“大胆假设,小心求证”的思路来做的吧。因为整个过程几乎是毫不费力的。哦对了,要注意,TextCNN里面有两个要点,第一个是多增加了一个Embedding层,保证对于oov的单词也能够具有一定的识别性,Embedding会更新参数,constant_Embedding不更新参数,两个输出结果concat后往后进行运算;第二就是池化层的操作,其实是按照channel维度进行的池化,这么一说的话,其实就是global avg pooling,但是channel下面就只有一个维度了。
数据增强
第一个是翻转和裁剪,翻转包括左右翻转和上下翻转,裁剪就是随机地裁剪图片的区域;
第二个是颜色变化,包括亮度、对比度、饱和度以及色调。
还包括旋转以及椒盐噪声等等。
图像增广(image augmentation)技术通过对训练图像做一系列随机改变,来产生相似但又不同的训练样本,从而扩大训练数据集的规模。图像增广的另一种解释是,随机改变训练样本可以降低模型对某些属性的依赖,从而提高模型的泛化能力。例如,我们可以对图像进行不同方式的裁剪,使感兴趣的物体出现在不同位置,从而减轻模型对物体出现位置的依赖性。我们也可以调整亮度、色彩等因素来降低模型对色彩的敏感度。
模型微调
贼尼玛有用的技能,今天总算清晰明了地get了,全部摘抄,我没什么想说的,被这些代码和文字折服了。
本节我们介绍迁移学习中的一种常用技术:微调(fine tuning)。如图9.1所示,微调由以下4步构成。
- 在源数据集(如ImageNet数据集)上预训练一个神经网络模型,即源模型。
- 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层跟源数据集的标签紧密相关,因此在目标模型中不予采用。
- 为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。
- 在目标数据集(如椅子数据集)上训练目标模型。我们将从头训练输出层,而其余层的参数都是基于源模型的参数微调得到的。
当目标数据集远小于源数据集时,微调有助于提升模型的泛化能力。
pretrained_net = models.resnet18(pretrained=False)
pretrained_net.load_state_dict(torch.load('/home/kesci/input/resnet185352/resnet18-5c106cde.pth'))
pretrained_net.fc = nn.Linear(512, 2)
output_params = list(map(id, pretrained_net.fc.parameters()))
feature_params = filter(lambda p: id(p) not in output_params, pretrained_net.parameters())
lr = 0.01
optimizer = optim.SGD([{'params': feature_params},
{'params': pretrained_net.fc.parameters(), 'lr': lr * 10}],
lr=lr, weight_decay=0.001)
以上,妙极。