zoukankan      html  css  js  c++  java
  • Embedding

    Embedding的含义

    根据tf.keras.layers.Embedding的解释

    是将正整数转换为固定长度的连续向量,它和one-hot编码的作用类似,都是对数据字符数值进行编码。

    不同之处是,embedding是将一个单纯的数值转换成一个长度唯一的概率分布向量,再避免one-hot编码产生的特征稀疏性问题的同时,也能增加特征的描述。

    需要注意的是,当embedding进行神经网络构建时,embedding层必须作为第一层对输入数据进行embedding处理。其配置的参数如下

    • input_dim: 配置字典的长度。embedding 是针对词频字典中的索引进行处理的,因此需要配置字典的长度。

    • output_dim: 配置神经网络层输出的维度。

    • embeddings_initializer: 配置embedding 矩阵的初始化

    • embeddings_regularizer: 配置embedding 矩阵的正则化方程

    • embedding_constraint: 配置embedding 的约束函数

    • mask_zero: 配置"0"是否为Padding的值,如果配置为True, 则将所有的"0"去掉

    • input_length: 配置输入语句的长度,将不足长度的用0填充。

      其中 input_dim 和 output_dim必须指定

    当时,我看这个解释还是比较懵逼。

    举个小例子吧,下面我们定义一个词汇表为200的嵌入层(例如从0到199的整数编码的字,包括0到199),一个32维的向量空间,其中将嵌入单词,以及输入文档,每个单词有50个单词。

    e = Embedding(input_dim=200, output_dim=32, input_length=50)

    Embedding的实例

    下面方法基于keras, 在tensorflow中我们可以使用 tf.keras.preprocessing.text.Tokenizer这个API库下的相关方法

    我们将定义一个小问题,我们有10个文本文档,每个文档都有一个学生提交的工作评论。每个文本文档被分类为正的“1”或负的“0”。这是一个简单的情感分析问题。

    首先,我们将定义文档及其类别标签。

    # define documents 定义文档
    docs = ['Well done!',
    		'Good work',
    		'Great effort',
    		'nice work',
    		'Excellent!',
    		'Weak',
    		'Poor effort!',
    		'not good',
    		'poor work',
    		'Could have done better.']
    # define class labels 定义分类标签
    labels = [1,1,1,1,1,0,0,0,0,0]
    

    接下来,我们来整数编码每个文件。这意味着把输入,嵌入层将具有整数序列。我们可以尝试其他更复杂的bag of word 模型比如计数或TF-IDF。

    Keras提供one_hot()函数来创建每个单词的散列作为一个有效的整数编码。我们用估计50的词汇表大小,这大大减少了hash函数的冲突概率。

    # integer encode the documents 独热编码
    vocab_size = 50
    encoded_docs = [one_hot(d, vocab_size) for d in docs]
    print(encoded_docs)
    

    [[6, 16], [42, 24], [2, 17], [42, 24], [18], [17], [22, 17], [27, 42], [22, 24], [49, 46, 16, 34]]

    每个词都能有0-49的一个索引值。例如 'well done' = [6, 16], 但是由于不同的序列有不同的长度,方便进行处理,因此我们需要进行padding, 将所有的输入序列的长度填充为4.

    # pad documents to a max length of 4 words 将不足长度的用0填充为长度4
    max_length = 4
    padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
    print(padded_docs)
    
    [[ 6 16  0  0]
     [42 24  0  0]
     [ 2 17  0  0]
     [42 24  0  0]
     [18  0  0  0]
     [17  0  0  0]
     [22 17  0  0]
     [27 42  0  0]
     [22 24  0  0]
     [49 46 16 34]]
    

    我们现在准备将我们的嵌入层定义为我们的神经网络模型的一部分。

    嵌入的词汇量为50,输入长度为4,我们将选择一个8维的嵌入空间。

    该模型是一个简单的二元分类模型。重要的是,嵌入层的输出将是每个8维的4个矢量,每个单词一个。我们将其平铺到一个32个元素的向量上以传递到密集输出层。

    # define the model 定义模型
    model = Sequential()
    model.add(Embedding(vocab_size, 8, input_length=max_length))
    model.add(Flatten())
    model.add(Dense(1, activation='sigmoid'))
    # compile the model 编译
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
    # summarize the model 打印模型信息
    print(model.summary())
    

    进行到这,我们一直需要关注的是在进行维度的转换,原本是10x4, 但是经过Embedding之后,其实会变成10x4x8.

    1. input_dim: vocal_size = 50 字典的大小,因为我们在进行one-hot编码时,每个词都是由 0-49 中的某个值作为索引值, 因而字典大小为 49+1 = 50;

    2. input_length: 4, 如果输入的向量长度不足为4,就会给向量填充0,直到向量长度为4。

    3. output_dim: 8 每个词的向量长度,在embedding之前,每个词只有一个索引值,因此我们需要将每个词的索 引转变成一个长度为8的概率分布向量。(10x4x1 => 10x4x8)

      此处我们可以明白embedding到底做了什么,举个栗子:

      ​ “公主”和“王妃” 使用One-hot编码 可能会得到: 公主 [1 0] 王妃 [0 1] 。

      ​ One-hot编码能够得到完全独立的两个01向量,并且当如果文本集够大,那就会导致稀疏矩阵。

      ​ 由于两者完全独立,表达关联特征的能力几乎就为0, 但王妃和公主是有关系,最基本的她们都是女性。

      ​ 而embedding会将one-hot编码(稀疏态),通过一些线性变换,让相互独立向量变成了有内在联系的关系 向量(密集态)即可能 公主 [ 1.0 0.25] 王妃 [ 0.6 0.75] 。


    补充

    使用tensorflow2.0中的tokenizer进行处理时。

    # 定义word2vec的函数,通过统计所有训练集中的字符出现频率,构建字典,并使用字典中的码值对训练集中的语句进行替换
    def tokenize(lang):
        # 使用高阶API tf.keras.preprocessing.text.Tokenize实例化一个转换器,构建字典并使用字典中的码值对训练集中的语句进行替换, oov_token: 配置不在字典中的字符的替换数字,一般使用“3”来替换。
        lang_tokenizer = tf.keras.preprocessing.text.Tokenizer(num_words=gConfig['enc_vocab_size'], oov_token=3)
        # 使用fit_on_texts方法对训练数据进行处理,构建字典
        lang_tokenizer.fit_on_texts(lang)
        # 转换器使用已经构建好的字典,将训练集的数据全部替换为字典的码值
        tensor = lang_tokenizer.texts_to_sequences(lang)
        # 为了提高计算效率,将训练语句的长度统一补全
        tensor = tf.keras.preprocessing.sequence.pad_sequences(tensor, padding='post')
    
        return tensor, lang_tokenizer
    

    其实里面还有很多方法,可以参考该博客

    参考

  • 相关阅读:
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)
    install ubuntu on Android mobile phone
    Mac OS, Mac OSX 与Darwin
    About darwin OS
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十)
    Linux下编译安装qemu和libvirt
    libvirt(virsh命令总结)
    深入浅出 kvm qemu libvirt
    自然语言交流系统 phxnet团队 创新实训 项目博客 (九)
    自然语言交流系统 phxnet团队 创新实训 项目博客 (八)
  • 原文地址:https://www.cnblogs.com/huang-xiang/p/12951930.html
Copyright © 2011-2022 走看看