这两天在写论文,天天写程序,没什么新脑洞,而且最近也遇到不少事。手动转载一下几篇新浪博客的文章,有几篇的阅读量和转载还挺不错。。。只是当时的文风也是醉了。

第一篇是“BP神经网络sim函数的MATLAB和C实现” (原文链接),争取做一些改写,尤其在排版上规范一点。

问题描述

BP神经网络属于ANN的一种,相对于DNN,CNN而言,是比较浅层的分类器。不过BPNN由于参数比较少,网络简单,还是有广泛的应用,尤其在传统的人工特征提取加分类器的算法中。因为这篇文章是在本科毕业设计的时候写的,当时还用了SVM,这里插一句我的观点,“SVM虽然调参比较复杂,网格法耗时,GA又存在局部最优的问题,但如果特征选择比较合理,它的表现还是非常有竞争力的”。

言归正传,由于要使用C++写界面,很希望实现神经网络的MATLAB和C的混合编程,问了度娘以后,发现不可以,因为MATLAB的神经网络库有专利,具体的解释见http://www.ilovematlab.cn/thread-103075-1-1.html

经过多次尝试后,决定采用“曲线救国”的方式,即利用MATLAB进行训练,再手动编写C代码,实现用于预测结果的sim函数。本次网络,采用newff函数建立神经网络net,输入层的传递函数为tansig,隐含层的传递函数为purelin.(若输入层采用logsig函数,方法类似)。注意: newff在新的MATLAB版本中已经有更新,具体更新可以去官网看。推荐《MATLAB神经网络43个案例分析》

下面以三层BP神经网络为例,sim函数的MATLAB实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
function out = myBPSim(net, Test_data)
% out = myBPSim(net, Test_data)
% Test_data,待分类的数据,每行表示一个特征向量
IW = net.IW{1,1}; % net是训练得到的网络,IW表示隐含层的权矩阵
% 维数 = 隐含层神经元个数 * 特征数
LW = net.LW{2,1}; % LW表示隐含层权矩阵,维数 = 1 * 隐含层神经元个数
b1 = net.b{1,1} % 输入层的阈值
b2 = net.b{2,1} % 隐含层的阈值
n1 = (IW * Test_data) + b1;
out1 = 2/(1 + exp(2 * n1)) - 1; % tansig函数的表达式,out1表示输入层的输出结果
out2 = LW * out1 + b2; % purelin函数就是形如 y = x,所以直接可以得到out2
end

有一点需要注意的是,《MATLAB智能算法——30个案例分析》 这本书的第25章P238存在错误,其中的式25-3和式25-4中的减号应改为加号,否则与实际结果有较大误差。

C语言对sim的实现与以上程序类似,需要注意的是矩阵的乘法,由于matlab采用了优化,所以其计算矩阵乘法的速度相对于C要快很多,我没有找到很好的解决方法,采用的仍然是无脑的for循环, C++代码样例如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void CClassify::DoClassify(IplImage *Src)
{
xxx // Some lines for feature generation
for(i = 0; i < 9; i++)
{
for(j = 0; j < 89; j++)
{
net1[i] += img_mat[j]*IW[j][i];
}
net1[i] = 2.00 /(1+exp(-2*(net1[i] + b1[i]))) -1; // tansig
}
for(i =0; i < 9; i++)
{
result += net1[i]*LW[i];
}
result = result + b2;
if(result > 0) Alm_flag = 1;
else Alm_flag = 0;
}