当前位置: 首页 > news >正文

站长交流平台微信商城开发用华网天下卓越

站长交流平台,微信商城开发用华网天下卓越,网络架构师主要做什么,wordpress固定心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会#xff0c;与大家一起成长。具体介绍#xff1a;仓颉专项#xff1a;飞机大炮我都会#xff0c;利器心法我还有。 2023年新一版的文章合集已经发布#xff0c;获取方式看这里#xff1a;又添十万字-CS的陋室2… 心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会与大家一起成长。具体介绍仓颉专项飞机大炮我都会利器心法我还有。 2023年新一版的文章合集已经发布获取方式看这里又添十万字-CS的陋室2023年文章合集来袭更有历史文章合集欢迎下载。 往期回顾 心法利器[102] | 大模型落地应用架构的一种模式心法利器[103] | 大模型bad case修复方案思考心法利器[104] | 基础RAG-向量检索模块含代码心法利器[105]  基础RAG-大模型和中控模块代码含代码心法利器[106]  基础RAG-调优方案 假期想着补点遗漏的知识所以选择了模型加速这块的工作这块我的深度肯定是不够的不过尝试动手做做实践收获还是不小而且形成一些自己需要的组件还是挺有用的所以记录一下。 目录 加速整体思路。环境和加速前准备。onnx加速。tensorRT加速。速度测试。 这里的很多代码都有参考这篇文章我特别摆在这里https://blog.csdn.net/m0_37576959/article/details/127123186感谢社区大佬的贡献。 加速整体思路 现在其实已经有大量的工具可以用来进行加速早在bert是主流的时代就已经有研究很多有关的技术了。今天所介绍的onnx和tensorRT也都是这个时代的产物后续成为这个时代的主流和代表性方案而且随着逐步迭代他们的封装也逐步变得简单让我们使用的难度也变低了不少。 目前这两者的加速思路其实也比较类似即主要分为两块 模型的重新编译使之转化为更适用于推理的格式并将其进行保存。加载保存的模型并用其进行推理。 因此我们核心需要做的就是上面两步的开发。 环境和加速前准备 无论是onnx和tensorrt因为加速依赖底层硬件和操作系统所以环境配置成了繁杂但不可绕开的工作此处我先把我目前的环境列举出来给大家提供参考 windows1116G内存i9-13900HXNVIDIA GeForce RTX 4070 Laptop GPU显存8G专用8G共享。CUDA Version: 12.3CUDNNcudnn-windows-x86_64-8.9.6.50_cuda12python3.9.13。torch2.1.2cu121transformers4.33.2onnx1.15.0onnxruntime1.16.3onnxruntime-gpu1.17.0基本直接pip install即可。tensorRTtensorrt-8.6.1.6.windows10.x86_64.cuda-12.0tensorrt8.6.1。 tensorrt环境配置可以参考这篇文章https://blog.csdn.net/KRISNAT/article/details/130789078核心流程如下 从NVIDIA官网上找到自己合适的版本解压。配置好环境变量同时有些文件要复制到cuda内。找到合适的python whl包进行安装。 环境配置好了肯定就还需要有原料了即需要加速的模型和原始推理方案这里我选择的是心法利器[104] | 基础RAG-向量检索模块含代码中提到的simcse模型。原始的加载和推理是这样的 import torch import torch.nn as nn import torch.nn.functional as F from loguru import logger from tqdm import tqdm from transformers import BertConfig, BertModel, BertTokenizerclass SimcseModel(nn.Module):# https://blog.csdn.net/qq_44193969/article/details/126981581def __init__(self, pretrained_bert_path, poolingcls) - None:super(SimcseModel, self).__init__()self.pretrained_bert_path  pretrained_bert_pathself.config  BertConfig.from_pretrained(self.pretrained_bert_path)self.model  BertModel.from_pretrained(self.pretrained_bert_path, configself.config)self.model.eval()# self.model  Noneself.pooling  poolingdef forward(self, input_ids, attention_mask, token_type_ids):out  self.model(input_ids, attention_maskattention_mask, token_type_idstoken_type_ids)return out.last_hidden_state[:, 0]class VectorizeModel:def __init__(self, ptm_model_path, device  cpu) - None:self.tokenizer  BertTokenizer.from_pretrained(ptm_model_path)self.model  SimcseModel(pretrained_bert_pathptm_model_path, poolingcls)self.model.eval()# self.DEVICE  torch.device(cuda if torch.cuda.is_available() else cpu)self.DEVICE  devicelogger.info(device)self.model.to(self.DEVICE)self.pdist  nn.PairwiseDistance(2)def predict_vec(self,query):q_id  self.tokenizer(query, max_length  200, truncationTrue, paddingmax_length, return_tensorspt)with torch.no_grad():q_id_input_ids  q_id[input_ids].squeeze(1).to(self.DEVICE)q_id_attention_mask  q_id[attention_mask].squeeze(1).to(self.DEVICE)q_id_token_type_ids  q_id[token_type_ids].squeeze(1).to(self.DEVICE)q_id_pred  self.model(q_id_input_ids, q_id_attention_mask, q_id_token_type_ids)return q_id_preddef predict_vec_request(self, query):q_id_pred  self.predict_vec(query)return q_id_pred.cpu().numpy().tolist()def predict_sim(self, q1, q2):q1_v  self.predict_vec(q1)q2_v  self.predict_vec(q2)sim  F.cosine_similarity(q1_v[0], q2_v[0], dim-1)return sim.cpu().numpy().tolist() 这里是有两个类分别是SimcseModel和VectorizeModel前者是模型类后者是应用类为什么这么分在这篇文章里有提及这里不赘述心法利器[104] | 基础RAG-向量检索模块含代码当然后面用加速模型推理的时候大家也会发现这个代码设计的优点。 另外值得强调的是早期版本的onnx对if的算子支持的不是很好所以大家尽量不要在模型类内增加这个if这个还是比较常见的所以特别说明。 onnx加速 加速的第一步是生成新编译好的模型文件这部分还是偏简单的直接照着写基本就可以了。 import torch from transformers import BertTokenizer from src.models.vec_model.simcse_model import SimcseModel# Reference: https://blog.csdn.net/m0_37576959/article/details/127123186 # ------------模型编译---------- # 1. 必要配置 MODEL_PATH  C:/work/tool/huggingface/models/simcse-chinese-roberta-wwm-ext MODEL_ONNX_PATH  ./data/model_simcse_roberta_output_20240211.onnx DEVICE  torch.device(cuda if torch.cuda.is_available() else cpu)# 2. 模型加载 tokenizer  BertTokenizer.from_pretrained(MODEL_PATH) model  SimcseModel(pretrained_bert_pathMODEL_PATH, poolingcls) # OPERATOR_EXPORT_TYPE  torch._C._onnx.OperatorExportTypes.ONNX model.eval() model.to(DEVICE)# 3. 格式定义 query  你好 encodings  tokenizer(query, max_length  200, truncationTrue, paddingmax_length, return_tensorspt) input_info  (encodings[input_ids].to(DEVICE),encodings[attention_mask].to(DEVICE),encodings[token_type_ids].to(DEVICE)) # model(input_info)# 4. 模型导出 output  torch.onnx.export(model,input_info,MODEL_ONNX_PATH,verboseFalse,export_paramsTrue,#    operator_export_typeOPERATOR_EXPORT_TYPE,opset_version12,input_names[input_ids, attention_mask, token_type_ids],  # 需要注意顺序不可随意改变, 否则结果与预期不符output_names[output],  # 需要注意顺序, 否则在推理阶段可能用错output_namesdo_constant_foldingTrue,dynamic_axes{input_ids: {0: batch_size, 1: length},token_type_ids: {0: batch_size, 1: length},attention_mask: {0: batch_size, 1: length},output: {0: batch_size}}) print(Export of {} complete!.format(MODEL_ONNX_PATH))# ------------模型校验---------- import onnxruntime as ort import onnxonnx_model  onnx.load(MODEL_ONNX_PATH) onnx.checker.check_model(onnx_model)# ------------模型校验---------- sess  ort.InferenceSession(MODEL_ONNX_PATH, providers[CUDAExecutionProvider]) query  你好 encodings  tokenizer(query, max_length  512, truncationTrue, paddingmax_length, return_tensorspt)def to_numpy(tensor):return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()input  {sess.get_inputs()[0].name: to_numpy(encodings[input_ids]),sess.get_inputs()[1].name: to_numpy(encodings[attention_mask]),sess.get_inputs()[2].name: to_numpy(encodings[token_type_ids]), } print(sess.run(None, input_feedinput)) print(model(encodings[input_ids].to(DEVICE),encodings[attention_mask].to(DEVICE),encodings[token_type_ids].to(DEVICE))) 这里的必要流程我都有些写注释应该基本足够了解了不过还是把重点讲讲吧。 首先是转化这块其所有流程的中心就落在torch.onnx.export这一个函数身上这点已经非常方便了前面所有的工作都是为了这一个函数所需要的原料在准备比较核心的参数只要是这几个 model核心需要转化的模型torch.nn.Module肯定是可以支持的也是比较常见的。args这里输入的内容是预期模型的参数格式描述格式本身还比较困难格式比较多样然而这里支持的是可以往里面塞例子这里的第三步也就是格式定义就是准备了一个例子。f这里是指输出的路径最终加速后的模型的路径当然也可以用文件对象就是open读取的那个对象。input_names定义好具体模型的输入类bert模型本身是有3个输入名称要定义清楚和args中一致且注意要按照顺序。output_names输出的名字这个自己定义好就行。dynamic_axes这里是指支持动态的变量这里是可以指明的动态会为速度带来一定的影响但是也会带来较高的灵活性一般动态的比较多的就是batch_size和句子长度了注意这里输入和输出都得写在里面。 然后就是推理这里的难度其实不大基本上按照脚本走就没有什么大问题值得注意的细节就一个onnx模型的推理需要的输入是numpy格式此时转化后记得要转化回来。 另外这里有一个函数onnx.checker.check_model这个函数是负责检验模型生成是否规范onnx底层是用protobuf定义的内部的各个节点的映射关系之类的都写在这里面为了保证整体符合规范所以出了这个函数具体细节可以参考这篇文章https://blog.csdn.net/qq_43456016/article/details/130256097。虽然我们这种转化比较简单但个人还是建议在脚本里都加上。 在完成新的模型文件生成后就可以开始推理了直接看新的推理程序吧。 class VectorizeModel_onnx(VectorizeModel):def __init__(self, ptm_model_path, onnx_path) - None:self.tokenizer  BertTokenizer.from_pretrained(ptm_model_path)self.model  ort.InferenceSession(onnx_path, providers[CUDAExecutionProvider])self.pdist  nn.PairwiseDistance(2)def _to_numpy(self, tensor):return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()def predict_vec(self,query):q_id  self.tokenizer(query, max_length  200, truncationTrue, paddingmax_length, return_tensorspt)input_feed  {self.model.get_inputs()[0].name: self._to_numpy(q_id[input_ids]),self.model.get_inputs()[1].name: self._to_numpy(q_id[attention_mask]),self.model.get_inputs()[2].name: self._to_numpy(q_id[token_type_ids]),}return torch.tensor(self.model.run(None, input_feedinput_feed)[0])def predict_sim(self, q1, q2):q1_v  self.predict_vec(q1)q2_v  self.predict_vec(q2)sim  F.cosine_similarity(q1_v[0], q2_v[0], dim-1)return sim.numpy().tolist() 这里的程序为了简单我是直接继承了上面提及的VectorizeModel有些必要的额函数就不用重新写了。这里的加载和推理其实都参考了前面的“模型校验”中的内容了加载用的是ort.InferenceSession至于推理与之不同的是推理需要对tokenizer后的变量转为numpy的格式另外输出这里为了和前面的函数对齐做好无缝切换所以把输出的结果转化为torch.tensor了。 tensorRT加速 tensorRT的加速需要基于onnx是需要对onnx进行进一步编译完成流程上核心坑主要有两个 环境配置必须满足python版本、cuda版本等信息而且nvidia下载速度较慢。数据类型等细节的对齐否则很容易失败。 详细的操作和尝试大家可以参考这篇文章可以说非常详细对于详细版大家可以看这个https://blog.csdn.net/m0_37576959/article/details/127123186 而我想在这里聊的是onnx本身所具有的编译tensorRT的功能就在这行代码里 model  ort.InferenceSession(onnx_path, providers[CUDAExecutionProvider]) 这里的providers中提供了3种[TensorrtExecutionProvider, CUDAExecutionProvider, CPUExecutionProvider]顾名思义分别对应tensorRT、GPU、CPU三种模式而这里的TensorrtExecutionProvider就是tensorRT编译的结果了。https://zhuanlan.zhihu.com/p/457484536 因此上面对VectorizeModel_onnx就能优化为这个形式了改个名字V2吧 class VectorizeModel_v2(VectorizeModel):def __init__(self, ptm_model_path, model_path, providers[CUDAExecutionProvider]) - None:# [TensorrtExecutionProvider, CUDAExecutionProvider, CPUExecutionProvider]self.tokenizer  BertTokenizer.from_pretrained(ptm_model_path)self.model  ort.InferenceSession(model_path, providersproviders)self.pdist  nn.PairwiseDistance(2)def _to_numpy(self, tensor):return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()def predict_vec(self,query):q_id  self.tokenizer(query, max_length  200, truncationTrue, paddingmax_length, return_tensorspt)input_feed  {self.model.get_inputs()[0].name: self._to_numpy(q_id[input_ids]),self.model.get_inputs()[1].name: self._to_numpy(q_id[attention_mask]),self.model.get_inputs()[2].name: self._to_numpy(q_id[token_type_ids]),}return torch.tensor(self.model.run(None, input_feedinput_feed)[0])def predict_sim(self, q1, q2):q1_v  self.predict_vec(q1)q2_v  self.predict_vec(q2)sim  F.cosine_similarity(q1_v[0], q2_v[0], dim-1)return sim.numpy().tolist() 速度测试 有了进行加速这事那就来对比一下加速的优化效率吧。 先来看看我的脚本 import time,random from tqdm import tqdm # 加载 device  torch.device(cuda if torch.cuda.is_available() else cpu) vec_model  VectorizeModel(C:/work/tool/huggingface/models/simcse-chinese-roberta-wwm-ext, devicedevice) vec_model  VectorizeModel_v2(C:/work/tool/huggingface/models/simcse-chinese-roberta-wwm-ext,./data/model_simcse_roberta_output_20240211.onnx,providers[CUDAExecutionProvider]) vec_model  VectorizeModel_v2(C:/work/tool/huggingface/models/simcse-chinese-roberta-wwm-ext,./data/model_simcse_roberta_output_20240211.onnx,providers[TensorrtExecutionProvider]) batch_sizes  [1,2,4,8,16,32]  # 单测 # q  [你好啊] # print(vec_model.predict_vec(q)) # print(vec_model.predict_sim(你好呀,你好啊))# 开始批跑 batch_sizes  [1,2,4,8,16] tmp_queries  [你好啊, 今天天气怎么样, 我要暴富] for b in batch_sizes:for i in tqdm(range(100),descwarmup):tmp_q  []for i in range(b):tmp_q.append(random.choice(tmp_queries))vec_model.predict_vec(tmp_q)for i in tqdm(range(1000),descbatch_size{}.format(b)):tmp_q  []for i in range(b):tmp_q.append(random.choice(tmp_queries))vec_model.predict_vec(tmp_q) 这里是4个部分分别是加载、单测测单独一个case、预热和开始批跑时间的测试用的tqdm最终的平均时间即可。事不宜迟直接给出结果吧单位item/sitem是指每次推理而非每条数据 batch_sizepytorchonnxtensorRT1107.57167.21204.40263.99103.82126.92440.5457.8170.51821.6929.4336.051610.5114.4617.24 这里可以看到onnx和tensorRT相比原始的pytorch模型的提升还是非常大的。 补充一个实验后的发现tensorRT的推理中当输入进去的数据的batch_size变化后都会有个不短的预热时间而在batch_size固定的那段时间速度还是比稳定的不知道是不是有什么bug还是这个编译情况就是如此有了解的大佬可以在评论区里说下看有没有什么解决方案。
http://www.hkea.cn/news/14459689/

相关文章:

  • 长宁网站建设制作怎样向顾客电销网站建设
  • 建设银行激活网站小程序询价表
  • 用微信小程序怎么做网站免费生成网站软件下载
  • 如何打造网站文娱热搜榜
  • 织梦网站怎么建设平顶山有做网站的公司
  • 厦工品牌网站设计h5设计制作
  • 成都网站建设龙兵wordpress 编辑权限
  • 山西网站备案百度一下网页版搜索引擎
  • 广西工程建设质量管理协会网站建筑工程网上报建流程
  • 为什么建设银行网站打不开任县企业做网站
  • 北京网站建设知名公司排名藁城外贸网站建设
  • 电子网站建设的实践目的极品wordpress素材教程网站
  • 网站开发常去的论坛中国公司网站建设方案
  • 网站建设需申请注册域名卓手机建网站
  • 高端建站平台设计风格出众网站的命名规则
  • 个人 申请域名做网站爱站网在线全集私人影视
  • 响应式网站国内外现状扬中新闻中心
  • 做设计的兼职网站哪些网站可以免费推广
  • 中国建设银行福州招聘信息网站网站背景 手机显示不全
  • 企业网站建设可以分为网站可信度建设
  • 福州网站建设制作网页设计的发展前景如何
  • 右安门网站建设网站快照描述
  • 知春路网站建设泉州做网站的企业
  • 下沙做网站的公众号怎么制作投票
  • 韩国网站如何切换中文摄影网页设计方案
  • 上海微网站设计网站开发人员应该用什么浏览器
  • 建设我们的网站教案网站备案对应的ip地址
  • 智能小程序开发工具下载如何优化网络延迟
  • 海拉尔北京网站建设网站建设4038gzs
  • 一个网站的页头大概做多大网站建设工资高吗