深度学习与未来
297
为了创建训练模型,构建两个流水线来简化文本规范化、向量化和建模步骤:
if __name__ == '__main__':
from transformer import TextNormalizer
from reader import PickledReviewsReader
from sklearn.pipeline import Pipeline
from sklearn.neural_network import MLPRegressor, MLPClassifier
from sklearn.feature_extraction.text import TfidfVectorizer
#
预处理过、经过词性标注的评论语料库路径
cpath = '../review_corpus_proc'
regressor = Pipeline([
('norm', TextNormalizer()),
('tfidf', TfidfVectorizer()),
('ann', MLPRegressor(hidden_layer_sizes=[500,150], verbose=True))
])
regression_scores = train_model(cpath, regressor, continuous=True)
classifier = Pipeline([
('norm', TextNormalizer()),
('tfidf', TfidfVectorizer()),
('ann', MLPClassifier(hidden_layer_sizes=[500,150], verbose=True))
])
classifer_scores = train_model(cpath, classifier, continuous=False)
类似于为
k
均值聚类选择
k
值,在初始神经网络原型中选择隐藏层的最佳数
量和大小与其说是技术不如说更像是艺术。每层层数和节点越多,模型就越
复杂,而更复杂的模型需要更多的训练数据。一个好的经验法则是从简单的
模型开始(初始层不应该包含比我们有实例更多的节点,并且应该包含不超
过两个层),在用
k
折交叉验证时迭代增加复杂性同时检测过拟合。
Scikit-Learn
提供了许多用于调整神经网络的功能,并且可以进行定制。例如,
默认情况下,
MLPRegressor
MLPClassifier
都使用
ReLU
激活函数(可用激
活参数指定)以及随机梯度下降来最小化代价函数(可用求解器参数指定):
Mean score for MLPRegressor: 0.27290534221341
Mean score for MLPClassifier: 0.7115215174722
MLPRegressor
效果并不好,从
R
2
分数看数据拟合度相当低。回归受益于相
对于实例数量维度减少的数量。可以通过维度诅咒的视角来解释这个问题
Pitchfork
评论平均长度约为
1000
个词,每个词为决策空间增加一个维度。由
298
12
于语料库总共仅包含约
18000
条评论,因此
MLPRegressor
根本没有足够的实
例来预测浮点精度的分数。
不过,我们也看到
MLPClassifier
结果稍好一些,可能值得进一步调整。为了
提高
MLPClassifier
性能,可以尝试添加和删除复杂性。可以通过向
hidden_
layer_sizes
添加更多层和神经元来增加复杂性。还可以增加
max_iter
参数
以增加训练的轮数,并给模型更长时间从反向传播中学习。
还可以通过删除层、减少神经元数量或用
alpha
参数向损失函数添加正则化项
来降低模型的复杂性,类似于
sklearn.linear_model.RidgeRegression
,这
会人为地缩减参数,有助于防止过拟合。
Scikit-Learn API
构建神经模型对于简单模型非常方便。但是,正如我们将
在下一节中将要看到的,像
TensorFlow
这样的库提供了更多的灵活性、模型
架构调整,以及更快的速度,利用
GPU
可以在更大数据集上进行扩展以获得
更高性能。
深度学习架构
正如经常用深度学习这个术语所概括的,诸如递归神经网络
RNN
),长期
短期记忆网络
LSTM
递归神经张量网络
RNTN
卷积神经网络
CNN
ConvNets
)及生成性对抗网络(
GAN
)等模型近年来越来越受欢迎。
虽然人们通常将深度神经网络定义为具有多个隐藏层的神经网络,但术语“深
度学习”实际上与现代人工神经网络
ANN
)没有明显区别。但是,不同的
体系结构确实在层内实现了独特的功能,使它们能对非常复杂的数据进行建
模。
例如,卷积神经网络
CNN
)将多层感知器与卷积层相结合,该卷积层迭代
地构建映射以提取重要特征,以及池化阶段,减少特征维度的同时保留其最
有信息量的成分。
CNN
对于建模图像数据、执行分类和摘要等任务非常有效。
深度学习与未来
299
为了对顺序语言数据建模,已经证明递归神经网络
RNN
)的变种诸如长短
期记忆(
LSTM
)网络特别有效。
RNN
的体系结构允许模型维持序列中词的
顺序并跟踪长期依赖性。例如,
LSTM
实现了门控单元,允许“记忆”“遗
忘”等功能。这种模型的变体在机器翻译和自然语言生成任务中非常流行。
TensorFlow
深度学习的框架
TensorFlow
是个分布式计算引擎,开放的深度学习框架。由谷歌开发,其目
标不仅是
GPU
、也是多机器网络的并行模型,它于
2015
11
月开源,并成
为最受欢迎的公共可用深度学习库之一。
TensorFlow
假设用户对神经网络架构非常熟悉,并且正在构建高度定制的数
据流图。在
TensorFlow
工作流中,首先指定每个层和所有超参数,然后将这
些步骤编译为静态图,运行会话以开始训练。虽然这使得深度学习模型随着
其复杂性增加更容易控制和优化,但也使得快速原型设计更具挑战性。
从本质上讲,深度学习模型只是个函数链,意味着许多深度学习库往往具
有功能性或冗长的、声明式风格。因此,包括
Keras
TF-slim
TFLearn
SkFlow
在内的其他库的生态系统已迅速发展,为深度学习提供了更抽
、面向对象的界面。在下一节中,我们将演示如何通过
Keras API
使用
TensorFlow
Keras
深度学习
API
虽然经常与深度学习框架(如
TensorFlow
Caffe
Theano
PyTorch
组合在一起,但
Keras
开放了深度学习的通用
API
规范。最初的
Keras
面是为
Theano
后端编写的,但在
TensorFlow
的开源和戏剧性流行之后
Keras API
迅速成为许多
TensorFlow
用户的默认设置,并于
2017
年初被拉入
TensorFlow
核心。
Keras
,一切都是对象,这使它成为一个特别方便的原型设计工具。为了
粗略地重新创建我们在上一节中使用的多层感知器分类器,创建一个
build_
network
函数来实例化一个
Sequential Keras
模型,添加两个
Dense
(意味着
300
12
完全连接隐藏层,第一个包含
500
个节点,第二个包含
150
个节点,两者都
采用整流线性单元作为激活参数。请注意,在我们的第一个隐藏层,需要传
入一个元组
input_shape
指定输入层的形状。
在输出层,必须指定一个函数,将前一层的维度压缩到与分类问题中的类数
相同的空间中。在这种情况下,我们用
softmax
,也是自然语言处理的流行选
择,它代表了与我们语料库的标记对齐的分类分布。然后,
build_network
数调用
compile
方法,为梯度下降指定所需的损失函数和优化器函数,最后
返回已编译的网络:
from keras.layers import Dense
from keras.models import Sequential
N_FEATURES = 5000
N_CLASSES = 4
def build_network():
"""
创建一个返回编译的神经网络的函数
"""
nn = Sequential()
nn.add(Dense(500, activation='relu', input_shape=(N_FEATURES,)))
nn.add(Dense(150, activation='relu'))
nn.add(Dense(N_CLASSES, activation='softmax'))
nn.compile(
loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy']
)
return nn
keras.wrappers.scikit_learn
模块开放了
KerasClassifier
KerasRegressor
,这两个封装器实现了
Scikit-Learn
接口。这意味着我们可以
Sequential
Keras
模型作为
Scikit-Learn
Pipeline
Gridsearch
的一部分。
要在工作流中使用
KerasClassifier
和上一节一样,
TextNormalizer
(如
4
章所述)和
Scikit-Learn
TfidfVectorizer
开始
pipeline
。我们用向量化
器的
max_features
参数传递
N_FEATURES
全局变量,这将确保我们的向量具有
与编译的神经网络的
input_shape
相同的维度。
深度学习与未来
301
对于我们这些被
Scikit-Learn
估算器惯坏了的人来说,建立深度学习模型一
开始就有点令人沮丧。
Keras
TensorFlow
对输入数据的大小和形状几乎
没有任何假设,也不会直觉决定决策空间的超参数。然而,学习通过
Keras
API
构建
TensorFlow
模型不仅使我们能够构建自定义模型,而且还可以在
sklearn.neural_network
模型的一小部分时间内训练它们。
最后,我们将
KerasClassifier
添加到
pipeline
中,传递网络的构建函数,所
需的轮数和可选的批量大小。请注意,我们必须将
build_network
作为函数传
递,而不是作为编译网络的实例传递:
if __name__ == '__main__':
from sklearn.pipeline import Pipeline
from transformer import TextNormalizer
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.feature_extraction.text import TfidfVectorizer
pipeline = Pipeline([
('norm', TextNormalizer()),
('vect', TfidfVectorizer(max_features=N_FEATURES)),
('nn', KerasClassifier(build_fn=build_network,
epochs=200,
batch_size=128))
])
现在可以用略微修改的
train_model
函数来运行和评价流水线。与上一节一样,
此函数将实例化语料库读取器,调用
documents
make_categorical
获取输
入和目标值
X
y
计算交叉验证分数、拟合和存储模型,并返回分数。
不幸的是,在编写本书时,
Scikit-Learn
封装的
Keras
模型的
pipeline
持久性
有些挑战,因为必须使用
Keras
特定的保存方法将神经网络组件保存为分层
数据格式(
.h5
)文件。作为一种解决方法,我们使用
Pipeline
索引首先存储
训练好的神经网络,然后使用
joblib
存储拟合
pipeline
的其余部分:
def train_model(path, model, saveto=None, cv=12):
"""
按照指定的路径从语料库中训练模型,并拟合完整的数据。
如果指定了保存到字典,则将
Keras
Sklearn
流水线组件分别写入磁盘。
返回分数
"""
corpus = PickledReviewsReader(path)
X = documents(corpus)

Get 基于Python的智能文本分析 now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.