Deeplearning4j 实战(3):简介Nd4j中Java与CPP技术的应用【转】
来源:互联网 发布:淘宝论文查重可靠吗 编辑:程序博客网 时间:2024/06/06 01:40
from:http://blog.csdn.net/wangongxi/article/details/54970231
Deeplearning4j中张量的计算是由一个叫Nd4j的库来完成的。它类似于Python中的numpy,对高维向量的计算有比较好的支持。并且,为了提高运算的性能,很多计算任务是通过调用C++来完成的。具体来说,底层C++运行张量计算可以选择的backend有:BLAS,OpenBLAS, Intel MKL等,上层Java逻辑是通过JavaCPP技术来调用这些库。JavaCPP是也是一个开源库(https://github.com/bytedeco/javacpp),和大部分其他JNI的技术一样,它的目的也是为了实现JVM on-heap memory 到 off-heap memory的映射和操作。它通过一些助记符可以将自己编写的C++类或者C++标准库中文件进行编译并自动生成C++ JNI代码,不需要手动编写。到目前为止,JavaCPP已经封装了包括OpenCV,ffmpeg等多个优秀的C++项目,方便了很多Java程序员对这些开源库的调用。小弟我自己看到网上对于JavaCPP的使用介绍并不是特别多,所以写了这篇博客,简单介绍下JavaCPP的基本使用,作为一篇入门的文章供大家参考,其中代码在windows 7上可以正常运行。
使用JavaCPP技术主要可以分为以下几个步骤:
1.编写Java的逻辑代码:可以是自己实现的Java类,也可以通过助记符引用C++的标准库
2.编译你所写的Java文件,生成字节码文件
3.运行步骤2中生成的字节码文件,自动生成C++ JNI代码
4.利用步骤3中生成的JNI代码,生成本地共享库/动态链接库
5.指定shared library路径,加载shared library并运行字节码(自动调用shared library)
由于C++中有很多高效的算法实现,比如排序、查找、全排列等等,而且据我了解Java中并没有全排列算法的实现,所以这里就结合以上说的5个步骤,以Java调用C++中的全排列算法(next_permutataion)为目标来具体说说JavaCPP技术的应用。
首先,我们在IDE环境中新建一个Maven工程,加入JavaCPP的Maven依赖如下:
然后,在工程中新建Java文件,代码如下:对于这段代码我做一些补充解释。@Platform和@Namespace都是对应于C++里的一些概念或语言特性做的Java级别的支持。目的也是简化JNI C++代码的开发,当后面编译生成JNI文件的时候,这些信息都会自动添加到.cpp文件中。代码中的sort和next_permutation是对应于C++标准库中的这两个算法的名称,也就是快速排序和全排列算法。注意,名称务必保持一致。在声明这两个方法的时候,IntPointer是作为入参的。它其实是C++指针的一个wrapper。在C++中,算法的入参一般是迭代器,当然指针也是一种迭代器,或者说迭代器是指针一种wrapper。这里我们的目的是对整型数组进行排序和全排列。在main方法中,就是具体的逻辑了。有一点要注意,就是必须先声明end IntPointer再声明begin IntPointer。原因我在最后会做些分析。
接下来,我们对Java代码进行编译,生成字节码文件。具体的命令是:javac -cp javacpp-1.3.1.jar cppalgo/Algorithm.java。这个命令在控制台完成,或者用IDE的outputjar应该也行。结果会生成.class文件。javacpp-1.3.1.jar这个jar包,就是Maven依赖加入后,从Maven仓库里下载的jar。
再接下来,我们生成C++ JNI文件。具体的命令是:java -jar javacpp-1.3.1.jar cppalgo.Algorithm。一般来说,运行这个命令它首先会生成JNI C++文件,然后调用C++编译器生成shared library。但是,在windows上,自动链接编译器,貌似是蛮麻烦的还容易配置出错。所以,实际上运行这个命令后,是可以生成.cpp文件,但也会报连接编译器的错误:
虽然报了错,但JNI的CPP文件是正常生成的,如下图中的红框:
既然我们有了JNI的C++文件,那么其实我们可以利用编译器,比如Visual Studio来对其进行编译生成shared library。我们在VS中新建dll项目(具体这里不详细讲了,和一般的dll项目一样,可网上查阅),项目命名为jniAlgorithm,也就是和生成的C++文件同名。将之前生成的JNI C++文件拷贝到项目的源文件目录中,并加上这一句:
此外,由于编译的时候需要调用jni.h之类的头文件,所以需要在项目的头文件引用配置中,将JDK中jni.h所在的目录路径添加进去。我自己的在VS2012中的额外头文件配置路径如下:此外,如果是64位的系统,还需要将整个项目配置成64位的dll输出,具体可网上搜索相关内容。
然后编译整个项目,如果成功,就会生成shared library,也就是windows平台上的dll文件。我这边生成的文件如下:
到此,整个工作已经接近完成。最后,在Java IDE中,执行那个文件,当然最好加上这一句:-Djava.library.path=动态链接库路径。也就是指定刚才动态链接库生成的路径,这样程序就可以找得到那个dll文件。执行的结果如下:
我们看到,无论是排序还是全排列,结果都符合我们的预期。也就是说,到此为止,一个简单的JavaCPP应用就完成了。最后,我说下可能存在的坑:
1.之前讲的,end Pointer需要比begin Pointer先声明的原因:在程序中,调用的position接口会改变指针的位置,并且这个位置信息会传到C++中。因此,要先声明end Pointer。
2.Pointer的get方法:将off-heap memory中的数据copy到on-heap中,这步不可缺少。
3.Pointer中存在deallocate方法,用于释放C++的内存。但是,Java中对象并不会被立刻gc,其实也不可能被立刻gc
总结一下。其实在Java调用C++的场景在算法中还是比较多的。原因可能在于
1.已经有很多高效的C++的算法库存在,如opencv等等
2.理论上,C++的执行效率会高于Java。毕竟JVM有些操作也是通过调用C++来做的。因此直接将大量运算就放在off-heap上进行,也是一种选择
3.内存利用率可能会更高。C++的缺点在于程序员需要自己管理内存,管理不当,可能会造成内存泄漏。但是这恰恰也是其有点,因为及时地释放内存,可以提高使用效率。不像Java,基本只能依赖gc。
- Deeplearning4j 实战(3):简介Nd4j中Java与CPP技术的应用【转】
- Deeplearning4j 实战(3):简介Nd4j中JavaCPP技术的应用
- 深度学习Deeplearning4j 入门实战(3):简介Nd4j中JavaCPP技术的应用
- Deeplearning4j 实战 (11):基于Nd4j的线性回归模型的实现
- Deeplearning4j 实战(1):Deeplearning4j 手写体数字识别【转】
- Deeplearning4j 实战(2):Deeplearning4j 手写体数字识别Spark实现【转】
- Deeplearning4j 实战(1):Deeplearning4j 手写体数字识别
- Deeplearning4j 实战(2):Deeplearning4j 手写体数字识别Spark实现
- java深度学习(一)Maven创建一个新的ND4J工程
- 用于WEB应用的Java技术简介
- .c与.cpp的应用
- Deeplearning4j 实战(4):Deep AutoEncoder进行Mnist压缩的Spark实现
- Deeplearning4j 实战(5):基于多层感知机的Mnist压缩以及在Spark实现
- Deeplearning4j 实战(6):基于LSTM的文本情感识别及其Spark实现
- 深度学习Deeplearning4j 入门实战(4):Deep AutoEncoder进行Mnist压缩的Spark实现
- 深度学习Deeplearning4j 入门实战(6):基于LSTM的文本情感识别及其Spark实现
- Deeplearning4j 实战 (9):强化学习 -- Cartpole任务的训练和效果测试
- Deeplearning4j 实战(6):基于LSTM的文本情感识别及其Spark实现
- alsa-lib 交叉编译以及声卡驱动测试
- 块级元素,行内元素,空(void)元素
- 第二天学习python
- LeetCode 62. Unique Paths
- spark 入门
- Deeplearning4j 实战(3):简介Nd4j中Java与CPP技术的应用【转】
- POJ 3404 Bridge over a rough river 再想想
- Python基础知识实例讲解
- java web工程中关于redirect重定向和forward页面转发的区别
- Shiro 认证
- linux线程基础
- 2.2-2.5 变量和类型
- 航空售票系统
- 孤儿进程与僵尸进程