Tensorflow-3-使用RNN生成中文小说

这篇文章不涉及RNN的基本原理,只是从选择数据集开始,到最后生成文本,展示一个RNN使用实例的过程。 对于深度学习的应用者,最应该关注的除了算法和模型,还应该关注如何预处理好自己的数据,合理降噪,以及如何在数据量不同的情况下选择合理的超参,来达到最理想的训练结果。 在经过近三个月的学习之后,我打算使用Tensorflow,创建一个LSTM RNN模型,使用中文小说作为数据源,训练RNN来生成中文小说文本。平时做练习训练数据都是英文,我想看看换成中文之后会是什么结果,能不能写出一些语义通顺的句子。 数据选取的是起点中文网的获奖历史小说『寒门首辅』,作者一袖乾坤。 整个notebook在我的github上,感兴趣的同学可以下载使用,不断尝试训练自己喜欢的风格的小说生成器。强烈建议大家使用notebook进行尝试,可以实时看到每一步的输出,学习效果更好。 以下就是整个应用过程。 来试试用起点中文网的历史小说『寒门首辅(一袖乾坤 著)』来做训练数据,看看这个RNN网络能产生一些什么样子的文本。 尝试过程中必遇到问题,也借此加深一些对RNN的理解。 首先我从网上下载到了『寒门首辅』的txt版本,打开时候发现有很多空行,还包含了很多不必要的链接,看起来是这样的。 预处理一下数据。 读入数据 设置一下要用多少个字来训练,方便调试。这里先用100000字进行训练 看看有多少行 先看看前15行是什么内容 把『章节目录』之前的行全部砍掉,一大堆没用的东西。 再来看看,第一行应该就进入正题了。 我查看了一下,这个小说一共有129万字左右。先把空行去掉吧。去掉空行之后应该就只有一半左右的行数了。 打印前20行看看什么情况 下一步,把每行里面的『空格』,『[]里的内容』,『<>里的内容』都去掉。 看下情况如何,打印前20句话。 可以看到空格都没了。下一步用正则去掉『[]』和『<>』中的内容,像上面的什么『[棉花糖小说网]』这些的,后面还有一些是包含在『<>』里的,一并去掉。 打印看效果 『[]』的内容已经没了。下一步去掉『<>』中的内容,方法同上。 下一步,把每句话最后的『……』换成『。』。 打印看效果 最后,还是把每句话里面包含的空格,都转换成『,』,就像『章节目录 第一章』,换成『章节目录,第一章』,感觉这一步可有可无了。 貌似还忘了一个要处理的,我们看看最后20行的情况。(如果你是用全文本来训练,最后很多行文本中会包括\r这样的特殊符号,要去掉。这里只用了100000字,所以看不到有\r的情况。)。如果有\\r的情况,用下面的方式去掉。 到这里数据就处理完了。再看看有多少行数据 因为模型只认识数字,不认识中文,所以将文字对应到数字,分别创建文字对应数字和数字对应文字的两个字典 创建一个符号查询表,把逗号,句号等符号与一个标志一一对应,用于将『我。』和『我』这样的类似情况区分开来,排除标点符号的影响。 预处理一下数据,并保存到磁盘,一遍下次直接读取。 读取我们需要的数据。 检查改一下当前Tensorflow的版本以及是否有GPU可以使用 这里的数据量还是很大的,129万左右个字符。建议使用GPU来训练。或者可以修改代码,只用一小部分数据来训练,节省时间。 正式进入创建RNN的阶段了。 我们的RNN不是原始RNN了,中间使用到LSTM和word2vec的功能。下面将基于Tensorflow,创建一个带2层LSTM层的RNN网络来进行训练。 首先设置一下超参。 创建输入,目标以及学习率的placeholder 创建rnn cell,使用lstm cell,并创建相应层数的lstm层,应用dropout,以及初始化lstm层状态。 创建embedding layer,提升效率 创建rnn节点,使用dynamic_rnn方法计算出output和final_state 用上面定义的方法创建rnn网络,并接入最后一层fully_connected layer计算rnn的logits 那么大的数据量不可能一次性都塞到模型里训练,所以用get_batches方法一次使用一部分数据来训练 创建整个RNN网络模型 开始训练模型 将使用到的变量保存起来,以便下次直接读取。 下次使用训练好的模型,从这里开始就好 要使用保存的模型,我们要讲保存下来的变量(tensor)通过指定的name获取到…

CategoriesML

Tensorflow-2-Tensorboard使用

一、概述 机器学习如此复杂,训练模型的时候,摸不清背后到底是如何运行的。自己设置的参数和关键变量,如果能看到在训练时的变化情况,可以为后面的参数调优阶段提供很大的便利。 Tensorboard就是这样一个工具。 它刻意将模型抽象成图像,tensor每一步是如何流动的,一目了然。 通过适当的代码设置,还能将指定的关键变量在训练时的变化情况绘制成曲线图,以便训练完成后观察变量的变化情况,来更加准确定位问题。 这篇文章简单介绍一下tensorboard的基本用法。 二、Tensorboard使用 tensorboard(以下简称tb)的操作,从创建一个FileWriter开始。 在接下来的代码中,我参照CS231N课程的数据集例子,用tensorflow(以下简称tf)写了一个Logistic Regression,并以此来说明tb的基本用法。 用到的notebook在我的github上可以找到。使用之前,请确保执行 来创建和我一样的运行环境。如有问题,可以留言或者ISSUE。 创建好环境之后,运行 激活conda环境,然后运行 来使用本例中的notebook。 下面的示例程序用tf做了一个两层的分类网络。将下图中的数据集分类。 最终分类效果是这样的。 tb的使用,大致归纳为三步: 调用tf中的FileWriter将自己关注的数据写到磁盘 在命令行使用tensorboard –logdir /path/to/log启动tb的web app 然后在本地浏览器输入localhost:6006来使用tb 下面具体看一下怎么使用。 1.生成模型图 生成模型图只需要一句话就行。比如说,现在已经初始化好了变量,处理好了数据,部分代码如下: 准备开始训练的时候,加上一句 例如,在session开始的时候添加就好。 我们要看整个模型的图像,因此传入session.graph对象。 这时,来到命令行,切换到notebook所在的目录,然后执行 logs/summary就是代码中定义的目录路径。tb启动后会提示到浏览器用localhost:6006去打开tb应用。 在浏览器打开后,切换到GRAPH标签,看到的模型图时这样的。 这个时候其他标签还没有内容,因为还没有在代码中进行添加。 上面的图片,就是现在这个模型的原始图像,没有进行任何分组和加工。看起来很乱,有一些标签,例如slice什么的,都不知道是什么意思。 图中, 每条曲线代表tensor的流向 每个椭圆代表一个操作,如add,matmul 每个圆角矩形代表一组操作,可以双击放大,看到这个组里面的细节 整张图片可以放大缩小,随意拖动;点开每个节点,右上角都会有这个节点的详细信息 下面来加工一下,为模型图分组,让图像更加清晰有条理。 2.使用name_scope分组 调用tf.name_scope()方法来为graph分组。 我想清楚看到 输入Inputs 标签Targets 两组Weight和bias变量 两个隐藏层的输出Logits_1和Logits_2 损失函数loss 训练准确率Accuracy以及 整个训练过程Train 示例代码如下。 输入Inputs 标签Targets 两组Weight和bias变量…

CategoriesML

Tensorflow-1-Tensorflow Moblie Android平台编译安装

之前就看到Tensorflow有手机平台的API了,今天终于抽了点时间出来鼓捣一下。 首先是把tensorflow克隆到本地一份。 既然是谷歌官方要求的,最好把–recurse-submodules加上,文档说可以避免一些数据结构序列化时的编译问题。 这是android demo的github主页。 准备编译 1.安装bazel bazel是谷歌自己的构建工具。tensorflow只能部分支持cmake或者gradle,而bazel是tensorflow工程的主要构建工具。 点这里下载Bazel。 Mac和Linux用户根据文档进行安装。Windows用户,按照官方建议到下面的链接下载demo的二apk文件,目前bazel在windows平台还处于试验阶段。 Windows用户点这里直接下载apk bazel安装成功与否,用bazel version检查版本即可。 2.下载NDK 点这里下载最新版本NDK。 最好下载r12b版本的,最新的r13b可能与bazel有兼容问题。 下载完成后解压到自定义目录,然后在~/.bash_profile(linux在~/.bashrc)下添加环境变量。环境变量的添加过程大家百度一下吧,不是这里的重点。 3.下载>=23 Android SDK Tensorflow Android Demo必须在大于等于23的API环境中编译。可以打开Android Studio中的SDK Manager来安装最新的SDK。 4. 编辑Tensorflow根目录下的WORKSPACE文件 回到tensorflow根目录,(当前在android目录就往上两级)。打开WORKSPACE文件。 在文件开头部分找到 这两部分定义了SDK和NDK的路径,把/path/to/your的部分改成系统相应的路径。然后将每一行前的注释去掉。如下: 开始编译 在tansorflow根目录执行, 进行编译,变异过程如下: 一切顺利的话,编译成功,如下图: 安装APK DEMO 变异成功之后bazel会在bazel-bin目录下面生成apk文件。用数据线连上手机,执行 即可安装到手机。 DEMO截图 TF Classify 图片分类的Demo。可以看到tf识别出了台式电脑和显示器。 TF Stylize 这个Demo很好玩,不只是将一张图片的风格渲染到摄像头,还能通过调节来综合两张图片的风格。 点击左上角的数字按钮,可以从128一直选到720。刚开始以为这个数值跟训练过程中的神经元数量有关。后来想想这些模型应该都是训练好了的,移动平台还没有能力进行这样的训练。看源码得知这个就是最终呈现的图片的尺寸,越高图片越清晰。但是相应的,对手机性能的要求就越高。我在魅族pro 6 plus上测试,选择256之后,就开始卡顿的厉害,720的话,定在一个点上大概5-7秒才能看到渲染之后的图像。 总结 市面上已经有很多运用深度学习的应用的例子。但是大多数都是只能让用户使用已经训练好的模型,而无法让用户自定义。比如我想用我自己喜欢的两张图片作为风格,来渲染视频,而不是图库中已有的。受限于移动平台自身的计算能力,目前还做不到;而把计算放到云端,用户体验又太差(prizma网络不好的时候要等很久,还可能失败…)。 期待用量子计算机来做深度计算哈哈哈~

CS231N-Lecture6 Training Neural Network part-2

一、概述 这一集讲了一些列不同的梯度下降算法,做了一些比较。 之后,讲到了Dropout机制,随机关闭一些neuron的训练方式可以使整个模型更加有效。 然后讲到了一点关于Model Ensemble的技巧。 最后,做了一个Convnet的引入,介绍了Convnet的历史起源,以及后人的一些成就。 二、梯度下降算法 SGD SGD(Stochastic Gradient Descent)就是之前一直在用的这种更新Weight的方式。如图。 现实当中,sgd是最慢的下降算法。先来看看问题所在。如图。 假设loss function映射成是一个垂直面上很深,但是水平面上很浅的地形。这样说好抽象,就想象成一个V字形好了。现在我就在这个V字的左半坡上。假设我往下走一步的话,我在垂直方向上下降的距离,会大于我在水平方向上前进的距离。又因为我因此,sgd会造成如下的问题,我在下降的过程中走很多的弯路,上下上下不断调整。如下图。 而每次在水平方向上前进的距离越大,我就能越快到达那个笑脸,也就是loss最低点。sgd的前进路线浪费了很多时间。 Momentum Momentum的方法,借用了物理中的加速度的概念。把整个loss function想象成一个碗,一个球从一侧滑落,朝最底部的会有一个加速度和摩擦力的累加。因此,当这个球找到一个下降的方向时,速度就会累加,并越来越快。如图。 上图中,learning_rate * dx就是标准的sgd,是一个下降的速度,mu * v就相当于摩擦力。因为速度不能一直累加。如果一直累加,球根本停不下来,会over shot偏离目标。 v就是要一直累加的下降加速度,用v去更新W。 mu通常设置成0.5 – 0.9之间的数值。 v通常初始化成0。 Nesterov Momentum 下图是一个普通的momentum下降。 gradient step就是learning_rate * dx;momentum step就是v;因此最终这次下降的值就是两个向量和actual step。 nesterov momentum就是在momentum的基础上,多想一步,在momentum step的尽头,考虑下一步该怎么走。如下图。 公式上唯一的区别就是在计算dx的时候要计算d(x + mu * vt-1)。因此要有一个变量保留一下上一次的速率。如下图。 将 替换成 然后进行代数运算就可以得到最后的下降公式 nag(Nesterov Accelerated Gradient)通常比momentum表现好一些。 AdaGrad adagrad所做的就是将历史的gradient平方都累加起来,然后在update的阶段,按照比例来缩放一下。 这样做就好像我记录下来之前所有走过的方向,然后综合一下,往某一个方向走一步。从代码看,我走的每一步距离都是在减小的。因此adagrad也有一个问题。…

CategoriesML

CS231N-Lecture5 Training Neural Network

一、概述 这一集讲了选择合适的activation function。 预处理数据。 Weight的初始化。 Batch Normalization的运用。 如何监督整个学习过程以便提早发现问题。 以及如何优化hyper parameter。 二、Neural Networks 讲激活函数之前讲了很多关于神经网络的历史。体会最深的就是,一个事物的兴起,不是自身力量就足够的。如果没有摩尔定律,没有大数据,神经网络的发展还不会被提上时代的议程。 激活函数,用来在线性的输入之后产生非线性的输出。非线性代表着解决更加复杂问题的能力。虽然说线性也能解决高复杂度问题,比如素描中画足够多的直线是可以在中间截出一个圆。但是远不如用非线性函数来得快和准确,并且其复杂性也让实践变得很难。 下图是一些激活函数。 Sigmoid 历史上,使用最多的是Sigmoid。它接收一个实数,然后产生一个[0, 1]的输出。 历史上使用最多,因为Sigmoid function可以用来表示一个neuron是否被激活这样的的概念。 但是Sigmoid有三个问题: 第一个问题,饱和的neuron会杀死backpropagation过程中的gradient。这个问题被称作vanishing gradient problem。 上图中,解释了vanishing gradient problem。 当x = 10和x = -10的时候,就是一个sigmoid就产生了一个saturated neuron(饱和神经元)。这个neuron的值接近0,或者接近1。如上图,在x = 10和x = -10的地方,y基本上是0和1。 Sigmoid function的导数是sigmoid * (1 – sigmoid)。 想象一下,sigmoid无限接近于1的时候,dsigmoid = ->1 * (1 – ->1) = -> 0(用->表示极限了…)。 另外,sigmoid无限接近于0的时候,dsigmoid =…

CategoriesML

CS231N-Lecture4 Backpropagation&Neural Network

一、概述 上一集结束之后,学到了score function,可以用SVM或者Softmax计算loss,可以在loss中增加regularization来获取更加合理的W,并且最后可以用Analytic Gradient(微积分)的方式计算loss function相对于W的gradient来更新W。如下图。 这一集讲了如何使用链式法则来反向传播gradients,来更新W和b,这个gradients反向传播的过程叫做Backpropagation。 Backpropagation之后,进入了Neural Network的介绍。 二、Backpropagation Computational Graph 在计算gradient并进行backpropagate(bp)的时候,借助computational graphs(cg)可以让整个过程更加清晰(对于新手来说更是这样)。在学习的起步阶段,可以借助它来理解bp的原理。但是当神经网络复杂了之后,再转换成cg看起来就很头疼了。就像这样。 tensorboard是cg可视化的一个很强大的工具。 一个computational graph是对整个神经网络的直观图形表述。 上图中,每一个矩形代表着input x和W;每一个圆代表着一个操作;箭头指明了元素在这个神经网络中的流向,从输入开始,一直到最终的loss输出。 其中,圆被称为一个门gate。数据每流经一个门,都会经过相应的数学变换。 bp如何实现 上图已经完成了forward pass的过程,输入从左到右,经过+,*,得到结果f。 上图中有三个输入,x,y,z;一个+ gate q;一个* gate f;最后得到输出f = 12。 红色框中,是+这个操作相对于x,y的求导; 蓝色框中,是*这个操作相对于+,z的求导; bp的过程,就是将运算顺序倒过来,从cg的最右端开始,利用链式法则(Chain Rule),依次将所有前面已经计算的到的导数,和当前元素的导数相乘,就是当前元素的gradient。 从最右端开始,f相对于自身的导数是1。如下图: 继续往左运算,遇到了* gate;这个门的算式就是f = qz,蓝色框中的算式。 要求出z的gradient,就是将之前已经计算出的gradient df / df = 1,与z本身的gradient相乘,即(df / df) * (df / dz)。 先求f相对于z的导数,df / dz = q;…

CategoriesML

CS231N-Lecture3 Loss Functions and Optimization

一、概述 在上一讲中,Andrej总结说在没有loss function的情况下,我们在用肉眼观察哪些分数是好的,哪些分数是坏的,如下图。 图中,cat的预测分数不是很好,2.9的分数比一些分数高,但是比deer,dog等的低;car的预测分数则很好,比所有其他分数都高;而frog的预测分数糟透了,比大部分的分数都要低。 这个lecture中讲的是用loss function来量化分数的好坏,并用optimizer来优化W和b,使loss最小化。 二、Loss Functions 下面介绍了两种loss function,SVM Cost和Softmax Cost(Cross-entropy cost)。 Multiclass SVM Cost 将所有不正确类型的分数和正确类型的分数的差 + 1之后的值,和0取最大值,最后将这些最大值相加,就是SVM Cost。 1) SVM Cost如何计算 下图是三个示例,具体展示SVM Cost是如何计算的。 视频中对为什么+1作了一些解释,但是不是很明白。还需要体会一下。1可以理解为是一个安全阀值。由于W可以初始化成大一些或者小一些,这是随机的。因此最终的预测分数也可以或大或小,因为W的缘故。这个1可能也是为了增加随机性而加上去的。Andrej说,选择1而是任意的,也就是说,你可以+2,+100,都是可以的,但是不能是0,和负数,这个也还不是很明白,有待体会。但是可能就像learning rate一样,太大了模型就不能和训练数据拟合了。这个1也可以想象成可以调整的hyper parameter,虽然最后Andrej说了这个不是hyper parameter… 在真正使用中,loss的值应该是将三个类型的loss相加,然后取平均值。 在上图中,也就是说,这一组W和b,作用在input image上之后,通过SVM Cost得到了一个loss值,这个值是4.6。 问题:为什么不能让j = yi?(j,和yi是svm cost公式中的两个脚标,上面的图片中有)因为如果j = yi,sj – syi = 0,max之后得到1,那么最终的loss都会+1,增大了的loss的数值。问题:loss的最大最小值可以是多少?最大值是无穷大,最小值是0。问题:如果W在初始化的时候都是很小的值,那么所有类型的score都约等于0,在上图的情况下,loss是多少?loss是2;通用的公式是,第一次计算出来的loss应该是预测类型的个数 – 1。我们应该用这个规律来检查W初始化了之后,神经网络第一次的运行是否正确。在只有三个类型的例子中,如果初始化了之后,第一次计算得到的loss大致上在2左右,那么说明一切基本正常,至少没有很大问题;但是如果这个数值大大偏离了2,那就要检查一下网络中会有很大的问题。 Hinge Loss and Squared Hinge Loss 上图中,上一个公式被称作Hinge Loss,相应的,下面一个就是Squared Hinge Loss。这两个计算loss的方法可以被理解成是一个hyper…

CategoriesML

CS231N-Lecture2 Image Classification Pipline

图片分类概述 一、概述 这一课标题是Image Classification Pip-line,大概就是讲了图片分类的整个框架流程。看完之后确实对于卷积网络底层是如何对图片进行分类的有了再进一步的认识,感觉又清晰了一些。 点击这里下载CS231N的所有课件PDF 图片是如何被分类的 图片分类用人类语言来描述大致就是将一个图片,通过某种方式,映射到一个标签上的过程。 图片分类的挑战 1) 语义层面 计算机只认识0和1,如何让计算机认识每张图片并进行分类,首要的就是把图片变成数字。 对于人类来说这为理解增加了难度。每张非黑白图片都会被转化程一个长 x 高 x 深的矩阵;例如一张300 * 100像素的图片,会转换成一个300 x 100 x 3的矩阵,作为分类器的输入,然后进一步通过数学计算,完成分类。 例子中的深度3表示表示彩色图片的色彩通道RGB。 2) 图片的明暗 这张图片中有两只猫,左边一只光线很暗,右边一只光线明亮。 必须让分类器对像素的敏感程度做出相应理想的反应,才能完成图中两只猫的识别。 3) 物体的不同形态或姿势 图片里都是猫,但是姿势各异。需要调整分类器对不同的姿势做出理想的反应,并成功将图片分类为猫也是挑战之一。 4) 遮挡 对于人类来说,虽然被遮挡了,但是我们一眼可以确认图片里的是猫。对于分类器来说,这是一个巨大的挑战。 分类器需要要根据图片中仅有一些特征,做出正确的反应并分类图片。 5) 背景融合 背景颜色和猫咪的颜色相差无几,意味着每个像素的矩阵数值十分接近。分类器要成功从很相近的数值中分辨出图片中的猫同样是很艰巨的任务。 另外,对于其他生活中的实际例子来说,例如排序,我们可以写一个冒泡算法,但是对于图片分类这样抽象的问题,是没有固定的算法可言的。 我们需要用到分类器,以及之后会涉及的神经网络,卷积神经网络的支持,来完成这项任务。 二、分类方法 K—NN分类 NN分类器 NN(Nearest Neighbors)分类通过计算目标与训练数据的距离来确定目标属于哪个分类的算法。 NN中有两种计算距离的方式; 课程中用python构建了一个简单的NN分类器: 红框中的代码就是在计算目标点与每一个训练数据的距离,并将最近的距离设置到Ypred中保存; NN分类器的弊端在于,测试的时候,效率很低。因为要将目标图片的每一行数据,和训练数据的所有行进行对比来计算最小距离。复杂度是线性上升的。 但是在图片分类任务中,我们最关心的是测试(应用)阶段的效率。因此后面会说到,不会用NN分类器来分类图片,而会使用在测试阶段效率很高的卷积网络来执行分类任务。 K-NN分类 K-NN分类和NN分类有点不同,NN分类中需要将目标图片的数据和所有训练数据进行对比,而K-NN中,只需要和临近的K个数据进行对比。 上图中,的NN classifier(中间的图片),在蓝色区域的左下角,有一小块的绿色区域,里面又一个绿色的点。这片区域被标成了绿色,是因为如果有任意点落在那个绿色区域里面,这个绿色的点将会是离这个点最近的点,因此这个落下的点会被标记成绿色。 KNN…

CategoriesML

Tensorflow-0-带GPU支持的安装与校验

Tensorflow-0-带GPU支持的安装与校验 零. 回顾与概述 这篇文章详细介绍了Tensorflow的安装和校验安装是否成功的教程,涵盖了在Ubuntu 16.04环境下GPU支持安装和非GPU支持的安装以及校验。 系统概览: Ubuntu 16.04 64位 NVIDIA GTX 770M 内容概览: 根据NVIDIA官方文档安装CUDA-Toolkit 校验CUDA安装是否成功 根据Tensorflow官方文档安装Tensorflow(GPU支持) 校验Tensorflow安装是否成功 原版文档很长,这篇文章给使用Ubuntu的朋友们提供一下便利! 一. Tensorflow入门资源推荐 我的第一份Tensorflow入门,给大家介绍一下,是Youtube里周莫烦的Tensorflow基础教程,翻墙点击这里带你去看! 下面好评很多,很基础,现在20集的样子,大家可以订阅,并且希望他能持续更新。 二. Tensorflow安装 首先请翻墙; 点击进入Tensofrflow官网Linux安装页。进入页面之后就会看到安装选择,可以安装非GPU支持的TF(Tensorflow以下简称TF)和GPU支持的TF,我们这边选择安装GPU支持的TF; 检查系统软件硬件是否符合NVIDIA要求; 完整的安装前检查如下: 检查系统GPU是否处于CUDA支持列表 通过 lspci | grep -i nvidia 来查看系统GPU型号;如果没有输入,请先运行update-pciids,然后再次运行上一个命令; 并且到 CUDA支持的GPU列表 查看系统GPU是否处于支持列表; 检查当前Linux版本处于CUDA支持列表 通过 uname -m && cat /etc/*release 来查看Linux版本; CUDA-8支持的Linux版本 检查系统安装了gcc 通过 gcc –version 来查看系统是否安装gcc;如果报错,请安装相应的开发工具包; 检查系统是否安装内核头文件,以及必要的开发工具包; 通过…

CategoriesML