背景:
个人认为机器学习、深度学习就在身边,从不遥远,如何让Android开发和常规的机器学习结合起来使用?这里分享一些摸索的过程。
基础资源:
机器学习入门,推荐吴恩达的课程Supervised Learning in Machine Learning: Regression and Classification (DeepLearning.AI) | Coursera,以及西瓜书等系列书籍。
目前比较热门的GitHub资源:
NCNN,https://github.com/Tencent/ncnn (见详细配置教程,以及自定义模型训练)
目录
Part01:《环境配置》
Part02:《C语言和MATLAB混编》
Part03:《Java语言和MATLAB混编》
Part01:《环境配置》
一、Windows环境(win7,VS2017+MATLAB_R2016b_x64)
1、在VS添加必要环境设置
链接文件:libmx.lib,libmex.lib和libmat.lib (位于MATLAB库目录);
头文件:engine.h,matrix.h,tmwtypes.h(位于MATLAB包含目录)
包含目录:D:\MATLAB\R2016b\extern\include;
库目录:
D:\ProgramFiles (x86)\SetupDir\MATLAB\R2016b\extern\lib\win64\microsoft;
D:\ProgramFiles (x86)\SetupDir\MATLAB\R2016b\extern\lib\win64\mingw64;
附加器目录: D:\ProgramFiles (x86)\SetupDir\MATLAB\R2016b\bin\win64; (可不加)
二、Linux环境(Centos7.5,gcc-7.3.0+matlab_R2016b_x64)
1、必要环境设置(matlab默认安装情况下)
链接文件:libmx.so,libmex.so和libmat.so
头文件:engine.h,matrix.h,tmwtypes.h
包含目录:/usr/local/MATLAB/R2016b/extern/include
库目录:/usr/local/MATLAB/R2016b/bin/glnxa64
2、 matlab引擎依赖条件
①matlab引擎依赖/bin/csh启动,所以不管你使用何种shell,都必须安装csh
#yum install chs (centos/redhat平台)
②gcc版本过低,会出现链接库的问题(经测试,6.1.0版本gcc也是可以的)
Part02:《C语言和MATLAB混编》
官方文档介绍
Type for MATLAB engine - MATLAB- MathWorks 中国
编写 C 程序以读取 MAT 文件数据- MATLAB & Simulink- MathWorks 中国
ps:这里为什么使用C语言和MATLAB混编?不仅因为MATLAB是一款功能非常强大的软件,而且支持C语言、JAVA语言等主流语言,可以直接将算法文件(.m类型)生成jar包,引用到Android开发中
一、C语言调用MATLAB示例
简单来说,本示例实现的是使用MATLAB编写一段数据处理的算法,生成m文件;在本地或者云服务器通过C语言调用MATLAB,执行算法文件,返回数据结果(如自行购买配置阿里云服务器,可从云端直接返回结果到客户端,达成联动)。(这里涉及C语言调用MATLAB混编的过程,纯属踩坑过程,记录备案)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#include "matrix.h"
#define BUFSIZE 256
#define N 120
int main()
{
//定义MATLAB Engine
Engine *ep;
//定义缓存空间,提取结果
char level,buffer[BUFSIZE + 1];
int i=25,num;
//定义MATLAB C函数库参数
mxArray *testdata = NULL, *result = NULL;
//这里自定义数组样例,可以使用data.mat导入
double cArray[N] = {
0 , 4 , 10 , 1 ,1 , 7 , 15 , 1 ,1 , 11 , 12 , 1 ,
1 , 23 , 14 , 1 ,1 , 25 , 18 , 1 ,1 , 26 , 14 , 1 ,
1 , 39 , 26 , 1 ,1 , 36 , 36 , 1 ,1 , 26 , 42 , 1 ,
1 , 39 , 36 , 1 ,1 , 38 , 31 , 2 ,1 , 36 , 35 , 2 ,
1 , 36 , 35 , 2 ,1 , 48 , 31 , 1 ,1 , 39 , 22 , 1 ,
1 , 17 , 11 , 1 ,1 , 33 , 13 , 1 ,2 , 65 , 9 , 1 ,
2 , 50 , 17 , 1 ,2 , 74 , 10 , 1 ,1 , 51 , 44 , 1 ,
1 , 28 , 62 , 1 ,1 , 17 , 37 , 1 ,1 , 7 , 21 , 2 ,
1 , 6 , 12 , 1 ,1 , 24 , 12 , 1 ,1 , 39 , 16 , 1 ,
2 , 49 , 13 , 1 ,1 , 29 , 30 , 1 ,1 , 24 , 33 , 2
};
//windows环境下,不用指定路径将engOpen的参数改为engOpen(NULL)
//使用engOpen("path")命令打开软件
if (!(ep = engOpen("/usr/local/MATLAB/R2016b/bin/matlab")))
{
printf("Can't start MATLAB engine!");
return EXIT_FAILURE;
}
//设置MATLAB无界面运行
engSetVisible(ep,false);
//创建矩阵
testdata = mxCreateDoubleMatrix(1, N, mxREAL);
//拷贝数组
memcpy((double *)mxGetPr(testdata), (double *)cArray, N * sizeof(double));
//传递数据到MATLAB环境
if(engPutVariable(ep, "input_data", testdata) == 1){
printf("Failed to send testdata to MATLAB !");
}
//传递指令,在MATLAB保存数据文件data.mat
engEvalString(ep, "save data.mat 'input_data';");
buffer[BUFSIZE] = '\0';
//指定缓存区
engOutputBuffer(ep, buffer, BUFSIZE);
//执行m文件
engEvalString(ep, "MTest");
//关闭缓存
engOutputBuffer(ep, NULL, 0);
//从工作区提取变量
if ((result = engGetVariable(ep, "num")) == NULL)
printf("The result of MATLAB is %s.\n", buffer);
for(;!(buffer[i]>='A' && buffer[i]<='Z');i++){
if(buffer[i]>='0' && buffer[i]<='9')
return_num=(int)(buffer[i]-48);
}
level=(char)buffer[i];
printf("The return_num is %d\n\n",num); //结果返回
printf("The level is %c\n\n",level);
}
else{
printf("There is something wrong with MTest.m!Check again!\n" );
}
//释放内存
mxDestroyArray(testdata);
mxDestroyArray(result);
//关闭软件
engClose(ep);
return EXIT_SUCCESS;
}
二、数据处理demo(MATLAB语言)
本示例代码实现的功能:在c语言里面往MATLAB传送一组数据,并输入指令调用MTest.m进行处理,得到返回结果kind和level(4x5维)。
文件说明:
data.mat:数据文件,1x120维;
net.m:自设计BP神经网络模型
clc
clear
load net ;
%***************************
%提取输入矩阵
%预处理
%***************************
TEMP = load( 'data.mat');
tmp = struct2cell(TEMP);
tmp=char(tmp);
row=size(tmp,1);
string=[];
target=[];
string=tmp;
col=size(string,2);
ch1=string(1:8:col);
ch2=string(2:8:col);
ch3=string(3:8:col);
ch4=string(4:8:col);
ch5=string(5:8:col);
ch6=string(6:8:col);
ch7=string(7:8:col);
ch8=string(8:8:col);
str1=[ch1',ch2'];
str2=[ch3',ch4'];
str3=[ch5',ch6'];
str4=[ch7',ch8'];
col1=smooth(hex2dec(str1),30);
col2=smooth(hex2dec(str2),30);
col3=smooth(hex2dec(str3),30);
col4=smooth(hex2dec(str4),30);
initdata=[col1 col2 col3 col4];
%按行列提取数据,阈值150
[row,col]=size(initdata);
yan=0;
for i=1:1:row
if initdata(i,4)>=150
yan=1;
end
end
if yan==1 && mean(initdata(:,2))>=10
kind='0x01';
else
if (mean(initdata(:,2))<18 & mean(initdata(:,1))<8 & mean(initdata(:,3))<10 )
target=1;
up=2;
elseif (mean(initdata(1:15,1))>=mean(initdata(16:30,1)) & (mean(initdata(1:15,2))>mean(initdata(16:30,2))) & (mean(initdata(:,2))>mean(initdata(:,1))) )
target=2;
else
target=0;
end
% xs
if mean(initdata(:,1))>2.5*mean(initdata(:,2))
for i=1:1:row
initdata(i,3)=10;
initdata(i,2)=10;
end
end
% xj
if mean(initdata(:,1))>160
for i=1:1:row
initdata(i,2)=10;
initdata(i,3)=10;
end
end
if (mean(initdata(:,2))>3*mean(initdata(:,1))) && mean(initdata(:,2))>3*mean(initdata(:,3))
for i=1:1:row
initdata(i,1)=16;
initdata(i,2)=initdata(i,2)+10;
end
end
if (mean(initdata(:,2))+mean(initdata(:,3)))>2*mean(initdata(:,1))
for i=1:1:row
initdata(i,1)=10;
end
end
% 预处理
temp1=initdata(1:10,1:3);
temp2=initdata(11:20,1:3);
temp3=initdata(21:30,1:3);
input_data1=[mean(temp1),mean(temp1(:,1)-temp1(:,2)),mean(temp1(:,1)-temp1(:,3))]';
input_data2=[mean(temp2),mean(temp2(:,1)-temp2(:,2)),mean(temp2(:,1)-temp2(:,3))]';
input_data3=[mean(temp3),mean(temp3(:,1)-temp3(:,2)),mean(temp3(:,1)-temp3(:,3))]';
% 仿真
y11=sim(net14,input_data1);
y21=sim(net24,input_data1);
y31=sim(net34,input_data1);
y41=sim(net44,input_data1);
y51=sim(net54,input_data1);
y12=sim(net14,input_data2);
y22=sim(net24,input_data2);
y32=sim(net34,input_data2);
y42=sim(net44,input_data2);
y52=sim(net54,input_data2);
y13=sim(net14,input_data3);
y23=sim(net24,input_data3);
y33=sim(net34,input_data3);
y43=sim(net44,input_data3);
y53=sim(net54,input_data3);
[~,kind11]=max(y11);
[~,kind21]=max(y21);
[~,kind31]=max(y31);
[~,kind41]=max(y41);
[~,kind51]=max(y51);
[~,kind12]=max(y12);
[~,kind22]=max(y22);
[~,kind32]=max(y32);
[~,kind42]=max(y42);
[~,kind52]=max(y52);
[~,kind13]=max(y13);
[~,kind23]=max(y23);
[~,kind33]=max(y33);
[~,kind43]=max(y43);
[~,kind53]=max(y53);
% 投票
kq=0;
xs=0;
jp=0;
cz=0;
yq=0;
kind_select1=[kind11;kind21;kind31;kind41;kind51];
kind_select2=[kind12;kind22;kind32;kind42;kind52];
kind_select3=[kind13;kind23;kind33;kind43;kind53];
for j=1:1:size(kind_select1,1)
if kind_select1(j)==3
xs=xs+1;
elseif kind_select1(j)==2
jp=jp+1;
elseif kind_select1(j)==2
cz=cz+1;
elseif kind_select1(j)==1
yq=yq+1;
else
kq=kq+1;
end
end
for j=1:1:size(kind_select2,1)
if kind_select2(j)==3
xs=xs+1;
elseif kind_select2(j)==2
jp=jp+1;
elseif kind_select2(j)==2
cz=cz+1;
elseif kind_select2(j)==1
yq=yq+1;
else
kq=kq+1;
end
end
for j=1:1:size(kind_select3,1)
if kind_select3(j)==3
xs=xs+1;
elseif kind_select3(j)==2
jp=jp+1;
elseif kind_select3(j)==2
cz=cz+1;
elseif kind_select3(j)==1
yq=yq+1;
else
kq=kq+1;
end
end
[~,kind_num]=max([xs,jp,yq]);
if xs==0 & jp==0 & yq==0
target=1;
end
%结果转化
if target==1
kind='0x00';
elseif target==2
load temp kind;
else
if kind_num==1
kind='0x02';
elseif kind_num==2
kind='0x03';
elseif kind_num==3
kind='0x04';
elseif kind_num==4
kind='0x04';
else
kind='0x00';
end
end
end
if (kind=='0x02'| kind=='0x03' | kind=='0x04' )& up~=0
kind='0x00';
up=up-1;
end
% 浓度分级
data=mean(initdata);
if strcmp(kind,'0x00')
level='0x01';
elseif strcmp(kind,'0x01')
if data(1,4)>=270
level='0x05';
elseif data(1,4)>=230
level='0x04';
elseif data(1,4)>=190
level='0x03';
elseif data(1,4)>=150
level='0x02';
else
level='0x01';
end
elseif strcmp(kind,'0x02')
if data(1,1)>=150
level='0x05';
elseif data(1,1)>=100
level='0x04';
elseif data(1,1)>=50
level='0x03';
elseif data(1,1)>=20
level='0x02';
else
level='0x01';
end
elseif strcmp(kind,'0x03')
if data(1,2)>=40
level='0x05';
elseif data(1,2)>=30
level='0x04';
elseif data(1,2)>=20
level='0x03';
elseif data(1,2)>=10
level='0x02';
else
level='0x01';
end
elseif strcmp(kind,'0x04')
if data(1,2)>=40
level='0x05';
elseif data(1,2)>=30
level='0x04';
elseif data(1,2)>=20
level='0x03';
elseif data(1,2)>=10
level='0x02';
else
level='0x01';
end
else
level='0x00';
end
//保存变量,打印结果
save temp kind up
kind
level