Py4j-RPC

python 使用灵活、方便在科研中被广泛的使用,Numpy和SciPy等科学计算库使其拥有强大的计算方式。很多机器学习和深度学习的库也都采用了python,然而在大数据、后台开发中仍然较多的使用Java来开发健壮的服务。如果你想要在Java中来调用Python代码的话,本文提供了一种思路,虽然不够健壮。

本文的初衷是在Java中调用Keras训练好的深度学习模型进行inference,模型的输入是Numpy数组。主要考虑几点:1).Java这边可以方便的打包成Jar包,方便部署,比如作为 spark 的 job 运行。2). Python这边如果要安装额外的库,安装方式越简单越好。
针对1).首先考虑的有deeplearning4j,可以通过maven使用。其次是Jython,Jep等工具提供了Java直接运行python代码的功能;再其次是完全通过网络来传递参数获取返回结果。另外,可考虑的是如果采用了Tensorflow训练模型,可以保存为Tensorflow模型,然后使用Java接口直接来调用。

deeplearning4j

deeplearning4j是一个Java语言的深度学习库,其能够与Spark框架对接。并且提供了导入keras模型的功能,然而对keras模型的支持并不完善,很多层还没有实现,尤其是keras2的出现,deeplearning4j支持情况很差。

Jython

Jython是纯Java实现的Jython VM。Jython在import 一个Python文件的时候,会编译生成.class文件,而不是.pyc文件。
使用Jython可以运行纯python实现的python库,无法使用用C写的Python扩展库,因为没有在ABI层兼容CPython。
Jython调用第三方的库,如自己编写的库,需要将包路径添加到sys.path中。
maven:

<dependency>    <groupId>org.python</groupId>    <artifactId>jython-standalone</artifactId>    <version>2.7.1</version></dependency>

Jep 是一个能够让Python和Java互相调用的软件包。可以使用CPython的扩展包,如Numpy和Pandas。其可以将Java的数组自动转换为numpy数组。
在使用pip install jep安装时需要编译本地模块。


RPC

对上面的工具都不满意,只能走一些其它路子了。想到跨语言、跨平台、数据交换等概念时自然容易想到JSON、XML、RPC这些词。那么采用远程过程调用是一种不错的方式。各种语言都有远程过程调用的工具,如Java的RMI,对象被序列化后通过网络传输。序列化可以是任意形式,JSON、XML或者自定义的格式。JSON-RPC-2.0的规范定义比较简单,可以为我们所使用。

RPC-server (Python)

建立TCP server监听连接,在每个连接中按照JSON-RPC 2.0规范解读和发送内容。建立函数名称到函数的map,这些函数供Java调用。函数的参数需要是一些基本类型,如果原来的参数是numpy数组,可以改成一维数组,再加额外个参数表示维度信息,如行数和列数。然后在函数中进行reshape,复制到numpy数组。

RPC-client (Java)

建立到RPC-server的socket连接,使用com.thetransactioncompany.jsonrpc2包向RPC-server发送请求。
参数传递可以使用Java的Map,会映射到Python的dict。

链接

  • 本文代码地址: github.com/makefile/py4j-rpc
  • https://scito.ch/content/fast-remote-procedure-calls-python-introducing-new-json-rpc-stream-protocol
  • http://software.dzhuvinov.com/json-rpc-2.0-base.html
  • https://ws.apache.org/xmlrpc/client.html
  • http://archive.apache.org/dist/ws/xmlrpc/