1、深度模型为什么需要部署在spark?
现在很多依赖于TensorFlow、PyTorch等深度学习框架训练的模型,都需要GPU的支持。训练好以后需要部署上线,如果是在线模块就需要将模型部署在serving上,但如果是离线模块且预测数据量较大的情况,使用GPU去预测速度就显得比较慢。这时就可以考虑将深度模型部署在spark上,利用深度学习框架的CPU计算方式。尽管CPU的计算相比GPU慢很多,但spark的并发计算能力是远超过GPU的,通过扩大和缩小spark使用的partition数量,就可以自由调整整体运行速度。
2、深度模型如何部署在spark?
深度模型在部署前,需要将该模型的训练python环境打包为tf2_spark.tar.gz
上传到HDFS,同时需要将模型打包为zip保存在当前路径(打包必须进入model_name目录内执行zip -r ../${model_name}.zip *
),在spark提交配置中修改spark.yarn.dist.archives
和spark.yarn.appMasterEnv.PYSPARK_PYTHON
如下:
spark-submit \
--queue ${yarn_queue} \
--deploy-mode cluster \
--conf spark.yarn.dist.archives="hdfs://difed/user/name/tf2_spark.tar.gz#mypython,${model_name}.zip#${model_name}" \
--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON="./mypython/tf2_spark/bin/python" \
--py-files model_builder.py \
inference.py ${input_path} ${output_path} ${model_name}
在python文件inference.py中,需要人为指定sc.pythonExec
,这样整个环境就配置完成了。需要注意的是,spark driver的python环境中不必安装TensorFlow,因为执行预测的环境都在executor中且是我们指定的PYSPARK_PYTHON
,因此import和构建模型的过程全部放在inference_batch
这个map函数中,避免在driver中执行报错。
from pyspark.sql import SparkSession
import sys
spark = SparkSession \
.builder \
.appName("spark_inference") \
.master("yarn") \
.config("spark.driver.memory", "4g") \
.config("spark.executor.memory", "13g") \
.config("spark.dynamicAllocation.maxExecutors", 200) \
.config("spark.dynamicAllocation.minExecutors", 100) \
.config("spark.executor.cores", 4) \
.config("spark.port.maxRetries", 100) \
.config("hive.exec.dynamic.partition", "true") \
.config("hive.exec.dynamic.partition.mode", "nonstrict") \
.enableHiveSupport() \
.getOrCreate()
def inference_batch(x_iter, model_dir):
import tensorflow as tf ## 在executor指定的python环境执行
import model_builder
model = model_builder.get_keras_model()
latest_cp = tf.train.latest_checkpoint(model_dir)
model.load_weights(latest_cp)
x = process_input(x_iter)
pred = model.predict(x, batch_size=1024)
pred = ','.join([str(p) for p in pred])
return pred
def inference(input_path, output_path, model_name):
sc = spark.sparkContext
sc.pythonExec = spark.conf.get("spark.yarn.appMasterEnv.PYSPARK_PYTHON")
sc.textFile(input_path, minPartitions=1000) \ ## 并行数可以自由调整,但不能有空partition
.mapPartitions(lambda x: inference_batch(x, model_name)) \
.saveAsTextFile(output_path)
if __name__ == '__main__':
input_path, output_path, model_name = sys.argv[1: 4]
inference(input_path, output_path, model_name)