• RNN模型与NLP应用(2):文本处理与词嵌入


    前文-电影评论情感分析

    这篇主要讲述从文本处理到词嵌入,输出的一个流程,从一个电影评论的情感分析数据集来展开
    请添加图片描述

    文本处理

    分词需要做大量的处理-----注意事项
    是否要将大写字母转化为小写字母
    去除停顿词. the a of
    拼写错误
    step1:分词
    请添加图片描述
    step2:建立词典
    在这里插入图片描述
    step3:one-hot encoding
    电影评论有长有短,这说明数据没有对齐
    在这里插入图片描述
    step4:对齐句子
    假定w=7,一个句子如果超过了7,将前面的截断,保留后面w个词,同时也可以保留前面词,截断后面的词,如果这个句子比w还短,则在前面pad it with zeros,这样都可以存储在一个矩阵里面请添加图片描述

    Word Embedding:Word to Vector

    请添加图片描述
    请添加图片描述
    d是词向量的维度,自己设置的,v是词汇表的大小
    我们的任务是学习训练出来的词向量会带有感情色彩,就比如好的感情色彩的词应该在一块,则它们的词向量应该相似

    请添加图片描述
    请添加图片描述
    Logistic Regression for Binary Classification

    from keras.models import Sequential
    from keras.layers import Flatten,Dense,Embedding
    embedding_dim=8
    model=Sequential()# 把神经网络的层按顺序搭起来
    model.add(Embedding(vocabulary,embedding_dim,input_length=word_num)) # 第一层为embedding层
    model.add(Flatten()) # 将上面的20*8的矩阵压平成一维向量,变成160维的向量
    model.add(Dense(1,activation='sigmoid'))# 全连接层输出的是一维,用sigmoid的激活函数
    model.summary()# 打印出模型的概要
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    请添加图片描述

    整个流程图示

    利用word Embedding层将每个单词映射到低维向量,所以每个长度为20的电影评论都可以被Flatten成160维向量,最后用线形分类回归器分成0和1的数,0代表负类评论,1代表正类评论请添加图片描述
    可以看到分类器有160个参数,加上偏置参数,总共有161个参数
    请添加图片描述

    代码实现

    环境配置:我的版本是tensorflow1.5.0+keras2.1.4, 其它版本可能会遇到点问题
    数据集:
    链接: https://pan.baidu.com/s/1us7AXURRpCoxgQY65YOylg
    提取码: data
    使用自带的IMDB数据库实现如下:

    from keras.preprocessing.text import Tokenizer
    from keras.preprocessing import sequence
    
    
    import os
    from keras.datasets import imdb
    from keras import preprocessing
    
    '举例操作:将词典和index对应'
    samples = ['He is an engineer.', 'He uses PC to work.']
    
    tokenizer = Tokenizer(num_words=1000)  # 创建分词器,设置为只考虑前1000个最常见的单词
    # num_words设置成 vocabulary,最后返回的是最常见的、出现频率最高的num_words个字词
    # 需要保留的最大词数,基于词频。只有最常出现的 num_words 词会被保留,
    tokenizer.fit_on_texts(samples)  # 构建单词索引,为每个单词分配一个整数(根据词典标签)
    # 只有前1000个词频最高的词才会被保留,相当于根据samples的内容,分配索引(每个词对应一个整数)
    # fit_on_texts使用一系列文档来生成token词典,texts为list类,每个元素为一个文档。
    # #num_words:处理的最大单词数
    # print(tokenizer.fit_on_texts(samples))
    sequences = tokenizer.texts_to_sequences(samples)  # 将字符串转换为整数索引组成的列表
    # 也就是得到词索引列表
    # texts_to_sequences(texts) 将多个文档转换为word下标的向量形式,
    # shape为[len(texts),len(text)] -- (文档数,每条文档的长度)
    print(sequences)
    one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
    # 不仅能使用二进制,也支持one-hot外的向量化编码模式,矩阵化=one_hot编码操作
    
    word_index = tokenizer.word_index  # 查看单词索引,此处为给samples标记的内容
    print('独立标签数:', len(word_index))
    print(word_index)
    print(one_hot_results)
    
    '嵌入层(Embeding)实现'
    # 1.利用Embedding层学习词嵌入
    # imdb数据集,使用keras的embedding层处理文字数据
    ##将评论限制为10000个常见单词,评论长度限制为20个单词,每个单词学习一个8维嵌入
    from keras.datasets import imdb
    from keras import preprocessing
    
    max_features = 10000  # 作为特征的单词个数
    maxlen = 20  # 在20个单词后截断文本,这些单词都属于上一行的最常见单词
    
    (x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
    # x_train表示的是训练数据(评论列表,每条评论由数字组成,对应单词在词典中出现的位置下标),
    # y_train表示的是训练的标签,标签0表示负面评论,1表示正面评论
    # num_words定义的是大于该词频的单词会被读取,词频越高的单词,其在单词表中的位置越靠前
    
    # 将整数序列进行对齐,也就是对列表进行填充或者裁切
    # imdb数据集中,单词的索引是从1开始的,不是从0开始的,所以可以使用0填充序列
    x_train = preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen)
    x_test = preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen)
    
    # 只使用了前20个单词作为判断依据,之前imdb的划分是基于全部评论
    
    '利用Embedding层学习词嵌入(定义模型)'
    from keras.models import Sequential  # Sequential为将神经网络的层按顺序搭起来
    from keras.layers import Dense, Embedding, Flatten
    
    model = Sequential()
    # 第一层是Embedding层,设定字典里10000个单词,Embedding层的输出是个20×8的矩阵,
    # 只考虑每条电影评论中最后的20个单词,每个单词用8维的向量来表示
    # 参数矩阵在此的维度是80000,矩阵的参数根据设定的每个单词表示的向量(8)*字典词个数10000得到
    model.add(Embedding(10000, 8, input_length=maxlen))
    model.add(Flatten())  ##将三维的嵌入张量展平为形状为(samples,maxlen*8)的二维张量
    model.add(Dense(1, activation='sigmoid'))  # 添加分类器
    model.compile(
        optimizer='rmsprop',
        loss='binary_crossentropy',
        metrics=['accuracy']
    )
    
    history = model.fit(x_train, y_train,
                        epochs=10,
                        batch_size=32,
                        validation_split=0.2)
    model.summary()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    从原始数据分析:

    '从零开始动手实现'
    # 从IMDB的原始文本开始学习,而不使用keras自带的imdb数据库。
    '处理IMDB原始数据的内容和标签对应'
    # imdb_dir = r'E:\python\data\aclImdb\aclImdb'  # 根据自己的情况改进
    imdb_dir = r'/Users/liuqian/PycharmProjects/pythonProject/data/aclImdb'
    train_dir = os.path.join(imdb_dir, 'train')  # 因为训练数据集分为train和test,所以需要进行分类
    
    # train中又分为积极pos和消极neg两类型的评价,因此需要进行区分
    labels = []
    texts = []
    for label_type in ['neg', 'pos']:  # 划分评论的正反倾向,并存到不同的文件
        # 遍历两个类别的数据集
        dir_name = os.path.join(train_dir, label_type)
        # print(dir_name)
        # /Users/liuqian/PycharmProjects/pythonProject/data/aclImdb/train/neg
        # /Users/liuqian/PycharmProjects/pythonProject/data/aclImdb/train/pos
    
        for fname in os.listdir(dir_name):
            # os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表(返回文件名)
            if fname[-4:] == '.txt':  # 判断后四位是不是.txt
                f = open(os.path.join(dir_name, fname), encoding='utf-8')
                texts.append(f.read())
                f.close()
                if label_type == 'neg':  # 此处进行标签的工作(对应txt附上不同标签)
                    labels.append(0)
                else:
                    labels.append(1)
                    # 1表示积极评论,0表示消极评论
    
    # 对imdb原始数据的文本进行分类
    from keras.preprocessing.text import Tokenizer  # 分词器
    from keras.preprocessing.sequence import pad_sequences   # 补位0
    import numpy as np
    
    max_len = 500  # 100个单词后截断评论,这个参数非常影响准确度
    training_samples = 2000  # 在2000个样本中训练
    validation_samples = 10000  # 在10000个样本上验证
    max_words = 10000  # 只考虑数据集中前10000个最常见的单词
    
    tokenizer = Tokenizer(num_words=max_words)
    tokenizer.fit_on_texts(texts)
    sequences = tokenizer.texts_to_sequences(texts)
    
    word_index = tokenizer.word_index
    
    data = pad_sequences(sequences, maxlen=max_len)
    
    labels = np.asarray(labels)  # 结构数据转化为ndarray
    print('shape of data tensor:', data.shape)
    print('shape of label tensor:', labels.shape)
    
    # 将数据划分为训练集和验证集
    # 注意要打乱数据,因为原始数据是分类排好序的
    indices = np.arange(data.shape[0])
    np.random.shuffle(indices)   # 重新排序返回一个随机序列
    data = data[indices]
    labels = labels[indices]
    
    x_train = data[:training_samples]
    y_train = labels[:training_samples]
    x_val = data[training_samples:training_samples + validation_samples]
    y_val = labels[training_samples:training_samples + validation_samples]
    
    # 解析glove词嵌入文件,构建一个将单词(字符格式)映射为其向量表示(数值向量)的索引
    
    #glov_dir = r'\data\imdb'
    glov_dir = r'/Users/liuqian/PycharmProjects/pythonProject'
    
    embeddings_index = {}
    f = open(os.path.join(glov_dir, 'data/glove.6B.100d.txt'), encoding='utf8')
    for line in f:
        values = line.split()
        word = values[0]
        coefs = np.asarray(values[1:], dtype='float32')
        embeddings_index[word] = coefs
    f.close()
    
    print('find %s word vectors' % len(embeddings_index))
    
    '准备GloVe词嵌入矩阵:'
    
    # 构造可以加载到embedding层中的嵌入矩阵
    embedding_dim = 100
    embedding_matrix = np.zeros((max_words, embedding_dim))
    for word, i in word_index.items():
        if i < max_words:
            embedding_vector = embeddings_index.get(word)
            if embedding_vector is not None:
                embedding_matrix[i] = embedding_vector
    
    '定义模型:'
    from keras.models import Sequential
    from keras.layers import Embedding, Dense, Flatten
    
    model = Sequential()
    
    model.add(Embedding(max_words, embedding_dim, input_length=max_len))  # 100维
    model.add(Flatten())
    model.add(Dense(32, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    model.summary()
    ##将准备好的glove矩阵加载到Embedding层,同时冻结Embedding层,道理和预处理方法都是一样的
    model.layers[0].set_weights([embedding_matrix])
    model.layers[0].trainable = False  # 冻结embedding层
    
    '编译模型'
    model.compile(
        optimizer='rmsprop',
        loss='binary_crossentropy',
        metrics=['acc']
    )
    
    history = model.fit(
        x_train, y_train,
        epochs=10,
        batch_size=32,
        validation_data=(x_val, y_val)
    )
    loss_and_acc = model.evaluate(x_val, y_val)
    print('loss=' + str(loss_and_acc[0]))
    print('acc=' + str(loss_and_acc[1]))
    model.save_weights('pre_trained_glove_model.h5')
    # loss=0.8123553492546082
    # acc=0.6564
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
  • 相关阅读:
    C高级 Day2
    Go学习笔记
    app商品详情原数据 API ——淘宝/天猫
    使用 k3d 在Windows上安装 k3s
    C++进阶--C++11(2)
    一种依靠压缩电磁铁制造暗物质虫洞的机器
    Encoder——Decoder工作原理与代码支撑
    Mediacodec 如何硬件解码到纹理的
    Aigtek高精度电流源仪器设计规范
    spring 微服务nacos未授权访问漏洞修复
  • 原文地址:https://blog.csdn.net/weixin_45768308/article/details/127462279