兼容PyTorch,25倍加速,國產(chǎn)!
↑?關(guān)注 + 星標(biāo)?,每天學(xué)Python新技能
后臺回復(fù)【大禮包】送你Python自學(xué)大禮包

數(shù)據(jù)量大:數(shù)據(jù)庫中有過億級別的圖片
模型簡單:比較常規(guī)的分類模型
400 多張顯卡,短期內(nèi)無法擴(kuò)容
對于訓(xùn)練/推理的吞吐有硬性指標(biāo)
上線時間緊迫
1、OneFlow 是眾多深度學(xué)習(xí)框架中,API 與 PyTorch 兼容性最高的,這樣方便工程師用最少的時間/人力成本,對已有項目代碼進(jìn)行遷移,減少學(xué)習(xí)成本。
2、OneFlow 動靜轉(zhuǎn)換十分方便,動態(tài)圖(Eager)模式的代碼簡單改動幾行就能轉(zhuǎn)換為靜態(tài)圖(nn.Graph)模式。
3、OneFlow 在框架層面做了大量優(yōu)化,nn.Graph 提供了簡潔、豐富的性能優(yōu)化選項,如算子融合(Kernel Fusion)、自動混合精度訓(xùn)練 (Auto Mixed Precision Training) 等。
將已有 PyTorch 的項目代碼完全遷移到 OneFlow
將項目代碼由動態(tài)圖模式(Eager Mode)改造為靜態(tài)圖模式(Graph Mode)
開啟 OneFlow Graph 模式下的各種優(yōu)化選項并訓(xùn)練模型
用 Serving 模塊部署模型上線
import torchvision.models as models_torchimport flowvision.models as models_flowresnet101_torch = models_torch.resnet101(pretrained=True)resnet101_flow = models_flow.resnet101()state_dict_torch = resnet101_torch.state_dict()state_dict_numpy = {key: value.detach().cpu().numpy() for key, value in state_dict_torch.items()}resnet101_flow.load_state_dict(state_dict_numpy)
class?ResNet101Graph(oneflow.nn.Graph):def __init__(self, input_shape, input_dtype=oneflow.float32):super().__init__()# 添加 ResNet101 nn.Moduleself.model = ResNet101Module(input_shape, input_dtype)self.loss_fn = ResNet101_loss_fn# 添加 對應(yīng)的 Optimizerof_sgd = torch.optim.SGD(self.model.parameters(), lr=1.0, momentum=0.0)self.add_optimizer(of_sgd)# 配置靜態(tài)圖的自動優(yōu)化選項_config_graph(self)def build(self, input):# 類似 nn.Module 的 forward 方法,這里是構(gòu)圖,包括了構(gòu)建后向圖,所以叫 buildout = self.model(input)loss = self.loss_fn(out)# build 里面支持構(gòu)建后向圖loss.backward()return loss
resnet101_graph?=?ResNet101Graph((args.batch_size,?3,?img_shape[1],?img_shape[0]))for?i?in?range(m):????loss?=?resnet101_graph(images)
一般推理時只需要前向計算,后向計算是不需要的,但在用戶這個特殊的模型里,部署和推理也是需要后向計算,只是不需要模型更新,這就導(dǎo)致用戶寫代碼時為了保留后向計算也誤把參數(shù)更新的邏輯保留下來了。據(jù)此可以省略參數(shù)的梯度計算,這里大概帶來了 75% 的加速;
進(jìn)而發(fā)現(xiàn)原任務(wù)(前向、后向、前向)中的第二次前向在部署時是多余的,可以裁剪掉,這里大概帶來了大約 33% 的加速。
增大 batch_size,默認(rèn) batch_size 為 1,此時 GPU 利用率為 30%,當(dāng)增大到 16 時,最高可以達(dá)到 90%,這里大約得到了 155% 的加速;
由于數(shù)據(jù)預(yù)處理在 CPU,網(wǎng)絡(luò)計算在 GPU,兩種設(shè)備接力執(zhí)行,這時使用 2 進(jìn)程進(jìn)行,給數(shù)據(jù)加載部分加一個互斥鎖,可以比較簡易的實現(xiàn) CPU 和 GPU 兩級流水線,這里帶來了 80% 的加速。
def?_config_graph(graph):if args.fp16:# 打開 nn.Graph 的自動混合精度執(zhí)行graph.config.enable_amp(True)if args.conv_try_run:# 打開 nn.Graph 的卷積的試跑優(yōu)化graph.config.enable_cudnn_conv_heuristic_search_algo(False)if args.fuse_add_to_output:# 打開 nn.Graph 的add算子的融合graph.config.allow_fuse_add_to_output(True)if args.fuse_pad_to_conv:# 打開 nn.Graph 的pad算子的融合????????graph.config.allow_fuse_pad_to_conv(True)
打開混合精度,測試得到了 36% 的加速
再打開卷積試跑優(yōu)化,測試得到了 7% 的加速,總加速為 43%
再打開 pad 和 conv 算子融合,測試得到了 19% 的加速,總加速為 62%
再打開 add 的算子的融合,測試得到了 2% 的加速,總加速為 64%
def?_config_graph(graph):if args.tensorrt:# 使用 TensorRT 后端執(zhí)行????????graph.config.enable_tensorrt(True)
nn.Graph 的使用教程,https://docs.oneflow.org/en/master/basics/08_nn_graph.html
nn.Graph 的 API 文檔,https://oneflow.readthedocs.io/en/master/graph.html
class?ResNet101InferenceGraph(oneflow.nn.Graph):def __init__(self):super().__init__()self.model = resnet101_graph.modeldef build(self, input):return self.model(input)inference_graph?=?ResNet101InferenceGraph()
unused_output?=?inference_graph(flow.zeros(1,?3,?224,?224))flow.save(inference_graph,?"model")docker?run?--rm?--runtime=nvidia?--network=host?-v$(pwd)/model:/models/resnet101/1?\??oneflowinc/oneflow-serving:nightly
docker run --rm --runtime=nvidia --network=host -v$(pwd)/model:/models/resnet101/1 \??oneflowinc/oneflow-serving:nightly?oneflow-serving?--model-store?/models?--enable-tensorrt?resnet101
curl?-v?localhost:8000/v2/health/ready#/usr/bin/env python3import numpy as npimport tritonclient.http as httpclientfrom PIL import Imagetriton_client = httpclient.InferenceServerClient(url='127.0.0.1:8000')image?=?Image.open("image.jpg")image = image.resize((224, 224))image = np.asarray(image)image = image / 255image = np.expand_dims(image, axis=0)# Transpose NHWC to NCHWimage = np.transpose(image, axes=[0, 3, 1, 2])image = image.astype(np.float32)input?=?httpclient.InferInput('INPUT_0',?image.shape,?"FP32")input.set_data_from_numpy(image, binary_data=True)output_placeholder = httpclient.InferRequestedOutput('OUTPUT_0', binary_data=True, class_count=1)output?=?triton_client.infer("resnet101",?inputs=[input],?outputs=[output_placeholder]).as_numpy('OUTPUT_0')print(output)
$ python3 triton_client.py[b'3.630257:499']????#?class?id?為?499,值為?3.630257
OneFlow項目地址:https://github.com/Oneflow-Inc/oneflow/
OneFlow用戶文檔:https://docs.oneflow.org/master/index.html
推薦閱讀
