首页 > 其他分享 >【Tensorflow】深度模型推理性能优化-微量优化

【Tensorflow】深度模型推理性能优化-微量优化

时间:2023-08-13 23:45:42浏览次数:43  
标签:node name 微量 graph 模型 Tensorflow model 优化 def

说到深度模型优化,可能想到最多的就是上GPU,对于CV、NLP这一类模型效果非常明显,一般RT能下降到原来的1/10。但是在实际中,会遇到一些排序类的模型 例如推荐模型DSMM、ESMM、DIN等模型,这些模型深度一般只有4、5层,上GPU后性能、RT反而下降,猜测原因可能是模型网络简单,导致反复IO,最终降低性能。

如何优化

一般CV、NLP这类网络复杂甚至是大模型,我们的优化方向一般是 tf -> gpu -> onnx -> tensorRT。而上述的小模型可能得用其他一些通用方案,参考文章 。

主要思路大致可以认为:  

  1. 裁剪不必要的节点,缩减图大小
  2. 合并部分节点、参数,缩减图大小
  3. 量化,降低精度

除了文章中提到以上方式,推理性能优化还有包括:

  1. 使用共享Embedding,这个理论上也算是缩减变量
  2. 数值类特征 + boundary 代替分类特征
  3. 缩小Emedding维度
  4. 减少重复特征的输入

对于第2点,分类特征很多时候是使用的string类型,实际在观察模型耗时的过程中会发现,Tensorflow中的ToString Op是非常耗时的。10%的分类特征,如果由String转为Float类型,RT能够下降10%~20%。综合模型效果,可以使用连续性数值特征 + boundary的方式代替直接使用分类特征,理论上这种方式不会降低模型效果。

第3点本质上是降低模型的网络复杂度。实际调优的过程中发现,适当降低embedding dim,不仅可以降低RT,甚至也能优化模型效果。具体多大需要看场景以及性能要求

第4点,参考文章 。这一点在推理侧进行优化,大致思路就是缓存部分特征,降低IO、带宽,最终达到优化整体推理链路的效果。

具体优化操作

开始前准备

在具体优化前,我们需要准备tensorboard,以及对应的tensorflow版本。

tensorboard可以查看模型图结构、模型耗时情况。但是tensorboard对tensorflow版本依赖很高,版本配置不对tensorboard本身不会报错,就是不给显示;对于刚开始配置阶段带来非常大的不方便,多数情况就会止步于此。

这边使用一个个人推荐的tensorboard镜像,部署命令如下:

docker run -d -it -p 8888:8888 -p 6006:6006 -v /root/jupyter:/home/jovyan/work -v /root/tensorboard_log:/tensorboard -e GRANT_SUDO=yes --user root --name=tensorboard jupyter/tensorflow-notebook:tensorflow-2.8.1

docker 启动后,在 jupyterlab 终端执行

pip install tensorboard-plugin-profile=2.8.0

分析模型

图结构

在准备好环境后,我们开始对模型进行分析。以下模型格式都是saved_model,因为这是tf-serving以及其他推理引擎默认的模型格式

import tensorflow as tf
model = tf.saved_model.load('./model')
graph_def = model.signatures['serving_default'].graph.as_graph_def()

# 保存graph_def为.pbtxt文件
tf.io.write_graph(graph_def, '.', 'model.pbtxt', as_text=True)

上述代码就可以将模型图结构保存,然后选取GRAPH页面,上传model.pbtxt 即可产出模型图结构

算子耗时

from tensorflow.profiler.experimental import Profile
import tensorflow as tf

with tf.device('/cpu:0'):
    with Profile('model-infer-log'):
        model = tf.saved_model.load('./model')
        infer = model.signatures['serving_default']
        for input_data in input_datas:
            predictions = infer(**input_data)

使用Profile这个包,会输出一堆的event文件。在tensorboard中,选择profile,按照要求,将这些event文件上传到指定的目录,即可看到每个算子的具体耗时情况。

模型参数

import tensorflow as tf

model_path = "model"

model =  tf.saved_model.load(model_path)
model_graph = model.signatures['serving_default'].graph.as_graph_def()

def describe_graph(graph_def, show_nodes=False):
  # print('Input Feature Nodes: {}'.format(
  #     [node.name for node in graph_def.node if node.op=='Placeholder']))
  # print('')
  print('Unused Nodes: {}'.format(
      [node.name for node in graph_def.node if 'unused'  in node.name]))
  print('')
  # print('Output Nodes: {}'.format( 
  #     [node.name for node in graph_def.node if (
  #         'predictions' in node.name or 'softmax' in node.name or '')]))
  # print('')
  print('Quantization Nodes: {}'.format(
      [node.name for node in graph_def.node if 'quant' in node.name]))
  print('')
  print('Constant Count: {}'.format(
      len([node for node in graph_def.node if node.op=='Const'])))
  print('')
  print('Variable Count: {}'.format(
      len([node for node in graph_def.node if 'Variable' in node.op])))
  print('')
  print('Identity Count: {}'.format(
      len([node for node in graph_def.node if node.op=='Identity'])))
  print('', 'Total nodes: {}'.format(len(graph_def.node)), '')

  if show_nodes==True:
    for node in graph_def.node:
      print('Op:{} - Name: {}'.format(node.op, node.name))
    
describe_graph(model_graph)

上述代码可以计算出当前图有多少变量、参数。优化模型最直观的表现就是参数变少了。

模型优化

prune模型

首先第一步,先确定模型的输出节点是什么。对于多输出模型,这点可能比较重要。在训练时设置的多输出,但是实际推理时可能只需要单输出。删除不需要的输出,可能会导致整个图的访问节点数量大幅度减少,从提升性能。

signature_def = model.signatures['serving_default']
for output in signature_def.outputs:
    print(output.name)

确定好输出节点后,开始优化模型:

from tensorflow.python.tools import freeze_graph
from tensorflow.python.saved_model import tag_constants
import os
def freeze_model(saved_model_dir ,output_node_names, output_filename):
  initializer_nodes = ''
  freeze_graph.freeze_graph(
      input_saved_model_dir=saved_model_dir,
      output_graph=output_filename,
      saved_model_tags = tag_constants.SERVING,
      output_node_names=output_node_names,
      initializer_nodes=initializer_nodes,
      input_graph=None,
      input_saver=False,
      input_binary=False,
      input_checkpoint=None,
      restore_op_name=None,
      filename_tensor_name=None,
      clear_devices=False,
      input_meta_graph=False,
  )
  print('graph freezed!')
    
freeze_model(model_path,"Sigmoid","./freeze.pb")

裁剪模型

from tensorflow.python.tools import optimize_for_inference_lib
from tensorflow.python.framework import dtypes

def optimize_graph(graph_filename, output_nodes):
    return optimize_for_inference_lib.optimize_for_inference(
    input_graph_def=get_graph_def_from_file(graph_filename),
    input_node_names=[],
    output_node_names=output_nodes,
        placeholder_type_enum=dtypes.float32
    )
    

optimize_model_graph = optimize_graph("freeze.pb" , ["Sigmoid"])
describe_graph(optimize_model_graph)

简单的两步,可以都通过上面describe_graph看下模型的具体情况;在优化理想的情况下,节点数量会有大幅度下降。

导出模型

在优化完成后再导出模型

def convert_graph_def_to_saved_model(export_dir, graph_def, signature_def):
    if tf.compat.v1.gfile.Exists(export_dir):
        tf.compat.v1.gfile.DeleteRecursively(export_dir)
    with tf.compat.v1.Session(graph=tf.Graph()) as session:
        tf.import_graph_def(graph_def, name='')
        tf.compat.v1.saved_model.simple_save(
            session,
            export_dir,
            inputs={
                node.name: session.graph.get_tensor_by_name(node.name) for node in signature_def.inputs if tf.dtypes.resource != node.dtype},
            outputs={node.name: session.graph.get_tensor_by_name(node.name) for node in signature_def.outputs }
        )
        print('Optimized graph converted to SavedModel!')

convert_graph_def_to_saved_model("optimized-model",optimize_model_graph, model.signatures['serving_default'])

至此优化完成。需要注意的时,模型的变量经过压缩后,变量名称也发生了变化。因此在推理时,需要注意输入层的key的值。

标签:node,name,微量,graph,模型,Tensorflow,model,优化,def
From: https://www.cnblogs.com/zhouwenyang/p/17627535.html

相关文章

  • 使用conda准备tensorflow环境流程
    requirement.txt是这样写的:tensorflow==2.10.1pandas==1.3.5numpy==1.21.6scikit-learn==1.0.2tqdm==4.64.1absl-py==1.4.0gdown==4.7.1步骤如下1找到tensorflow对应python版本访问官网https://tensorflow.google.cn/install/source#tested_build_configurations,......
  • SAM-U升级SAM | 带你分析SAM的弱点并重新优化设计填补空缺
    前言 最近,SAM向通用人工智能迈出了重要的一步。同时,它的可靠性和公平性也引起了人们的极大关注,尤其是在医疗保健领域。在这项研究中,作者提出了SAM线索的Multi-box即时触发不确定性估计,以证明分割病变或组织的可靠性。作者使用具有先验分布参数的蒙特卡罗来估计SAM预测的分布,使......
  • System.currentTimeMillis()高并发性能优化
    摘要:System.currentTimeMillis()性能问题的研究、测试与优化。  性能优化使用的测试环境:jdk版本jdk8  操作系统:macOS版本:13.2.1芯片:AppleM1CPU核数:8核  System.currentTimeMillis()是Java极其常用的API,广泛地用来获取时间戳或统计代码执行耗时等,在我们的......
  • 拓端tecdat|R语言实现k-means聚类优化的分层抽样(Stratified Sampling)分析各市镇的人
    最近我们被客户要求撰写关于k-means聚类的研究报告,包括一些图形和统计输出。简介假设我们需要设计一个抽样调查,有一个完整的框架,包含目标人群的信息(识别信息和辅助信息)。如果我们的样本设计是分层的,我们需要选择如何在总体中形成分层,以便从现有的辅助信息中获得最大的优势。换句话......
  • sql优化
    sql优化参考博客:SQL优化的几种方法常见的SQL优化方法sql优化的N种方法_持续更新史上最全SQL优化方案sql语句用大写解析sql语句时,把小写的字母转换成大写的再执行对查询进行优化,应尽量避免全表扫描,首先考虑在where及orderby上建立索引。应尽量避免在where子句中进行以......
  • 斜率优化DP
    前置芝士单调队列优化DP⌈写不动数据结构呜呜呜,先来补这个⌋对于一个DP,我们想优化祂的⌈转移⌋有些题目的可选状态有以下特征需要寻找最值可选状态区间平移存在可以永久去除的多余状态感性的讲,可行性是一个滑动窗口,状态两两之间都可以⌈直接比较出优劣......
  • 如何用随机方法求解组合优化问题(一)
    什么是组合优化问题定义优化问题设\(x\)是决策变量,\(D\)是\(x\)的定义域,\(f(x)\)是指标函数,\(g(x)\)是约束条件。则优化问题可以表示为求解满足\(g(x)\)的\(f(x)\)最小值问题。即:\[\min_{x\inD}(f(x)|g(x))\]组合优化问题如果在定义域\(D\)上,满足约束条件......
  • 10 张图帮你搞定 TensorFlow 数据读取机制
    一、tensorflow读取机制图解首先需要思考的一个问题是,什么是数据读取?以图像数据为例,读取数据的过程可以用下图来表示:假设我们的硬盘中有一个图片数据集0001.jpg,0002.jpg,0003.jpg……我们只需要把它们读取到内存中,然后提供给GPU或是CPU进行计算就可以了。这听起来很容易,但事实远没有......
  • 【BP回归预测】基于粒子群算法优化BP神经网络实现数据回归预测附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 国标GB28181视频平台LntonGBS(源码版)国标视频平台在网络不稳定的强况下重复申请视频拉
    LntonGBS是基于国标GB28181协议的视频云服务平台,支持将国标协议的设备统一接入并进行集中管理。平台具备优秀的视频能力,包括视频监控直播、录像、云存储、回放、平台级联、语音对讲、智能告警等功能,在线下场景中已有大量落地应用。我们在项目测试中发现,LntonGBS通过web页面请求拉流......