by SA16225335,吴倩
一 简介
2016年科大网络程序设计课程即将结束,笔者在这里写下人生的第一篇博客,来总结一下这门课程给我带来的启发和提升,并且作为人生的又一个起点开始生命的下一次征程。首先在这里要感谢孟宁老师的教导,孟宁老师在课程中一反常态,并没有使用传统的上课授课的方式,而是采用项目驱动的方法,由学生在老师的带动下主动开发,在这门课程中,班里70多个学生共同完成了这个项目。作为一个菜鸟,我必须惭愧的承认我对这个项目并没有什么直接的贡献,只在PPT知识共享时,对Theano框架的知识进行了共享。“林花谢了春红,太匆匆,无奈朝来寒雨晚来风”,时光总是匆匆,在这门课中,我完整的学习了python语法,理解了关于神经网络学习的原理,并且对CNN,RNN,深度学习框架及图像处理有了一定的了解。在这个寒假,我将继续学习神经网络的相关知识。坚持总会有结果,明年我会继续选修孟宁老师的高软课程,定跟上老师步伐。总之,感谢老师让我踏入新世界的大门。
二 什么是深度学习
Andrew Ng曾经说过“我们相信(神经网络代表的深度学习)是让我们获得最接近于人工智能的捷径”。这就是我们要学习深度学习的重要的原因。相对于网络上一提到神经网络就会提到的反向传播,激活函数,特征基向量,卷积神经网络,笔者在这里想用自己浅薄的知识来谈谈自己对神经网络的理解。
我在接触神经网络之前,曾看过一个关于对生物体大脑形象化的描述,人的大脑中有成千上亿的神经元细胞(甚至更多),它们都长着像电线一样的轴突,神经元在我们的大脑中构成一个网状结构,当人们对外部事件进响应时,神经元细胞会产生兴奋也就是化学信号顺着神经元的网状结构进行传播,最终产生人的各种反应。以上相应凡有高中学历的大家都了解整个过程,故而不进行详述。而进行深度学习的神经网络,就是根据大脑的反馈机构进行设计的。最简单的神经网络一般有三层,第一层是输入层,第二层是隐藏层,第三层是输出层,第一层输入数据后,隐藏层根据自己神经上的比重对输入层数据进行自己的处理,最后在第三层输出层进行输出。我们把神经网络假设为一个小孩,在他的成长过程中,他将不断的接收到各种各样的信息,而神经网络也是如此,我们不断的用各种数据训练它,是他在隐藏层的每个分支都有不同的权重,在训练过程中,权重不断的变化,当训练集达到一个数量时,会得到一个相对稳定的权重,这就如同大脑中的电信号传播一样,每个神经元都带着不同大小的神经信号,最后形成人的各种反应,而神经网络也是如此。我们不断的训练它,使它不断的纠正自己,最后实现预测功能。
三 关于Theano的学习
3.1 Theano定义
Theano是一个Python库,专门用于定义、优化、求值数学表达式,效率高,适用于多维数组。Theano是一个Python库,用于定义、优化、求值数学表达式,即简单来说,它就是一个代数符号系统。在数学表达式中的一个符号就是一个variable对象,对象之间用加减乘除等操作符连接起来,就变成一个图,成为graph.在将theano运用于神经网络时,就是将网络表示成一个巨大的公式。比如z=x+y这样的表达式,就会组成成下面的图。
代码编写如下:
import theano
from theano import tensor
# declare two symbolic floating-point scalars
a = tensor.dscalar()
b = tensor.dscalar()
# create a simple expression
c = a + b
# convert the expression into a callable object that takes (a,b)
# values as input and computes a value for c
f = theano.function([a,b], c)
# bind 1.5 to 'a', 2.5 to 'b', and evaluate 'c'
assert 4.0 == f(1.5, 2.5)
3.2 使用Theano的优势
1.使研究深度学习的各位们减少花在推导数和实现算法上的精力。
2. 紧密集成Numpy,在Theano的编译函数中使用numpy.ndarray
3.透明的使用Gpu,使得执行数据密集型的计算速度高达CPU的140倍
4.高效的符号分解---替你计算一个或多个输入函数的推导
5.速度和稳定性优化
6.动态生成C语言代码,计算表达式更快速
7.广泛的单元测试和自我验证,能检测和诊断许多类型的错误
8.让你轻松的编写Deep Learning模型,并提供运行在GPU上的选择,他使得构建学习模型更加容易
3.3 为什么使用Theano
1.深度学习最好使用一些库,比如Theano。主要是因为反向传播调整参数时,需要求导。链式求导本身没有难处。
但是深度学习的神经网络架构设计的比较复杂,层数又多(15层不是梦)。
在隐藏层多的神经网络中,推导公式不忍直视,人工求导显然不是明智的。
Theano提供了grad梯度函数,自动根据表达式求一阶导数,grad(cost,param),其中cost函数可以是一个超长超长的表达式。
param则可以是一个超大超大的数组或是矩阵。
显然,有了grad函数,我们可以专心设计正向传播的I/O,反向传播只要一个grad函数即可。省去了复杂的公式推导
2.使用Python组织逻辑,C编译执行,CUDA并行加速计算,是非常好的实验平台。
它的库源码中包含大量注释,并且提供深度学习的几个基本模型的代码实现文档。
每篇文档都采用paper的形式,集中了许多大牛的论文的精华、各种小trick,也给出了论文的具体引用,方便按图索骥。
CUDA(Compute Unified Device Architecture),显卡厂商NVidia推出的运算平台。 CUDA™是一种由NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题。 它包含了CUDA指令集架构(ISA)以及GPU内部的并行计算引擎。
3.4 原理介绍
在Theano中,每个可导运算都带有一个grad函数,对应于图中每一步单独的求导(边)。比如 theano.tensor.nnet.sigmoid :
def grad(self, inp, grads):
x, = inp
gz, = grads
y = scalar_sigmoid(x)
rval = gz * y * (1.0 - y)
assert rval.type.dtype.find('float') != -1
return [rval]
对所有可导运算使用链式法则,即在图中沿着边和节点传播,就求出了最后我们想要的导数。整个过程大抵如此,细节部分可以翻看一下这篇博客。http://colah.github.io/posts/2015-08-Backprop/
3.5 原理介绍
Theano基于Python的面向对象,所以它的神经网络也是基于面向对象的思路去写的。
【对象】
它认为,浅层网络的中分类器,深度网络中的每个层,都是一个对象。
在这个对象里,你被指定了输入格式,你只需要做两件事:
根据格式,定义参数、定义输出。
【数据读入/处理】
从文件读入数据,并且对数据进行全局分享处理(shared)
theano.tensor中封装的着大量的惰性函数。这些惰性函数,在Python里是不会执行的。需要在theano.function()里执行。
【主过程:前向传播构建&反向传播迭代】
创建各个神经网络层、分类器的实例对象,由I/O首尾相连,最后利用分类器构建cost函数,完成前向传播。
利用各个层对象的参数、cost函数,构建梯度表达式,以及updates列表。
为训练集、验证集、测试集创建以theano.function()为壳的模型。
使用mini-batch梯度法分批训练训练集,测试验
3.6 编程基础
theano.tensor常用数据类型
学习theano,首先要学的就是theano.tensor使用,其是基础数据结构,功能类似于Python.numpy,教程网站为:http://deeplearning.Net/software/theano/library/tensor/basic.html
在theano.tensor数据类型中,有double、int、uchar、float等各种类型,不过我们最常用到的是int和float类型,float是因为GPU一般是float32类型,所以在编写程序的时候,我们很少用到double,常用的数据类型如下:
数值:iscalar(int类型的变量)、fscalar(float类型的变量)
一维向量:ivector(int 类型的向量)、fvector(float类型的向量)、
二维矩阵:fmatrix(float类型矩阵)、imatrix(int类型的矩阵)
三维float类型矩阵:ftensor3
四维float类型矩阵:ftensor4
其它类型只要把首字母变一下就可以了,更多类型请参考:http://deeplearning.net/software/theano/library/tensor/basic.html#theano.tensor.TensorV
3.7 编程实例
实例1:
import theano
x=theano.tensor.iscalar('x')#声明一个int类型的变量x
y=theano.tensor.pow(x,3)#定义y=x^3
f=theano.function([x],y)#定义函数的自变量为x(输入),因变量为y(输出)
print f(2)#计算当x=2的时候,函数f(x)的值
print f(4)#计算当x=4时,函数f(x)=x^3的值
实例2:
import theano
x =theano.tensor.fscalar('x')#定义一个float类型的变量x
y= 1 / (1 + theano.tensor.exp(-x))#定义变量y
f= theano.function([x],y)#定义函数f,输入为x,输出为y
print f(3)#计算当x=3的时候,y的值
例3:function使用示例
我们再看一个多个自变量、同时又有多个因变量的函数定义例子:
import theano
x, y =theano.tensor.fscalars('x', 'y')
z1= x + y
z2=x*y
f =theano.function([x,y],[z1,z2])#定义x、y为自变量,z1、z2为函数返回值(因变量)
print f(2,3)#返回当x=2,y=3的时候,函数f的因变量z1,z2的值 为x,输出为y
print f(3)#计算当x=3的时候,y的值
3.8 学习深度学习必须要学习的几个函数
例1、求偏导数
theano有个很好用的函数,就是求函数的偏导数theano.grad(),比如上面的S函数,我们要求当x=3的时候,s函数的导数,代码如下:
import theano
x =theano.tensor.fscalar('x')#定义一个float类型的变量x
y= 1 / (1 + theano.tensor.exp(-x))#定义变量y
dx=theano.grad(y,x)#偏导数函数
f= theano.function([x],dx)#定义函数f,输入为x,输出为s函数的偏导数
print f(3)#计算当x=3的时候,函数y的偏导数
例2、共享变量
共享变量是多线程编程中的一个名词,故名思议就是各线程,公共拥有的变量,这个是为了多线程高效计算、访问而使用的变量。因为深度学习中,我们整个计算过程基本上是多线程计算的,于是就需要用到共享变量。在程序中,我们一般把神经网络的参数W、b等定义为共享变量,因为网络的参数,基本上是每个线程都需要访问的。
import theano
import numpy
A=numpy.random.randn(3,4);#随机生成一个矩阵
x = theano.shared(A)#从A,创建共享变量x
print x.get_value()
通过get_value()、set_value()可以查看、设置共享变量的数值
例3、共享变量参数更新
前面我们提到theano.function函数,有个非常重要的参数updates,updates是一个包含两个元素的列表或tuple,updates=[old_w,new_w],当函数被调用的时候,这个会用new_w替换old_w,具体看一下下面例子:
import theano
w= theano.shared(1)#定义一个共享变量w,其初始值为1
x=theano.tensor.iscalar('x')
f=theano.function([x], w, updates=[[w, w+x]])#定义函数自变量为x,因变量为w,当函数执行完毕后,更新参数w=w+x
print f(3)#函数输出为w
print w.get_value()#这个时候可以看到w=w+x为4
这个主要用于梯度下降的时候,要用到。比如updates=[w,w-α*(dT/dw)],其中dT/dw就是我们梯度下降的时候,损失函数对参数w的偏导数,α是学习率。
3.9 应用方向
逻辑回归,三层神经网络,卷积神经网络等
四 项目简介
4.1 项目地址
coding.net:https://coding.net/u/sharon12/p/np2016-1765866307/git/tree/master
4.2 项目概述
4.2.1 项目功能
输入血常规图片,程序通过处理图片上的数据,进行性别和年龄的预测。(暂只能处理独墅湖高教区的体检单)
4.2.2 具体流程
输入图片->图片OCR识别->将识别出来的数值存入MongoDB->根据机器学习方法生成模型并进行预测
4.2.3 项目概要
该项目主要分为三个部分。第一部分是web端图片的导入和结果的显示;第二部分是OCR识别模块,用来进行图片的处理并将处理数据存储进mongodb;第三部分是学习预测模块,用来进行性别和年龄的预测。
4.3 运行环境
安装前置依赖
# 安装 Python 发布版本,dev包必须安装,很多用pip安装包都需要编译
sudo apt-get install python2.7 python2.7-dev python3.2 python3.2-dev
# 很多pip安装的包都需要libssl和libevent编译环境
sudo apt-get install build-essential libssl-dev libevent-dev libjpeg-dev libxml2-dev libxslt-dev
安装python模块
PS: 装python模块时最好每一步进入python命令行尝试import是否成功
# 安装pip
sudo apt-get install python-pip
# 安装numpy,
sudo apt-get install python-numpy # http://www.numpy.org/
# 安装opencv
sudo apt-get install python-opencv # http://opencv.org/
#装完后需要更新环境变量
vim /etc/bash.bashrc
#在文件末尾添加两行代码
export PYTHONPATH=$PYTHONPATH:/usr/local/lib/python2.7/dist-packages
export PYTHONPATH="${PYTHONPATH+${PYTHONPATH}:}/usr/local/lib/python2.7/site-packages"
##安装OCR和预处理相关依赖
sudo apt-get install tesseract-ocr
sudo pip install pytesseract
sudo apt-get install python-tk
sudo pip install pillow
# 安装Flask框架、mongo
sudo pip install Flask
sudo apt-get install mongodb # 如果找不到可以先sudo apt-get update
sudo service mongodb started
sudo pip install pymongo
如果import cv2报no module name cv2。需要从源码编译opencv安装,教程地址如下:OPENCV2.4.9源码安装
安装tensorflow
pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.12.0rc0-cp27-none-linux_x86_64.whl
运行demo
cd BloodTestReportOCR
python view.py # upload图像,在浏览器打开http://yourip:8080
4.4 部分文件功能简介
view.py
Web 端上传图片到服务器,存入mongodb并获取oid
imageFilter.py
对图像透视裁剪和OCR进行了简单的封装,以便于模块间的交互,规定适当的接口
imageFilter = ImageFilter() # 可以传入一个opencv格式打开的图片
num = 22
print imageFilter.ocr(num)
ocr函数 - 模块主函数返回识别数据
用于对img进行ocr识别,他会先进行剪切,之后进一步做ocr识别,返回一个json对象 如果剪切失败,则返回None @num 规定剪切项目数
perspect函数做 - 初步的矫正图片
用于透视image,他会缓存一个透视后的opencv numpy矩阵,并返回该矩阵 透视失败,则会返回None,并打印不是报告 @param 透视参数
关于param
参数的形式为[p1, p2, p3 ,p4 ,p5]。 p1,p2,p3,p4,p5都是整型,其中p1必须是奇数。
p1是高斯模糊的参数,p2和p3是canny边缘检测的高低阈值,p4和p5是和筛选有关的乘数。
如果化验报告单放在桌子上时,有的边缘会稍微翘起,产生比较明显的阴影,这种阴影有可能被识别出来,导致定位失败。 解决的方法是调整p2和p3,来将阴影线筛选掉。但是如果将p2和p3调的比较高,就会导致其他图里的黑线也被筛选掉了。 参数的选择是一个问题。 前列们在getinfo.default中设置的是一个较低的阈值,p2=70,p3=30,这个阈值不会屏蔽阴影线。 如果改为p2=70,p3=50则可以屏蔽,但是会导致其他图片识别困难。
就现在来看,得到较好结果的前提主要有三个
化验单尽量平整
图片中应该包含全部的三条黑线
图片尽量不要包含化验单的边缘,如果有的话,请尽量避开有阴影的边缘。
filter函数 - 过滤掉不合格的或非报告图片
返回img经过透视过后的PIL格式的Image对象,如果缓存中有PerspectivImg则直接使用,没有先进行透视 过滤失败则返回None @param filter参数
autocut函数 - 将图片中性别、年龄、日期和各项目名称数据分别剪切出来
用于剪切ImageFilter中的img成员,剪切之后临时图片保存在out_path, 如果剪切失败,返回-1,成功返回0 @num 剪切项目数 @param 剪切参数
剪切出来的图片在BloodTestReportOCR/temp_pics/ 文件夹下
函数输出为data0.jpg,data1.jpg……等一系列图片,分别是白细胞计数,中性粒细胞记数等的数值的图片。
classifier.py
用于判定裁剪矫正后的报告和裁剪出检测项目的编号
imgproc.py
将识别的图像进行处理二值化等操作,提高识别率 包括对中文和数字的处理
digits
将该文件替换Tesseract-OCR\tessdata\configs中的digits
4.5 实验结果
首先在终端输入view.py,在后台会展示index.html页面,在页面选择文件上传并点击提交,后台会调用imageFilter.py中的ocr,对图像进行灰度化,裁剪和OCR识别,并将图片和识别出来的数据存入数据库并在页面进行展示
然后点击生成报告,这次程序中根据fid将数据从mongodb数据库中读出数据,并在页面上进行展示,读取不准确的地方可以修改。
最后,我们调用已经训练好的神经网络,将数据输入进去进行预测,以下是预测结果。
由于笔者并没有直接参与实验代码的编写,故这里只叙述了关于整个实验的主要文件的用途和运行的详细过程,并对自己分享的Theano框架进行了详细的介绍。若想要了解更多关于本次实验更细致的事情,请参考以下链接:
1.http://blog.csdn.net/u014659656/article/details/53887507#课程心得体会
2.http://rp38.cn/2016/12/25/np2016/
在那里,你会得到关于更多实验详尽的描述。
五 个人心得
自从来到科大后,才感觉到大神林立,然而自己对时间的利用却并不充分。这门课中,也是仅仅能够跟上项目更新的步伐。在接下来的日子里,会继续对不足的知识点进行学习,更加深入的理解神经网络和深度学习的知识,做更多关于这一方面的研究。
六 学习链接
2.theano文档