基于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 json import numpy as np import os from 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 setuptools setuptools.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 pickle import os import time import argparse import json import gzip import json import numpy as np import sys sys.path.append(os.path.dirname(os.path.dirname(__file__))) from pyspark import SparkConf,SparkContext from pyspark.sql.session import SparkSession from 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