的底层语言,你会用 C++ 构建深度神经网络算法 python吗

看了这个排行榜,达妹只想说:流水的编程语言,铁打的Java,C/C++!!

人工智能的前景已经不用多说了,越来越多的人看重人工智能的前景,想要在这互联网的风口有一番作为。要做到这点,首先要确定进入人工智能行业,该学习哪门语言!

Rankred 网站发布了该网站评出的2017年7大最佳的人工智能编程语言——Python第一!

近来,尤其是在机器人领域,Python 已经有了翻天覆地的变化。其中一个原因是Python(和 C ++)是 ROS 中的两种主要编程语言。

如同 Java 一样,它也是一种解释性语言。但与 Java 不同的是,Python 的重点是易用性。Python 不需要很多时间来做常规的事情,如定义和强制转换变量类型。这些在编程里面本是很平常的事。另外,Python 还有大量的免费库,这意味着当你需要实现一些基本的功能时不必“重新发明轮子”。而且由于它与 C / C ++ 代码之间可以进行简单的绑定,这就意味着代码繁重部分的性能可以植入这些语言,从而避免性能损失。

随着越来越多的电子产品开始支持“开箱即用”Python(与 RaspberryPi 一道),我们可能会在机器人中看到更多 Python。

很多人都认为 C / C ++ 对新的机器人科学家来说是一个良好的开端。

其主要原因是如今有大量的硬件库都使用这两种语言。它们适用于低级别的硬件,允许实时性能,是非常成熟的编程语言。现在,你可能会使用 C++ 远超过 C,因为 C++ 具有更大的实用性。C ++ 是 C 语言的扩展,从基础的 C 学起,你也会收获很多,特别是当你发现一个硬件库是用 C 编写的。但是 C / C ++ 编写的硬件库不像 Python 或 MATLAB 那样简单易用。使用 C 来执行类似的功能,可能需要相当长的时间,并且需要更多的代码行。尽管如此,由于机器人极其依赖实时性能,所以 C 和 C ++ 是最接近机器人科学家心目中“标准语言”的编程语言。

LISP 是世界上第二古老的编程语言(FORTRAN 更古老,但只差一年)。相比本文提到很多其它编程语言,它的应用并不广泛。不过在人工智能编程领域它还是相当重要的。ROS 的一部分是用 LISP 写的,虽然你不需要掌握这个来使用 ROS。

Java 对程序员“掩盖”底层存储功能,这使得 Java 对程序的要求要比 C 语言对程序的要求更低一些,但这意味着你对底层代码的运行逻辑了解比较少。从软件工程的基础到探索机器人技术的未来,你很可能已经学习了 Java。

像 C# 和 MATLAB 一样,Java 是一种解释性语言,这意味着它不会被编译成机器代码。相反,Java 虚拟机在运行时解释指令。使用 Java,理论上让你可以在不同的机器上运行相同的代码,这得感谢 Java 虚拟机。在实践中,这不总是可行的,有时会导致代码运行缓慢。但是 Java 在一部分机器人学中非常流行,因此你也许需要它。

Prolog是一种与计算语言和人工智能相关的逻辑编程语言和语义推理引擎。它具有灵活而且强大的框架,被广泛应用于定理证明,非数字编程,自然语言处理和AI。

Prolog 是一种具有形式逻辑的声明语言。AI开发者重视其预设计的搜索机制,非确定性,回溯机制,递归性质,高级抽象和模式匹配。

JavaScript 是一种高级、面向对象的直译语言,主要用于使网页交互和创建在线程序,包括游戏。

在JavaScript中,学习对话模型并不重要。学习服务器端的数据,然后通过Ajax调用学习者进行预测。 JavaScript有很多好用的库,我们总结其中3个:

ConventJS:实现深度学习的库——在浏览器中训练卷积神经网络。它支持完全连接的层以及非线性神经网络模块,分类和回归成本函数。

Synaptic:一个用于node.js.的神经网络库。 其通用算法是无架构的,可以用于开发和训练几乎所有类型的一阶和二阶神经网络架构。

Mind:它使用矩阵实现来处理训练数据。你可以完全自定义网络拓扑和上传/下载已学习的minds。

Haskell 是1990年开发的强静态类型,非限定性编程语言。由于Haskell开发人员不多,小公司很少尝试Haskell。

Haskell 做得很好的是抽象(抽象数学,而不是Java OOP)。它允许具有表达性的、高效的库表达AI算法。例如,HLearn使用常见的代数结构(模块,单群等)来表达和提高简单机器学习算法速度。

虽然你可以用任何语言编写这些算法,但Haskell相比其他语言更具表现力,同时保持不错的性能。例如,Haskell写的faster cover trees 。

本文由百家号作者上传并发布,百家号仅提供信息发布平台。文章仅代表作者个人观点,不代表百度立场。未经作者许可,不得转载。

前段时间写过一些关于OpenCV基础知识方面的系列文章,主要内容是面向OpenCV初学者,介绍OpenCV中一些常用的函数的接口和调用方法,相关的内容在OpenCV的手册里都有更详细的解释,当时自己也是边学边写,权当为一种笔记的形式,所以难免有浅尝辄止的感觉,现在回头看来,很多地方描述上都存在不足,以后有时间,我会重新考虑每一篇文章,让成长系列对基础操作的介绍更加详细一些。

OpenCV进阶之路相比于成长系列,不会有太多的基础函数的介绍,相对来说会更偏向于工程实践,通过解决实际问题来说明某些较高级函数的用法和注意事项,主要内容会集中在特征提取、机器学习和目标跟踪几个方向。所以这个系列文章知识点没有先后顺序之分,根据个人平时工作学习中遇到的问题而定。

这篇文章主要介绍OpenCV中神经网络的用法,并通过车牌字符的识别来说明一些参数设置,函数调用顺序等,而关于神经网络的原理在博客机器学习分类里已经详细的讲解与实现了,所以本文中就不多加说明。

车牌识别是计算机视觉在实际工程中一个非常成功的应用,虽然现在技术相对来说已经成熟,但是围绕着车牌定位、车牌二值化、车牌字符识别等方向,还是不时的有新的算法出现。通过学习车牌识别来提升自己在图像识别方面的工程经验是非常好的,因为它非常好的说明了计算机视觉的一般过程:

图像→预处理→图像分析→目标提取→目标识别

而整个车牌识别过程实际上相当于包含了两个上述过程:1,是车牌的识别;2,车牌字符的识别。

这篇文章其实主要是想介绍OpenCV中神经网络的用法,而不是介绍车牌识别技术。所以我们主要讨论的内容集中在车牌字符的识别上,关于定位、分割等不多加叙述叙述。

在深度学习(将特征提取作为训练的一部分)这个概念引入之前,一般在准备分类器进行识别之前都需要进行特征提取。因为一幅图像包含的内容太多,有些信息能区分差异性,而有些信息却代表了共性。所以我们要进行适当的特征提取把它们之间的差异性特征提取出来。

这里面我们计算二种简单的字符特征:梯度分布特征、灰度统计特征。这两个特征只是配合本篇文章来说明神经网络的普遍用法,实际中进行字符识别需要考虑的字符特征远远要比这复杂,还包括相似字特征的选取等,也由于工作上的原因,这一部分并不深入的介绍。

1,首先是梯度分布特征,该特征计算图像水平方向和竖直方向的梯度图像,然后通过给梯度图像分划不同的区域,进行梯度图像每个区域亮度值的统计,以下是算法步骤:

<1>将字符由RGB转化为灰度,然后将图像归一化到16*8

<4>对滤波后的图像,计算图像总的像素和,然后划分4*2的网络,计算每个网格内的像素值的总和。

<5>将每个网络内总灰度值占整个图像的百分比统计在一起写入一个向量,将两个方向各自得到的向量并在一起,组成特征向量。

image); // 计算图像中像素灰度值总和

2,第二个特征非常简单,只需要将图像归一化到特定的大小,然后将图像每个点的灰度值作为特征即可。

<1>将图像由RGB图像转换为灰度图像;

<2>将图像归一化大小为8×4,并将图像展开为一行,组成特征向量。

关于神经网络的原理我的博客里已经写了两篇文章,并且给出了C++的实现,所以这里我就不提了,下面主要说明在OpenCV中怎么使用它提供的库函数。

CvANN_MLP是OpenCV中提供的一个神经网络的类,正如它的名字一样(multi-layer perceptrons),它是一个多层感知网络,它有一个输入层,一个输出层以及1或多个隐藏层。

4.1. 首先我们来创建一个网络,我们可以利用CvANN_MLP的构造函数或者create函数。

上面是分别是构造函数和cteate成员函数的接口,我们来分析各个形参的意思。

layerSizes:一个整型的数组,这里面用Mat存储。它是一个1*N的Mat,N代表神经网络的层数,第i列的值表示第i层的结点数。这里需要注意的是,在创建这个Mat时,一定要是整型的,uchar和float型都会报错。

比如我们要创建一个3层的神经网络,其中第一层结点数为x1,第二层结点数为x2,第三层结点数为x3,则layerSizes可以采用如下定义:

或者用一个数组来初始化:

后面两个参数则是SIGMOID激活函数中的两个参数α和β,默认情况下会都被设置为1。

4.2. 设置神经网络训练参数

神经网络训练参数的类型存放在CvANN_MLP_TrainParams这个类里,它提供了一个默认的构造函数,我们可以直接调用,也可以一项一项去设。

它的参数大概包括以下几项。

train_method:训练方法,OpenCV里提供了两个方法一个是很经典的反向传播算法BACKPROP,另一个是弹性反馈算法RPROP,对第二种训练方法,没有仔细去研究过,这里我们运用第一种方法。

剩下就是关于每种训练方法的相关参数,针对于反向传播法,主要是两个参数,一个是权值更新率bp_dw_scale和权值更新冲量bp_moment_scale。这两个量一般情况设置为0.1就行了;太小了网络收敛速度会很慢,太大了可能会让网络越过最小值点。

我们一般先运用它的默认构造函数,然后根据需要再修改相应的参数就可以了。如下面代码所示,我们将迭代次数改为了5000次。

4.3. 神经网络的训练

我们先看训练函数的接口,然后按接口去准备数据。

inputs:输入矩阵。它存储了所有训练样本的特征。假设所有样本总数为nSamples,而我们提取的特征维数为ndims,则inputs是一个nSamples?ndims的矩阵,我们可以这样创建它。

我们需要将我们的训练集,经过特征提取把得到的特征向量存储在inputs中,每个样本的特征占一行。

outputs:输出矩阵。我们实际在训练中,我们知道每个样本所属的种类,假设一共有nClass类。那么我们将outputs设置为一个nSample行nClass列的矩阵,每一行表示一个样本的预期输出结果,该样本所属的那类对应的列设置为1,其他都为0。比如我们需要识别0-9这10个数字,则总的类数为10类,那么样本数字“3”的预期输出为[0,0,1,0,0,0,0,0,0,0];

sampleWeights:一个在使用RPROP方法训练时才需要的数据,所以这里我们不设置,直接设置为Mat()即可。

sampleIdx:相当于一个遮罩,它指定哪些行的数据参与训练。如果设置为Mat(),则所有行都参与。

params:这个在刚才已经说过了,是训练相关的参数。

flag:它提供了3个可选项参数,用来指定数据处理的方式,我们可以用逻辑符号去组合它们。UPDATE_WEIGHTS指定用一定的算法去初始化权值矩阵而不是用随机的方法。NO_INPUT_SCALE和NO_OUTPUT_SCALE分别用于禁止输入与输出矩阵的归一化。

一切都准备好后,直接开始训练吧!

识别是通过Cv_ANN_MLP类提供的predict来实现的,知道原理的会明白,它实际上就是做了一次向前传播。

在进行识别的时候,我们对图像进行特征提取,把它保存在inputs里,通过调用predict函数,我们得到一个输出向量,它是一个1*nClass的行向量,其中每一列说明它与该类的相似程度(0-1之间),也可以说是置信度。我们只用对output求一个最大值,就可得到结果。这个函数的返回值是一个无用的float值,可以忽略。

1,我们需要读取所有的训练样本,将它们的路径在保存在vector<string>中。

这里面我的车牌字符,因为1和I、0和O是一样的,所以数字加字母一共34类,其中每类有200个样本图像,共34*200个训练样本。

2,计算特征。我们按顺序读入图像,调用特征计算函数,把得到的结合保存在input对应的行中,同时把图像对应的预期输出保存在output中。

3,创建神经网络,这里我们计算得到的特征维数为48维,所以我们简单的设计一个3层的神经网络,输入层有48个结点,隐藏层也为48个结点,输出层为34个结点。然后神经网络的训练方法选用BACKPROP,迭代次数设置为5000次。

4,调用训练函数进行训练,并保存训练得到的权值矩阵,直接调用save成员函数即可。

5,识别测试,我们可以用单张图像进行测试,也可以选定一个测试集去进行测试,比如可以用一半的图像作为训练集,一半的图像作为测试集。这里我们可以加载已经训练好的权值矩阵,而不用重新训练,只要开始有保存了xml文件。但是记得你还是要创建一个网络后,才能加载进来。

这里我简单的做了一下测试,在这两个特征下,网络设置为3层[48,48,34],一半图像为测试集,得到的识别率为98%,我相信通过尝试调整网络的层数以及选用更好的特征,一定会得到更满意的识别率。PS(工作中用的是SVM识别器,正常采集到的车牌,字符识别率在99.8%以上)。但是神经网络识别器有个很大的优点就是,一旦网络训练好,识别需要的数据文件非常小,而且速度很快。

看到文章下的评论多是需求字符样本的,希望拿到字符样本的同学不要将其用于商业用途或者创建分享下载的链接。博文里用的样本是每类200张图像的测试样本,下面给出一份每类50个图像的样本子集,我以为用来做学术测试已经够了,出于公司利益考虑,请勿再向我索要完整样本。

我要回帖

更多关于 神经网络算法 python 的文章

 

随机推荐