问题背景:当数据科学从业者在线下通过TensorFlow/Keras将神经网络模型训练出来之后,因为线上使用Java进行工程实现而与模型无法良好对接,导致形成了工程和策略之间的gap。
本文主要探讨尝试了几种可能的解决方案以及相对应的结果和优缺点。
结论优先
- Java分布式方案:笔者尝试的方式中,暂时没有能有效对接TensorFlow/Keras模型和线上分布式Java Based Spark(下文中均用JBS替代)的交互模式。(如有可行方式,欢迎在留言中探讨)
- Python/Java分布式方案:JBS处理的中间数据通过HDFS和Pyspark/Java对接处理,通过TensorflowOnSpark/Java Tensorflow将Tensorflow模型分布式部署到集群节点中进行工程化预测。
- Java单节点方案:JBS处理的中间数据通过在单节点GPU上,通过Java Based Tensorflow对数据进行处理之后返回JBS分布式处理。
- Java分布式(手动)方案:将Java Based Tensorflow手动部署到集群节点,JBS通过调用集群节点程序方式通过模型预测实现分布式。
Java分布式方案尝试经验
1. 采用PMML文件对接策略模型和线上工程:
-
Keras:
- 方式:通过keras2pmml项目对keras模型转换到pmml文件格式,然后跟java对接。
- 问题:该项目已经很久没人维护升级,版本停留在0.1.主要能支持一些DNN结构模型,对RNN和CNN等更复杂的结构模型无法进行正确转换,需要修改大量源代码。
- 改进方案:部分activation类型改进方案-如何把神经网络keras模型转PMML文件?
-
结论:对复杂神经网络模型不可行。
-
Tensorflow:
-
方式:采用jpmml-tensorflow项目,将keras模型转换为tensorflow的savemodel类文件之后,通过github项目代码进行转换为pmml文件。
-
如何将keras模型转换为savemodel类:
model = keras.models.load_model("model.h5") sess = keras.backend.get_session() builder = tf.saved_model.builder.SavedModelBuilder(saved_model_dir) builder.add_meta_graph_and_variables(sess, ['serve']) builder.save()
-
- 问题:该项目支持的模型种类也只有DNN,并不支持CNN或者RNN等更复杂的模型。所以中间会报模型种类无法找到illegal的error。
-
结论:对复杂神经网络模型也不可行。
-
方式:采用jpmml-tensorflow项目,将keras模型转换为tensorflow的savemodel类文件之后,通过github项目代码进行转换为pmml文件。
-
结论:
- PMML工程方案对于复杂神经网络的支持性不完善,但对于简单的神经网络以及其他传统机器学习模型来说,PMML方式因为其通用性,是良好的算法和工程衔接的桥梁。
- PMML工程方案对于复杂神经网络的支持性不完善,但对于简单的神经网络以及其他传统机器学习模型来说,PMML方式因为其通用性,是良好的算法和工程衔接的桥梁。
2. Deeplearning4J方式转换模型应用:
-
Keras:
- 方式:采用deeplearning4j的方式,将模型文件通过deeplearning4j方式导入java,再通过JBS进行预测处理。
-
问题:
- 项目对Keras 2.0的支持处于beta版本,会对一些神经网络层出现bug,比如像ELU层会报错。所以使用的时候,或者去除ELU等有问题神经网络层,或者采用Keras 1.0进行构建网络。
- 在进行JBS分布式预测的时候,出现了一些网络结构无法解析的错误,猜测可能是因为在spark集群的序列化和反序列化过程中出现了问题。但deeplearning4j官网架构图显示其对于Spark的支持,所以不确定是否是使用方式问题导致了分布式出现模型结构解析问题。
-
结论:在分布式(可能是序列化过程中)结构中,deeplearning4j项目还存在一些问题,无法与JBS正常兼容。
3. Java Based Tensorflow方式应用模型:
-
Keras/Tensorflow:
-
步骤一:将keras模型先转换为tensorflow静态图模型文件,.pb格式或者ckpt格式。(ckpt与pb的异同:Tensorflow学习笔记-模型保存与加载)
-
如何将keras模型转换为ckpt文件类型:
model = keras.models.load_model("model.h5") sess = keras.backend.get_session() saver = tf.train.Saver() save_path = saver.save(sess, "/tmp/model.ckpt")
如何将keras模型转换为pb文件类型:
keras模型保存为tensorflow的二进制模型
-
步骤二: 然后通过Java Based Tensorflow读取pb文件,对数据进行预测。(关于java如何调用tensorflow模型例子:TensorFlow-Java-Examples)
-
问题:
- 单机的情况下,可以采用java来调用tensorflow。
- 分布式的情况下,由于tensorflow底层是cpp,所以在序列化打包和反序列的时候会出现问题,导致分布式节点机器无法正常调用。
- 所以只有在单机情况下才能跟java兼容。或者分布式采用pyspark中的tensorflowonspark包或者通过预先在分布式集群节点中部署本地tensorflow服务,然后java远程调用tensorflow服务来实现手动分布式
-
各方案优缺点:
-
Pyspark/Java分布式:
- 优点:通过TensorflowOnSpark/Java Tensorflow可以实现Tensorflow在分布式集群上的工程化部署。
- 缺点:与线上JBS交互需要通过HDFS做中间层,文件IO的效率会影响线上工程服务的速率。
-
Java单机:
- 优点:跟线上Java工程兼容,无需HDFS的IO。
- 缺点:需要使用GPU机器提升单机预测效率,没有利用分布式集群,性价比相对较低。
-
Java手动分布式:
- 优点:利用分布式集群资源,且跟线上工程Java兼容。
- 缺点:手动部署集群效率太低。