基于PySpark的深度学习模型(CPU版)推理项目
一 目的
针对图数据量较大,利用深度模型进行推理耗时严重的问题,充分利用分布式平台可多核并行推理的优势,实现分布式推理流程。
二 方法
主要思路:
① 模型封装:将模型推理方法封装成python 库的架包
② 安装架包:将该架包安装到项目所需的python环境中
③ 打包环境:打包环境上传到分布式平台
④ 分布式调用:利用该环境运行分布式推理代码
1. 模型封装
(1) 在自己项目下编写setup.py文件
示例目录结构如下:
NE|-- ne_predict| -- __init__.py| -- weights_128_1482.hdf5| -- model_config.json| -- predict_emb.py|-- MANIFEST.in-- setup.py |
对于项目中包含的其它资源文件(如模型、配置文件、词表等)。在执行setup之前,新建名为"MANIFEST.in"的文件,将这些资源文件按以下形式写入该文件:
MANIFEST.in
include ne_predict/* |
(2) init.py文件简单示例
from .predict_emb import Predictions |
(3)predict_emb.py文件简单示例
import jsonimport numpy as npimport osfrom tensorflow.keras.models import Model, model_from_json# NE推理class Predictions(): #将模型读取及配置放到init方法里,避免多次加载 def __init__(self): # 读取模型配置 self.base_path = os.path.dirname(__file__) self.model_name = "weights_128_1482.hdf5" self.model_config = "model_config.json" with open(os.path.join(self.base_path,self.model_config),'r',encoding='utf8') as fp: self.json_data = fp.readlines()[0] # 获取模型配置信息 self.model = model_from_json(self.json_data) self.model.load_weights(os.path.join(self.base_path,self.model_name)) # 使用数据进行推理 self.init_model = Model(inputs=self.model.input,outputs=self.model.get_layer('hidden_1').output) # 按照自身业务解析数据、调用模型进行推理、返回推理结果 def predict(self,predict_data): # 解析数据 degree = predict_data["degree"] md5 = predict_data["md5"] name = predict_data["name"] predict_data_array = np.array([degree]) # 使用训练模型对推理数据进行推理 # result = init_model.predict(predict_data_array, batch_size=batch_size, max_queue_size=1, workers=workers, use_multiprocessing=False) _result = self.init_model(predict_data_array) result = _result.numpy().tolist()[0] rst = {"md5":md5,"degree":result,"name":name} return rst |
(4) setup文件简单示例
import setuptoolssetuptools.setup( name="ne_predict", # 必选参数 author='Qianxin', # 可选参数 author_email='', # 可选参数 version = "1.0.1", # 必选参数,版本信息根据自己的需求进行管理 description="Neighbor_Encoder Predictions", # 可选参数 url='', # 可选参数 license="Apache-2.0", # 可选参数 packages=setuptools.find_packages(), # 必选参数,自动查找包含__init__.py的目录 include_package_data=True, # 可选参数 install_requires=["tensorflow>=2.4.1", "numpy>=1.19.2"], # 可选参数,安装本项目所需依赖 eg:["grpcio>=1.47.0", "ujson>=2.0.0,<=5.4.0", "pandas==1.1.5; python_version<'3.7'", "pandas>=1.2.4; python_version>'3.6'",] classifiers=[], # 可选参数,程序的所属分类列表 eg:["Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8",], python_requires='>=3.7.13', # 可选参数,安装本项目所需python版本) |
(5) 压缩
切换到自己项目所需python环境,执行命令进行压缩,生成python可执行文件。
python setup.py bdist_wheel |
2. 安装架包
执行压缩后,生成python可执行文件,示例目录结构如下:
NE|-- build|-- dist| -- ne_predict-1.0.1-py3-none-any.whl|-- ne_predict| -- __init__.py| -- weights_128_1482.hdf5| -- model_config.json| -- predict_emb.py|-- ne_predict.egg-info|-- MANIFEST.in-- setup.py |
切换到dist目录下,执行安装包文件。
pip install ne_predict-1.0.1-py3-none-any.whl |
如果后续对封装的内容有修改,可先卸载已安装的封装架包,然后重新打包再安装。
3. 打包环境
切换到自己项目运行所需的环境目录,对环境进行打包并上传到分布式平台。
tar -zcvf py3.7_ne1.0.tar.gz py3.x(环境名称) |
hdfs dfs -copyFromLocal py3.7_ne1.0.tar.gz /home/hdp-ait/xxx |
4. 分布式调用
封装分布式推理方法,如示例中的spark_predict方法,该方法中初始化推理模型对象,然后利用mapPartitions方法实现分布式推理。
import pickleimport osimport timeimport argparseimport jsonimport gzipimport jsonimport numpy as npimport syssys.path.append(os.path.dirname(os.path.dirname(__file__)))from pyspark import SparkConf,SparkContextfrom pyspark.sql.session import SparkSessionfrom ne_predict import Predictions# 分布式推理def spark_predict(predict_data): result = [] # 创建对象 predictions = Predictions() # 按照分区迭代推理 for data in predict_data: predict_rst = predictions.predict(data) result.append(predict_rst) return iter(result)if __name__ == '__main__': # 读取配置文件和用户在命令行输入的信息 conf = SparkConf().setAppName("embedding_data") sc = SparkContext(conf=conf) spark=SparkSession(sc) spark.conf.set("spark.sql.crossJoin.enabled","true") # 对推理数据进行预处理 begin = time.time() # 读取数据 2.47亿 embedding_df = spark.read.json("/home/hdp-ait/tianye02/domainFilter_new/domainFilterRes") print("Number of embedding_df: ", embedding_df.count()) end = time.time() print('process data time: '+str(end-begin)+'s. ') # 使用模型进行推理 begin = time.time() embedding_rdd = embedding_df.rdd.repartition(3000) # print("partitions:", embedding_rdd.getNumPartitions()) predict_begin = time.time() _predict_result_rdd = embedding_rdd.mapPartitions(spark_predict) # output results to files predict_result_rdd = _predict_result_rdd.repartition(1000) predict_result_rdd_df = predict_result_rdd.toDF() predict_end = time.time() print('predict data time: '+str(predict_end-predict_begin)+'s. ') predict_result_rdd_df.write.format("json").mode("overwrite").options(compression="gzip").save("/home/hdp-ait/wangwei22/0202_03") end = time.time() print('predict time: '+str(end-begin)+'s. ') |
提交任务到分布式平台
spark-submit --master yarn --keytab /home/wangwei22/.wangwei22.keytab --principal wangwei22 --queue root.hdp_ait --deploy-mode cluster --driver-memory 14G --num-executors 200 --executor-memory 14G --executor-cores 1 --archives hdfs:/home/hdp-ait/wangwei22/py3.7_ne1.0.tar.gz#py3.7 --conf spark.pyspark.driver.python=./py3.7/py3.7/bin/python3 --conf spark.pyspark.python=./py3.7/py3.7/bin/python3 predict.py
spark-submit --master yarn --keytab /home/wangwei22/.wangwei22.keytab --principal wangwei22 --queue root.hdp_ait --deploy-mode cluster --driver-memory 14G --num-executors 200 --executor-memory 14G --executor-cores 1 --archives hdfs:/home/hdp-ait/wangwei22/py3.7_ne1.0.tar.gz#py3.7 --conf spark.pyspark.driver.python=./py3.7/py3.7/bin/python3 --conf spark.pyspark.python=./py3.7/py3.7/bin/python3 predict.py

浙公网安备 33010602011771号