ANN_MLP简介
OpenCV中的ML模块实现了前馈人工神经网络,具体地说是多层感知器(MLP),是最常用的神经网络类型。 MLP由输入层,输出层和一个或多个隐藏层组成。 MLP的每一层包括一个或多个与来自上一层和下一层的神经元定向连接的神经元。 如图所示,一个具有三个输入,两个输出的三层感知器,隐藏层包括五个神经元:
MLP中的所有神经元都是相似的。它们中的每一个都有几个输入链接(它将前一层中的几个神经元的输出值作为输入)和几个输出链接(它将响应传递给下一层中的几个神经元)。 将从前一层检索到的值与某些权重相加,每个神经元个体加上偏差项。 使用激活函数f对总和进行变换,对于不同的神经元也可能不同。
换句话说,给定第n层的输出
xj
,第n + 1层的输出
yi
为:
ui=Σj(wn+1i,j∗xj)+wn+1i,bias
yi=f(ui)
可以使用不同的激活函数。 ML实现三个标准函数:
- 恒等函数( ANN_MLP::IDENTITY ): f(x)=x
- 对称sigmoid函数(ANN_MLP :: SIGMOID_SYM):MLP默认函数,
f(x)=β∗(1−e−αx)/(1+e−αx)
。
β=1,α=1
时为标准sigmoid函数:
- 高斯函数( ANN_MLP::GAUSSIAN ): f(x)=βe−αx∗x 尚不完全支持。
在ML中,所有神经元具有相同的激活函数,具有由用户指定的相同的自由参数 (α,β) ,并且不会被训练算法改变。
所以,神经网络的工作过程如下:
- 以特征向量作为输入。向量大小等于输入层的大小;
- 将值传递给第一个隐藏层;
- 使用权重和激活函数计算隐藏层的输出;
- 将输出传递到下层直到输出层。
所以,神经网络计算需要知道所有权重 wn+1i,j 。
网络规模越大(隐藏层的数量和规模越大),网络的灵活性就越高。训练集上的错误可以做得很小。但在网络规模达到极限后,测试集上的误差通常会开始增加。此外,较大的网络比较小的网络训练的时间要长得多,因此使用PCA :: operator()或类似的技术对数据进行预处理,并且尽量用较小的网络对基本特征进行训练。
网络结构:
MLP和训练算法的参数。可以通过构造函数初始化结构,也可以在创建结构后调整各个参数。
主要参数
class ANN_MLP::Params
Mat layerSizes //网络每层中的神经元个数。第一个元素指定输入层中神经元的数量。最后一个元素为输出层中神经元的数量。
int activateFunc//激活函数。目前唯一完全支持的激活函数是ANN_MLP::SIGMOID_SYM。
double fparam1//激活函数的第1个参数α,默认为0
double fparam2//激活函数的第2个参数β,默认为0
TermCriteria termCrit//训练算法的终止条件。可以指定最大迭代次数(maxCount)或迭代之间的误差变化大小(epsilon)
int trainMethod//MLP的训练方法(ANN_MLP_TrainParams::BACKPROP-反向传播算法或ANN_MLP_TrainParams::RPROP -RPROP算法)
double param1//训练方法的参数; RPROP为rp_dw0,BACKPROP为bp_dw_scale
double param2//训练方法的参数;RPROP为rp_dw_min,BACKPROP为bp_moment_scale
与许多其他ML模型一起构建和训练不同,在MLP模型中这些步骤是分开的。首先,使用非缺省构造函数或方法ANN_MLP :: create()创建具有指定拓扑的网络。所有的权重都设置为零。然后,使用一组输入和输出向量来训练网络。训练过程可以重复多次,即可根据新的训练数据调整权重。
ML有两种用于训练MLP的算法。 第一种算法是经典的随机顺序反向传播算法。 第二个(默认)是批量RPROP算法。
反向传播算法参数:
double bpDWScale//权重梯度项的强度;建议值约为0.1;
double bpMomentScale//惯性项的强度(前两次迭代的权重之差);该参数提供了一些惯性来平滑权重的随机波动;它可以从0(禁用功能)到1以及更高;建议值约为0.1左右
RPROP算法参数:
double prDW0
double rpDWPlus
double rpDWMinus
double rpDWMin
double rpDWMax
ANN_MLP使用示例
OpenCV3中ANN_MLP使用示例:
#include "opencv2/opencv.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace ml;
int main()
{
//训练数据及对应标签
float trainingData[8][2] = {{480,500},{50,130},{110,32},{490,60},{60,190},{200,189},{78,256},{45,315}};
float labels[8] = {0,1,0,0,1,0,1,1};
Mat trainingDataMat(8, 2, CV_32FC1, trainingData);
Mat labelsMat(8, 1, CV_32FC1, labels);
//建立模型
Ptr<ANN_MLP> model = ANN_MLP::create();
//共5层:输入层+3个隐藏层+1个输出层,输入层、隐藏层每层均为2个perceptron
Mat layerSizes = (Mat_<int>(1, 5) << 2, 2, 2, 2, 1);
//设置各层的神经元个数
model->setLayerSizes(layerSizes);
//激活函数
model->setActivationFunction(ANN_MLP::SIGMOID_SYM);
//MLP的训练方法
model->setTrainMethod(ANN_MLP::BACKPROP,0.1,0.9);
//训练模型
Ptr<TrainData> trainData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
model->train(trainData);
Mat src = Mat::zeros(512, 512, CV_8UC3);
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
Mat sampleMat = (Mat_<float>(1, 2) << i, j);
Mat responseMat;
model->predict(sampleMat, responseMat);
float p = responseMat.ptr<float>(0)[0];
if (p> 0.5)
src.at<Vec3b>(j, i) = Vec3b(0,125,125);
else
src.at<Vec3b>(j, i) = Vec3b(125,125,0);
}
}
//绘制出训练数据在图中的分布
Mat dst1 = src.clone();
for (int i = 0; i < sizeof(trainingData[0]); i++)
{
float q = labels[i];
//根据训练数据对应的标签不同绘制不同的颜色:1对应红色,0对应绿色
if (q == 1)
circle(dst1, Point(trainingData[i][0],trainingData[i][1]), 5, Scalar(0,0,255), -1, 8);
else
circle(dst1, Point(trainingData[i][0],trainingData[i][1]), 5, Scalar(0,255,0), -1, 8);
}
//在原图像范围内随机生成20个点,并使用训练好的神经网络对其进行预测,并绘制出预测结果
Mat dst2 = src.clone();
for (int i = 0; i < 20; i++)
{
RNG rngx(i);
float x = rngx.uniform(0,512);
RNG rngy(i*i);
float y = rngy.uniform(0,512);
Mat trainingDataMat = (Mat_<float>(1,2)<<x,y);
Mat response;
model->predict(trainingDataMat,response);
float q = response.ptr<float>(0)[0];
if (q > 0.5)
circle(dst2, Point(x,y), 5, Scalar(0,0,255), -1, 8);
else
circle(dst2, Point(x,y), 5, Scalar(0,255,0), -1, 8);
}
imshow("output1", dst1);
imshow("output2", dst2);
waitKey(0);
return 0;
}
相关链接:
1. OpenCV API Reference:Neural Networks
2. wikipedia:Artificial neural network
3. wikipedia:Backpropagation