每个训练实例是一个400维特征的列向量(20,本身

作者: 编程  发布:2019-09-06

本文主要以ORL_64x64人脸数据库识别为例,介绍如何使用基于matlab的CDBN工具箱。至于卷积深度置信网络(CDBN,Convolutional Deep Belief Network)的理论知识,只给出笔者整理的一些学习资源。

由于需要在一个Android项目中使用神经网络,而经过测试发现几个Github上开源项目的训练效果就是不如Matlab的工具箱好,所以就想在Android上使用Matlab神经网络代码(可是。。。)

最近在做基于无线感知的身份识别这个工作,在后期数据处理阶段,需要使用二分类的方法进行训练模型。本身使用matlab做,所以看了一下网上很多都是使用libsvm这个工具箱,就去下载了,既然用到了想着就把这个东西梳理一下,顺便记录一下过程中的遇到的问题。

在这篇文章中,会实现一个BP(backpropagation)算法,并将之应用到手写的阿拉伯数字(0-9)的自动识别上。

参考以下学习资料

这个问题大概处理了两天,原本预计5个小时的。。。

1、 Libsvm下载与安装

训练数据集(training set)如下:一共有5000个训练实例(training instance),每个训练实例是一个400维特征的列向量(20*20 pixel image)。用 X 矩阵表示整个训练集,则 X 是一个 5000*400 (5000行 400列)的矩阵

  • CSDN博客---受限玻尔兹曼机学习笔记
  • CSDN博客---深度信念网络(Deep Belief Network)
  • 知乎---卷积神经网络工作原理直观的解释
  • 量子位公众号---一文了解各种卷积结构原理及优劣
  • 中国知网博硕论文---基于卷积深度置信网络的歌手识别
  • CDBN paper

过程遇到了诸多一手坑以及看到相关资料的对新手不友好,所以就把过程记录下来希望能给后来者一些帮助

Libsvm这个工具箱是台湾大学林智仁(Lin Chih-Jen)教授等开发的一套基于SVM的模式识别的软件包,网上也有详细的介绍,还有源代码,很方便学习。

另外,还有一个5000*1的列向量 y ,用来标记训练数据集的结果。比如,第一个训练实例对应的输出结果为数字:5

据笔者了解,目前,比较流行的深度学习框架,如TensorFlow、DeepLearning4j等不支持CDBN。GitHub上有基于Matlab的CDBN工具箱:CDBN工具箱下载链接下面简要介绍该工具箱。从GitHub上下载的压缩包解压后再打开,文件目录如下:

这个教程从0开始讲如何在Android App中使用Matlab的神经网络代码

下载:

 

9159.com 1CDBN工具箱的文件目录其中,最为重要的肯定是toolbox。toolbox里面有三个lib,分别是CDBN,DBN,Softmax库。本文将用到CDBN和Softmax两个库。9159.com 2toolbox下的三个lib需要注意的是,由于这个工具箱不是官方版的,因此可能存在某些bug,后面会涉及到笔者使用工具箱过程中的一些经验。

整个过程大概可以分成这么几步:

我用的是现在比较新的一个版本:libsvm-3.23

①模型表示

介绍一下本文搭建的进行人脸识别的卷积深度置信网络的结构。

  1. 首先你要在Matlab中写一个完整的神经网络
    1. 获取样本
    2. 样本导入
    3. 神经网络建模
    4. 神经网络训练
    5. 神经网络测试(优化建模)
  2. 然后你要在Matlab中重写一个神经网络,第二个神经网络的特殊之处是
    1. 首先这个神经网络必须写成函数,具体有几个细节
    2. 把第一个神经网络的训练结果net网络保存成mat文件
    3. 把相关需要用的但无法直接写入代码的数据也保存成mat文件(比如数据归一化的参数)
    4. 然后在函数中把上面几个mat文件导入,基本上就是一个完整的神经网络模型了
    5. 再加上一个神经网络计算语句,并把结果返回,这个函数就完成了
  3. 然后把这个Matlab神经网络函数进行打包,打包的结果是一个jar包
  4. 然后把这个jar包连同另一个jar包一块导入Andorid工程,并添加为外部依赖
  5. 最后在Android工程中写一个专门调用这个jar包接口代码的函数,传入输入变量,返回计算结果
  6. ()

安装:安装过程比较简单,下载好工具包之后傻瓜操作就可以了

我们使用三层的神经网络模型:输入层、一个隐藏层、和输出层。将训练数据集矩阵 X 中的每一个训练实例 用load指令加载到Matlab中:

  • 主体结构:两个卷积受限玻尔兹曼机(CRBM,Convolutional Restricted Boltzmann Machine)堆叠(每个CRBM后都接有池化层),顶层采用Softmax,实现分类。

  • 第一个CRBM:

 

A、解压到matlab安装根目录toolbox下(其他目录也行,最好放这儿,比较好找,其他地方哪天说不定删掉) D:Program FilesMATLABR2015btoolbox

9159.com 3

9159.com 4第一个CRBM参数

1.在Matlab中写一个完整的神经网络

B、 打开matlab之后设置好当前路径:D:Program FilesMATLABR2015btoolboxlibsvm-3.23matlab,在命令行输入mex –setup,选择编译环境。(编译环境比较重要,需要将这个工具箱中的源码使用C编译器编译,不然无法使用)

 

  • 第二个CRBM:

1.1.获取样本就不说了

9159.com 5

由于我们使用三层的神经网络,故一共有二个参数矩阵:Θ(1) (Theta1)和 Θ(2) (Theta2),它是预先存储在 ex4weights.mat文件中,使用load('ex4weights')加载到Matlab中,如下:

9159.com 6第二个CRBM参数

1.2.样本导入

9159.com 7

9159.com 8

  • Softmax层神经元个数40个,最大迭代次数maxIter=1000,代价函数为交叉熵代价函数(Cross-Entropy Error)

  • 其他参数其他诸如学习速率等的参数使用CDBN-mastertoolboxCDBNLIBdefault_layer2D.m中的默认值。

如何导入数据呢,一般matlab中有通用的数据存储格式,那就是Mat格式,但是我并不知道怎么编写这个格式

C、 在命令行输入 make 进行编译,在D:Program FilesMATLABR2015btoolboxlibsvm-3.23matlab 生成svmtrain.mexw64、svmpredict.mexw64、libsvmread.mexw64,

 

以下讲解编程步骤。

在我发现有办法可以把txt中的数据导入进去之后我就选定它了,因为这种格式也非常方便我用android输出,也就是说它是一种比较通用的信息交换格式

libsvmwrite.mexw64这四个文件,仔细查看,如果没有编译成功也无法使用。

参数矩阵Θ(1) (Theta1) 和 Θ(2) (Theta2) 的维数是如何确定的呢?

  • 步骤一:安装工具箱只需运行setup_toolbox.m即可。安装工具箱其实只是把用到的一些函数添加到matlab的搜索路径,因此你完全可以把工具箱内所有的文件都复制到你当前的路径下,不过肯定麻烦啦!

  • 步骤二:加载和矩阵化数据

具体的操作方法非常简单:

D、到这一步其实应该是没啥问题了,可以在命令行输入 which svm,会输出你之前工具箱所在的那个路径。如果都没啥问题,就可以使用了,不放心还可以使用它自带的数据进行测试。

一般,对于一个特定的训练数据集而言,它的输入维数 和输出的结果数目是确定的。比如,本文中的数字图片是用一个400维的特征向量代表,输出结果则是0-9的阿拉伯数字,即一共有10种输出。而中间隐藏层的个数则是变化的,根据实际情况选择隐藏层的数目。本文中隐藏层单元个数为25个。故参数矩阵Θ(1) (Theta1)是一个25*401矩阵,行的数目为25,由隐藏层的单元个数决定(不包括bias unit),列的数目由输入特征数目决定(加上bias unit之后变成401)。同理,参数矩阵Θ(2) (Theta2)是一个10*26矩阵,行的数目由输出结果数目决定(0-9 共10种数字),列的数目由隐藏层数目决定(25个隐藏层的unit,再加上一个bias unit)。神经网络的结构图如下:

  1. 你在txt中按这种格式保存数据:每行用回车隔开,每列用空格隔开
  2. 然后你在matlab中load这个文件,就能得到一个数据的矩阵了

2、 svm 的使用

9159.com 9

%load datadataFortrain=load('ORL_64x64StTrainFile1.txt');%注意修改路径train_data=dataFortrain(:,1:end-1)';%训练样本train_data=reshape(train_data,[64,64,1,360]);%矩阵化训练样本trainL=dataFortrain;%训练样本标签dataFortest=load('ORL_64x64StTestFile1.txt');%注意修改路径test_data=dataFortest(:,1:end-1)';%测试样本test_data=reshape(test_data,[64,64,1,40]);%注意修改路径testL=dataFortest;%测试样本标签

代码如下:

svm的使用也比较简单,不过也根据需求而定,可以做one-class、two-class,当然也可以实现多分类。这都取决于svm模型的参数设定,关于参数详细可以doc svmtrain在matlab帮助文档中查看。

 

重点讲一下第四行。StTrainFile1.txt中有360行,4097列。每一行是一幅人脸图像(像素为64X64=4096)的4096个灰度值,最后一列是该幅人脸图像的标签,表明其属于哪个人的(共40人,即分类数目为40)。由此可见,一幅二维图像被拉成了向量进行存储,因此在数据输入CDBN前,我们要对向量进行矩阵化,调用matlab的reshape方法,最终生成一个4维的矩阵,四个维度分别是64,64,1,360。倒数第二行同理。

 

1 训练:model = svmtrain(trainlabel,traindata,PARAMETERS);2 3 预测:[predictlabel,predictacc] =svmpredict(testlabel,testdata,model);

②代价函数

  • 步骤三:定义层参数工具箱把一层layer定义为一个struct对象。
alldata = load('alldata.txt');
alldata = alldata(:,:);

PARAMETERS一般是用键值对的方式,如‘-s 0 -c 100 -g 0.8 -t 2 -b 1’ 可以没有,没有就是默认参数。一般来说为了达到好的结果都会进行调参

未考虑正则化的神经网络的代价函数如下:

 

简单列一下主要参数:(红色的是我实验中用到的参数)

9159.com 10

%INITIALIZE THE PARAMETERS OF THE NETWORK %first layer settinglayer{1} = default_layer2D();layer{1}.inputdata=train_data;%输入训练样本layer{1}.n_map_v=1;layer{1}.n_map_h=9;layer{1}.s_filter=[7 7];layer{1}.stride=[1 1];layer{1}.s_pool=[2 2]; layer{1}.batchsize=90;layer{1}.n_epoch=1;

%second layer settinglayer{2} = default_layer2D();layer{2}.n_map_v=9;layer{2}.n_map_h=16;layer{2}.s_filter=[5 5];layer{2}.stride=[1 1];layer{2}.s_pool=[2 2];layer{2}.batchsize=10;layer{2}.n_epoch=1;

1.3. 1.4. 1.5. 这几个过程照着代码修改还是比较简单的(虽然matlab很久没用让我当时读得有点困难。。。),稍微提这么几点:

-s svm类型:SVM设置类型

其中,m等于5000,表示一共有5000个训练实例;K=10,总共有10种可能的训练结果(数字0-9)

需要注意的是,layer{i}=default_layer2D()这条语句是必须的,且必须位于所有层参数定义语句的最前面。原因:如果layer{i}=default_layer2D()这条语句不位于最前面的话,在这条语句前面的参数赋值语句实质不起作用,这些参数还是取默认值。特别是对于第一层,因为default_layer2D()方法中是没有定义inputdata字段的,如果layer{1}.inputdata=train_data这条语句位于layer{1}=default_layer2D()前面,则会出现“使用未定义字段”的错误。补充:要注意根据自己使用的数据集的情况设定层的输入类型,对[0,1]之间的数据集,应该使用二值神经网络,设定 layer{i}.type_input = 'Binary';其他数据集,应该设为layer{i}.type_input = 'Gaussian';至于二者的区别,自行百度,这里不展开了。

  1. (把经典书目《MATLAB神经网络30个案例分析》的源码包放到工作路径再进行阅读修改)
  2. 输出数据需要进行一下矩阵转换
  3. 使用newff工具函数来构建神经网络,使用matlab内部的工具箱(其实就是库函数)来建模、训练和计算,不需要自己写逻辑代码
  4. 中间各种矩阵的变换感觉不是很习惯,可以参看一下工作空间里的变量状态,或者一步步打印一些变量的结果来看

0 -- C-SVC:C-支持向量分类机; C代表惩罚系数,C越大表示对错误分类的惩罚越大,通过自己实验发现这个C确实对准确率影响很大,C的选择很关键。

 

  • 步骤四:训练CDBN网络这个过程是无监督学习,只需调用cdbn2D方法即可。

 

1 --v-SVC:v-支持向量分类机;

假设函数 hθ(x(i)) 和 hθ(x(i))k 的解释

在调用cdbn2D方法之前,CDBN-mastertoolboxCDBNLIBmex中的crbm_forward2D_batch_mex.c要先用mex命令编译生成crbm_forward2D_batch_mex.mexw64文件才能供matlab调用

clc;
clear;
 
%导入300组数据
alldata = load('alldata.txt');
alldata = alldata(:,:);
 
%输入输出数据
input = alldata(:,2:33);
outputtemp = alldata(:,1);
%输出数据需要处理一下
output = zeros(300,2);%预先分配内存
for i=1:300
    switch outputtemp(i)
        case 0
            output(i,:) = [1 0];%意思是如果数据结果是0,则输出层的状态是[1 0],或者用第一个输出节点表示
        case 1 %能直接识别带小数位的数据
            output(i,:) = [0 1];
    end
end
 
%从中随机抽取280组数据作为训练数据,20组数据作为预测数据
k = rand(1,300);
[m,n] = sort(k);
 
input_train = input(n(1:280),:)';
output_train = output(n(1:280),:)';
 
input_test = input(n(281:300),:)';
output_test = output(n(281:300),:)';
 
%输入输出数据进行归一化处理
[inputn,inputps] = mapminmax(input_train);
[outputn,outputps] = mapminmax(output_train);
 
%网络结构构建32-6-2
net=newff(inputn,outputn,6);
 
%网络参数配置(迭代次数,学习率,目标)
net.trainParam.epochs=100;
net.trainParam.lr=0.1;
net.trainParam.goal=0.0004;
 
%网络训练
net=train(net,inputn,outputn);
 
%BP网络预测
%预测数据归一化
inputn_test=mapminmax('apply',input_test,inputps);
 
%网络预测输出
an=sim(net,inputn_test);
 
%网络输出反归一化
BPoutput=mapminmax('reverse',an,outputps);
 
%结果分析
figure(1)
plot(BPoutput,':og')
hold on
plot(output_test,'-*');
legend('预测输出','期望输出')
title('BP网络预测输出','fontsize',12)
ylabel('函数输出','fontsize',12)
xlabel('样本','fontsize',12)
%预测误差
error=BPoutput-output_test;
 
figure(2)
plot(error,'-*')
title('BP网络预测误差','fontsize',12)
ylabel('误差','fontsize',12)
xlabel('样本','fontsize',12)
 
figure(3)
plot((output_test-BPoutput)./BPoutput,'-*');
title('神经网络预测误差百分比')
 
errorsum = sum(abs(error))

2 – 一类SVM:​单类别-支持向量机,不需要类标号,用于支持向量的密度估计和聚类。这种思路可能更适合对于那种异常检测的应用,这个单类模型需要有很高的区分度。

我们是通过如下公式来求解hθ(x(i))的:a(1) = x  再加上bias unit a0(1) ,其中,x 是训练集矩阵 X 的第 i 行(第 i 个训练实例)。它是一个400行乘1列的 列向量,上标(1)表示神经网络的第几层

mex crbm_forward2D_batch_mex.c

 

3 -- e -SVR:ε-支持向量回归机。

z(2) =  Θ(1)  a(1)  ,再使用 sigmoid函数作用于z(2),就得到了a(2),它代表隐藏层的每个神经元的值。a(2)是一个25行1列的列向量。

在编译前,crbm_forward2D_batch_mex.c要先修改:128行的out_id要改成在最开始的位置定义,否则编译时会出现“缺少:在类型前面’”的报错信息(PS:第一次遇到这么奇葩的报错,当时怀疑C语言是不是白学了),原因:VS2010的C编译器只支持C89标准,对C99标准支持不完全,而在C89标准中,变量需要放到函数体的前面声明,先声明再使用。

最后输出的结果还可以,虽然正确率一般,因为样本太少 。但是还能接受,是可以解释的结果:

4 -- v-SVR:n-支持向量回归机。

a(2) = sigmoid(z(2)) ,再将隐藏层的25个神经元,添加一个bias unit ,就a0(2)可以计算第三层(输出层)的神经单元向量a(3)了。a(3)是一个10行1列的列向量。

%% ----------- GO TO 2D CONVOLUTIONAL DEEP BELIEF NETWORKS ------------------%% tic;[model,layer] = cdbn2D;save('model_parameter','model','layer');toc;trainD = model{1}.output;%训练样本的第一个CRBM的输出,是一个4维矩阵trainD1 = model{2}.output;%训练样本的第二个CRBM的输出,是一个4维矩阵

9159.com 11.png)

3、4对应回归问题,用到可以试一下。

同理,z(3) =  Θ(2)  a(2) ,  a(3) = sigmoid(z(3)) 此时得到的 a(3) 就是假设函数 hθ(x(i))

我们来比较一下train_data、trainD、trainD1的大小

 9159.com 12

-t 核函数类型:核函数设置类型

由此可以看出:假设函数 hθ(x(i))就是一个10行1列的列向量,而 hθ(x(i))k 就表示列向量中的第 k 个元素。【也即该训练实例以 hθ(x(i))的概率取数字k?

9159.com 13train_data、trainD、trainD1

 

0 – 线性核:u'v

举个例子: hθ(x(6)) = (0, 0, 0.03, 0, 0.97, 0, 0, 0, 0, 0)T      【hθ(x(i))的输出结果是什么,0-1之间的各个元素的取值概率?matlab debug???】

现在再看看卷积神经网络的图示,是不是很好理解了呢?

 

1 – 多项式核:(r*u'v coef0)^degree

它是含义是:使用神经网络 训练 training set 中的第6个训练实例,得到的训练结果是:以0.03的概率是 数字3,以0.97的概率是 数字5

9159.com 14卷积神经网络图示

2.在Matlab中重写这个神经网络,为导出jar包做准备

2 – RBF核:exp(-gamma|u-v|^2)

(注意:向量的下标10 表示 数字0)

  • 步骤五:将测试样本输入训练好的CDBN网络,提取高维特征

2.1.首先这个神经网络必须写成函数

3 – sigmoid:tanh(r*u'v coef0)

 

这段代码可以直接copy,修改好变量名即可!

在matlab写一个函数的过程是这样的

-d degree : 用于多项式核函数,默认值是3

训练样本集的 结果向量 y (label of result)的解释

%% ------------ TESTDATA FORWARD MODEL WITH THE PARAMETERS ------------------ %%% FORWARD MODEL OF NETWORKSH = length;layer{1}.inputdata = test_data;fprintf('output the testdata features:>>...n');tic;if H >= 2% PREPROCESSS INPUTDATA TO BE SUITABLE FOR TRAIN layer{1} = preprocess_train_data2D;model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);for i = 2:H layer{i}.inputdata = model{i-1}.output; layer{i} = preprocess_train_data2D; model{i}.output = crbm_forward2D_batch_mex(model{i},layer{i},layer{i}.inputdata);endelselayer{1} = preprocess_train_data2D;model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);endtestD = model{1}.output;%训练样本的第一个CRBM的输出,是一个4维矩阵testD1 = model{2}.output;%训练样本的第二个CRBM的输出,是一个4维矩阵toc;
  1. 在工作空间中右键新建函数,重命名后打开,就是这样
    9159.com 15.png)9159.com 16
  2. matlab中的函数在这里一起趁热讲了(自己复习一遍)

    1. 整个函数有一头一尾两句固定的声明,头是以function开始,然后是:返回值

    函数名(函数参数),尾是end,虽然一开始看得不适应,但是习惯还是很好理解的,跟其他的语言差不多
    1.  返回值可以没有,那就是直接 函数名(函数参数)
    2.  返回值可以有多个,参数也可以有多个,他们的形式是这样:function
        [x,y,z]=sphere(theta,phi,rho)
    3.  注意Matlab中不会对函数类型进行声明,所以很多时候你在写函数的时候一开始就要对输入参数进行一个检查 
    
    1. 然后下面接着是官方注释,第一句是摘要,之后是详细说明,这些东西会在预览的时候显示
    2. 接下来就是函数体了,你可以做各种事情,逻辑语句、调用其他函数
    3. 最后在end之前你需要定义返回值,matlab在这块有点特殊,你不用显示地指定return哪个变量,因为你第一句声明里有返回值变量,所以只要你的函数内容中有这个变量,那么最后执行到end的时候就会自动返回这个变量这时候的状态
    4. -----调用函数------
    5. 调用函数的形式跟函数声明的第一句是一毛一样的:[输出参数表]=函数名(输入参数表)
    6. 调用函数时,输入和输出参数的顺序应与函数定义时的一致,数目一定不能多于函数定于中的,可能可以少于
    7. 为什么可以少于,因为在函数内部可以通过nargin()和nargout()获取函数被调用时用户指定的输入、输出参数个数。所以如果这个函数里边有针对不同的少于输入少于输出的情况进行if else的话,就可以自动适应
  3. 那么在这里,我的输出是一个int,输入是一个行矩阵,或者说一个数组,我的函数开头就这么写了:
    function output = annforecastthi(input_test)

-g gamma :多项式核函数、RBF核函数、sigmoid核函数。默认是1/k(num_features)

由于神经网络的训练是监督学习,也就是说:样本训练数据集是这样的格式:(x(i), y(i)),对于一个训练实例x(i),我们是已经确定知道了它的正确结果是y(i),而我们的目标是构造一个神经网络模型,训练出来的这个模型的假设函数hθ(x),对于未知的输入数据x(k),能够准确地识别出正确的结果。

同样的,我们来看一下test_data、testD、testD1的大小:

 

-r coef0 :多项式核函数、sigmoid核函数。默认是0

因此,训练数据集(traing set)中的结果数据 y 是正确的已知的结果,比如y(600) = (0, 0, 0, 0, 1, 0, 0, 0, 0, 0)表示:训练数据集中的第600条训练实例它所对应的正确结果是:数字5 (因为,向量y(600)中的第5个元素为1,其它所有元素为0),另外需要注意的是:当向量y(i) 第10个元素为1时 代表数字0。

9159.com 17test_data、testD、testD1的大小比较

2.2.然后为了不在这个函数里对神经网络进行训练(因为matlab的设定就是无法把训练函数编译成Jar包),需要把先前神经网络中训练好的net保存成mat文件再在这里直接导出

-c cost : C-SVC使用的惩罚因子C,epsilon-SVR, and nu-SVR中也使用 ,默认值为1

 

  • 步骤六:训练Softmax分类器,同时进行识别这里我们用到 softmaxExercise(inputData,labels,inputData_t,labels_t)这个函数参数说明:- inputdata:训练样本的CDBN输出,要求是二维矩阵-labels:训练样本的标签-inputData_t:测试样本的CDBN输出,要求是二维矩阵-labels_t:测试样本的标签由于CDBN的输出是4维矩阵,因此在训练Softmax分类器前,需要把矩阵拉成向量。代码如下,可直接copy,修改变量名即可!
  1. 把先前神经网络中训练好的net保存成mat文件 非常简单。直接在运算结束后再工作空间中右键net变量,保存为mat文件就可以了
  2. 然后导入的时候稍微有点麻烦
    1. 其实load mat文件有两种方式,一种是命令行方式,一种是函数方式。两种方式功能上没什么区别,但是推荐在函数里用函数方式
    2. 以导入一个结构体(归一化参数)为例:
      1. 命令行方式 :load anninputps inputps;
      2. 函数方式:
        9159.com 18
    3. 而导入net数据的时候还要麻烦一些:
      1. 命令行方式:load annnet net;
      2. 函数方式:(后边还要加一句把结构体转型成网络格式)
        9159.com 19
  3. 这里需要导入三个mat文件,一个net和两个归一化参数(后边要用来反归一化)

-n nu : nu-SVC, one-class SVM, and nu-SVR使用的参数nu。默认值为0.5

③BP(back propagation)算法

 

-p epsilon : epsilon-SVR的损失函数所用参数,默认0.1

BP算法是用来 计算神经网络的代价函数的梯度。

%% ------------------------------- Softmax ---------------------------------- %%fprintf('train the softmax:>>...n');tic;% TRANSLATE THE OUTPUT TO ONE VECTORtrainDa = [];trainLa=trainL;for i= 1:sizea1 = [];a2 = [];a3 = [];for j = 1:size a1 = [a1;reshape(trainD,size*size,1)];endfor j = 1:size(trainD1,3) a2 = [a2;reshape(trainD1,size(trainD1,2)*size(trainD1,1),1)];enda3 = [a3;a1;a2];trainDa = [trainDa,a3];endtestDa = [];testLa=testL;for i= 1:sizeb1 = [];b2 = [];b3 = [];for j = 1:size b1 = [b1;reshape(testD,size*size,1)];endfor j =1:size b2 = [b2;reshape(testD1,size*size,1)];endb3 = [b3;b1;b2];testDa = [testDa,b3];end

关于为什么不能把神经网络的训练函数编译成jar包

-m cachesize :设置缓存大小,默认100M

计算梯度,本质上是求偏导数。来求解偏导数我们可以用传统的数学方法:求偏导数的数学计算公式来求解。这也是Ng课程中讲到的“Gradient Checking”所用的方法。但当我们的输入特征非常的多(上百万...),参数矩阵Θ非常大时,就需要大量地进行计算了(Ng在课程中也专门提到,当实际训练神经网络时,要记得关闭 "Gradient Checking")。而这也是神经网络大拿Minsky 曾经的一个观点:(可参考这篇博文:神经网络浅讲)

我们来看一下拉成向量后的trainDa以及testDa的大小

MATLAB官方论坛中看到这样一个回答:
You will not be able to compile any function which trains the network (like ADAPT). Though the link does not explicitly list these funcions (like ADAPT), they fall under the 'All other command line functionality'.
However, you can deploy a M function code which uses a pre-trained network. I believe the SIM function will deploy fine.
The workflow I see is:
1. In MATLAB, train you network using test input/output
2. Save the network (mat file?)
3. Create a deployable function which then uses the pretrained network for new data. The network itself would not change/adapt/train in this function
4. Compile and deploy the above function
大意:MATLAB compile不支持对神经网络工具箱中涉及到训练的函数命令进行编译,只能编译那些用在已训练好的网络上的函数命令

-e epsilon :终止标准公差,默认0.001

Minsky认为,如果将计算层增加到两层,计算量则过大,而且没有有效的学习算法。所以,他认为研究更深层的网络是没有价值的。

9159.com 20拉成向量后的trainDa以及testDa的大小

所以解决方法就是在matlab下训练好网络,将net保存为mat文件,然后再写一个m文件,load进mat文件

-h shrinking :是否使用缩减的启发式

 

对比一下,train_data和test_data在矩阵化之前的大小:

 

-b probability_estimates :是否训练SVC或SVR模型进行概率估计,0或1

而BP算法,则解决了这个计算量过大的问题。BP算法又称反向传播算法,它从输出层开始,往输入层方向以“某种形式”的计算,得到一组“数据“,而这组数据刚好就是我们所需要的 梯度。

9159.com 21train_data和test_data在矩阵化之前的大小

2.3.最后返回计算结果,第二个神经网络模型也是神经网络计算函数就完成了

-wi weight : C-SVC

Once you have computed the gradient, you will be able to train the neural network 
by minimizing the cost function J(Θ) using an advanced optimizer such as fmincg.

可见,CDBN作为特征提取器,将4096维特征映射到了9873维特征,提高了Softmax的分类能力!

output=find(BPoutput(:,1)==max(BPoutput(:,1)));

-v n: n-折交叉验证,必须大于等于2

 

softmaxExercise.m中有这样一段注释:

整个函数是这样:

-q : quiet mode (no outputs)

 Sigmoid 函数的导数

9159.com 22softmaxExercise.m中的注释

 

 %关于网格搜索调参:网格搜索其实就是穷举给定范围内c和g的值来选择模型,c和g给定的范围不要太大,不然穷举次数太多导致程序跑起来太慢。%寻找最优c和g% c 的变化范围是 2^(-2),2^(-1.5),...,2^(10), g 的变化范围是 2^(-4),2^(-3.5),...,2^(4)[bestacc,bestc,bestg] = SVMcgForClass(trainlabelk,traindatak,-2,10,-4,4,3,0.5,0.5,0.9);%将得到的最高的参数bestc和bestg用来训练模型cmd = ['-c ',num2str,' -g ',num2str,' -t ',num2str(2),' -b ',num2str(1)];model = svmtrain(trainlabel,traindatak,cmd);

至于为什么要引入Sigmoid函数,等我有了更深刻的理解再来解释(Ng课程中也有提到)。Sigmoid函数的导数有一个特点,即Sigmoid的导数可以用Sigmoid函数自己本身来表示,如下:

因此在调用softmaxExercise方法前,要做以下4个工作:

function output = annforecastthi(input_test)
%ANNFORECAST
%   输入长度为32的行矩阵,输出为1或2
 
A = load('annnet.mat');
B = fieldnames(A);
net = A.(B{1});
net = network(net);
 
C = load('anninputps.mat');
D = fieldnames(C);
inputps = C.(D{1});
 
E = load('annoutputps.mat');
F = fieldnames(E);
outputps = E.(F{1});
 
%BP网络预测
%预测数据归一化
inputn_test=mapminmax('apply',input_test',inputps);
 
%网络预测输出
an=sim(net,inputn_test);
 
%网络输出反归一化
BPoutput=mapminmax('reverse',an,outputps);
 
%结果分析
%根据网络输出找出数据属于哪类
output=find(BPoutput(:,1)==max(BPoutput(:,1)));
 
end

3、 遇到的问题

9159.com 23

  • 修改softmaxExercise.m第22行的numClasses,如本文改为40
  • 修改softmaxExercise.m第96行的maxIter,本文取1000

 

A 分类模型

 

PS:个人觉得softmaxExercise方法应该增加两个入口参数,即numClasses和maxIter,如此才能更好体现封装的思想。

3.把这个Matlab神经网络函数打包成一个jar包导出

多分类:

证明过程如下:(将 证明过程中的 f(x) 视为 g(z) 即可 )

  • softmaxCost.m中定义需要的损失函数,只需要改第90行

3.1.吐槽

  我要做的是不同人的身份识别,比如我现在有20个人的数据,我需要识别出这20个人,这样一看好像就是个多分类问题,一个多分类模型就可以搞定,我也用了一些matlab中自带的一个应用于多分类的svm(这个在2014版以后的matlab中有):

9159.com 24

3.2.安装java开发环境

Mdl = fitcecoc(traindata,trainlabel);[preb] = predict(Mdl,testdata);

 

cost = -(1. / numCases) * sum(sum(groundTruth .* log   (lambda / 2.) * sum(sum);
  1. 安装java开发环境是很简单的事情,正常的步骤是这样
    1. 去甲骨文的官网下最新的jdk文件
      1. 选择windows64位的下载
      2. 不要选jre,区别是jre只能用来运行,不能用来编译,它也比jdk要小很多
      3. 这个网站下东西可能很慢,这个时候可以自行搜索一些网盘里提供的
    2. 点击这个jdk.exe文件进行安装,安装过程没什么好说的
    3. 安装完好像说现在的jdk不配置环境变量也没关系,但以前的要配置环境变量,那就配置吧,这个会单独在后边写
  2. 9159.com,然后我其实是之前就有安装的,但是在后边生成Jar包的时候出现了问题
    1. 经过排查,发现是jdk的版本相对matlab版本太高了:目前我的这个matlab2015b对应的是jdk7,所以我现在jdk8都不可以。(参考:matlab 2014a 用jdk1.7;matlab 2013a 用jdk1.6)
    2. 于是就只能降低jdk版本了,如何降低呢,其实很简单,你的系统中是可以同时安装多个jdk版本的不会冲突,最后你希望编译的时候用哪个版本,就在环境变量里配置哪个版本,非常方便
      9159.com 25.png)9159.com 26
    3. 但是下载的时候也会遇到个问题,因为官网找不到旧版本的下载,我就是搜索了一个然后安装,安装完修改了一下环境变量,最后ok了

  但是后来一想,这个模型根本没法扩展,人多了就没法用了,实际根本不可行。这样根本没法扩展,更多的人来怎么办?

Sigmoid 函数的Matlab实现如下(sigmoidGradient.m):

这条语句即可,原文件使用的是交叉熵代价函数。

 

基于异常检测的多分类(one class SVM):这个实现方法比较多(有一对一,一对多等),可以根据不同的数据集以及应用场景确定

 

  • 有必要的话可以修改 softmaxPredict.m中内容,个人觉得完全没必要,保留即可。

3.3.配置环境变量

  直接用每个人的数据给自己训练一个模型,这样得到N个不同的模型,用不同的测试数据测试,显然结果不是很好,这个对训练数据的要求很高,如果做人脸识别或者指纹识别这种,可能更适合这种方式。

9159.com 27

最后调用softmaxExercise方法

配置JAVA环境变量

前面两种都试了,效果不理想,所以只能用基于二分类的多分类,给每个人建立模型的时候,将其他所有不是这个人的数据作为负样本进行训练,这样虽然说扩展性也不是很好,但还是有进行扩展的空间。

g = zeros(size(z));

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the gradient of the sigmoid function evaluated at
%               each value of z (z can be a matrix, vector or scalar).

g = sigmoid(z) .* (1 - sigmoid(z));
% =============================================================
softmaxExercise(trainDa,trainLa,testDa,testLa);toc;
  1. 具体的做法是:

B、可能性评估出现Line search fails in two-class probability estimates

9159.com 28

完整代码

  因为每个人只有50条左右的数据,所以在给每个人训练样本时,正负样本的比例接近几十倍。当然这个问题确实会有,但是为了模型的准确性也不可避免这样做。

 

FaceRecognitionDemo.mclear;%load datadataFortrain=load('ORL_64x64StTrainFile1.txt');train_data=dataFortrain(:,1:end-1)';train_data=reshape(train_data,[64,64,1,360]);trainL=dataFortrain;dataFortest=load('ORL_64x64StTestFile1.txt');test_data=dataFortest(:,1:end-1)';test_data=reshape(test_data,[64,64,1,40]);testL=dataFortest;%INITIALIZE THE PARAMETERS OF THE NETWORK %first layer settinglayer{1} = default_layer2D();layer{1}.inputdata=train_data;layer{1}.n_map_v=1;layer{1}.n_map_h=9;layer{1}.s_filter=[7 7];layer{1}.stride=[1 1];layer{1}.s_pool=[2 2];layer{1}.batchsize=90;layer{1}.n_epoch=1;%second layer settinglayer{2} = default_layer2D();layer{2}.n_map_v=9;layer{2}.n_map_h=16; layer{2}.s_filter=[5 5];layer{2}.stride=[1 1];layer{2}.s_pool=[2 2];layer{2}.batchsize=10;layer{2}.n_epoch=1;%% ----------- GO TO 2D CONVOLUTIONAL DEEP BELIEF NETWORKS ------------------ %% tic;[model,layer] = cdbn2D;save('model_parameter','model','layer');toc;trainD = model{1}.output;trainD1 = model{2}.output;%% ------------ TESTDATA FORWARD MODEL WITH THE PARAMETERS ------------------ %%% FORWARD MODEL OF NETWORKSH = length;layer{1}.inputdata = test_data;fprintf('output the testdata features:>>...n');tic;if H >= 2 % PREPROCESSS INPUTDATA TO BE SUITABLE FOR TRAIN layer{1} = preprocess_train_data2D;model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);for i = 2:H layer{i}.inputdata = model{i-1}.output; layer{i} = preprocess_train_data2D; model{i}.output = crbm_forward2D_batch_mex(model{i},layer{i},layer{i}.inputdata);endelselayer{1} = preprocess_train_data2D;model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);endtestD = model{1}.output;testD1 = model{2}.output;toc;%% ------------------------------- Softmax ---------------------------------- %%fprintf('train the softmax:>>...n');tic;% TRANSLATE THE OUTPUT TO ONE VECTORtrainDa = [];trainLa=trainL;for i= 1:sizea1 = [];a2 = [];a3 = [];for j = 1:size a1 = [a1;reshape(trainD,size*size,1)];endfor j = 1:size(trainD1,3) a2 = [a2;reshape(trainD1,size(trainD1,2)*size(trainD1,1),1)];enda3 = [a3;a1;a2];trainDa = [trainDa,a3];endtestDa = [];testLa=testL;for i= 1:sizeb1 = [];b2 = [];b3 = [];for j = 1:size b1 = [b1;reshape(testD,size*size,1)];endfor j =1:size b2 = [b2;reshape(testD1,size*size,1)];endb3 = [b3;b1;b2];testDa = [testDa,b3];endsoftmaxExercise(trainDa,trainLa,testDa,testLa);toc;
    1. 我的电脑——属性——高级设置——高级——环境变量
    2. 在系统变量里添加一个键值对:JAVA_HOME(大小写不敏感),和jdk安装后的位置路径(为javac.exe所在目录D:Program FilesJavajdk1.6.0_13bin的上一层)
    3. 9159.com 29.png)9159.com 30
    4. 配置完之后这样可以验证
    5. 9159.com 31.png)9159.com 32
  1. 另外说一点是,即使配置了这个java path,但Eclipse和AS中还有独立的配置:
    Eclipse:Window -> Preferences->Java -> Compiler 设置 "Compiler compliance level" 为 1.6 (相应版本)
    AS:点击File,选择Other Settings,选择Default Project ,Structure...

  开始训练模型和测试,使用70%训练集,30测试集的原则进行数据集划分,在人数少时识别效果非常好,在人数多时出现了很奇怪的问题:结果接近两个极端,一个很好,一个很差,而且重复很多次实验,仍然是这样,没有别的结果出现,差的结果占百分之七八十。反复检查之后发现坏结果发生时,命令行会输出这样一句话:Line search fails in two-class probability estimates

训练神经网络时的“symmetry”现象---随机初始化神经网络的参数矩阵(权值矩阵Θ)

运行截图及准确率

配置path

百度之后发现这个问题也确实有人遇到过但不是很多,本人也是菜鸟,所以还真不知道哪里出了问题,参考网上的说法(

随机初始化参数矩阵,就是对参数矩阵Θ(L)中的每个元素,随机地赋值,取值范围一般为[ξ ,-ξ],ξ 的确定规则如下:

9159.com 33运行截图19159.com 34运行截图29159.com 35运行截图3

  1. 也是在系统变量里添加
  2. 变量名是path,值是【.;%JAVA_HOME%bin;%JAVA_HOME%jrebin;D:Program FilesMATLABR2015bbin】
  3. 现在我其实是这样的,居然也可以,不是很懂 【%Java_Home%bin;%Java_Home%jrebin;C:ProgramDataOracleJavajavapath;%SystemRoot%system32;%SystemRoot%;%SystemRoot%System32Wbem;%SYSTEMROOT%System32WindowsPowerShellv1.0;C:Program Files (x86)Calibre2;C:Program FilesMATLABR2015bruntimewin64;C:Program FilesMATLABR2015bbin;C:Program FilesMATLABR2015bpolyspacebin;C:Program FilesMATLABMATLAB Runtimev90runtimewin64】

9159.com 36

9159.com 37

97.5%的识别率,还是可以接受的,一方面是数据集好,另一方面是搭建得网络好。读者可以试一试调整CDBN网络的参数,比如增大epoch,看能否获得更高的识别率。为了方便读者研究,附上所有文件。

配置CLASSPATH

9159.com 38

 

本Demo文件汇总下载链接(原链接失效,此为新版连接),提取码:7f6i

  1. 也是在系统变量里添加
  2. 变量名是path,值是【.;%JAVA_HOME%lib;%JAVA_HOME%libtools.jar;D:Program FilesMATLABR2015btoolboxjavabuilderjarjavabuilder.jar;%JAVAHOME%libdt.jar;%JAVA_HOME%libtools.jar】
  3. 现在我其实是这样的,居然也可以,不是很懂【.;%Java_Home%bin;%Java_Home%libdt.jar;%Java_Home%libtools.jar】

有回答说这个是单纯效果不好的原因,我有点怀疑,但是为什么只有两个极端呢,这个结果不好应该是个随机的,至少结果分布应该正常的,这完全就不是我想看到的结果。所以我打开了svm的源码,找到输出那条语句的地方:

假设将参数矩阵Θ(L) 中所有的元素初始化0,则 根据计算公式:a1(2) = Θ(1) *  (参看视频,完善)会导致 a(2) 中的每个元素都会取相同的值。

以下是使用此工具箱的几点提示:

 

9159.com 39

因此,随机初始化的好处就是:让学习 更有效率

  • 原始工具箱只在LINUX系统测试过,由于LINUX系统和WINDOWS系统的文件分隔符不同,因此DemoCDBN_Binary_2D.m的第83行、cdbn2D.m的第15、24行、 setup_toolbox.m的文件分隔符要修改。
  • 源程序存在bug,即若样本个数不是batchsize的整数倍的话,会出错,因此在此bug排除前,应将batchsize设置为样本数目的因数
  • 类别标签不要用负数或0,比如进行二分类,标签不要设为-1和1,可以设为1和2,这是因为softmaxCost.m文件中的第18行建立稀疏矩阵时会以标签作为矩阵的索引,如果设为0或负数,肯定会报错:矩阵索引必须为正数

3.4.打包的操作

果然,在可能性计算的时候,就没有进去这个循环,而是直接跳出了,突然想到可能模型并没有训练,去看了一下训练好的模型,结果是这样:

This range of values ensures that the parameters are kept small and makes the learning more efficient

在2015版本中操作跟前面版本的可能有很大的不同(跟2013都不一样,前面的也各自不一样orz),就只说在这个版本中的步骤

9159.com 40

 

  1. 在命令行区域输入命令:deploytool,弹出对话框,然后你选择第三个library compiler
    9159.com 41.png)9159.com 42
  2. 于是打开了一个大界面,在这个界面里要做五件事
    1. 1这选择java
    2. 2这点击添加你的这个m函数(2旁边这个框保持原样,不用打钩)
    3. 3这块一般都会改一你觉得适合的名字
    4. 关键4这一定要把你m函数中load的数据文件一块加进来
    5. 点击开始打包
  3. 9159.com 43.png)9159.com 44
  4. 打包需要一点时间,结束后如果成功就会在工作空间路径下生成一个项目,项目中能找到输出Jar文件,这个就是我们的要的
    9159.com 45.png)9159.com 46 

里面全是空的,支持向量都没有,ok那就是说,一开始由于样本的不均衡导致svm觉得这两类训练数据完全分不开就直接罢工不干了…好吧,就是数据集惹的祸。

随机初始化的Matlab实现如下:可以看出,它是先调用 randInitializeWeights.m 中定义的公式进行初始化的。然后,再将 initial_Theta1 和 initial_Theta2 unroll 成列向量

4、把jar导入工程中

后面改了训练样本中正负样本的比例,就不会出现这个问题了。

initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size);
initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels);

% Unroll parameters
initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)];
  1. 除了刚才生成的这个Jar包之外,还需要导入另一个Jar包,这个jar包就是MATLAB中带的jarbuild.jar 这个包,一般路径是E:Program FilesMATLABR2013atoolboxjavabuilderjar   (MATLAB解析jar包文件)
  2. 用AS往Android工程导入JAR包的步骤是这样的
    1. 将jar文件复制、粘贴到app的libs目录(app—src—main—libs)中(此时虽然jar已经复制黏贴过来了,但是还未导入,所以看不到jar中包含的内容。而已导入的jar,则可以看到jar中内容)
    2. 右键点击jar文件,并点击弹出菜单中的“Add As Library”,将jar文件作为类库添加到项目中
    3. 删除jar包 的步骤
      1. 选中项目
      2. 点击 File——>Project structure——>module——>app
      3. 选择 “dependencies”,选择你要删除的jar包,点击减号
  3. 用Eclipse往JAVA工程导入JAR包的步骤是这样的
    1. 在java工程下新建一个lib文件夹(不新建也行,只是为了规范),直接把jar包拖入这个文件夹
    2. 右键,添加依赖
    3. 9159.com 47.png)9159.com 48

参考链接:

 

 

randInitializeWeights.m 的实现如下:

5、写一个专门的工具方法作为调用Matlab函数的接口,传入输入变量,返回计算结果

 

怎么写:

function W = randInitializeWeights(L_in, L_out)
%RANDINITIALIZEWEIGHTS Randomly initialize the weights of a layer with L_in
%incoming connections and L_out outgoing connections
%   W = RANDINITIALIZEWEIGHTS(L_in, L_out) randomly initializes the weights 
%   of a layer with L_in incoming connections and L_out outgoing 
%   connections. 
%
%   Note that W should be set to a matrix of size(L_out, 1   L_in) as
%   the column row of W handles the "bias" terms
%
% You need to return the following variables correctly 
W = zeros(L_out, 1   L_in);

% ====================== YOUR CODE HERE ======================
% Instructions: Initialize W randomly so that we break the symmetry while
%               training the neural network.
%
% Note: The first row of W corresponds to the parameters for the bias units
%
epsilon_init = 0.12;
W = rand(L_out, 1   L_in) * 2 * epsilon_init - epsilon_init;

% =========================================================================

end
  1. 导入结束后,你能看到其实是这样的
  2. 所以你写接口的话非常简单
    1. 先new一个这个类,然后调用类的这个方法,输入输出
    2. 直接结束

 

然后写的话需要注意这么几点:

 

  1. (参数和返回值的数据类型什么的,matlab 的帮助文档matlab builer for JA中说得很详细)
  2. 必须catch一下MWException,这个是matlab里边的
  3. 输入:
    1. 你的matlab函数是这样写的:output = annforecastthi(input_test)
    2. 你的函数里是把输入当成一个大小为32的行矩阵来用的,所以正常想在这应该是输入一个数组
    3. 但是根据代码提示,你会发现不完全是这样,而是:第一个参数是输出数据个数,之后是一个个的输入数据,输入数据可以直接是一个数组
  4. 输出:
    1. 同样,我在matlab函数里写的输入是一个int值,为1或者2
    2. 但是在这里,你的输出是一个Object[ ],如果输出只有一个的话,那就是result[0]
    3. 另外如果result[0]返回的是一个数组,可以通过如下的方法解析(供参考)
      1. MWNumericArray a = new MWNumericArray(Double.valueOf(result[0].toString()),MWClassID.DOUBLE);
      2. MWNumericArray temp = (MWNumericArray)result[0];
      3. float [][] weights=(float[][])temp.toFloatArray();

 

 

 

public class TestMatlab {
       public static void main(String[] args){
              try {
                     ANNMatlab annMatlab = new ANNMatlab();
                      double[] array = {74.5,75.5 ,83.3 ,93.4 ,93.9 ,90.1 ,86.1 ,... };
                     Object result[]=annMatlab.annforecastthi( 1,array);
                     //函数第一个参数是输出数据个数,之后的就是是输入数据。
                                     System.out.println("result==" result[ 0]);
              } catch (MWException e) {
                     e.printStackTrace();
              }
       }
}

BP算法的具体执行步骤如下:

 

对于每一个训练实例(x, y),先用“前向传播算法”计算出 activations(a(2), a(3)),然后再对每一层计算一个残差δj(L) (error term)。注意:输入层(input layer)不需要计算残差。

然后在JAVA项目中运行,获得了正确的输入

9159.com 49

9159.com 50

 

9159.com 51.png)

具体的每一层的残差计算公式如下:(本文中的神经网络只有3层,隐藏层的数目为1)

但是当把这个项目放在Android项目中运行的时候,发现崩溃并且报错了

对于输出层的残差计算公式如下,这里的输入层是第1层,隐藏层是第2层,输出层是第3层

 

9159.com 52

 

残差δ(3)是一个向量,下标 k 表示,该向量中的第 k 个元素。yk 就是前面提到的表示 样本结果的向量y 中的第 k 个元素。(这里的向量 y 是由训练样本集的结果向量y分割得到的)

6、Android项目中无法直接使用Matlab中导出的jar包

上面的减法公式用向量表示为:δ(3)= a(3) - y,因此δ(3)维数与a(3)一样,它与分类输出的数目有关。在本例中,是10,故δ(3)是一个10*1向量

根据前文的正确操作到这一步的时候,你会发现Android项目还是崩溃了,并且报这样的错

 

【java.lang.UnsatisfiedLinkError: Failed to find the required library libmwmclmcrrt.so.9.0 on java.library.path. 】

对于隐藏层的残差计算公式如下:

这个错误的意思是:在java路径上缺少这个so文件

9159.com 53

这个java路径可以通过【System.out.println(System. getProperty("java.library.path")); 】这句代码打印,我这里打印结果是zycn根文件夹,也就是整个项目的根文件夹

 

而这个libmwmclmcrrt.so.9.0又是什么呢

当每一层的残差计算好之后,就可以更新 Δ(delta) 矩阵了,Δ(delta) 矩阵与 参数矩阵有相同的维数,初始时Δ(delta) 矩阵中的元素全为0.

  1. so文件和dll文件都是动态链接库(说白了就是一些库函数),dll文件是windows系统中使用的,而so文件是Linux系统中使用的
  2. 而这个libmwmclmcrrt.so.9.0大概是matlab代码需要的,但是为什么需要呢?不应该搞定之后都会有吗?
    1. 搜索引擎上一些缺少.so文件的问题发生在Linux系统下,然后他们的解决办法都是一个,重新配置环境变量,因为好像在linux上配置这个环境变量很容易出问题()()()()()()
    2. 搜索引擎上还有缺少dll文件的,一部分是环境变量的配置问题,一部分是需要手动安装某个800多M的文件(如果你要在没有安装matlab的机器上用java调用这些jar包,怎么办?也是可以的,不过,不过你要先在机器上安装matlab提供的MATLAB Compiler Runtime (MCR) ,它的安装文件在D:program filesstudyMATLABR2007btoolboxcompilerdeploywin32下(你的安装目录下)文件名MCRInstaller.exe)()()
    3. 但这里因为在java项目中能成功运行,在android中不行,所以自然会想到是android系统的环境变量配置问题或者说就是跟android系统有关
% nnCostFunction.m
Theta1_grad = zeros(size(Theta1));% Theta1_grad is a 25*401 matrix--矩阵Θ(1) ,由Δ(1)的值来更新
Theta2_grad = zeros(size(Theta2));% Theta2_grad is a 10*26 matrix--矩阵Θ(2) ,由Δ(2) 的值来更新

后来在matlab官方论坛和stackoverflow上更换了下关键词【直接matlab android】,有找到对于这个问题的直接解释,还有曲线救国的办法。相关的问题还很多,看来是很多人都遇到了这个问题

 

 

它的定义(计算公式)如下:

The .jar files that Compiler SDK generates cannot be run on Android. The .jar has a small interface to call upon the machine code library that is MCR, and otherwise the .jar contains encrypted data files. The encrypted data files are the "compiled" .m code, which is not compiled to java, but rather to MATLAB's internal threaded interpreter. MCR decrypts the encrypted pcode'd .m files and uses them as data to be processed by the threaded interpreter. The encrypted data files themselves can be fairly operating system independent, but you need MCR to interpret them, and MCR is in x86 or x64 machine code for all versions of MATLAB since about R2009a. Android does not run on x86 or x64: Android runs on ARM processors (or possibly PowerPC as well, I am not certain.)
In short, you cannot use Compiler SDK to generate for anything useful on Android.
At this time, the only way to deploy for Android is to use Simulink with Target set to Android. You can have your Simulink blocks call a MATLAB Function block which is specialized MATLAB code (that has to be careful about how it allocates memory.) There is not much graphics you can do with this mechanism but it is the best that is available at this time.
I happened to look last night at some of the blocks available for deployment to a couple of the Android Galaxy devices. There is a block which accepts R, G, and B signals and displays the result as the screen. It would require computing the entire screen, I suspect. Some of the routines in the Vision toolbox help in that.
大意:matlab生成的jar包不能直接在android上运行,还需要用一个叫MCR的东西进行解码(The MATLAB Compiler Runtime (MCR) has the same System requirements as MATLAB. See System Requirements - Android is not one of them.它是matlab代码解析器),而MCR目前只能运行在X86或者X64的CPU上,但因为android是运行在ARM CPU上,所以是不可能使用的。
然后它说:此时,部署Android的唯一方法是使用Simulink与目标设定为Android。你可以有你的Simulink模块调用MATLAB函数的MATLAB代码块是专业(需注意如何分配内存)没有多大的图形可以做这种机制,但它是最好的,此时可用。
后边这个就看不懂了:我碰巧看的最后一个晚上的一些块可供部署到一对夫妇的安卓银河设备。有一个块,它接受R,G和B信号,并显示屏幕的结果。它将需要计算整个屏幕,我怀疑。一些例程中的“视觉工具箱”中的帮助。
 
I have not read about what can be done in R2016a. The situation as of R2015b was that in order to generate code for Android from MATLAB, what you needed to do was include the MATLAB code in a MATLAB Function block in Simulink and tell Simulink to target Android; there was no direct path for MATLAB to Android.
大意:你需要做的是包括在Simulink MATLAB功能块的matlab代码告诉Simulink目标Android
 
However, you should be able to use the MATLAB Coder product to generate a standalone C/C library from your MATLAB code and then invoke that from your Android application, possibly using JNI.
大意:你可以使用一个叫MATLAB Coder的工具来生成可以独立运行的C/C 库,他们可以在android中通过JNI来直接运行
 
MATLAB code that is put into a Simulink MATLAB Function Block (with appropriate adjustments made) can be generated for Android target using Simulink. There are a bunch of restrictions on this, but I think it can access the Android Sensor information for supported devices (Galaxy S4, Galaxy Note 2)
大意:matlab代码,把MATLAB的一个Simulink功能块(适当调整)可以为Android使用Simulink生成目标。有一些限制,但我认为它可以访问支持的设备Android传感器信息(Galaxy S4,Galaxy Note 2)
 
From MATLAB, you can communicate with Android camera and with Android sensors (at least for some models), but it is not possible to generate code for Android. You need to use Simulink to generate code for Android.
MATLAB Coder does not know about Android, so MATLAB Coder cannot generate Android calls for user interaction, networking, graphics, and so on. MATLAB Coder can generally generate C or C , but unless it has been given information about the target system, MATLAB Coder has a library of calls that is not even as complete as the Standard C Library. This is not enough to create an Android "app"; at most it is enough to create a utility program.
Simulink does know how to target Android, so if you have a Simulink model and use the Android-specific blocks, Simulink can create apps. See http://www.mathworks.com/hardware-support/android-programming-simulink.html
大意:可以用Simulink
 
.so files are Linux Shared Object libraries. Those .so files are only available for Intel x86 (32 bit) and x64 (64 bit) instruction set (including AMD CPUs that implement those.) They are not available for ARM or other instruction architectures.
大意:.so文件本身也只能再X86的系统上使用,而不能在ARM上使用(这个存疑)
 
The .jar file requires the MATLAB Compiler Runtime (a freely redistributable component that you get with MATLAB Compiler and MATLAB Builder products) to be present. The MCR has a much larger footprint than is suitable for the typical Android device (it's like a copy of MATLAB itself, without the user interface).
You could think about either
1)Running your MATLAB .jar file remotely on a server, and having your Android application connect to it, or
2)Instead of using MATLAB Compiler and Builder products, use MATLAB Coder, which will convert a subset of the MATLAB language directly into C code. This C code doesn't require the MCR, and could be compiled to run directly on Android. Make sure your MATLAB algorithm falls within, or can be expressed in, the appropriate subset of the MATLAB language.
大意:前面都一样不说了,后边提了两个解决办法:1)不要再app上用Matlab代码,转移到服务器上;2)用MATLAB Coder编译成可以不需要MCR支持才能运行的C/C 文件
 
A new feature in Matlab 2014a:
http://www.mathworks.com/help/simulink/samsung-galaxy-android-devices.html
You can now directly install (limited set of) models to Samsung Android devices, and this should work actually on any Android device.
大意:2014的新版本中,你可以直接把matlab模型安装在三星安卓设备上,实际上就可以安装在所有安卓设备上

9159.com 54

 

在这里,δ(L 1)是一个列向量,(a(1))T是一个行向量,相乘后,得到的是一个矩阵。

总结一下上面的内容:

 

  1. 直接在android app上使用deploytool生成的jar包是不行的,因为它不能独立运行,还需要MCR的支持,而由于CPU的原因MCR是不能运行在android环境的
  2. 那么其他可行的间接办法有这些
    1. 不要在app上用Matlab代码,转移到服务器上
    2. MATLAB Coder编译成可以不需要MCR支持才能运行的C/C 文件,然后使用JNI的方法在android app上使用
    3. 可以通过一种【include the MATLAB code in a MATLAB Function block in Simulink and tell Simulink to target Android】的方法来做

计算出 Δ(delta) 矩阵后,就可以用它来更新 代价函数的导数了,公式如下:

 

9159.com 55

对于第一个间接办法,肯定是可行的,但由于目前我这条件的限制,是无法实现了

 

对于第二个间接办法,肯定也是可行的,不过稍显复杂,目前我对此也没有涉猎

对于一个训练实例(training instance),一次完整的BP算法运行Matlab代码如下:

对于第三个间接办法,我去简单了解了一下,但是搞下来毫无头绪:

9159.com 56

  1. 首先我没有找到step by step的教程,所以只能一个个自己去搜索
  2. 于是先去看了matlab的simulate系统,两个感受:
    1. 功能非常丰富繁杂
    2. 找不到所谓的跟搞一个android虚拟机有关的东西
    3. 这个中文入门教程还可以:
  3. 然后我看了下这个什么三星虚拟机,发现:这个东西好像只是跟什么传感器有关,可以在matlab中获取三星手机传感器的数据,跟我现在的需求没有关系
  4. 最后时间关系没有继续探索下去
for i = 1:m
    a1 = X(i, :)'; %the i th input variables, 400*1
    z2 = Theta1 *  a1;
    a2 =  sigmoid( z2 ); % Theta1 * x superscript i
    a2 = [ 1; a2 ];% add bias unit, a2's size is 26 * 1
    z3 = Theta2 * a2;
    a3 = sigmoid( z3 ); % h_theta(x)

    error_3 = a3 - Y( :, i ); % last layer's error, 10*1  第三层的残差计算公式
    %error_2 = ( Theta2' * error_3 ) .*  ( a2 .* (1 - a2) );% g'(z2)=g(z2)*(1-g(z2)), 26*1

    err_2 =  Theta2' * error_3; % 26*1
    error_2 = ( err_2(2:end) ) .*  sigmoidGradient(z2);% 去掉 bias unit 对应的 error units

    Theta2_grad = Theta2_grad   error_3 * a2'; % Δ(L) = Δ(L)   δ(L 1)* (a(L))T
    Theta1_grad = Theta1_grad   error_2 * a1';
end

Theta2_grad = Theta2_grad / m; % video 9-2 backpropagation algorithm the 11 th minute
Theta1_grad = Theta1_grad / m; %这里的结果就是 Di,j(L)

 

9159.com 57

7、另一个解决办法

 

其实推荐使用上面的第一个或第二个间接办法,都很不错

④梯度检查(gradient checking)

不过最后我采用了个间接但是比较简单可能效果不好的方法:直接找了一个java写的神经网络开源项目,读了一下了解怎么用,就直接放进app中使用了

梯度检查的原理如下:由于我们通过BP算法这种巧妙的方式求得了代价函数的导数,那它到底正不正确呢?这里就可以用 高等数学 里面的导数的定义(极限的定义)来计算导数,然后再比较:用BP算法求得的导数 和 用导数的定义 求得的导数 这二者之间的差距。

所以这个教程其实还差一步没有结束,之后有空把JNI学一下再来更新这个部分

导数定义(极限定义)---非正式定义,如下:

 

9159.com 58

参考资料:已在文中列出

9159.com 59

可能正是这种通过定义直接计算的方式 运算量很大,所以课程视频中才提到:在正式训练时,要记得关闭 gradient checking

从下面的 gradient checking 结果可以看出(二者计算出来的结果几乎相等),故 BP算法的运行是正常的。

9159.com 60

 

⑤神经网络的正则化

对于神经网络而言,它的表达能力很强,容易出现 overfitting problem,故一般需要正则化。正则化就是加上一个正则化项,就可以了。注意 bias unit不需要正则化

9159.com 61

 

在lambda==1,训练的迭代次数MaxIter==50的情况下,训练的结果如下:代价从一开始的3.29...到最后的 0.52....

训练集上的精度:Training Set Accuracy: 94.820000

9159.com 62

Training Neural Network... 
Iteration     1 | Cost: 3.295180e 00
Iteration     2 | Cost: 3.250966e 00
Iteration     3 | Cost: 3.216955e 00
Iteration     4 | Cost: 2.884544e 00
Iteration     5 | Cost: 2.746602e 00
Iteration     6 | Cost: 2.429900e 00
.....
.....
.....
Iteration    46 | Cost: 5.428769e-01
Iteration    47 | Cost: 5.363841e-01
Iteration    48 | Cost: 5.332370e-01
Iteration    49 | Cost: 5.302586e-01
Iteration    50 | Cost: 5.202410e-01

9159.com 63

 

对于神经网络而言,很容易产生过拟合的现象,比如当把参数 lambda 设置成 0.1,并且训练次数MaxIter 设置成 200时,训练结果如下:训练精度已经达到了99.94%,很可能是 overfitting 了

9159.com 64

Training Neural Network... 
Iteration     1 | Cost: 3.303119e 00
Iteration     2 | Cost: 3.241696e 00
Iteration     3 | Cost: 3.220572e 00
Iteration     4 | Cost: 2.637648e 00
Iteration     5 | Cost: 2.182911e 00
....
......
.........
Iteration   197 | Cost: 8.177972e-02
Iteration   198 | Cost: 8.171843e-02
Iteration   199 | Cost: 8.169971e-02
Iteration   200 | Cost: 8.165209e-02

Training Set Accuracy: 99.940000

9159.com 65

 

⑥使用Matlab的 fmincg 函数 最终得到 参数矩阵Θ

9159.com 66

 

9159.com 67

% Create "short hand" for the cost function to be minimized
costFunction = @(p) nnCostFunction(p, ...
                                   input_layer_size, ...
                                   hidden_layer_size, ...
                                   num_labels, X, y, lambda);

% Now, costFunction is a function that takes in only one argument (the
% neural network parameters)
[nn_params, cost] = fmincg(costFunction, initial_nn_params, options);

9159.com 68

代码中最后一行 fmincg(costFunction, initial_nn_params, options) 将求得的神经网络的参数nn_params返回。initial_nn_params 就上前面提到的使用随机初始化后初始化的参数矩阵。

 

整个求解代价函数、梯度、正则化的 Matlab代码如下:nnCostFunction.m文件

function [J grad] = nnCostFunction(nn_params, ...
                                   input_layer_size, ...
                                   hidden_layer_size, ...
                                   num_labels, ...
                                   X, y, lambda)
%NNCOSTFUNCTION Implements the neural network cost function for a two layer
%neural network which performs classification
%   [J grad] = NNCOSTFUNCTON(nn_params, hidden_layer_size, num_labels, ...
%   X, y, lambda) computes the cost and gradient of the neural network. The
%   parameters for the neural network are "unrolled" into the vector
%   nn_params and need to be converted back into the weight matrices. 
% 
%   The returned parameter grad should be a "unrolled" vector of the
%   partial derivatives of the neural network.
%

% Reshape nn_params back into the parameters Theta1 and Theta2, the weight matrices
% for our 2 layer neural network
Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size   1)), ...
                 hidden_layer_size, (input_layer_size   1));

Theta2 = reshape(nn_params((1   (hidden_layer_size * (input_layer_size   1))):end), ...
                 num_labels, (hidden_layer_size   1));

% Setup some useful variables
m = size(X, 1);

% You need to return the following variables correctly 
J = 0;
Theta1_grad = zeros(size(Theta1));% Theta1_grad is a 25*401 matrix
Theta2_grad = zeros(size(Theta2));% Theta2_grad is a 10*26 matrix

% ====================== YOUR CODE HERE ======================
% Instructions: You should complete the code by working through the
%               following parts.
%
% Part 1: Feedforward the neural network and return the cost in the
%         variable J. After implementing Part 1, you can verify that your
%         cost function computation is correct by verifying the cost
%         computed in ex4.m
X = [ones(m,1) X]; P00*401
a_super2 = sigmoid(Theta1 * X'); % attention a_super2 is a 25*5000 matrix
a_super2 = [ones(1,m);a_super2]; 
					

本文由9159.com发布于编程,转载请注明出处:每个训练实例是一个400维特征的列向量(20,本身

关键词: 9159.com