keras 是一个用 Python 编写的高级神经网络 API, 它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行. Keras 的开发重点是支持快速的实验. 能够以最小的时延把你的想法转换为实验结果, 是做好研究的关键.
本文以 Kaggle 上的项目: IMDB 影评情感分析为例, 学习如何用 Keras 搭建一个神经网络, 处理实际问题. 阅读本文需要对神经网络有基础的了解.
文章分为两个部分:
Keras 中的一些基本概念. API 用法. 我会给出一些简单的使用样例, 或是给出相关知识链接.
IMDB 影评情感分析实战. 用到的都是第一部分中讲到的知识点.
Model
Dense 全连接层
- keras.layers.core.Dense(units, activation=None, use_bias=True, k
- ernel_initializer='glorot_uniform', bias_initializer='zeros', ke
- rnel_regularizer=None, bias_regularizer=None, activity_regulariz
- er=None, kernel_constraint=None, bias_constraint=None)
- # as first layer in a sequential model:
- # as first layer in a sequential model:
- model = Sequential()
- model.add(Dense(32, input_shape=(16,)))
- # now the model will take as input arrays of shape (*, 16)
- # and output arrays of shape (*, 32)
- # after the first layer, you don't need to specify
- # the size of the input anymore:
- model.add(Dense(32))
嵌入层 Embedding
- keras.layers.embeddings.Embedding(input_dim, output_dim, embeddi
- ngs_initializer='uniform', embeddings_regularizer=None, activity
- _regularizer=None, embeddings_constraint=None, mask_zero=False,
- input_length=None)
有兴趣的看这个链接 https://machinelearningmastery.com/use-word-embedding-layers-deep-learning-keras/
其实就是 Word to vector. 这一层的作用就是得到用词向量表示的文本.
input_dim: 词表的大小. 即不同的词的总个数.
output_dim: 想要把词转换成多少维的向量.
input_length: 每一句的词的个数
比如如下代表: 我们输入一个 M*50 的矩阵, 这个矩阵中不同的词的个数为 200, 我们想把每个词转换为 32 维向量. 返回的是一个 (M,50,32) 的张量.
一个句子 50 个词, 每个词是 32 维向量, 共 M 个句子. 所以是 e.shape=(M,50,32)
e = Embedding(200, 32, input_length=50)
LSTM 层.
LSTM 是循环神经网络的一种特殊情况. http://deeplearning.net/tutorial/lstm.html
简单来说, 我们此前说过的神经网络, 包括 CNN, 都是单向的, 没有考虑序列关系, 但是某个词的意义与其上下文是有关的, 比如 "我用着小米手机, 吃着小米粥", 两个小米肯定不是一个意思. 在做语义分析的时候, 需要考虑上下文. 循环神经网络 RNN 就是干这个事情的. 或者说 "这部电影质量很高, 但是我不喜欢". 这个句子里既有正面评价, 又有负面评价, 参考上下文的 LSTM 会识别出 "但是" 后面的才是我们想要重点表达的.
- keras.layers.recurrent.LSTM(units, activation='tanh', recurrent_
- activation='hard_sigmoid', use_bias=True, kernel_initializer='gl
- orot_uniform', recurrent_initializer='orthogonal', bias_initiali
- zer='zeros', unit_forget_bias=True, kernel_regularizer=None, rec
- urrent_regularizer=None, bias_regularizer=None, activity_regular
- izer=None, kernel_constraint=None, recurrent_constraint=None, bi
- as_constraint=None, dropout=0.0, recurrent_dropout=0.0)
池化层
keras.layers.pooling.GlobalMaxPooling1D() #对时间信号的全局最大池化
input: 形如( samples, steps, features) 的 3D 张量
output: 形如 (samples, features) 的 2D 张量
- keras.layers.pooling.MaxPooling1D(pool_size=2, strides=None, pad
- ding='valid')
- keras.layers.pooling.MaxPooling2D(pool_size=(2, 2), strides=None
- , padding='valid', data_format=None)
- keras.layers.pooling.MaxPooling3D(pool_size=(2, 2, 2), strides=N
- one, padding='valid', data_format=None)
- ....
数据预处理
文本预处理
- keras.preprocessing.text.text_to_word_sequence(text,
- filters=base_filter(), lower=True, split=" ")
- keras.preprocessing.text.one_hot(text, n,
- filters=base_filter(), lower=True, split=" ")
- keras.preprocessing.text.Tokenizer(num_words=None, filters=base_
- filter(),
- lower=True, split=" ")
Tokenizer 是一个用于向量化文本, 或将文本转换为序列( 即单词在字典中的下标构
成的列表, 从 1 算起) 的类.
num_words: None 或整数, 处理的最大单词数量. 若被设置为整数, 则分词器
将被限制为处理数据集中最常见的 num_words 个单词
不管 num_words 是几, fit_on_texts 以后词典都是一样的, 全部的词都有对应的 index. 只是在做 texts_to_sequences 时所得结果不同.
会取最常出现的 (num_words - 1) 个词对应的 index 来代表句子.
注意 num_words 不同时, 准换后 X_t 的不同. 只取词典中出现最多的 num_words - 1 代表句子. 如果一个句子中出现特别生僻的词, 就会被过滤掉. 比如一个句子 ="x y z".y,z 不在词典中最常出现的 top num_words-1 的话, 最后这个句子的向量形式则为[x_index_in_dic]
- t1="i love that girl"
- t2='i hate u'
- texts=[t1,t2]
- tokenizer = Tokenizer(num_words=None)
- tokenizer.fit_on_texts(texts) #得到词典 每个词对应一个 index.
- print( tokenizer.word_counts) #OrderedDict([('i', 2), ('love', 1), ('that', 1), ('girl', 1), ('hate', 1), ('u', 1)])
- print( tokenizer.word_index) #{
- 'i': 1, 'love': 2, 'that': 3, 'girl': 4, 'hate': 5, 'u': 6
- }
- print( tokenizer.word_docs) #{
- 'i': 2, 'love': 1, 'that': 1, 'girl': 1, 'u': 1, 'hate': 1
- })
- print( tokenizer.index_docs) #{
- 1: 2, 2: 1, 3: 1, 4: 1, 6: 1, 5: 1
- }
- tokennized_texts = tokenizer.texts_to_sequences(texts)
- print(tokennized_texts) #[[1, 2, 3, 4], [1, 5, 6]] 每个词由其 index 表示
- X_t = pad_sequences(tokennized_texts, maxlen=None) #转换为 2d array 即矩阵形式. 每个文本的词的个数均为 maxlen. 不存在的词用 0 表示.
- print(X_t)#[[1 2 3 4][0 1 5 6]]
序列预处理
- keras.preprocessing.sequence.pad_sequences(sequences, maxlen=None
- , dtype='int32',
- padding='pre', truncating='pre', value=0.)
返回一个 2 阶张量
- keras.preprocessing.sequence.skipgrams(sequence, vocabulary_size
- ,
- window_size=4, negative_samples=1., shuffle=True,
- categorical=False, sampling_table=None)
- keras.preprocessing.sequence.make_sampling_table(size, sampling_
- factor=1e-5)
keras 实战: IMDB 影评情感分析
数据集介绍
labeledTrainData.tsv/imdb_master.CSV 影评数据集 已经标注对电影是正面 / 负面评价
testData.tsv 测试集 需要预测评论是正面 / 负面
主要步骤
数据读取
数据清洗 主要包括去除停词, 去除 HTML tag, 去除标点符号
模型构建
嵌入层: 完成词到向量的转换
LSTM
池化层: 完成重要特征抽取
全连接层: 分类
数据加载
- import pandas as pd
- import matplotlib.pyplot as plt
- import numpy as np
- df_train = pd.read_csv("./dataset/word2vec-nlp-tutorial/labeledTrainData.tsv", header=0, delimiter="\t", quoting=3)
- df_train1=pd.read_csv("./dataset/imdb-review-dataset/imdb_master.csv",encoding="latin-1")
- df_train1=df_train1.drop(["type",'file'],axis=1)
- df_train1.rename(columns={'label':'sentiment',
- 'Unnamed: 0':'id',
- 'review':'review'},
- inplace=True)
- df_train1 = df_train1[df_train1.sentiment != 'unsup']
- df_train1['sentiment'] = df_train1['sentiment'].map({'pos': 1, 'neg': 0})
- new_train=pd.concat([df_train,df_train1])
数据清洗
用 bs4 处理 HTML 数据
过滤出单词
去除停用词
- import re
- from bs4 import BeautifulSoup
- from nltk.corpus import stopwords
- def review_to_words( raw_review ):
- review_text = BeautifulSoup(raw_review, 'lxml').get_text()
- letters_only = re.sub("[^a-zA-Z]", " ", review_text)
- words = letters_only.lower().split()
- stops = set(stopwords.words("english"))
- meaningful_words = [w for w in words if not w in stops]
- return( " ".join( meaningful_words ))
- new_train['review']=new_train['review'].apply(review_to_words)
- df_test["review"]=df_test["review"].apply(review_to_words)
Keras 搭建网络
文本转换为矩阵
- Tokenizer 作用于 list(sentence)得到词典. 将词用词在词典中的 Index 做替换, 得到数字矩阵
- pad_sequences 做补 0. 保证矩阵每一行数目相等. 即每个句子有相同数量的词.
- list_classes = ["sentiment"]
- y = new_train[list_classes].values
- print(y.shape)
- list_sentences_train = new_train["review"]
- list_sentences_test = df_test["review"]
- max_features = 6000
- tokenizer = Tokenizer(num_words=max_features)
- tokenizer.fit_on_texts(list(list_sentences_train))
- list_tokenized_train = tokenizer.texts_to_sequences(list_sentences_train)
- list_tokenized_test = tokenizer.texts_to_sequences(list_sentences_test)
- print(len(tokenizer.word_index))
- totalNumWords = [len(one_comment) for one_comment in list_tokenized_train]
- print(max(totalNumWords),sum(totalNumWords) / len(totalNumWords))
- maxlen = 400
- X_t = pad_sequences(list_tokenized_train, maxlen=maxlen)
- X_te = pad_sequences(list_tokenized_test, maxlen=maxlen)
模型构建
词转向量
- inp = Input(shape=(maxlen, ))
- print(inp.shape) # (?, 400) #每个句子 400 个词
- embed_size = 128 #每个词转换成 128 维的向量
- x = Embedding(max_features, embed_size)(inp)
- print(x.shape) #(?, 400, 128)
LSTM 60 个神经元
GlobalMaxPool1D 相当于抽取出最重要的神经元输出
DropOut 丢弃部分输出 引入正则化, 防止过拟合
Dense 全连接层
模型编译时指定损失函数, 优化器, 模型效果评测标准
- x = LSTM(60, return_sequences=True,name='lstm_layer')(x)
- print(x.shape)
- x = GlobalMaxPool1D()(x)
- print(x.shape)
- x = Dropout(0.1)(x)
- print(x.shape)
- x = Dense(50, activation="relu")(x)
- print(x.shape)
- x = Dropout(0.1)(x)
- print(x.shape)
- x = Dense(1, activation="sigmoid")(x)
- print(x.shape)
- model = Model(inputs=inp, outputs=x)
- model.compile(loss='binary_crossentropy',
- optimizer='adam',
- metrics=['accuracy'])
模型训练
- batch_size = 32
- epochs = 2
- print(X_t.shape,y.shape)
- model.fit(X_t,y, batch_size=batch_size, epochs=epochs, validation_split=0.2)
使用模型预测
- prediction = model.predict(X_te)
- y_pred = (prediction> 0.5)
来源: https://www.cnblogs.com/sdu20112013/p/10428471.html