编辑 | 言有三
这一次我们讲讲keras这个简单、流行的深度学习框架,一个图像分类任务从训练到测试出结果的全流程。
相关的代码、数据都在我们 Git 上,希望大家 Follow 一下这个 Git 项目,后面会持续更新不同框架下的任务。
Keras是一个非常流行、简单的深度学习框架,它的设计参考了torch,用Python语言编写,是一个高度模块化的神经网络库,支持GPU和CPU。能够在TensorFlow,CNTK或Theano之上运行。 Keras的特点是能够快速实现模型的搭建, 简单方便地让你实现从想法到实验验证的转化,这都是高效地进行科学研究的关键。
Keras的安装非常简单,但是需要先安装一个后端框架作为支撑,TensorFlow, CNTK,Theano都可以,但是官网上强烈建议使用TensorFlow作为Keras的后端进行使用。本例以TensorFlow 140 版本作为Keras的后端进行测试。
通过上面两条命令就可以完成TensorFlow和Keras的安装,此处需要注意的一点是Keras的版本和TensorFlow的版本要对应,否则会出现意外的错误。具体版本对应关系可在网上进行查询。
31 MNIST实例
MNIST手写字符分类被认为是深度学习框架里的“Hello Word!”,下面简单介绍一下MNIST数据集案例的测试。Keras的官方github的example目录下提供了几个MNIST案例的代码,下载mnist_mlppy,mnist_cnnpy文件,本地运行即可,其他文件读者也可以自行测试。
32 数据定义
前面我们介绍了MNIST数据集实例,很多读者在学习深度学习框架的时候都卡在了这一步,运行完MNIST实例之后无从下手,很大原因可能是因为不知道怎么处理自己的数据集,这一节我们通过一个简单的图像二分类案例,介绍如何实现一个自定义的数据集。
数据处理有几种方式,一种是像MNIST、CIFAR数据集,这些数据集的特点是已经为用户打包封装好了数据。用户只要load_data即可实现数据导入。其实就是事先把数据进行解析,然后保存到pkl 或者h5等文件中,然后在训练模型的时候直接导入,输入到网络中;另一种是直接从本地读取文件,解析成网络需要的格式,输入网络进行训练。但是实际情况是,为了某一个项目我们不可能总是找到相应的打包好的数据集供使用,这时候自己建立一个dataset就十分重要。
Keras提供了一个图像数据的数据增强文件,调用这个文件我们可以实现网络数据加载的功能。
此处采用keras的processing模块里的ImageDataGenerator类定义一个图像分类任务的dataset生成器:
下面简单地介绍一下上面的代码,完整代码请移步Git工程。
Keras的processing模块中提供了一个能够实时进行数据增强的图像生成类ImagGenerator,该类下面有一个函数flow_from_directory,顾名思义该函数就是从文件夹中获取图像数据。关于ImageGenerator更多的使用可以参考官方源码。数据集结构组织如下:
此处还需要注意的一点是,我们现在进行的是简单的图像分类任务训练,假如要完成语义分割,目标检测等任务,则需要自定义一个类(继承ImageDataGenerator),具体实现可以查询相关代码进行参考。
Keras网络模型搭建有两种形式,Sequential 顺序模型和使用函数式API的 Model 类模型。本教程的例子采用一个简单的三层卷积,以及两层全连接和一个分类层组成的网络模型。由于函数式API更灵活方便,因此下面采用函数式方法搭建模型,模型定义如下:
41 函数式API
即输出是12通道,卷积核大小33,步长为2,padding='same'表示边缘补零
axis表示需要归一化的坐标轴,bn_axis=3,由于采用TensorFlow作为后端,因此这句代码表示在通道数坐标轴进行归一化。
x = Flatten()(x) 表示将卷积特征图进行拉伸,以便和全连接层Dense()进行连接。
Dense()实现全连接层的功能,1200是输出维度,‘relu'表示激活函数,使用其他函数可以自行修改。
最后一层采用‘softmax’激活函数实现分类功能。
最终返回Model,包含网络的输入和输出。
42 模型编译
网络搭建完成,在网络训练前需要进行编译,包括学习方法、损失函数、评估标准等,这些参数分别可以从optimizer、loss、metric模块中导入。具体代码如下:
其中callbacks模块包含了TensorBoard, ModelCheckpoint,LearningRateScheduler等功能,分别可以用来可视化模型,设置模型检查点,以及设置学习率策略。
51 模型训练
Keras模型训练过程非常简单,只需一行代码,设置几个参数即可,具体代码如下:
首先指定数据生成器,train_generator, 前面介绍过;steps_per_epoch是每次epoch循环的次数,通过训练样本数除以batch_size得到;epochs是整个数据集重复多少次训练。
Keras是高度封装的,在模型训练过程中,看不到网络的预测结果和网络的反向传播过程,只需定义好损失函数,事实上,网络定义中的模型输出会包含网络的输入和输出。
52 训练过程可视化
keras可以采用tensorboard实现训练过程的可视化。执行完下面的命令就可以在浏览器访问>
数据预处理
模型能聊的内容也取决于选取的语料。如果已经具备了原始聊天数据,可以用SQL通过关键字查询一些对话,也就是从大库里选取出一个小库来训练。从一些论文上,很多算法都是在数据预处理层面的,比如Mechanism-Aware Neural Machine for Dialogue Response Generation就介绍了,从大库中抽取小库,然后再进行融合,训练出有特色的对话来。
对于英语,需要了解NLTK,NLTK提供了加载语料,语料标准化,语料分类,PoS词性标注,语意抽取等功能。
另一个功能强大的工具库是CoreNLP,作为 Stanford开源出来的工具,特色是实体标注,语意抽取,支持多种语言。
下面主要介绍两个内容:
中文分词
现在有很多中文分词的SDK,分词的算法也比较多,也有很多文章对不同SDK的性能做比较。做中文分词的示例代码如下。
# coding:utf8
'''
Segmenter with Chinese
'''
import jieba
import langid
def segment_chinese_sentence(sentence):
'''
Return segmented sentence
'''
seg_list = jiebacut(sentence, cut_all=False)
seg_sentence = u" "join(seg_list)
return seg_sentencestrip()encode('utf8')
def process_sentence(sentence):
'''
Only process Chinese Sentence
'''
if langidclassify(sentence)[0] == 'zh':
return segment_chinese_sentence(sentence)
return sentence
if __name__ == "__main__":
print(process_sentence('飞雪连天射白鹿'))
print(process_sentence('I have a pen'))
以上使用了langid先判断语句是否是中文,然后使用jieba进行分词。
在功能上,jieba分词支持全切分模式,精确模式和搜索引擎模式。
全切分:输出所有分词。
精确:概率上的最佳分词。
所有引擎模式:对精确切分后的长句再进行分词。
jieba分词的实现
主要是分成下面三步:
1、加载字典,在内存中建立字典空间。
字典的构造是每行一个词,空格,词频,空格,词性。
上诉书 3 n
上诉人 3 n
上诉期 3 b
上诉状 4 n
上课 650 v
建立字典空间的是使用python的dict,采用前缀数组的方式。
使用前缀数组的原因是树结构只有一层 - word:freq,效率高,节省空间。比如单词"dog", 字典中将这样存储:
{
"d": 0,
"do": 0,
"dog": 1 # value为词频
}
字典空间的主要用途是对输入句子建立有向无环图,然后根据算法进行切分。算法的取舍主要是根据模式 - 全切,精确还是搜索。
2、对输入的语句分词,首先是建立一个有向无环图。
有向无环图, Directed acyclic graph (音 /ˈdæɡ/)。
图 3-2 DAG
DAG对于后面计算最大概率路径和使用HNN模型识别新词有直接关系。
3、按照模式,对有向无环图进行遍历,比如,在精确模式下,便利就是求最大权重和的路径,权重来自于在字典中定义的词频。对于没有出现在词典中的词,连续的单个字符也许会构成新词。然后用HMM模型和Viterbi算法识别新词。
精确模型切词:使用动态规划对最大概率路径进行求解。
最大概率路径:求route = (w1, w2, w3 ,, wn),使得Σweight(wi)最大。Wi为该词的词频。
更多的细节还需要读一下jieba的源码。
自定义字典
jieba分词默认的字典是:1998人民日报的切分语料还有一个msr的切分语料和一些txt小说。开发者可以自行添加字典,只要符合字典构建的格式就行。
jieba分词同时提供接口添加词汇。
Word embedding
使用机器学习训练的语言模型,网络算法是使用数字进行计算,在输入进行编码,在输出进行解码。word embedding就是编解码的手段。
图 3-3 word embedding, Ref #7
word embedding是文本的数值化表示方法。表示法包括one-hot,bag of words,N-gram,分布式表示,共现矩阵等。
Word2vec
近年来,word2vec被广泛采用。Word2vec输入文章或者其他语料,输出语料中词汇建设的词向量空间。详细可参考word2vec数学原理解析。
使用word2vec
安装完成后,得到word2vec命令行工具。
word2vec -train "data/reviewtxt" \
-output "data/reviewmodel" \
-cbow 1 \
-size 100 \
-window 8 \
-negative 25 \
-hs 0 \
-sample 1e-4 \
-threads 20 \
-binary 1 \
-iter 15
-train "data/reviewtxt" 表示在指定的语料库上训练模型
-cbow 1 表示用cbow模型,设成0表示用skip-gram模型
-size 100 词向量的维度为100
-window 8 训练窗口的大小为8 即考虑一个单词的前八个和后八个单词
-negative 25 -hs 0 是使用negative sample还是HS算法
-sample 1e-4 采用阈值
-threads 20 线程数
-binary 1 输出model保存成2进制
-iter 15 迭代次数
在训练完成后,就得到一个model,用该model可以查询每个词的词向量,在词和词之间求距离,将不同词放在数学公式中计算输出相关性的词。比如:
vector("法国") - vector("巴黎) + vector("英国") = vector("伦敦")"
对于训练不同的语料库,可以单独的训练词向量模型,可以利用已经训练好的模型。
其它训练词向量空间工具推荐:Glove。
Seq2Seq
2014年,Sequence to Sequence Learning with Neural Networks提出了使用深度学习技术,基于RNN和LSTM网络训练翻译系统,取得了突破,这一方法便应用在更广泛的领域,比如问答系统,图像字幕,语音识别,撰写诗词等。Seq2Seq完成了encoder + decoder -> target的映射,在上面的论文中,清晰的介绍了实现方式。
图 3-4 Seq2Seq, Ref #1
也有很多文章解读它的原理。在使用Seq2Seq的过程中,虽然也研究了它的结构,但我还不认为能理解和解释它。下面谈两点感受:
a RNN保存了语言顺序的特点,这和CNN在处理带有形状的模型时如出一辙,就是数学模型的设计符合物理模型。
图 3-5 RNN, Ref #6
b LSTM Cell的复杂度对应了自然语言处理的复杂度。
图 3-6 LSTM, Ref #6
理由是,有人将LSTM Cell尝试了多种其它方案传递状态,结果也很好。
图 3-7 GRU, Ref #6
LSTM的一个替代方案:GRU。只要RNN的Cell足够复杂,它就能工作的很好。
使用DeepQA2训练语言模型
准备工作,下载项目:
git clone >
DeepQA2将工作分成三个过程:
数据预处理:从语料库到数据字典。
训练模型:从数据字典到语言模型。
提供服务:从语言模型到RESt API。
预处理
DeepQA2使用Cornell Movie Dialogs Corpus作为demo语料库。
原始数据就是movie_linestxt 和movie_conversationstxt。这两个文件的组织形式参考READMEtxt
deepqa2/dataset/preprocesserpy是将这两个文件处理成数据字典的模块。
train_max_length_enco就是问题的长度,train_max_length_deco就是答案的长度。在语料库中,大于该长度的部分会被截断。
程序运行后,会生成dataset-cornell-20pkl文件,它加载到python中是一个字典:
word2id存储了{word: id},其中word是一个单词,id是int数字,代表这个单词的id。
id2word存储了{id: word}。
trainingSamples存储了问答的对话对。
比如 [[[1,2,3],[4,5,6]], [[7,8,9], [10, 11, 12]]]
1,2,3 12 都是word id。
[1,2,3] 和 [4,5,6] 构成一个问答。 [7,8,9] 和 [10, 11, 12] 构成一个问答。
开始训练
cp configsampleini configini # modify keys
python deepqa2/trainpy
configini是配置文件, 根据configsampleini进行修改。训练的时间由epoch,learning rate, maxlength和对话对的数量而定。
deepqa2/trainpy大约100行,完成数据字典加载、初始化tensorflow的session,saver,writer、初始化神经元模型、根据epoch进行迭代,保存模型到磁盘。
session是网络图,由placeholder, variable, cell, layer, output 组成。
saver是保存model的,也可以用来恢复model。model就是实例化variable的session。
writer是查看loss fn或者其他开发者感兴趣的数据的收集器。writer的结果会被saver保存,然后使用tensorboard查看。
Model
Model的构建要考虑输入,状态,softmax,输出。
定义损耗函数,使用AdamOptimizer进行迭代。
最后,参考一下训练的loop部分。
每次训练,model会被存储在 save路径下,文件夹的命名根据机器的hostname,时间戳生成。
提供服务
在TensorFlow中,提供了标准的serving模块 - tensorflow serving。但研究了很久,还专门看了一遍 《C++ Essentials》,还没有将它搞定,社区也普遍抱怨tensorflow serving不好学,不好用。训练结束后,使用下面的脚本启动服务,DeepQA2的serve部分还是调用TensorFlow的python api。
cd DeepQA2/save/deeplearningcobravulcan20170127175256/deepqa2/serve
cp dbsamplesqlite3 dbsqlite3
python managepy runserver 0000:8000
测试
POST /api/v1/question >
serve的核心代码在serve/api/chatbotmanagerpy中。
使用脚本
scripts/start_trainingsh 启动训练
scripts/start_tensorboardsh 启动Tensorboard
scripts/start_servingsh 启动服务
对模型的评价
目前代码具有很高的维护性,这也是从DeepQA项目进行重构的原因,更清晰的数据预处理、训练和服务。有新的变更可以添加到deepqa2/models中,然后在trainpy和chatbotmanagerpy变更一下。
有待改进的地方
a 新建models/rnn2py, 使用dropout。目前DeepQA中已经使用了Drop
b tensorflow rc012x中已经提供了seq2seq network,可以更新成tf版本
c 融合训练,目前model只有一个库,应该是设计一个新的模型,支持一个大库和小库,不同权重进行,就如Mechanism-Aware Neural Machine for Dialogue Response Generation的介绍。
d 代码支持多机多GPU运行。
e 目前训练的结果都是QA对,对于一个问题,可以有多个答案。
f 目前没有一个方法进行accuracy测试,一个思路是在训练中就提供干扰项,因为当前只有正确的答案,如果提供错误的答案(而且越多越好),就可以使用recall_at_k方法进行测试。
机器人家上了解到的,希望对你有用
1、可视化特征图:在卷积层中,每个过滤器都会产生一个特定的特征图。通过对这些特征图进行可视化,可以直观地了解网络提取到的特征。可以使用相应的可视化工具如TensorBoard等。
2、特征重要性分析:可以使用一些特征重要性分析方法,比如PermutationImportance、ShapleyValue等。通过这些方法,可以得到不同EEG特征在分类或者回归任务中的重要性。
3、直接查看卷积核:卷积层的过滤器(也叫卷积核)决定了网络如何对输入数据进行处理。在图像处理中,可以将卷积核可视化为图像,但是在EEG处理中没有类似的方法。不过,可以通过查看不同卷积核的大小和形状以及它们响应的脑区域来推断它们所提取的特征。在训练机器学习模型时,经常需要缓存模型。 ModelCheckpoint 是Pytorch Lightning中的一个Callback,它就是用于模型缓存的。它会监视某个指标,每次指标达到最好的时候,它就缓存当前模型。 Pytorch Lightning文档 介绍了ModelCheckpoint的详细信息。
我们来看几个有趣的使用示例。
示例1 注意,我们把epoch和val_loss信息也加入了模型名称。
示例2 这个使用例子非常像示例1,唯一的差别在于指标的名称是由我们自己指定的,而不是由Pytorch Lightning自动生成的 ( auto_insert_metric_name=False )。通过这样的方式,我们可以使用类似 val/mrr 的指标名。从而统一tensorboard和pytorch lightning对指标的不同描述方式。
Pytorch Lightning把ModelCheckpoint当作最后一个CallBack,也就是它总是在最后执行。这一点在我看来很别扭。如果你在训练过程中想获得best_model_score或者best_model_path,它对应的是上一次模型缓存的结果,而并不是最新的模型缓存结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)