IMDB影评倾向分类 - N-Gram
catalogue
. 数据集
. 模型设计
. 训练
1. 数据集
0x1: IMDB影评数据
本数据库含有来自IMDB的25,000条影评,被标记为正面/负面两种评价
from keras.datasets import imdb (X_train, y_train), (X_test, y_test) = imdb.load_data(path="imdb_full.pkl",
nb_words=None,
skip_top=,
maxlen=None,
test_split=0.1)
seed=,
start_char=,
oov_char=,
index_from=) . path:如果你在本机上已有此数据集(位于'~/.keras/datasets/'+path),则载入。否则数据将下载到该目录下
. nb_words:整数或None,要考虑的最常见的单词数,任何出现频率更低的单词将会被编码到0的位置。
. skip_top:整数,忽略最常出现的若干单词,这些单词将会被编码为0
. maxlen:整数,最大序列长度,任何长度大于此值的序列将被截断
. seed:整数,用于数据重排的随机数种子
. start_char:字符,序列的起始将以该字符标记,默认为1因为0通常用作padding
. oov_char:字符,因nb_words或skip_top限制而cut掉的单词将被该字符代替
. index_from:整数,真实的单词(而不是类似于start_char的特殊占位符)将从这个下标开始
返回值两个Tuple,(X_train, y_train), (X_test, y_test),其中
X_train和X_test:序列的列表,每个序列都是词下标的列表。如果指定了nb_words,则序列中可能的最大下标为nb_words-。如果指定了maxlen,则序列的最大可能长度为maxlen
y_train和y_test:为序列的标签,是一个二值list
0x2: 数据预处理
影评已被预处理为词下标构成的序列,单词的下标基于它在数据集中出现的频率标定,例如整数3所编码的词为数据集中第3常出现的词,类似下面这张图

h的词频在数据集中的频率排名第一,所以它的编码为1
X_train[]
[, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ] y_train[]
将语料集转化为一个词频组合的编号集
0x2: N-Gram生成
需要注意的是,kera的dataset默认采用1-Gram的分组方式,如果我们需要使用2-Gram、N-Gram等情况,需要在预处理阶段进行拼接
if ngram_range > :
print('Adding {}-gram features'.format(ngram_range))
# Create set of unique n-gram from the training set.
ngram_set = set()
for input_list in X_train:
for i in range(, ngram_range + ):
set_of_ngram = create_ngram_set(input_list, ngram_value=i)
ngram_set.update(set_of_ngram)
print('ngram_set.pop')
print(ngram_set.pop())

将1-Gram进行"两两组合",得到2-Gram,同时组合后的2-Gram需要再次进行index编号,编号的起始就从max_features开始,因为在1-Gram的时候,我们已经把0-max_features的编号都使用过了
但是要注意一个问题,2-Gram对应的组合数量和1-Gram是几何倍数增加的,对计算和内存的要求也成倍提高了
0x3: 填充序列pad_sequences
得到的数据是一个2D的数据,shape是
X_train shape: (, )
X_test shape: (, )
2500是max_features,即我们只从训练语料库中选取排名前2500词频的词,400代表maxlen,我们认为对话的长度最长为400,把所有不足400的都padding到400长度
Relevant Link:
https://github.com/fchollet/keras/blob/master/examples/imdb_fasttext.py
2. 模型设计
0x1: 嵌入层
model.add(Embedding(max_features,
embedding_dims,
input_length=maxlen))
输入数据的维度就是max_features,即我们选取的词频列表中排名前max_features的词频,输入维度为embedding_dims = 50
0x2: 池化层 - 池化是一种低损降维的好方法
在通过卷积获得了特征(features)之后,下一步我们希望利用这些特征去做分类。理论上讲,人们可以把所有解析出来的特征关联到一个分类器,例如softmax分类器,但计算量非常大。例如:对于一个96X96像素的图像,假设我们已经通过8X8个输入学习得到了400个特征。而每一个卷积都会得到一个(96 − 8 + 1) * (96 − 8 + 1) = 7921的结果集,由于已经得到了400个特征,所以对于每个样例(example)结果集的大小就将达到892 * 400 = 3,168,400 个特征。这样学习一个拥有超过3百万特征的输入的分类器是相当不明智的,并且极易出现过度拟合(over-fitting).
所以就有了pooling这个方法,本质上是把特征维度区域的一部分求个均值或者最大值,用来代表这部分区域。如果是求均值就是mean pooling,求最大值就是max pooling
之所以这样做,拿图像识别举例子,是因为:我们之所以决定使用卷积后的特征是因为图像具有一种“静态性”的属性,这也就意味着在一个图像区域有用的特征极有可能在另一个区域同样适用。因此,为了描述大的图像,一个很自然的想法就是对不同位置的特征进行聚合统计。这个均值或者最大值就是一种聚合统计的方法。
另外,如果人们选择图像中的连续范围作为池化区域,并且只是池化相同(重复)的隐藏单元产生的特征,那么,这些池化单元就具有平移不变性(translation invariant)。这就意味着即使图像经历了一个小的平移之后,依然会产生相同的(池化的)特征
model.add(GlobalAveragePooling1D())
Relevant Link:
https://keras-cn.readthedocs.io/en/latest/layers/embedding_layer/
http://www.cnblogs.com/bzjia-blog/p/3415790.html
https://keras-cn.readthedocs.io/en/latest/layers/pooling_layer/
3. 训练
'''This example demonstrates the use of fasttext for text classification
Based on Joulin et al's paper:
Bags of Tricks for Efficient Text Classification
https://arxiv.org/abs/1607.01759
Results on IMDB datasets with uni and bi-gram embeddings:
Uni-gram: 0.8813 test accuracy after epochs. 8s/epoch on i7 cpu.
Bi-gram : 0.9056 test accuracy after epochs. 2s/epoch on GTX 980M gpu.
''' from __future__ import print_function
import numpy as np
np.random.seed() # for reproducibility from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Embedding
from keras.layers import GlobalAveragePooling1D
from keras.datasets import imdb def create_ngram_set(input_list, ngram_value=):
"""
Extract a set of n-grams from a list of integers.
>>> create_ngram_set([, , , , , ], ngram_value=)
{(, ), (, ), (, ), (, )}
>>> create_ngram_set([, , , , , ], ngram_value=)
[(, , ), (, , ), (, , ), (, , )]
"""
return set(zip(*[input_list[i:] for i in range(ngram_value)])) def add_ngram(sequences, token_indice, ngram_range=):
"""
Augment the input list of list (sequences) by appending n-grams values.
Example: adding bi-gram
>>> sequences = [[, , , ], [, , , , ]]
>>> token_indice = {(, ): , (, ): , (, ): }
>>> add_ngram(sequences, token_indice, ngram_range=)
[[, , , , , ], [, , , , , , ]]
Example: adding tri-gram
>>> sequences = [[, , , ], [, , , , ]]
>>> token_indice = {(, ): , (, ): , (, ): , (, , ): }
>>> add_ngram(sequences, token_indice, ngram_range=)
[[, , , , ], [, , , , , , ]]
"""
new_sequences = []
for input_list in sequences:
new_list = input_list[:]
for i in range(len(new_list) - ngram_range + ):
for ngram_value in range(, ngram_range + ):
ngram = tuple(new_list[i:i + ngram_value])
if ngram in token_indice:
new_list.append(token_indice[ngram])
new_sequences.append(new_list) return new_sequences # Set parameters:
# ngram_range = will add bi-grams features
ngram_range =
max_features =
maxlen =
batch_size =
embedding_dims =
nb_epoch = print('Loading data...')
(X_train, y_train), (X_test, y_test) = imdb.load_data(
path="/home/zhenghan/keras/imdb_full.pkl",
nb_words=max_features
) # truncate the dataset
truncate_rate = 0.4
X_train = X_train[:int(len(X_train) * truncate_rate)]
y_train = y_train[:int(len(y_train) * truncate_rate)]
X_test = X_test[:int(len(X_test) * truncate_rate)]
y_test = y_test[:int(len(y_test) * truncate_rate)] print("X_train[0]")
print(X_train[])
print('y_train[0]')
print(y_train[]) print(len(X_train), 'train sequences')
print(len(X_test), 'test sequences')
print('Average train sequence length: {}'.format(np.mean(list(map(len, X_train)), dtype=int)))
print('Average test sequence length: {}'.format(np.mean(list(map(len, X_test)), dtype=int))) if ngram_range > :
print('Adding {}-gram features'.format(ngram_range))
# Create set of unique n-gram from the training set.
ngram_set = set()
for input_list in X_train:
for i in range(, ngram_range + ):
set_of_ngram = create_ngram_set(input_list, ngram_value=i)
ngram_set.update(set_of_ngram)
print('ngram_set.pop')
print(ngram_set.pop()) # Dictionary mapping n-gram token to a unique integer.
# Integer values are greater than max_features in order
# to avoid collision with existing features.
start_index = max_features +
token_indice = {v: k + start_index for k, v in enumerate(ngram_set)}
indice_token = {token_indice[k]: k for k in token_indice} # max_features is the highest integer that could be found in the dataset.
max_features = np.max(list(indice_token.keys())) +
print('max_features: ')
print(max_features) # Augmenting X_train and X_test with n-grams features
X_train = add_ngram(X_train, token_indice, ngram_range)
X_test = add_ngram(X_test, token_indice, ngram_range) print("X_train[0]")
print(X_train[])
print('X_test[0]')
print(X_test[]) print('Average train sequence length: {}'.format(np.mean(list(map(len, X_train)), dtype=int)))
print('Average test sequence length: {}'.format(np.mean(list(map(len, X_test)), dtype=int))) print('Pad sequences (samples x time)')
X_train = sequence.pad_sequences(X_train, maxlen=maxlen)
X_test = sequence.pad_sequences(X_test, maxlen=maxlen)
print('X_train shape:', X_train.shape)
print('X_test shape:', X_test.shape) print('Build model...')
model = Sequential() # we start off with an efficient embedding layer which maps
# our vocab indices into embedding_dims dimensions
model.add(Embedding(max_features,
embedding_dims,
input_length=maxlen)) # we add a GlobalAveragePooling1D, which will average the embeddings
# of all words in the document
model.add(GlobalAveragePooling1D()) # We project onto a single unit output layer, and squash it with a sigmoid:
model.add(Dense(, activation='sigmoid')) model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy']) model.fit(X_train, y_train,
batch_size=batch_size,
nb_epoch=nb_epoch,
validation_data=(X_test, y_test))

Relevant Link:
https://keras-cn.readthedocs.io/en/latest/other/datasets/
https://keras-cn.readthedocs.io/en/latest/preprocessing/sequence/
Copyright (c) 2017 LittleHann All rights reserved
IMDB影评倾向分类 - N-Gram的更多相关文章
- 学习笔记TF019:序列分类、IMDB影评分类
序列分类,预测整个输入序列的类别标签.情绪分析,预测用户撰写文字话题态度.预测选举结果或产品.电影评分. 国际电影数据库(International Movie Database)影评数据集.目标值二 ...
- AI - TensorFlow - 示例02:影评文本分类
影评文本分类 文本分类(Text classification):https://www.tensorflow.org/tutorials/keras/basic_text_classificatio ...
- 使用RNN进行imdb影评情感识别--use RNN to sentiment analysis
原创帖子,转载请说明出处 一.RNN神经网络结构 RNN隐藏层神经元的连接方式和普通神经网路的连接方式有一个非常明显的区别,就是同一层的神经元的输出也成为了这一层神经元的输入.当然同一时刻的输出是不可 ...
- 基于keras中IMDB的文本分类 demo
本次demo主题是使用keras对IMDB影评进行文本分类: import tensorflow as tf from tensorflow import keras import numpy a ...
- Python深度学习案例1--电影评论分类(二分类问题)
我觉得把课本上的案例先自己抄一遍,然后将书看一遍.最后再写一篇博客记录自己所学过程的感悟.虽然与课本有很多相似之处.但自己写一遍感悟会更深 电影评论分类(二分类问题) 本节使用的是IMDB数据集,使用 ...
- Keras学习笔记(完结)
使用Keras中文文档学习 基本概念 Keras的核心数据结构是模型,也就是一种组织网络层的方式,最主要的是序贯模型(Sequential).创建好一个模型后就可以用add()向里面添加层.模型搭建完 ...
- 我的Keras使用总结(1)——Keras概述与常见问题整理
今天整理了自己所写的关于Keras的博客,有没发布的,有发布的,但是整体来说是有点乱的.上周有空,认真看了一周Keras的中文文档,稍有心得,整理于此.这里附上Keras官网地址: Keras英文文档 ...
- Pytorch文本分类(imdb数据集),含DataLoader数据加载,最优模型保存
用pytorch进行文本分类,数据集为keras内置的imdb影评数据(二分类),代码包含六个部分(详见代码) 使用环境: pytorch:1.1.0 cuda:10.0 gpu:RTX2070 (1 ...
- 用迁移学习创造的通用语言模型ULMFiT,达到了文本分类的最佳水平
https://www.jqr.com/article/000225 这篇文章的目的是帮助新手和外行人更好地了解我们新论文,我们的论文展示了如何用更少的数据自动将文本分类,同时精确度还比原来的方法高. ...
随机推荐
- BZOJ2561最小生成树——最小割
题目描述 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最 ...
- HDU1251 字典树板子题
题意:中文题,统计以某字符串作为前缀的字符串个数 刚学字典树,理解起来十分简单,就是维护一个多叉树,这里用的是链表版本,后面就用的是数组版本了,个人更喜欢数组版本,这里的链表版本就因为 莫名其妙的错误 ...
- Marriage Match III HDU - 3277(二分权值 + 拆点 建边)
题意: 只不过是hdu3081多加了k种选择 想一下,最多能玩x轮,是不是就是每个女生能最多选x个男生 现在题中的每个女生比3081多了k中选择 那就把女生拆点 i i‘ i --> i ...
- new Date()导致日期增加了一天
问题是:将字符串 "Sun Nov 12 14:00:00 CST 2017" 转成Date类型 有一个简单的方法是直接使用new Date(),但是这个方法对于某些日期的计算, ...
- Linux block(1k) block(4k) 换算 gb
输入 df 显示1k blocks 大小 再输入 df -h 显示 gb换算大小 结论 block(1k) 计算公式为: block(1k) /1024/1000 = xx gb ...
- UOJ #207. 共价大爷游长沙(LCT + 异或哈希)
题目 维护一颗动态树,并维护一个点对集合 \(S\) . 动态查询一条边,是否被集合中所有点对构成的路径包含. \(n \le 100000, m \le 300000\) 题解 orz 前辈 毛爷爷 ...
- flowable6.4.1+springboot使用dmn
resources/dmn/strings_1.dmn <?xml version="1.0" encoding="UTF-8"?> <def ...
- 【BZOJ3165】[HEOI2013]Segment(李超线段树)
[BZOJ3165][HEOI2013]Segment(李超线段树) 题面 BZOJ 洛谷 题解 似乎还是模板题QwQ #include<iostream> #include<cst ...
- python中,print函数的sep和end参数
print函数是我们经常使用的,但是它的sep和end参数或许对很多python使用者相对陌生,他们可以让我们的打印更具有个性化. 先来看下官方解释, sep:分割值与值,默认是一个空格 end:附件 ...
- 如何优雅的解决mac安装zsh不执行.bash_profile
最近刚刚重装了系统,并安装了优雅的shell命令工具zsh,突然发现我放在我的工作目录下的.bash_profile居然在启动的时候执行,导致我的java的一些配置没有注册到bash中.然后查资料得知 ...