【科学计算与数学建模】词嵌入模型

一、one-hot 编码

  • 任务描述
  • 相关知识
    • one-hot 编码简介
    • 单词级的 one-hot 编码
    • 字符级的one-hot编码
    • 用keras实现单词级的one-hot编码
  • 编程要求
  • 测试说明

任务描述

本关任务:简单掌握文本转 one-hot 编码操作。

相关知识

为了完成本关任务,你需要掌握:

  1. one-hot 编码简介
  2. 单词级的 one-hot 编码
  3. 字符级的one-hot编码
  4. 用keras实现单词级的one-hot编码
one-hot 编码简介

在前面的实训中,我们已经使用过简单的one-hot编码,one-hot编码是将标记转换为向量的最常用,最基本的方法。对于单词级别的one-hot编码,它将每个单词与一个唯一的整数索引相关联,然后将这个整数索引i转换为长度为N的二进制向量(N是词表的大小),这个向量只有第i个元素是1,其余都是0,对于字符级别的one-hot编码,它将每个字符与一个唯一的整数索引相关联,其余与单词级别的类似。

单词级的 one-hot 编码

初始数据:每个样本是列表的一个元素(本例中的样本是一个句子,但也可以是一篇文档) 现在我们通过以下方式来完成单词级的one-hot编码(该步骤不需要学员实现),代码如下:


  1. import numpy as np
  2. #自行创建的简单数据
  3. samples = ['The cat sat on the mat.', 'The dog ate my homework.']
  4. # 构建数据中所有标记的索引,用一个字典来存储
  5. token_index = {}
  6. for sample in samples:
  7. # 利用split方法对样本进行分词.
  8. for word in sample.split():
  9. if word not in token_index:
  10. #为每个唯一单词指定一个唯一索引
  11. token_index[word] = len(token_index) + 1
  12. #没有为索引编号0指定单词
  13. #对样本进行分词
  14. # 只考虑每个样本前max_length个单词。
  15. max_length = 10
  16. #结果返回给results:
  17. results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))
  18. for i, sample in enumerate(samples):
  19. for j, word in list(enumerate(sample.split()))[:max_length]:
  20. index = token_index.get(word)
  21. #指定唯一的元素为1
  22. results[i, j, index] = 1.
  23. #查看索引字典
  24. print(token_index)
  25. print(results[1,1])#样本列表的第二个元素的第二个单词编码情况

代码执行结果:


  1. {'The': 1,
  2. 'cat': 2,
  3. 'sat': 3,
  4. 'on': 4,
  5. 'the': 5,
  6. 'mat.': 6,
  7. 'dog': 7,
  8. 'ate': 8,
  9. 'my': 9,
  10. 'homework.': 10}
  11. [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
字符级的one-hot编码

与上面类似现在我们通过以下方式来完成单词级的 one-hot 编码,请复制代码到 .ipynb 文件中并运行,代码如下:


  1. import string
  2. samples = ['The cat sat on the mat.', 'The dog ate my homework.']
  3. characters = string.printable #所以可以打印的ASCII字符
  4. #创建索引字典
  5. token_index = dict(zip(characters, range(1, len(characters) + 1)))
  6. #为所有可能打印的字符创建一个字典
  7. max_length = 50
  8. results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))
  9. for i, sample in enumerate(samples):
  10. for j, character in enumerate(sample[:max_length]):
  11. index = token_index.get(character)
  12. results[i, j, index] = 1.
  13. print(token_index)#查看索引字典
  14. print(results[1,1])#样本列表的第二个元素的第二个字符编码情况

代码执行结果:


  1. {'The': 1,
  2. 'cat': 2,
  3. 'sat': 3,
  4. 'on': 4,
  5. 'the': 5,
  6. 'mat.': 6,
  7. 'dog': 7,
  8. 'ate': 8,
  9. 'my': 9,
  10. 'homework.': 10,
  11. 'a.': 11,
  12. 'panda.': 12,
  13. 'is.': 13 ,
  14. 'sleeping.': 14}
  15. [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
用keras实现单词级的one-hot编码

我们可以通过以下简单的方式用keras来实现one-hot编码(该步骤不需要学员实现),请复制代码到.ipynb文件中并运行,代码如下:


  1. from keras.preprocessing.text import Tokenizer
  2. samples = ['The cat sat on the mat.', 'The dog ate my homework.']
  3. #创建一个分词器
  4. # 只考虑前1000个最常见的单词
  5. tokenizer = Tokenizer(num_words=1000)
  6. # 构建单词索引
  7. tokenizer.fit_on_texts(samples)
  8. # 将字符串转换为整数索引的组成的列表
  9. sequences = tokenizer.texts_to_sequences(samples)
  10. # 可以直接得到one-hot编码二进制表示
  11. # 分词器也支持除one-hot编码外的其他向量化模式
  12. one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
  13. # 找回单词索引
  14. word_index = tokenizer.word_index
  15. word_index

代码执行结果:


  1. {'the': 1,
  2. 'cat': 2,
  3. 'sat': 3,
  4. 'on': 4,
  5. 'mat': 5,
  6. 'dog': 6,
  7. 'ate': 7,
  8. 'my': 8,
  9. 'homework': 9}

编程要求

根据提示,在右侧编辑器补充代码。

  1. 给上述samples列表新增一个元素‘a panda is sleeping’

  2. 自行完成单词级别的分词任务,并查看索引字典和样本列表的第二个元素的第二个单词的编码情况。(注意索引是0开始)

  3. 创建字符级 one-hot 编码索引字典,查看第三个元素中的第三个字符的编码情况

测试说明

平台会对你编写的代码进行测试。

开始你的任务吧,祝你成功!

代码部分

import numpy as np
import string
from keras.preprocessing.text import Tokenizer

"""
单词级的 one-hot 编码
"""
def word_one_hot(samples):
    # x,y表示显示的第x个元素的第y个单词

    # 构建数据中所有标记的索引,用一个字典来存储
    token_index = {}
    for sample in samples:
        ########## Begin ##########
        # 利用split方法对样本进行分词.
        for word in sample.split():
            if word not in token_index:
                #为每个唯一单词指定一个唯一索引
                token_index[word] = len(token_index)
                #没有为索引编号0指定单词

        ########## End ##########

    # 只考虑样本前max_length个单词
    max_length = 10

    #结果返回给results:
    results = np.zeros((len(samples), max_length, max(token_index.values())+1))
    for i, sample in enumerate(samples):
        for j, word in list(enumerate(sample.split()))[:max_length]:
            index = token_index.get(word)        
            #唯一的元素为1
            results[i, j, index] = 1

    ########## Begin ##########
    # 查看索引字典和样本列表的第二个元素的第二个单词的编码情况
    # print(token_index) 
    print(results[1,1])
    ########## End ##########



"""
字符级的one-hot编码
"""
def char_one_hot(samples):
    # x,y表示显示的第x个元素的第y个字符

    # 可以打印的ASCII字符
    characters = string.printable  
    
    ########## Begin ##########
    #创建索引字典
    token_index = dict(zip(characters, range(0, len(characters) )))
    #为所有可能打印的字符创建一个字典
    max_length = 50
    results = np.zeros((len(samples), max_length, max(token_index.values())+1 ))

    ########## End ##########

    for i, sample in enumerate(samples):
        for j, character in list(enumerate(sample[:max_length])):
            index = token_index.get(character)
            results[i, j, index] = 1.
            
    ########## Begin ##########
    # 查看索引字典和样本列表的第三个元素的第三个单词的编码情况
    # print(token_index)#查看索引字典
    ###################
   
    print(results[2,2])#样本列表的第3个元素的第3个字符编码情况
    ########## End ##########



########## Begin ##########
# 给 samples 列表新增一个元素‘a panda is sleeping’
samples = ['The cat sat on the mat.',
           'The dog ate my homework.',
           'a panda is sleeping.'
           ]



#创建一个分词器
# 只考虑前1000个最常见的单词
tokenizer = Tokenizer(num_words=1000)
# 构建单词索引
tokenizer.fit_on_texts(samples)
# 将字符串转换为整数索引的组成的列表
sequences = tokenizer.texts_to_sequences(samples)
# 可以直接得到one-hot编码二进制表示
# 分词器也支持除one-hot编码外的其他向量化模式
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')


########## End ##########

word_one_hot(samples)

char_one_hot(samples)

"""
用keras实现单词级的one-hot编码
"""
tokenizer = Tokenizer(num_words=1000)
tokenizer.fit_on_texts(samples)

word_index = tokenizer.word_index
print(word_index)

二、词嵌入模型

  • 任务描述
  • 相关知识
    • 词嵌入简介
    • 利用Embedding层学习词嵌入
      • 实例化Embedding层
      • 加载IMDB数据
    • 构建keras模型并训练拟合模型
  • 编程要求
  • 测试说明

任务描述

本关任务:使用 keras 实现词嵌入模型。

相关知识

为了完成本关任务,你需要掌握:

  1. 词嵌入简介
  2. 利用Embedding层学习词嵌入
  3. 构建keras模型并训练拟合模型
词嵌入简介

将单词与向量相关联的另外一个强大的方法就是词嵌入,one-hot编码得到的向量是二进制的、稀疏的(绝大部分你元素都是0)、维度很高(维度大小等于词表中的单词个数),而词嵌入是低微的浮点数向量(即密集向量,与稀疏向量相对),如下图所示,与one-hot编码得到的词向量不同,词嵌入是从数据中学习得到的。常见的词向量维度是256、512或1024(处理非常大的词表时)。与此相对,one-hot编码的词向量维度通常是20000或者更高(对应包含20000个标记的词表),因此词向量可以将更多的信息塞入更低的维度中。

,

利用Embedding层学习词嵌入
实例化Embedding层

可以将Embedding层理解为一个字典,将整数索引(表示特定单词)映射为密集向量。它接收整数作为输入,并在内部字典查找这些整数,然后返回相关联的向量。

在我们通过以下方式来实例化一个Embedding(该步骤不需要学员实现),请复制代码到.ipynb文件中并运行,代码如下:


  1. from keras.layers import Embedding
  2. # Embedding层至少需要2个参数
  3. # 标记的个数(这里是1000,即最大单词索引+1)和嵌入维度(这里是64)
  4. embedding_layer = Embedding(1000, 64)
加载IMDB数据

本节使用IMDB数据集,它包含来自互联网电影数据库(IMDB)的50000条严重两极分化的评论。数据集被分为用于训练的25000条评论和用于测试的25000条评论,训练集和测试集都包含50%的正面评论和50%的负面评论。

可以通过以下方式构造我们的数据集(该步骤不需要学员实现),请复制代码到.ipynb文件中并运行,代码如下:


  1. from keras.datasets import imdb
  2. from keras import preprocessing
  3. # 作为特征的单词,即选取出现频率最高的单词数量
  4. max_features = 10000
  5. # 在这么多单词后截断文本
  6. # (这些单词都属于前max_features个最常见单词)
  7. maxlen = 20
  8. #将数据集加载为列表
  9. (x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
  10. # 将整数列表转换成形状为(samples,maxlen)的二维整数张量
  11. x_train = preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen)
  12. x_test = preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen)
构建keras模型并训练拟合模型

  1. from keras.models import Sequential
  2. from keras.layers import Flatten, Dense
  3. model = Sequential()
  4. # 指定 Embedding 层的最大输入长度,以便后面将嵌入输入展平。
  5. model.add(Embedding(2000, 4, input_length=10))
  6. # 将三维的嵌入张量展平为(samples, maxlen * 8)的二维张量
  7. model.add(Flatten())
  8. # 添加分类器
  9. model.add(Dense(1, activation='sigmoid'))
  10. model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
  11. model.summary()
  12. history = model.fit(x_train, y_train,
  13. epochs=10,
  14. batch_size=32,
  15. validation_split=0.2)

  1. _________________________________________________________________
  2. Layer (type) Output Shape Param #
  3. =================================================================
  4. embedding_2 (Embedding) (None, 10, 4) 8000
  5. _________________________________________________________________
  6. flatten_1 (Flatten) (None, 40) 0
  7. _________________________________________________________________
  8. dense_1 (Dense) (None, 1) 41
  9. =================================================================
  10. Total params: 8,041
  11. Trainable params: 8,041
  12. Non-trainable params: 0
  13. _________________________________________________________________
  14. Train on 20000 samples, validate on 5000 samples
  15. Epoch 1/10
  16. 20000/20000 [==============================] - 3s 169us/step - loss: 0.6759 - acc: 0.6049 - val_loss: 0.6399 - val_acc: 0.6800
  17. Epoch 2/10
  18. 20000/20000 [==============================] - 1s 43us/step - loss: 0.5659 - acc: 0.7421 - val_loss: 0.5469 - val_acc: 0.7202
  19. Epoch 3/10
  20. 20000/20000 [==============================] - 1s 44us/step - loss: 0.4753 - acc: 0.7806 - val_loss: 0.5114 - val_acc: 0.7380
  21. Epoch 4/10
  22. 20000/20000 [==============================] - 1s 44us/step - loss: 0.4265 - acc: 0.8077 - val_loss: 0.5009 - val_acc: 0.7454
  23. Epoch 5/10
  24. 20000/20000 [==============================] - 1s 44us/step - loss: 0.3933 - acc: 0.8254 - val_loss: 0.4982 - val_acc: 0.7540
  25. Epoch 6/10
  26. 20000/20000 [==============================] - 1s 44us/step - loss: 0.3671 - acc: 0.8393 - val_loss: 0.5014 - val_acc: 0.7530
  27. Epoch 7/10
  28. 20000/20000 [==============================] - 1s 47us/step - loss: 0.3438 - acc: 0.8531 - val_loss: 0.5052 - val_acc: 0.7520
  29. Epoch 8/10
  30. 20000/20000 [==============================] - 1s 60us/step - loss: 0.3226 - acc: 0.8654 - val_loss: 0.5132 - val_acc: 0.7482
  31. Epoch 9/10
  32. 20000/20000 [==============================] - 1s 55us/step - loss: 0.3026 - acc: 0.8762 - val_loss: 0.5213 - val_acc: 0.7490
  33. Epoch 10/10
  34. 20000/20000 [==============================] - 1s 53us/step - loss: 0.2843 - acc: 0.8854 - val_loss: 0.5301 - val_acc: 0.7464

编程要求

根据提示,在右侧编辑器补充代码,需要完成的步骤如下:

  1. 导入包 Sequential,Flatten,Dense,Embedding
  2. 定义一个序列模型
  3. 添加一个Embedding层,标记个数 10000,维度 8,输入长度是maxlen
  4. 添加一个Flatten层
  5. 添加一个全连接层,输出维度是1,激活函数‘sigmoid’
  6. 编译模型,优化器选取‘rmsprop’,损失函数选取‘binary_crossentropy’,评估方式是‘acc’
  7. 用.summary()方法查看模型架构
  8. 拟合模型,epoch选取 10,batch_size选取 32,validation_split为 0.2

测试说明

平台会对你编写的代码进行测试。

开始你的任务吧,祝你成功!

代码部分

from keras import preprocessing

########## Begin ##########
# 导入包 Sequential,Flatten,Dense,Embedding
from keras.models import Sequential
from keras.layers import Flatten
from keras.layers import Dense
from keras.layers import Embedding
from keras.datasets import imdb
from keras import preprocessing
########## End ##########

import os

def main():
    max_features = 10000
    maxlen = 20
    # 加载数据
    (X_train, y_train), (X_test, y_test) = imdb.load_data(path="/data/workspace/myshixun/imdb.npz",num_words=max_features)

    # 重塑数据形状为(samples, maxlen)的二维整数张量
    X_train = preprocessing.sequence.pad_sequences(X_train, maxlen=maxlen)
    X_test = preprocessing.sequence.pad_sequences(X_test, maxlen=maxlen)

    ########## Begin ##########
    # 定义一个序列模型
    model = Sequential()
    # 添加一个Embedding层,标记个数 10000,维度 8,输入长度是maxlen
    model.add(Embedding(10000, 8, input_length=maxlen))
    # 添加一个Flatten层
    model.add(Flatten())
    # 添加一个全连接层,输出维度是1,激活函数‘sigmoid’, 作为分类器
    model.add(Dense(1, activation='sigmoid'))
    # 编译模型,优化器选取‘rmsprop’,损失函数选取‘binary_crossentropy’,评估方式是‘acc’
    model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
    # 拟合模型,epoch选取 10,batch_size选取 32,validation_split为 0.2
    model.fit(X_train, y_train,epochs=10, batch_size=32, validation_split=0.2)
    # 打印模型结构
    model.summary()
    return model
    ########## End ##########

版权声明:本文为博主作者:草堂春睡足原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/Hisser/article/details/136854193

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2024年4月16日
下一篇 2024年4月16日

相关推荐