我在学习项目https://github.com/zonetrooper32/VDCNN 的时候,觉得vdcnn.py里Embedding的用法有误,原代码中的写法为:
embedded_chars = Embedding(input_dim=sequence_length, output_dim=embedding_dim)(inputs) #embdding层的输入是inputs
Embedding函数的官方文档:https://keras.io/zh/layers/embeddings/
- input_dim: int > 0。词汇表大小, 即,最大整数 index + 1。
- output_dim: int >= 0。词向量的维度。
- embeddings_initializer:
embeddings
矩阵的初始化方法 (详见 initializers)。 - embeddings_regularizer:
embeddings
matrix 的正则化方法 (详见 regularizer)。 - embeddings_constraint:
embeddings
matrix 的约束函数 (详见 constraints)。 - mask_zero: 是否把 0 看作为一个应该被遮蔽的特殊的 "padding" 值。 这对于可变长的 循环神经网络层 十分有用。 如果设定为
True
,那么接下来的所有层都必须支持 masking,否则就会抛出异常。 如果 mask_zero 为True
,作为结果,索引 0 就不能被用于词汇表中 (input_dim 应该与 vocabulary + 1 大小相同)。 - input_length: 输入序列的长度,当它是固定的时。 如果你需要连接
Flatten
和Dense
层,则这个参数是必须的 (没有它,dense 层的输出尺寸就无法计算)。
输入尺寸为 (batch_size, sequence_length)
的 2D 张量。
输出尺寸为 (batch_size, sequence_length, output_dim)
的 3D 张量。
先不管batch_size,我们假设batch_size=1,就是每次只考虑一条句子,把句子处理成输入input text。
我设置每个input text的最大长度为1024(字符数为1024),即sequence_length=1024,如果句子字符少于1024或多于1024,则使用padding或者截断来保证得到一个包含1024个字符的input text。其中每个字符用该字符在对应的字符table中的整数序号来表示,因此inout text实际上是一个1024维的向量,其中每一个维度是一个连续值,代表这个字符在table中的位置。
因此应该设input_length=sequence_length=1024
又因为字母表中总共有68个字母,因此应该设input_dim=68
在我的文本分类问题中,对句子中的每个字符做character embedding,其中embedding的特征维度为16,因此应该设output_dim=16 。所以最终得到的embedded_chars实际上是一个尺寸为1024*16的二维向量,其中每个字符用一个16维的特征向量表示。
简单来说就是,1024个字符输进去,得到的是(1024, 16)这么大的一个矩阵
所以我把代码改成了:
embedded_chars = Embedding(input_dim=68, output_dim=embedding_dim,input_length=sequence_length)(inputs)
(神奇的是改正之后模型效果更差了,简直不可理喻)
此外还有一个问题就是:
到底Keras的Embedding直接就是一个训练好的模型直接做到字符->特征向量之间的转换,还是说当场训练特征向量呢。
已经预训练好的话又不像,因为keras好像没说用了什么预训练模型;
但是说当场训练好像也不对,怎么能又做分类又训练字符embedding呢?
这个时候查看网上的回答,发现了一个十分优秀的讲解,基本解答了本问题:
https://juejin.im/entry/5acc23f26fb9a028d1416bb3
就是说embedding层的训练是与模型的训练同时进行的(或许可以引进Word2Vec预训练模型提高效果?但这样的话就得换成以word为单位而不是以character为单位)。
此外,还有这个博客,精炼地讲解了Keras模型的基础知识:https://blog.csdn.net/ssswill/article/details/88310812