关于transformer的一些基础知识,之前在看李宏毅视频的时候总结了一些,可以看here,到写此文章时,也基本忘的差不多了,故也不深究,讲两个关于transformer的基本应用,来方便理解与应用。
序列标注
1. 加载数据
1 | #加载数据 |
其中load_treebank代码:
1 | def load_treebank(): |
加载后可以看到,train_data
和test_data
都是list,其中每一个sample都是tuple,分别是input和target。如下:
1 | 0] train_data[ |
2. 数据处理
1 |
|
3. 模型部分
1 | class PositionalEncoding(nn.Module): |
这里有几点可能需要注意的:
- PositionalEncoding
因为self attention是没有像rnn位置信息编码的,所以transformer引入了positional encoding,使用绝对位置进行编码,对每一个输入加上position信息,可以看self.pe
,这个一个static lookup table。目前也出现一些使用relative positional encoding的,也就是加入相对位置编码,这个在ner任务中挺常见,比如TENER和Flat-Lattice-Transformer。但是最近google证明这种相对位置编码只是引入了更多的信息特征进来😭😭😭😭。。
扯完上面这个,进入正题,那就是如何计算的。
看forward部分,发现首先进行了torch.transpose操作,然后进行self.position_embedding,这个transpose是否让你感到困惑呢?
如果没有就不用看了😭😭😭。。。
一般输入Embedding的shape是(batch_size, seq_length),然后对每个seq_length那维的token进行编码获取对应的feature。但是这里将其transpose了,变成了(seq_length, batch_size),这种操作是否理解呢?ok,举个例子:
1 | tensor([[1, 2, 3], |
这个就是我们通常理解的(batch_size, seq_length),如果将其transpose下就变成了:
1 | tensor([[1, 4], |
囔,是不是理解了呢,是对position进行embedding,然后接着看PositionalEncoding是如何forward的。
1 | def forward(self, x): |
那么上述例子就是指获取self.pe
前70个长度的位置编码信息,然后和x
进行相加返回,从而带入了位置编码信息。
- TransformerEncoder部分
1 | 512, nhead=8) encoder_layer = nn.TransformerEncoderLayer(d_model= |
这部分就容易理解了,使用多少nhead和TransformerEncoder的num_layers。
句子极性二分类
这地方基本和之前一样,就是linear n_out=2,然后交叉熵算loss就行。
我稍微改动了下源码,这样理解起来会更方便。
1 | class Transformer(nn.Module): |
总结
目前nlp都变成了微调时代,关于transformer网络结构,感兴趣可以点击我上面链接,可以看看从代码层面如果实现encoder和decoder部分。