# 影评分类 深度学习

## Python深度学习案例1--电影评论分类(二分类问题)

2018-11-09 21:50:25 qq_43452804 阅读数 785
• ###### 深度学习30天系统实训

选择深度学习当下流行框架Tensorflow进行案例实战，选择经典的计算机视觉与自然语言处理经典案例以及绚丽的AI黑科技实战，从零开始带大家一步步掌握深度学习的原理以及实战技巧。课程具体内容包括：神经网络基础知识...

66课时 766分钟 14926人学习 唐宇迪
免费试看

1. 加载IMDB数据集

from keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

train_data[0]

train_labels[0]


max([max(sequence) for sequence in train_data])


9999

word_index = imdb.get_word_index()
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])


2. 将整数序列编码为二进制矩阵

import numpy as np

def vectorize_sequences(sequences, dimension=10000):
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
results[i, sequence] = 1
return results

x_train = vectorize_sequences(train_data)

x_test = vectorize_sequences(test_data)

x_train[0]


array([ 0., 1., 1., …, 0., 0., 0.])

y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')


3. 模型定义

from keras import models
from keras import layers

model = models.Sequential()


4. 编译模型

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])


5. 配置优化器

from keras import optimizers

model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss='binary_crossentropy', metrics=['accuracy'])


6. 使用自定义的损失和指标

from keras import losses
from keras import metrics

model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss=losses.binary_crossentropy, metrics=[metrics.binary_crossentropy])


7. 留出验证集

x_val = x_train[:10000]
partial_x_train = x_train[10000:]

y_val = y_train[:10000]
partial_y_train = y_train[10000:]


8. 训练模型

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])

history = model.fit(partial_x_train, partial_y_train, epochs=20, batch_size=512, validation_data=(x_val, y_val))

history_dict = history.history
history_dict.keys()


9. 绘制训练损失和验证损失

import matplotlib.pyplot as plt

history_dict = history.history
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']

epochs = range(1, len(loss_values) + 1)
# ’bo‘表示蓝色原点，’b’表示蓝色实线
plt.plot(epochs, loss_values, 'bo', label='Training loss')
plt.plot(epochs, val_loss_values, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()


10. 绘制训练精度和验证精度

plt.clf()     # 清除图像
acc = history_dict['acc']
val_acc = history_dict['val_acc']

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

plt.show()


11. 从头开始训练一个模型

model = models.Sequential()

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])

model.fit(x_train, y_train, epochs=4, batch_size=512)
results = model.evaluate(x_test, y_test)


results

[0.28940243008613586, 0.88488]


12. 使用训练好的模型在新数据上生成预测结果

model.predict(x_test)


array([[0.20151292],
[0.9997969 ],
[0.9158534 ],
…,
[0.1382984 ],
[0.0817486 ],
[0.69964325]], dtype=float32)

13. 总结

1. 加载数据集->对数据集进行预处理->模型定义->编译模型->配置优化器->使用自定义的损失和指标->留出验证集->训练模型->绘制图像
2. 对于二分类问题，网络的最后一层应该是只有一个单元并使用sigmoid激活Dense层，网络输出应该是0~1范围内的标量，表示概率值
3. 对于二分类问题的sigmoid标量输出，应该使用binary_crossentropy（二元交叉熵）损失函数。

## 方法 | 机器学习(深度学习)通用工作流程

2018-01-19 15:54:18 zwqjoy 阅读数 4545
• ###### 深度学习30天系统实训

选择深度学习当下流行框架Tensorflow进行案例实战，选择经典的计算机视觉与自然语言处理经典案例以及绚丽的AI黑科技实战，从零开始带大家一步步掌握深度学习的原理以及实战技巧。课程具体内容包括：神经网络基础知识...

66课时 766分钟 14926人学习 唐宇迪
免费试看

# 机器学习(深度学习)通用工作流程

## 1. 定义问题并装载数据集(Defining the problem and assembling a dataset)

• 输入数据是什么？你希望预测什么？只有在能够获得训练数据的情况下你才能进行预测：举个例子，如果你同时又电影的影评和对应的情感注释，你只能从中学习分类电影影评的情绪。因此，数据可用性是这个阶段的限制因素（除非你有办法雇人帮你收集数据）
• 你面临什么类型的问题？它是二元分类吗？还是多类分类？标量回归？向量回归？多类多标签分类？或者其他的类型，例如聚类，生成问题或者增强学习？识别问题的类型能够指导你选择模型的构架，损失函数等等

• 你假设你可以根据给定的输入预测输出
• 你假设你的可用数据有足够的信息用于学习输入与输出之间的关系

## 3. 决定一个验证策略(Deciding on an evaluation protocol)

• 保留一个hold-out验证集，当你有足够多的数据时，用这种方法
• K-fold 交叉验证。数据太少，不足以使用第一种验证方法的使用，用这种方法。
• 迭代 K-fold 交叉验证。只有很少的数据可用时，用于执行高度准确的模型评估。

• 正如前面提到的那样，你的数据应该格式化为张量
• 通常情况下，这些张量的值被缩小为较小的值，比如说缩放到[-1,1]或者[0,1]
• 如果不同的特征采取不同范围的值，那么数据应该做归一化处理
• 你可能想做一些特征工作，特别是对于数据集不大的问题

## 5. 开发一个比基线好的模型(Developing a model that does better than a baseline)

• 你假设你可以根据给定的输入预测输出
• 你假设你的可用数据有足够的信息用于学习输入与输出之间的关系

• 最后一层的激活函数，这为网络的输入设定了限制。例如，在IMDB分类问题中，最后一层使用了sigmoid; 在回归问题中，最后一层没有使用任何激活函数
• 损失函数，这应该与你正在尝试解决的问题的类型相匹配。例如在IMBD二元分类问题中，使用了binary_crossentropy，回归问题中使用了mse等等。
• 优化配置，你将使用什么优化器？学习率是多少？在大多数情况在，使用rmsprop和默认的学习率是安全的。

[0,1]之间的回归问题 sigmoid mse 或者 binary_crossentropy

## 6. 全面升级：开发一个过拟合的模型

1. 增加网络层
2. 让网络层变大
3. 训练更多次

• 添加Dropout
• 尝试不同的体系结构的网络：添加或者删除网络层
• 添加 L1/L2 正则化
• 尝试不同的超参数（例如每一层的神经元个数或者优化器学习率），以获得最佳的参数选择
• (可选)迭代特征工程：添加新特征，或者删除似乎没有提供信息的特征

## 瞎聊深度学习——IMDB影评文本分类

2019-05-12 21:31:05 qq_35164554 阅读数 740
• ###### 深度学习30天系统实训

选择深度学习当下流行框架Tensorflow进行案例实战，选择经典的计算机视觉与自然语言处理经典案例以及绚丽的AI黑科技实战，从零开始带大家一步步掌握深度学习的原理以及实战技巧。课程具体内容包括：神经网络基础知识...

66课时 766分钟 14926人学习 唐宇迪
免费试看

## IMDB

IMDB数据集是Tensorflow中带有的数据集，其中包含来自互联网电影库的50000条影评文本，首先来下载该数据集并且查看一下：

### 加载数据（如果缓存中没有回自动下载该数据）：

import tensorflow as tf
from tensorflow import keras
import numpy as np

imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

### 查看数据：

print("Trraining entries:{},labels:{}".format(len(train_data),len(train_labels)))

print(train_data[0])

print(len(train_data[0]),len(train_data[10]),len(train_data[100]))

train_data = keras.preprocessing.sequence.pad_sequences(train_data,
value=0,
maxlen=256)

value=0,
maxlen=256)
print(len(train_data[0]),len(train_data[10]),len(train_data[100]))

sequences：浮点数或整数构成的两层嵌套列表

maxlen：None或整数，为序列的最大长度。大于此长度的序列将被截短，小于此长度的序列将在后部填0.

dtype：返回的numpy array的数据类型

truncating：‘pre’或‘post’，确定当需要截断序列时，从起始还是结尾截断

value：浮点数，此值将在填充时代替默认的填充值0

### 构建模型

vocab_size = 10000

model = keras.Sequential()

model.summary()

### 损失函数和优化器

model.compile(optimizer=tf.train.AdamOptimizer(),
loss='binary_crossentropy',
metrics=['accuracy'])

### 创建验证集

x_val = train_data[:10000]
partial_x_train = train_data[10000:]

y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]

### 训练模型并且评估模型

history = model.fit(partial_x_train,
partial_y_train,
epochs=40,
batch_size=512,
validation_data=(x_val, y_val),
verbose=1)
results = model.evaluate(test_data, test_labels)

print(results)

## Python深度学习（电影评论分类：二分类问题）

2020-04-21 01:14:55 a15261893837 阅读数 91
• ###### 深度学习30天系统实训

选择深度学习当下流行框架Tensorflow进行案例实战，选择经典的计算机视觉与自然语言处理经典案例以及绚丽的AI黑科技实战，从零开始带大家一步步掌握深度学习的原理以及实战技巧。课程具体内容包括：神经网络基础知识...

66课时 766分钟 14926人学习 唐宇迪
免费试看

电影评论分类数据集加载

import tensorflow as tf
import tensorflow.keras as keras
#所有imdb.*使用keras.datasets.imdb.*

train_data[0]
word_index = keras.datasets.imdb.get_word_index()

​

​

## 深度学习之文本与序列--基于Keras的IMDB电影评论分类

2018-06-30 13:43:01 apengpengpeng 阅读数 2181
• ###### 深度学习30天系统实训

选择深度学习当下流行框架Tensorflow进行案例实战，选择经典的计算机视觉与自然语言处理经典案例以及绚丽的AI黑科技实战，从零开始带大家一步步掌握深度学习的原理以及实战技巧。课程具体内容包括：神经网络基础知识...

66课时 766分钟 14926人学习 唐宇迪
免费试看

【应用场景】

• 文本分类、时间序列分类。eg. 确定一篇文章的主题，确定一本书的作者
• 时间序列的相互比较。eg. 文本相似度，股票行情预测
• 语言序列的学习。eg. 英译汉，汉译英，翻译系统
• 情感分析。eg. 一条微博携带的情感色彩，电影评论好与坏
• 时间序列预测。eg. 在一个确定地点预测未来的天气，给出最近的天气

【用文本数据工作】

• 将text分割成word， 将每个word装换成vector；
• 将text分割成character，将每个character装换成vector；
• 提取word和character的n-gram，并将每个n-gram转换成一个vector。

• token：指的是将文本分割成word、character、n-gram，其中word、character、n-gram均可称为是token
• tokenization：将文本转化成token的过程；
• n-grams：从一句话中抽出N个连续词组成的集合。举个例子：“The cat sat on the mat.”；
那么2-grams：{“The”, “The cat”, “cat”, “cat sat”, “sat”, “sat on”, “on”, “on the”, “the”, “the mat”, “mat”}
，同样，3-grams：{“The”, “The cat”, “cat”, “cat sat”, “The cat sat”, “sat”, “sat on”, “on”, “cat sat on”, “on the”, “the”, “sat on the”, “the mat”, “mat”, “on the mat”}；
• bag-of-words：指的是无序的词库集合，也就是经过tokenization之后产生的集合。

Tips:

• 在提取n-grams时，其实这个过程就像是在提取一句话的特征，那么在深度学习中，就是用一维卷积、RNN等方法去替代n-grams；
• 虽然现在越来越多的复杂的任务均转移到了深度学习，但是在处理一些轻量级的任务时，不可避免的去使用n-grams，还有一些传统高效的方法，比如：逻辑回归、随机森林。

【token的两种编码方式】

• one-hot
one-hot是一种常见的编码方式，通过几个toy example来了解一下

import numpy as np

samples = ['The cat sat on the mat.', 'The dog ate my homework.']

# 10
# 定义一个集合，得到{'The': 1, 'cat': 2, 'sat': 3, 'on': 4, 'the': 5, 'mat.': 6, 'dog': 7, 'ate': 8, 'my': 9, 'homework.': 10}，也就是筛选出这个句子中对应的了哪些词，然后并赋予索引值，其实就是个词库
token_index = {}
for sample in samples:
for word in sample.split():
if word not in token_index:
token_index[word] = len(token_index) + 1

#　限制了读取的句子的长度，一句话最长10个词
max_length = 10
results = np.zeros(shape=(len(samples),
max_length,
max(token_index.values()) + 1))

# print(results) 2, 10, 11
for i, sample in enumerate(samples):
for j, word in list(enumerate(sample.split()))[:max_length]:
index = token_index.get(word)
results[i, j, index] = 1.
print(results)


import numpy as np
import string
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
# 预先定义一个字符集 '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#\$%&\\'()*+,-./:;<=>?@[\\]^_{|}~‘
characters = string.printable
token_index = dict(zip(range(1, len(characters) + 1), characters))

max_length = 50
results = np.zeros((len(samples), max_length, max(token_index.keys()) + 1))
for i, sample in enumerate(samples):
for j, character in enumerate(sample):
for key, value in token_index.items():
if value == character:
index = key
results[i, j, index] = 1.

print(results)



samples = ['The cat sat on the mat.', 'The dog ate my homework.']
tokenizer = Tokenizer(num_words=1000)
tokenizer.fit_on_texts(samples)

sequences = tokenizer.texts_to_sequences(samples)
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')

word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))


samples = ['The cat sat on the mat.', 'The dog ate my homework.']

dimensionality = 1000
max_length = 10

results = np.zeros((len(samples), max_length, dimensionality))
for i, sample in enumerate(samples):
for j, word in list(enumerate(sample.split()))[:max_length]:
# 计算hash值
index = abs(hash(word)) % dimensionality
results[i, j, index] = 1

print(results)

• 词嵌入（word-embedding）
word-embedding也是对文本进行编码的一种方法，相比与one-hot，word-embedding显得更为灵活，我们来对比一下：

one-hot是高维的（词库中有多少个token，就有多少维），稀疏的（大部分均为0），是二分的，硬编码的；

word-emedding是低维的浮点型张量，能够用更低的维度去叠加更多的信息，全连接的，是从数据中学习而来；word-embedding具体获取的方式有两种：
1）在神经网络中添加embedding层去学习word-embedding，它是在词向量之间反映出语义关系，将人类自然语言映射到几何空间中。比如，我们希望同义词被嵌入到相似的词向量中。

拿上面的例子简单解释一下，这四个词是嵌入到2D空间中的向量，这几个词中一些语义关系会通过几何代换进行编码，我们发现两组的相似的向量，从cat到tiger，从dog到wolf，这组向量会被解释为“从宠物到野生动物”这种语义关系，同样的，从dog到cat， 从wolf到tiger，这组向量会被解释为“从犬类到猫科动物”。因此我们能更好的去理解word-embedding相比于one-hot具有好的灵活性，每一个词向量所在的空间位置都是有确定的语义关系，我们通过神经网络将这种语义关系学习出来。word-embedding类似于找到一个空间（或多个空间），在每个空间中都包含着许多词（同义词），这些词在这个空间不是孤立，都是有特定语义的。但是因为不同的任务中的embedding-space不同，都是唯一的，正所谓“具体问题具体分析”，所以需要进行重新学习。
2）另一种方式是利用预训练的word-embedding，尤其是适用于拥有少量的训练数据的情况下，预训练的原理在此不再赘述，原理和做图像分类时利用ImgaeNet中的VGG16结构一样，重利用在复杂问题上学习到的特征应用到自己的任务中，这是一种简单而有效的方法。我们在预训练中采用已有的word-embedding预计算的数据库，例如，word2vec，Glove。
Notes：在预训练模型我们始终应该注意的是所有预训练的模型在训练的时候参数不应该被更新，若将所有参数进行更新，由于随机初始化隐藏层引发的巨大的梯度更新将会破坏掉已经训练的特征。
【举个栗子】
我们利用IMDB电影评论数据做好的评论和不好的评论的分类，并以GLoVE作为预计算的word-embedding空间。
• 数据集
IMDB数据集------自行翻墙下载或者下方留言邮箱
GLoVE数据------百度网盘
• 模型建立与完整代码
该模型是添加了embedding层
import os
from keras.preprocessing.text import Tokenizer
import numpy as np
from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense
import matplotlib.pyplot as plt

# settings
max_len = 100
training_samples = 200
validation_samples = 10000
max_words = 10000
embedding_dim = 100

def process_data():
'''
处理IMDB数据,将数据按标签分为pos，neg
:return: labels,texts
'''
imdb_dir = 'D:\\text2sequences\\aclImdb\\aclImdb'
train_dir = os.path.join(imdb_dir, 'train')

labels = []
texts = []

for label_type in ['pos', 'neg']:
dir_name = os.path.join(train_dir, label_type)
for fname in os.listdir(dir_name):
if fname[-4:] == '.txt':
f = open(os.path.join(dir_name, fname), 'r', encoding='UTF-8')
f.close()
if label_type == 'neg':
labels.append(0)
else:
labels.append(1)

return labels, texts

def tokennize_data():
'''
将text向量化，切分训练集和验证集
:return:x_train, y_train, x_val, y_val即训练集和验证集的label和text
'''

labels, texts = process_data()
tokenizer = Tokenizer(num_words=max_words)
tokenizer.fit_on_texts(texts=texts)
sequences = tokenizer.texts_to_sequences(texts=texts)
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))

labels = np.asarray(labels)
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]

return x_train, y_train, x_val, y_val, word_index

def parse_word_embedding(word_index):
'''
将预计算的词向量空间的word建立索引和矩阵
:return:
'''
glove_dir = 'D:\\text2sequences\\glove.6B'

embeddings_index = {}
f = open(os.path.join(glove_dir, 'glove.6B.100d.txt'), 'r', encoding='UTF-8')
for  line in f:
values = line.split()
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
embeddings_index[word] = coefs

f.close()
print('Found %s word vectors.' % len(embeddings_index))

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

return embedding_matrix

def train_model():
'''
训练模型
:return:训练时loss,acc
'''
model = Sequential()
model.summary()

# 将GLOVE加载到模型中
x_train, y_train, x_val, y_val, word_index = tokennize_data()
embedding_matrix = parse_word_embedding(word_index)
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False

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))
model.save('pre_trained_glove_model.h5')

return history

def plott_results():
'''
作图
'''
history = train_model()
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()

if __name__ == '__main__':
plott_results()

• 训练效果与评估分析
训练效果

• 版本改进
我们将embedding层变为可训练的，可以对embedding层的参数进行更新。修改train_model函数为以下：

def train_model():
'''
训练模型
:return:训练时loss,acc
'''
model = Sequential()
model.summary()

# 将GLOVE加载到模型中
x_train, y_train, x_val, y_val, word_index = tokennize_data()
embedding_matrix = parse_word_embedding(word_index)

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))
model.save('pre_trained_glove_model.h5')

return history
`
• 训练结果和评估分析
训练效果

评估分析
看来，联合学习的embeeding层训练出来的效果不如预训练的embeeding层效果好，这个效果貌似更差。同时我们对模型进行评估，在测试集上得到的准确率只有0.51，可见在小样本上进行训练是有多么的困难。

#### 【参考文献】

• 《DEEP LEARNING with Python》
一本很好的有关深度学习的书籍，能让你构建一个正确的、系统的深度学习的思想和体系，值得推荐~
• 电子版链接–百度网盘

#### 【感谢】

• 邮箱：zhangpeng@webprague.com