日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

Dynamic Shape優化案例:使用Blade優化輸入為Dynamic Shape的ResNet50

常規推理優化普遍針對輸入為Static Shape的模型,如果實際推理的模型Shape發生變化,推理優化效果就可能失效。在實際生產中,輸入為Dynamic Shape的模型越來越多,因此對不同輸入Shape的推理過程具有強烈的優化需求。本文介紹如何使用Blade優化輸入為Dynamic Shape的模型。

使用限制

本文使用的環境需要滿足以下版本要求:

  • 系統環境:Linux系統中使用Python 3.6及其以上版本。

  • 框架:PyTorch 1.7.1。

  • 設備及后端:NVIDIA T4、CUDA 11.0。

  • 推理優化工具:Blade 3.17.0及其以上版本。

操作流程

使用Blade優化輸入為Dynamic Shape的ResNet50流程如下:

  1. 步驟一:準備工作

    構建測試數據和模型,本文使用torchvision中標準的ResNet50模型。

  2. 步驟二:配置用于優化的config

    根據Dynamic Shape的范圍配置Blade config。

  3. 步驟三:調用Blade優化模型

    調用blade.optimize接口優化模型,并保存優化后的模型。

  4. 步驟四:驗證性能與正確性

    對優化前后的推理速度及推理結果進行測試,從而驗證優化報告中信息的正確性。

  5. 步驟五:加載運行優化后的模型

    集成Blade SDK,加載優化后的模型進行推理。

步驟一:準備工作

  1. 下載模型預訓練參數與測試數據。

    預訓練參數選自torchvision,為了加速下載過程,已將其存儲至OSS中。測試數據隨機選自ImageNet-1k驗證集,預處理操作已完成,您可以下載后直接使用。

    wget http://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/share/dynamic_ranges_pratice/resnet50-19c8e357.pth -O resnet50-19c8e357.pth
    wget http://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/share/dynamic_ranges_pratice/imagenet_val_example.pt -O imagenet_val_example.pt
  2. 定義模型、加載模型參數和測試數據,并生成TorchScript。

    import torch
    import torchvision
    
    # 構建Resnet50。
    model = torchvision.models.resnet50().eval().cuda()
    # 加載預訓練參數。
    ckpt = torch.load('resnet50-19c8e357.pth')
    model.load_state_dict(ckpt)
    # 加載測試數據。
    example_input = torch.load('imagenet_val_example.pt').cuda()
    # 生成TorchScript。
    traced_model = torch.jit.trace(model, example_input).cuda().eval()

步驟二:配置用于優化的config

根據Dynamic Shape的范圍配置Blade config,Blade支持任意維度的動態范圍。本文以Batch維度演示config的配置。

  1. 定義Dynamic Shape的范圍。

    一組有效的動態范圍,需要包括以下三個字段:

    • min:表示dynamic shape的下界。

    • max:表示dynamic shape的上界。

    • opts:表示需要特別優化的Shape,可以設置多個。通常優化后的模型在這些Shape上的推理加速比更高。

    上述三個字段需要符合以下規則:

    • minmaxopts中的每組Shape的長度相等,且等于網絡的輸入數量。

    • minmaxopts中的每組Shape對應位置的數值需要滿足min_num <= opt_num <= max_num

    例如構建如下Dynamic Shape的范圍。

    shapes = {
        "min": [[1, 3, 224, 224]],
        "max": [[10, 3, 224, 224]],
        "opts": [
            [[5, 3, 224, 224]],
            [[8, 3, 224, 224]],
        ]
    }

    此外,Blade支持設置多個動態范圍。如果Dynamic Shape的上界和下界范圍過大,可能會導致優化后的模型加速不明顯,您可以將一個大的范圍拆分為多個小范圍,通常能夠帶來更好的加速效果。關于如何設置多個動態范圍,請參見下文的附錄:設置多個動態范圍

  2. 通過定義好的Dynamic Shape范圍構建Blade config。

    import blade
    import blade.torch as blade_torch
    
    # Blade Torch相關config,用于設置Dynamic Shapes。
    blade_torch_cfg = blade_torch.Config()
    blade_torch_cfg.dynamic_tuning_shapes = shapes
    
    # Blade相關config,用于關閉FP16的精度檢查,以獲得最好的加速效果。
    gpu_config = {
        "disable_fp16_accuracy_check": True,
    }
    blade_config = blade.Config(
        gpu_config=gpu_config
    )

步驟三:調用Blade優化模型

  1. 調用blade.optimize對模型進行優化,示例代碼如下。關于該接口的詳細描述,請參見Python接口文檔

    with blade_torch_cfg:
        optimized_model, _, report = blade.optimize(
            traced_model,          # 模型路徑。
            'o1',                  # o1無損優化。
            config=blade_config,
            device_type='gpu',     # 面向GPU設備優化,
            test_data=[(example_input,)]  # 測試數據。
        )

    優化模型時,您需要注意以下事宜:

    • blade.optimize的第一個返回值為優化后的模型,其數據類型與輸入的模型相同。在這個示例中,輸入的是TorchScript,返回的是優化后的TorchScript。

    • 您需要確保輸入的test_data在定義的Dynamic Shape范圍內。

  2. 優化完成后,打印優化報告。

    print("Report: {}".format(report))

    打印的優化報告類似如下輸出。

    Report: {
      "software_context": [
        {
          "software": "pytorch",
          "version": "1.7.1+cu110"
        },
        {
          "software": "cuda",
          "version": "11.0.0"
        }
      ],
      "hardware_context": {
        "device_type": "gpu",
        "microarchitecture": "T4"
      },
      "user_config": "",
      "diagnosis": {
        "model": "unnamed.pt",
        "test_data_source": "user provided",
        "shape_variation": "undefined",
        "message": "Unable to deduce model inputs information (data type, shape, value range, etc.)",
        "test_data_info": "0 shape: (1, 3, 224, 224) data type: float32"
      },
      "optimizations": [
        {
          "name": "PtTrtPassFp16",
          "status": "effective",
          "speedup": "4.06",
          "pre_run": "6.55 ms",
          "post_run": "1.61 ms"
        }
      ],
      "overall": {
        "baseline": "6.54 ms",
        "optimized": "1.61 ms",
        "speedup": "4.06"
      },
      "model_info": {
        "input_format": "torch_script"
      },
      "compatibility_list": [
        {
          "device_type": "gpu",
          "microarchitecture": "T4"
        }
      ],
      "model_sdk": {}
    }

    從優化報告可以看出本示例的優化中,PtTrtPassFp16優化項生效,帶來了約4.06倍左右的加速,將模型在測試數據上的推理耗時從6.55 ms下降到了1.61 ms。上述優化結果僅為本示例的測試結果,您的優化效果以實際為準。關于優化報告的字段詳情請參見優化報告

  3. 調用PyTorch的相關函數保存并加載優化后的TorchScript模型。

    file_name = "resnet50_opt.pt"
    # 將優化后的模型保存到本地。
    torch.jit.save(optimized_model, file_name)
    # 從硬盤中加載優化后的模型。
    optimized_model = torch.jit.load(file_name)

步驟四:驗證性能與正確性

優化完成后,通過Python腳本對優化報告的信息進行驗證。

  1. 定義benchmark方法,對模型進行10次預熱,然后運行100次,最終取平均的推理時間作為推理速度。

    import time
    
    @torch.no_grad()
    def benchmark(model, test_data):
        # 切換模型至驗證模式。
        model = model.eval()
        
        # 預熱。
        for i in range(0, 10):
            model(test_data)
            
        # 開始計時運行。
        num_runs = 100
        start = time.time()
        for i in range(0, num_runs):
            model(test_data)
        torch.cuda.synchronize()
        elapsed = time.time() - start
        rt_ms = elapsed / num_runs * 1000.0
        
        # 打印結果。
        print("{:.2f} ms.".format(rt_ms))
        return rt_ms
  2. 定義一系列不同Shape的測試數據。

    dummy_inputs = []
    batch_num = [1, 3, 5, 7, 9]
    for n in batch_num:
        dummy_inputs.append(torch.randn(n, 3, 224, 224).cuda())
  3. 遍歷每組測試數據,分別調用benchmark方法對優化前與優化后的模型進行測試,并打印結果。

    for inp in dummy_inputs:
        print(f'--------------test with shape {list(inp.shape)}--------------')
        print("  Origin model inference cost:     ", end='')
        origin_rt = benchmark(traced_model, inp)
        print("  Optimized model inference cost:  ", end='')
        opt_rt = benchmark(optimized_model, inp)
        speedup = origin_rt / opt_rt
        print('  Speed up: {:.2f}'.format(speedup))
        print('')

    系統返回如下類似結果。

    --------------test with shape [1, 3, 224, 224]--------------
      Origin model inference cost:     6.54 ms.
      Optimized model inference cost:  1.66 ms.
      Speed up: 3.94
    
    --------------test with shape [3, 3, 224, 224]--------------
      Origin model inference cost:     10.79 ms.
      Optimized model inference cost:  2.40 ms.
      Speed up: 4.49
    
    --------------test with shape [5, 3, 224, 224]--------------
      Origin model inference cost:     16.27 ms.
      Optimized model inference cost:  3.25 ms.
      Speed up: 5.01
    
    --------------test with shape [7, 3, 224, 224]--------------
      Origin model inference cost:     22.62 ms.
      Optimized model inference cost:  4.39 ms.
      Speed up: 5.16
    
    --------------test with shape [9, 3, 224, 224]--------------
      Origin model inference cost:     28.83 ms.
      Optimized model inference cost:  5.25 ms.
      Speed up: 5.49

    從結果可以看出對于不同Shape的測試數據,優化后模型的推理速度是原始模型的3.94~5.49倍。上述優化結果僅為本示例的測試結果,您的優化效果以實際為準。

  4. 使用準備工作階段準備的真實測試數據example_input,驗證優化模型的正確性。

    origin_output = traced_model(example_input)
    _, pred = origin_output.topk(1, 1, True, True)
    print("origin model output: {}".format(pred))
    opt_output = optimized_model(example_input)
    _, pred = origin_output.topk(1, 1, True, True)
    print("optimized model output: {}".format(pred))

    系統返回如下類似結果。

    origin model output: tensor([[834]], device='cuda:0')
    optimized model output: tensor([[834]], device='cuda:0')

    從上述結果可以看出優化前后模型對于測試數據example_input的預測均為第834類。

步驟五:加載運行優化后的模型

完成驗證后,您需要對模型進行部署,Blade提供了Python和C++兩種運行時SDK供您集成。關于C++的SDK使用方法請參見使用SDK部署TensorFlow模型推理,下文主要介紹如何使用Python SDK部署模型。

  1. 可選:在試用階段,您可以設置如下的環境變量,防止因為鑒權失敗而程序退出。
    export BLADE_AUTH_USE_COUNTING=1
  2. 獲取鑒權。
    export BLADE_REGION=<region>
    export BLADE_TOKEN=<token>
    您需要根據實際情況替換以下參數:
    • <region>:Blade支持的地域,需要加入Blade用戶群獲取該信息,用戶群的二維碼詳情請參見獲取Token
    • <token>:鑒權Token,需要加入Blade用戶群獲取該信息,用戶群的二維碼詳情請參見獲取Token
  3. 加載運行優化后的模型。

    除了增加一行import blade.runtime.torch,您無需為Blade的接入編寫額外代碼,即原有的推理代碼無需任何改動。

    import torch
    import blade.runtime.torch
    # <your_optimized_model_path>替換為優化后的模型路徑。
    opt_model_dir = <your_optimized_model_path>
    # <your_infer_data>替換為用于推理的數據。
    infer_data = <your_infer_data>
    
    model = torch.jit.load(opt_model_dir)
    output = model(infer_data)

附錄:設置多個動態范圍

如果Dynamic Shape的上界和下界范圍過大,可能會導致優化后的模型加速不明顯,您可以將一個大的范圍拆分為多個小范圍,通常能夠帶來更好的加速效果。例如設置如下Dynamic Shape。

shapes1 = {
    "min": [[1, 3, 224, 224]],
    "max": [[5, 3, 224, 224]],
    "opts": [
        [[5, 3, 224, 224]],
    ]
}
shapes2 = {
    "min": [[5, 3, 224, 224]],
    "max": [[10, 3, 224, 224]],
    "opts": [
        [[8, 3, 224, 224]],
    ]
}
shapes = [shapes1, shapes2]

您可以使用該shapes配置上述提及的優化config,詳情請參見步驟二:配置用于優化的config