(原型) 基于追踪的选择性构建移动解释器 (Android 和 iOS)¶
作者: Chen Lai <https://github.com/cccclai>, Dhruv Matani <https://github.com/dhruvbird>
警告
基于追踪的选择性构建是一种原型功能,用于最大程度地减少库大小。由于追踪结果依赖于模型输入和追踪环境,如果追踪器在与移动解释器不同的环境中运行,则运算符列表可能与实际使用的运算符列表不同,并且可能会出现缺少运算符的错误。
简介¶
本教程介绍了一种新的方法来定制构建移动解释器,以进一步优化移动解释器的大小。它将编译二进制文件中包含的运算符集限制为目标模型实际需要的运算符集。这是一种技术,可以减少 PyTorch 的二进制大小,从而使其更适合移动部署。基于追踪的选择性构建运行一个模型,使用特定的代表性输入,并记录调用了哪些运算符。然后,构建将仅包含这些运算符。
以下是使用基于追踪的选择性方法构建自定义移动解释器的流程。
准备包含捆绑输入的模型
import numpy as np
import torch
import torch.jit
import torch.utils
import torch.utils.bundled_inputs
from PIL import Image
from torchvision import transforms
# Step 1. Get the model
model = torch.hub.load('pytorch/vision:v0.7.0', 'deeplabv3_resnet50', pretrained=True)
model.eval()
scripted_module = torch.jit.script(model)
# Export full jit version model (not compatible lite interpreter), leave it here for comparison
scripted_module.save("deeplabv3_scripted.pt")
# Export lite interpreter version model (compatible with lite interpreter)
# path = "<base directory where models are stored>"
scripted_module._save_for_lite_interpreter(f"${path}/deeplabv3_scripted.ptl")
model_file = f"${path}/deeplabv3_scripted.ptl"
# Step 2. Prepare inputs for the model
input_image_1 = Image.open(f"${path}/dog.jpg")
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
input_tensor_1 = preprocess(input_image_1)
input_batch_1 = input_tensor_1.unsqueeze(0) # create a mini-batch as expected by the model
scripted_module = torch.jit.load(model_file)
scripted_module.forward(input_batch_1) # optional, to validate the model can run with the input_batch_1
input_image_2 = Image.open(f"${path}/deeplab.jpg")
input_tensor_2 = preprocess(input_image_2)
input_batch_2 = input_tensor_2.unsqueeze(0) # create a mini-batch as expected by the model
scripted_module = torch.jit.load(model_file)
scripted_module.forward(input_batch_2) # optional, to validate the model can run with the input_batch_2
# Step 3. Bundle the model with the prepared input from step2. Can bundle as many input as possible.
bundled_model_input = [
(torch.utils.bundled_inputs.bundle_large_tensor(input_batch_1), ),
(torch.utils.bundled_inputs.bundle_large_tensor(input_batch_2), )]
bundled_model = torch.utils.bundled_inputs.bundle_inputs(scripted_module, bundled_model_input)
bundled_model._save_for_lite_interpreter(f"${path}/deeplabv3_scripted_with_bundled_input.ptl")
构建跟踪器
MACOSX_DEPLOYMENT_TARGET=10.9 CC=clang CXX=clang++ MAX_JOBS=16 TRACING_BASED=1 python setup.py develop
使用包含捆绑输入的模型运行跟踪器
./build/bin/model_tracer --model_input_path ${path}/deeplabv3_scripted_with_bundled_input.ptl --build_yaml_path ${path}/deeplabv3_scripted.yaml
Android¶
获取 Android 中的 Image Segmentation 演示应用程序:https://github.com/pytorch/android-demo-app/tree/master/ImageSegmentation
基于追踪构建 libtorch lite for android:通过运行以下命令,为所有 4 个 Android ABI(
armeabi-v7a
、arm64-v8a
、x86
、x86_64
)构建 libtorch for android
SELECTED_OP_LIST=${path}/deeplabv3_scripted.yaml TRACING_BASED=1 ./scripts/build_pytorch_android.sh
如果将在具有 x86
的 Pixel 4 模拟器上进行测试,请使用命令 BUILD_LITE_INTERPRETER=1 ./scripts/build_pytorch_android.sh x86
指定 ABI 以节省构建时间。
SELECTED_OP_LIST=${path}/deeplabv3_scripted.yaml TRACING_BASED=1 ./scripts/build_pytorch_android.sh x86
构建完成后,将显示库路径
BUILD SUCCESSFUL in 55s
134 actionable tasks: 22 executed, 112 up-to-date
+ find /Users/chenlai/pytorch/android -type f -name '*aar'
+ xargs ls -lah
-rw-r--r-- 1 chenlai staff 13M Feb 11 11:48 /Users/chenlai/pytorch/android/pytorch_android/build/outputs/aar/pytorch_android-release.aar
-rw-r--r-- 1 chenlai staff 36K Feb 9 16:45 /Users/chenlai/pytorch/android/pytorch_android_torchvision/build/outputs/aar/pytorch_android_torchvision-release.aar
在 ImageSegmentation 应用程序中使用从源代码构建的 PyTorch Android 库:在路径中创建一个名为 libs 的文件夹,该路径从存储库根目录开始为 ImageSegmentation/app/libs。将 pytorch_android-release 复制到路径
ImageSegmentation/app/libs/pytorch_android-release.aar
。将 pytorch_android_torchvision(从 Pytorch Android Torchvision Nightly 下载)复制到路径ImageSegmentation/app/libs/pytorch_android_torchvision.aar
。更新ImageSegmentation/app/build.gradle
中的 dependencies 部分,如下所示:
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation(name:'pytorch_android-release', ext:'aar')
implementation(name:'pytorch_android_torchvision', ext:'aar')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.facebook.fbjni:fbjni-java-only:0.0.3'
}
更新 ImageSegmentation/build.gradle
中的 all projects 部分,如下所示:
allprojects {
repositories {
google()
jcenter()
flatDir {
dirs 'libs'
}
}
}
测试应用程序:在 Android Studio 中构建并运行 ImageSegmentation 应用程序
iOS¶
获取 iOS 中的 ImageSegmentation 演示应用程序:https://github.com/pytorch/ios-demo-app/tree/master/ImageSegmentation
为 iOS 构建 libtorch lite:
SELECTED_OP_LIST=${path}/deeplabv3_scripted.yaml TRACING_BASED=1 IOS_PLATFORM=SIMULATOR ./scripts/build_ios.sh
从项目中删除 Cocoapods(仅当您运行了 pod install 时才需要此步骤)
pod deintegrate
使用自定义构建的库链接 ImageSegmentation 演示应用程序:
在 XCode 中打开您的项目,转到您的项目 Target 的 **Build Phases - Link Binaries With Libraries**,单击 **+** 号并添加位于 build_ios/install/lib 中的所有库文件。导航到项目 **Build Settings**,将 **Header Search Paths** 的值设置为 build_ios/install/include,将 **Library Search Paths** 的值设置为 build_ios/install/lib。在构建设置中,搜索 **other linker flags**。在 -all_load 下面添加一个自定义链接器标志。最后,通过选择构建设置、搜索 Enable Bitcode 并将值设置为 **No** 来禁用目标的 bitcode。
在 Xcode 中构建并测试应用程序。
结论¶
在本教程中,我们演示了一种新的方法来自定义构建 PyTorch 的高效移动解释器 - 基于追踪的选择性构建,在 Android 和 iOS 应用程序中。
我们通过一个 Image Segmentation 示例展示了如何将输入捆绑到模型,通过跟踪具有捆绑输入的模型生成操作符列表,以及使用来自跟踪结果的操作符列表从源代码构建自定义 torch 库。
自定义构建仍在开发中,我们将在未来继续改进其大小。但是请注意,API 在未来版本中可能会发生变化。
感谢您的阅读!我们始终欢迎任何反馈,因此请在此处创建问题 <https://github.com/pytorch/pytorch/issues>`。
了解更多
要详细了解 PyTorch Mobile,请参阅 PyTorch Mobile 主页 <https://pytorch.ac.cn/mobile/home/>
要详细了解 Image Segmentation,请参阅 Android 中的 Image Segmentation DeepLabV3 教程 <https://pytorch.ac.cn/tutorials/beginner/deeplabv3_on_android.html>_