机器学习和生物信息学实验室联盟

标题: Matlab Compiler Runtime与tomcat应用于matlab和java混编及网站开发 [打印本页]

作者: xingpengwei    时间: 2017-7-19 22:20
标题: Matlab Compiler Runtime与tomcat应用于matlab和java混编及网站开发
本帖最后由 xingpengwei 于 2017-7-19 22:30 编辑

        Matlab Compiler Runtime(MCR)
        “MATLAB Runtime 是一组独立的共享库,可用于在未安装 MATLAB 的计算机上执行编译后的 MATLAB 应用程序或组件。 MATLAB, MATLAB Compiler与 MATLAB Runtime 配合使用,可以快速、安全地创建和分发数值应用程序或软件组件。”
        MCR还可以配合matlab的Library Compile package编译matlab代码为c++、java、python等语言
        所以我们可以把使用library compile package把matlab程序编译成jar,然后配合tomcat发布javaweb网站。
        之前使用matlab程序做网站的做法都是在server上装一个matlab,web的java后台调用系统命令启动matlab,执行matlab脚本,存储结果web在使用java代码调用结果文件。这样做网站响应速度会很慢,而且占web server的很大资源。
        使用mcr要好很多。

        下边我们来动手实践吧(matlab2017a,windows8.1,server:ubuntu14.04)加粗显示的都是趟过的报错坑:
        首先我们要明确我们的任务,我们的最终目标是要把依赖第三方工具包(一个深度信念网络包)的matlab程序编译成jar(涉及一个很复杂的第三方包,不知道能不能成),混合到web的java后台代码中。(成的话,我们就算实践了mcr最复杂的用法)
        所以:
        1、在windows本机上使用library compile package编译matlab代码
        2、先在windows平台上配置环境试验是否可以运行jar
        3、在linux服务器上配置环境试验是否可以运行jar
        4、编写网站配合tomcat上传运行jar

        1、在windows本机上使用library compile package编译matlab代码
        首先只要使用matlab编译java,都是要配置和matlab相对应的jdk的
        在Matlabd的Command Windows中输入version -java
        没错,最新的matlab2017a也是 'Java 1.7.0_60-b19 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode'
        所以装1.8的,可以下载一个1.7zip版,配置环境变量
        打开cmd 分别输入命令java -version和javac -version分别验证编译和运行版本。
        javac没配置好,编译jar包是要报错的。
        jdk版本版本不对是要报错的。

        编译jar时内存不足也是会报错的:Failed to embed unzip in your applicationUpdate resource failed: 00000000CE555B5,Failed to embed installer splash screen ...toolbox\compiler\Resources\default_splash.png. Update resource failed: 0000000037E55CB0
        编写主函数脚本,这个脚本要做到对外提供一个接口之类的作用,比如我们这个文件是根据用户输入的文件路径,生成深度信念网络跑出来的特征:
  1. function []=getDbnFeat(file_path)
  2.     [tits, seqs]=fastaread(file_path);
  3.     num=length(tits);
  4.     len=length(char(seqs(1)));

  5.     Y=zeros(num,1);
  6.     X=zeros(num,len*4);
  7.     %onehot
  8.     for i=1:num

  9.         str=char(tits(i));
  10.         temp=strsplit(str,'|');
  11.         label=char(temp(2));
  12.         if label=='1'
  13.             Y(i)=0;
  14.         else
  15.             Y(i)=1;
  16.         end


  17.         img=zeros(len,4);
  18.         for j=1:len
  19.             seq=char(seqs(1,i));
  20.             switch seq(j)
  21.                 case 'A'
  22.                     img(j,:)=[0,0,0,1];
  23.                 case 'C'
  24.                     img(j,:)=[0,0,1,0];
  25.                 case 'G'
  26.                     img(j,:)=[0,1,0,0];
  27.                 case 'U'
  28.                     img(j,:)=[1,0,0,0];
  29.                 case 'T'
  30.                     img(j,:)=[1,0,0,0];
  31.             end
  32.         end
  33.         X(i,:)=img(:);

  34.     end

  35.     inputs = X;
  36.     targets = Y;
  37.     load('dbn.mat');
  38.     feat=dbn.getFeature(inputs);
  39.     feat_label=[feat,targets];
  40.     csvwrite('feat_mid.csv',feat_label);
  41.     S = fileread('feat_mid.csv');
  42.     feat_dim=100;
  43.     attribute='';
  44.     for i=1:feat_dim
  45.         attribute=[attribute,'@attribute Fea',int2str(i),' numeric',char(10)];
  46.     end
  47.     header=['@relation m6a_dbn',char(10),attribute,'@attribute class {0,1}',char(10),'@data',char(10)];

  48.     S = [header,  S];
  49.     FID = fopen('feat.arff', 'w');
  50.     if FID == -1, error('Cannot open file'); end
  51.     fwrite(FID, S, 'char');
  52.     fclose(FID);
  53. end
  54.    
复制代码

       
        [attach]3468[/attach]
        选择要编译的语言,点击+好选择编写好的主函数脚本,更改生成的jar名
        [attach]3470[/attach]
        library compile package会自动选择函数脚本依赖的文件,但是真得会有可能并没有那么智能,特别是我们这种复杂的第三方包。
        [attach]3469[/attach]
        点击右上角package对号按钮,开始一段漫长的编译。
        tips:
        1、不要涉及mex等平台特定性文件,默认编译的jar文件是平台不相关的,这样部署到linux网站才有可行性,所以不要涉及平台特定性文件。
        2、函数内涉及调用mat怎么办,没事,library compile package会智能关联依赖,一并打包。
        3、函数外涉及mat调用咋办,就是java调用mat,这个有一个叫JMatIO的可以用。https://sourceforge.net/projects/jmatio/
        4、涉及二次存储的(比如本例中先使用matlab自带的csvwrite存储成csv文件,再读取csv略改变成arff文件),要注意,library compile package会自动把中间文件打包进jar中,这样会导致程序出错,因为每次调用jar文件,程序都是对jar内部存储中间文件做修改,方法是打包时删点文件夹中的中间文件和结果文件,然后在打开library compile package,这样library compile package就不会自动关联依赖,不删除直接在依赖列表中删除会报错
        点击这个启动library compile package
        5、编译成功后,运行报错可能会提示少什么类,在第三方包中找到包含相应类的m文件,添加到依赖文件列标中。
        编译成功后会生成三个文件夹:
        “-for_redistribution包含用于安装应用程序和MATLAB Runtime的文件,可以将这份文件复制到没有安装Matlab的电脑上,安装该文件,在安装过程中会提示要安装独立的共享库MATLAB Runtime,安装之后不需要Matlab也可以运行编译后的Matlab的程序或者元件(The MATLAB Runtime is a standalone set of shared libraries that enables the execution of compiled MATLAB applications or components on computers that do not have MATLAB installed)。
        -for_redistribution_files_only文件夹包含应用程序的重新发布所需的文件。这些文件可以分发到那些有MATLAB或者有 MATLAB Runtime 的用户的电脑上。
        -for_testing文件夹包含创建的所有由MCC创建的文件,像二进制文件和jar,头和源文件,使用这些文件来测试安装。 -PackagingLog.txt是由编译器生成的日志文件。 如果.jar库中的内容不熟悉也可以找到doc下的html文件夹,打开index.html,里面有Javadoc参考资料。” --marine0131
        我们使用for_redistribution_files_only或者for_testing的jar文件进行下一步。
       
        2、先在windows平台上配置环境试验是否可以运行jar
        请配置mcr前一定要把这个官方文档读透,虽然并不能解决很多出错,但是会让你排除很多不对的博客的胡说八道
        https://cn.mathworks.com/help/co ... matlab-runtime.html
        https://cn.mathworks.com/help/co ... va-environment.html
        其中有一点值得注意的是,没装matlab的可以装一个800m到1G的mcr installer,装过matlab(10G)的是不用装mcr的,除非你想使用不同版本的matlab运行时。很多帖子因为出错都同时装了matlab和mcr,虽然最后也成功了,但是都是画蛇添足。
        matlab命令行中执行 mcrinstaller 会出现存放mcrinstaller的目录'C:\Program Files\MATLAB\R2017a\toolbox\compiler\deploy\win64\MCRInstaller.exe'我感觉这是让你拷给别人以便对方没有matlab环境能使用你的程序。如果你没有装matlab,应该 去官网直接下载mcr installer。
        确保环境变量中的Path中包含C:\Program Files\MATLAB\R2017a\runtime\win64;C:\Program Files\MATLAB\R2017a\bin,特别是前者\runtime\win64存放了mcr运行需要的dll库。
        确保不同机器上的matlab版本或者mcr版本一致,否则行不通。

        在eclipse中新建java项目导入生成的jar包和MATLAB的安装目录或者MATLAB Runtime的安装目录下的toolbox\javabuilder\jar\win64\javabuilder.jar
        编写测试代码:
  1. package test;

  2. import java.io.FileNotFoundException;
  3. import java.io.IOException;

  4. import com.mathworks.toolbox.javabuilder.MWException;



  5. import getDbnFeat.*;

  6. public class test {

  7.         public static void main(String[] args) throws FileNotFoundException, IOException {
  8.                
  9.                 DbnFeat matlab;
  10.                 String path=args[0];
  11.                 try {
  12.                         matlab = new DbnFeat();
  13.                         matlab.getDbnFeat(path);
  14.                 } catch (MWException e) {
  15.                         // TODO Auto-generated catch block
  16.                         e.printStackTrace();
  17.                 }
  18.                
  19.         }

  20. }
复制代码

        能注意避开以上可能出现的错误,基本就能正常执行。

        3、在linux服务器上配置环境试验是否可以运行jar
        由于平台差异性,在server上配置还是有很多差异的。
        我再server上配置了jdk1.7,并把tomcat配置从1.8改为了1.7.
        重装了matlab2017a
        装在server端装matlab有几点:
        1、server自身存储一般都很小,linux的matlab默认是装在/usr/local下的,装到一般基本会报内存不足,必须装在/mnt外接硬盘上
        要使用配置文件装:
        创建文件夹 ~/matlabSetup
        在其下创建两个文件 installer_input2.txt and activate.ini.

        In installer_input2.txt:
        destinationFolder=Path/To/Destination/Folder/
        fileInstallationKey=xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
        agreeToLicense=yes
        outputFile=/tmp/matlab.log
        mode=silent
        activationPropertiesFile=~/matlabSetup/activate.ini
        licensePath=~/matlabSetup/license.lic
        product.MATLAB
               
        product.MATLAB这行是设置只安装matlab主程序,默认全安装可以去掉这行。
       
        In activate.ini:
        isSilent=true
        activateCommand=activateOffline
        licenseFile=~/matlabSetup/license.lic

        license.lic文件为crack文件夹中的license-standlone.lic
       
        ssh中执行:

        cd /media/mathworks
        sudo ./install  -mode silent -inputFile ~/matlabSetup/installer_input2.txt

        即可。
       
        配置jdk,确保matlab命令行中输入getenv JAVA_HOME能得到正确的javahome路径。
         和windows一样装有matlab就不用装mcr,但是必须让程序找到runtime库,不配置直接运行jar会报这个最普遍出现的错误:
        Failed to find the library libmwmclmcrrt.so.XXXX
        很多人又装了matlab又装了mcr,然后配置了LD_LIBRARY_PATH解决了问题,官方文档也说要配置LD_LIBRARY_PATH,但是啥也没说一笔带过。
        其实缺什么补什么就可以,使用find / -name libmwmclmcrrt 找到这个so链接文件,然后把路径添加到LD_LIBRARY_PATH,和windows的Path中的runtime\win64是一个作用。
        LD_LIBRARY_PATH不能随便改,这个东西是先与系统默认的库文件加载自定义库文件的,如果先加载了不兼容C库的文件之类的,整个系统都会直接崩掉,并启动不了!(相当于删库跑路,之前有过惨痛教训)
        改了LD_LIBRARY_PATH,ssh上基本就可以运行jar了。
       
        4、编写网站配合tomcat上传运行jar
        接下来就是利用jar配合java编写web后台,然后部署网站了,
        但是,linux的ssh里能运行不一定tomcat里能运行,java后台代码里要利用ProcessBuilder的environment 方法再设置一遍LD_LIBRARY_PATH
        否则web还会报Failed to find the library libmwmclmcrrt.so.XXXX的错。

  1. ProcessBuilder pb = new ProcessBuilder(new String[] { "java", "-classpath", ".:./javabuilder.jar:./getDbnFeat.jar","test","in.txt" }).directory(new File(directory));
  2.                         Map<String, String> env = pb.environment();

  3.                         env.put("LD_LIBRARY_PATH", "/mnt/Matlab/runtime/glnxa64");
  4.                         Process process=pb.start();
  5.                         process.waitFor();
  6.        
复制代码


        最后不知道为啥windows下用eclipse打的调用matlab jar文件和javabuilder.jar生成特征的java代码的jar包,linux上回报错,classpath路径也改成了相对路径,我使用了直接使用linux本地javac编译java执行的方式:
  1. javac -classpath ./javabuilder.jar:./getDbnFeat.jar  ./test.java
  2. java -classpath .:./javabuilder.jar:./getDbnFeat.jar test p1_n1_H.txt
复制代码

        第一行使用javac编译, classpath参数设置依赖(windows用;分割多个依赖包,linux使用:分割多个依赖包)
        第二行利用生成的class文件对输入序列编码特征。
作者: zouquan    时间: 2017-7-29 15:33
赞!!!!




欢迎光临 机器学习和生物信息学实验室联盟 (http://123.57.240.48/) Powered by Discuz! X3.2