From 1c3f8b691bf7aed99663570176681444f4f0bb28 Mon Sep 17 00:00:00 2001 From: Svetlana Karslioglu Date: Wed, 25 Jun 2025 09:29:02 -0700 Subject: [PATCH 1/4] test --- .github/workflows/check-redirects.yml | 63 ++++++ beginner_source/vt_tutorial.py | 293 -------------------------- check_redirects.sh | 45 ++++ 3 files changed, 108 insertions(+), 293 deletions(-) create mode 100644 .github/workflows/check-redirects.yml delete mode 100644 beginner_source/vt_tutorial.py create mode 100755 check_redirects.sh diff --git a/.github/workflows/check-redirects.yml b/.github/workflows/check-redirects.yml new file mode 100644 index 00000000000..b93c6a082c9 --- /dev/null +++ b/.github/workflows/check-redirects.yml @@ -0,0 +1,63 @@ +name: Check Redirects for Deleted Files + +on: + pull_request: + paths: + - '**/*.rst' + - '**/*.py' + +jobs: + check-redirects: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Check for deleted/renamed files and redirects + run: | + # Get list of deleted or renamed files in this PR + DELETED_FILES=$(git diff --name-status ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep '^D\|^R' | awk '{print $2}' | grep -E '\.(rst|py|ipynb)$' | grep -v 'redirects.py') + + if [ -z "$DELETED_FILES" ]; then + echo "No deleted or renamed files found. Skipping check." + exit 0 + fi + + echo "Deleted or renamed files:" + echo "$DELETED_FILES" + + # Check if redirects.py has been updated + REDIRECTS_UPDATED=$(git diff --name-status ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep -q '^M\|^A' | grep 'redirects.py' && echo "yes" || echo "no") + + if [ "$REDIRECTS_UPDATED" == "no" ]; then + echo "::error::Files were deleted or renamed but redirects.py was not updated. Please add redirects for deleted/renamed files." + exit 1 + fi + + # Check if each deleted file has a redirect entry + MISSING_REDIRECTS=0 + for FILE in $DELETED_FILES; do + # Convert file path to URL path format (remove extension and adjust path) + URL_PATH=$(echo $FILE | sed 's/\.rst$//g' | sed 's/\.py$//g' | sed 's/\.ipynb$//g' | sed 's/^tutorials\///g') + + # Check if this path exists in redirects.py + if ! grep -q "\"$URL_PATH\"" tutorials/redirects.py; then + echo "::error::Missing redirect for deleted file: $FILE (URL path: $URL_PATH)" + MISSING_REDIRECTS=1 + fi + done + + if [ $MISSING_REDIRECTS -eq 1 ]; then + echo "::error::Please add redirects for all deleted/renamed files to redirects.py" + exit 1 + fi + + echo "All deleted/renamed files have proper redirects. Check passed!" + diff --git a/beginner_source/vt_tutorial.py b/beginner_source/vt_tutorial.py deleted file mode 100644 index 777098be946..00000000000 --- a/beginner_source/vt_tutorial.py +++ /dev/null @@ -1,293 +0,0 @@ -""" -Optimizing Vision Transformer Model for Deployment -================================================== - -`Jeff Tang `_, -`Geeta Chauhan `_ - -Vision Transformer models apply the cutting-edge attention-based -transformer models, introduced in Natural Language Processing to achieve -all kinds of the state of the art (SOTA) results, to Computer Vision -tasks. Facebook Data-efficient Image Transformers `DeiT `_ -is a Vision Transformer model trained on ImageNet for image -classification. - -In this tutorial, we will first cover what DeiT is and how to use it, -then go through the complete steps of scripting, quantizing, optimizing, -and using the model in iOS and Android apps. We will also compare the -performance of quantized, optimized and non-quantized, non-optimized -models, and show the benefits of applying quantization and optimization -to the model along the steps. - -""" - - - -############################################################################### -# What is DeiT -# --------------------- -# -# Convolutional Neural Networks (CNNs) have been the main models for image -# classification since deep learning took off in 2012, but CNNs typically -# require hundreds of millions of images for training to achieve the -# SOTA results. DeiT is a vision transformer model that requires a lot less -# data and computing resources for training to compete with the leading -# CNNs in performing image classification, which is made possible by two -# key components of of DeiT: -# -# - Data augmentation that simulates training on a much larger dataset; -# - Native distillation that allows the transformer network to learn from -# a CNN’s output. -# -# DeiT shows that Transformers can be successfully applied to computer -# vision tasks, with limited access to data and resources. For more -# details on DeiT, see the `repo `_ -# and `paper `_. -# - - -###################################################################### -# Classifying Images with DeiT -# ------------------------------- -# -# Follow the ``README.md`` at the DeiT repository for detailed information on how to -# classify images using DeiT, or for a quick test, first install the -# required packages: -# -# .. code-block:: python -# -# pip install torch torchvision timm pandas requests - -####################################################### -# To run in Google Colab, install dependencies by running the following command: -# -# .. code-block:: python -# -# !pip install timm pandas requests - -############################# -# then run the script below: - -from PIL import Image -import torch -import timm -import requests -import torchvision.transforms as transforms -from timm.data.constants import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD - -print(torch.__version__) -# should be 1.8.0 - - -model = torch.hub.load('facebookresearch/deit:main', 'deit_base_patch16_224', pretrained=True) -model.eval() - -transform = transforms.Compose([ - transforms.Resize(256, interpolation=3), - transforms.CenterCrop(224), - transforms.ToTensor(), - transforms.Normalize(IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD), -]) - -img = Image.open(requests.get("https://raw.githubusercontent.com/pytorch/ios-demo-app/master/HelloWorld/HelloWorld/HelloWorld/image.png", stream=True).raw) -img = transform(img)[None,] -out = model(img) -clsidx = torch.argmax(out) -print(clsidx.item()) - - -###################################################################### -# The output should be 269, which, according to the ImageNet list of class -# index to `labels file `_, maps to ``timber -# wolf, grey wolf, gray wolf, Canis lupus``. -# -# Now that we have verified that we can use the DeiT model to classify -# images, let’s see how to modify the model so it can run on iOS and -# Android apps. -# - - -###################################################################### -# Scripting DeiT -# ---------------------- -# To use the model on mobile, we first need to script the -# model. See the `Script and Optimize recipe `_ for a -# quick overview. Run the code below to convert the DeiT model used in the -# previous step to the TorchScript format that can run on mobile. -# - - -model = torch.hub.load('facebookresearch/deit:main', 'deit_base_patch16_224', pretrained=True) -model.eval() -scripted_model = torch.jit.script(model) -scripted_model.save("fbdeit_scripted.pt") - - -###################################################################### -# The scripted model file ``fbdeit_scripted.pt`` of size about 346MB is -# generated. -# - - -###################################################################### -# Quantizing DeiT -# --------------------- -# To reduce the trained model size significantly while -# keeping the inference accuracy about the same, quantization can be -# applied to the model. Thanks to the transformer model used in DeiT, we -# can easily apply dynamic-quantization to the model, because dynamic -# quantization works best for LSTM and transformer models (see `here `_ -# for more details). -# -# Now run the code below: -# - -# Use 'x86' for server inference (the old 'fbgemm' is still available but 'x86' is the recommended default) and ``qnnpack`` for mobile inference. -backend = "x86" # replaced with ``qnnpack`` causing much worse inference speed for quantized model on this notebook -model.qconfig = torch.quantization.get_default_qconfig(backend) -torch.backends.quantized.engine = backend - -quantized_model = torch.quantization.quantize_dynamic(model, qconfig_spec={torch.nn.Linear}, dtype=torch.qint8) -scripted_quantized_model = torch.jit.script(quantized_model) -scripted_quantized_model.save("fbdeit_scripted_quantized.pt") - - -###################################################################### -# This generates the scripted and quantized version of the model -# ``fbdeit_quantized_scripted.pt``, with size about 89MB, a 74% reduction of -# the non-quantized model size of 346MB! -# - -###################################################################### -# You can use the ``scripted_quantized_model`` to generate the same -# inference result: -# - -out = scripted_quantized_model(img) -clsidx = torch.argmax(out) -print(clsidx.item()) -# The same output 269 should be printed - -###################################################################### -# Optimizing DeiT -# --------------------- -# The final step before using the quantized and scripted -# model on mobile is to optimize it: -# - -from torch.utils.mobile_optimizer import optimize_for_mobile -optimized_scripted_quantized_model = optimize_for_mobile(scripted_quantized_model) -optimized_scripted_quantized_model.save("fbdeit_optimized_scripted_quantized.pt") - - -###################################################################### -# The generated ``fbdeit_optimized_scripted_quantized.pt`` file has about the -# same size as the quantized, scripted, but non-optimized model. The -# inference result remains the same. -# - - - -out = optimized_scripted_quantized_model(img) -clsidx = torch.argmax(out) -print(clsidx.item()) -# Again, the same output 269 should be printed - - -###################################################################### -# Using Lite Interpreter -# ------------------------ -# -# To see how much model size reduction and inference speed up the Lite -# Interpreter can result in, let’s create the lite version of the model. -# - -optimized_scripted_quantized_model._save_for_lite_interpreter("fbdeit_optimized_scripted_quantized_lite.ptl") -ptl = torch.jit.load("fbdeit_optimized_scripted_quantized_lite.ptl") - - -###################################################################### -# Although the lite model size is comparable to the non-lite version, when -# running the lite version on mobile, the inference speed up is expected. -# - - -###################################################################### -# Comparing Inference Speed -# --------------------------- -# -# To see how the inference speed differs for the four models - the -# original model, the scripted model, the quantized-and-scripted model, -# the optimized-quantized-and-scripted model - run the code below: -# - -with torch.autograd.profiler.profile(use_cuda=False) as prof1: - out = model(img) -with torch.autograd.profiler.profile(use_cuda=False) as prof2: - out = scripted_model(img) -with torch.autograd.profiler.profile(use_cuda=False) as prof3: - out = scripted_quantized_model(img) -with torch.autograd.profiler.profile(use_cuda=False) as prof4: - out = optimized_scripted_quantized_model(img) -with torch.autograd.profiler.profile(use_cuda=False) as prof5: - out = ptl(img) - -print("original model: {:.2f}ms".format(prof1.self_cpu_time_total/1000)) -print("scripted model: {:.2f}ms".format(prof2.self_cpu_time_total/1000)) -print("scripted & quantized model: {:.2f}ms".format(prof3.self_cpu_time_total/1000)) -print("scripted & quantized & optimized model: {:.2f}ms".format(prof4.self_cpu_time_total/1000)) -print("lite model: {:.2f}ms".format(prof5.self_cpu_time_total/1000)) - -###################################################################### -# The results running on a Google Colab are: -# -# .. code-block:: sh -# -# original model: 1236.69ms -# scripted model: 1226.72ms -# scripted & quantized model: 593.19ms -# scripted & quantized & optimized model: 598.01ms -# lite model: 600.72ms -# - - -###################################################################### -# The following results summarize the inference time taken by each model -# and the percentage reduction of each model relative to the original -# model. -# - -import pandas as pd -import numpy as np - -df = pd.DataFrame({'Model': ['original model','scripted model', 'scripted & quantized model', 'scripted & quantized & optimized model', 'lite model']}) -df = pd.concat([df, pd.DataFrame([ - ["{:.2f}ms".format(prof1.self_cpu_time_total/1000), "0%"], - ["{:.2f}ms".format(prof2.self_cpu_time_total/1000), - "{:.2f}%".format((prof1.self_cpu_time_total-prof2.self_cpu_time_total)/prof1.self_cpu_time_total*100)], - ["{:.2f}ms".format(prof3.self_cpu_time_total/1000), - "{:.2f}%".format((prof1.self_cpu_time_total-prof3.self_cpu_time_total)/prof1.self_cpu_time_total*100)], - ["{:.2f}ms".format(prof4.self_cpu_time_total/1000), - "{:.2f}%".format((prof1.self_cpu_time_total-prof4.self_cpu_time_total)/prof1.self_cpu_time_total*100)], - ["{:.2f}ms".format(prof5.self_cpu_time_total/1000), - "{:.2f}%".format((prof1.self_cpu_time_total-prof5.self_cpu_time_total)/prof1.self_cpu_time_total*100)]], - columns=['Inference Time', 'Reduction'])], axis=1) - -print(df) - -""" - Model Inference Time Reduction -0 original model 1236.69ms 0% -1 scripted model 1226.72ms 0.81% -2 scripted & quantized model 593.19ms 52.03% -3 scripted & quantized & optimized model 598.01ms 51.64% -4 lite model 600.72ms 51.43% -""" - -###################################################################### -# Learn More -# ~~~~~~~~~~~~~~~~~ -# -# - `Facebook Data-efficient Image Transformers `__ -# - `Vision Transformer with ImageNet and MNIST on iOS `__ -# - `Vision Transformer with ImageNet and MNIST on Android `__ diff --git a/check_redirects.sh b/check_redirects.sh new file mode 100755 index 00000000000..4a0020c9c68 --- /dev/null +++ b/check_redirects.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Get the base branch (usually main or master) +BASE_BRANCH="main" +CURRENT_BRANCH=$(git branch --show-current) + +# Get list of deleted or renamed files in this branch compared to base +DELETED_FILES=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH | grep '^D\|^R' | awk '{print $2}' | grep -E '\.(rst|py|ipynb)$' | grep -v 'redirects.py') + +if [ -z "$DELETED_FILES" ]; then + echo "No deleted or renamed files found. Skipping check." + exit 0 +fi + +echo "Deleted or renamed files:" +echo "$DELETED_FILES" + +# Check if redirects.py has been updated +REDIRECTS_UPDATED=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH | grep -E '^M|^A' | grep 'redirects.py' && echo "yes" || echo "no") + +if [ "$REDIRECTS_UPDATED" == "no" ]; then + echo "ERROR: Files were deleted or renamed but redirects.py was not updated." + exit 1 +fi + +# Check if each deleted file has a redirect entry +MISSING_REDIRECTS=0 +for FILE in $DELETED_FILES; do + # Convert file path to URL path format (remove extension and adjust path) + URL_PATH=$(echo $FILE | sed 's/\.rst$//g' | sed 's/\.py$//g' | sed 's/\.ipynb$//g' | sed 's/^tutorials\///g') + + # Check if this path exists in redirects.py + if ! grep -q "\"$URL_PATH\"" tutorials/redirects.py; then + echo "ERROR: Missing redirect for deleted file: $FILE (URL path: $URL_PATH)" + MISSING_REDIRECTS=1 + fi +done + +if [ $MISSING_REDIRECTS -eq 1 ]; then + echo "ERROR: Please add redirects for all deleted/renamed files to redirects.py" + exit 1 +fi + +echo "All deleted/renamed files have proper redirects. Check passed!" + From d03f15b07f5fb29b68128a6d4cb9b700208cbbad Mon Sep 17 00:00:00 2001 From: Svetlana Karslioglu Date: Wed, 25 Jun 2025 19:54:54 -0700 Subject: [PATCH 2/4] Add check redirects GH action --- .../scripts/check_redirects.sh | 27 +- .github/workflows/check-redirects.yml | 56 +--- beginner_source/vt_tutorial.py | 293 ++++++++++++++++++ 3 files changed, 317 insertions(+), 59 deletions(-) rename check_redirects.sh => .github/scripts/check_redirects.sh (54%) create mode 100644 beginner_source/vt_tutorial.py diff --git a/check_redirects.sh b/.github/scripts/check_redirects.sh similarity index 54% rename from check_redirects.sh rename to .github/scripts/check_redirects.sh index 4a0020c9c68..c3009e519c9 100755 --- a/check_redirects.sh +++ b/.github/scripts/check_redirects.sh @@ -1,12 +1,16 @@ #!/bin/bash -# Get the base branch (usually main or master) -BASE_BRANCH="main" -CURRENT_BRANCH=$(git branch --show-current) +if [ "$CURRENT_BRANCH" == "$BASE_BRANCH" ]; then + echo "Running on $BASE_BRANCH branch. Skipping check." + exit 0 +fi + # Get list of deleted or renamed files in this branch compared to base -DELETED_FILES=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH | grep '^D\|^R' | awk '{print $2}' | grep -E '\.(rst|py|ipynb)$' | grep -v 'redirects.py') +DELETED_FILES=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH --diff-filter=DR | grep -E '\.(rst|py|md)$' | grep +| awk '{print $2}' | grep -E '\.(rst|py|md)$' | grep -v 'redirects.py') +# Check if any deleted or renamed files were found if [ -z "$DELETED_FILES" ]; then echo "No deleted or renamed files found. Skipping check." exit 0 @@ -16,10 +20,10 @@ echo "Deleted or renamed files:" echo "$DELETED_FILES" # Check if redirects.py has been updated -REDIRECTS_UPDATED=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH | grep -E '^M|^A' | grep 'redirects.py' && echo "yes" || echo "no") +REDIRECTS_UPDATED=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH --diff-filter=AM | grep 'redirects.py' && echo "yes" || echo "no") if [ "$REDIRECTS_UPDATED" == "no" ]; then - echo "ERROR: Files were deleted or renamed but redirects.py was not updated." + echo "ERROR: Files were deleted or renamed but redirects.py was not updated. Please update .github/scripts/redirects.py to redirect these files." exit 1 fi @@ -27,11 +31,11 @@ fi MISSING_REDIRECTS=0 for FILE in $DELETED_FILES; do # Convert file path to URL path format (remove extension and adjust path) - URL_PATH=$(echo $FILE | sed 's/\.rst$//g' | sed 's/\.py$//g' | sed 's/\.ipynb$//g' | sed 's/^tutorials\///g') - - # Check if this path exists in redirects.py - if ! grep -q "\"$URL_PATH\"" tutorials/redirects.py; then - echo "ERROR: Missing redirect for deleted file: $FILE (URL path: $URL_PATH)" + REDIRECT_PATH=$(echo $FILE | sed -E 's/(.+)_source\/(.+)\.(py|rst|md|ipynb)$/\1\/\2.html/') + + # Check if this path exists in redirects.py as a key (without checking the target) + if ! grep -q "\"$REDIRECT_PATH\":" redirects.py; then + echo "ERROR: Missing redirect for deleted file: $FILE (should have entry for \"$REDIRECT_PATH\")" MISSING_REDIRECTS=1 fi done @@ -42,4 +46,3 @@ if [ $MISSING_REDIRECTS -eq 1 ]; then fi echo "All deleted/renamed files have proper redirects. Check passed!" - diff --git a/.github/workflows/check-redirects.yml b/.github/workflows/check-redirects.yml index b93c6a082c9..942fa3df942 100644 --- a/.github/workflows/check-redirects.yml +++ b/.github/workflows/check-redirects.yml @@ -1,63 +1,25 @@ -name: Check Redirects for Deleted Files +name: Check Redirects for Deleted or Renamed Files on: pull_request: paths: - '**/*.rst' - '**/*.py' + - '**/*.md' jobs: check-redirects: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.11' - - - name: Check for deleted/renamed files and redirects + - name: Run redirect check script run: | - # Get list of deleted or renamed files in this PR - DELETED_FILES=$(git diff --name-status ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep '^D\|^R' | awk '{print $2}' | grep -E '\.(rst|py|ipynb)$' | grep -v 'redirects.py') - - if [ -z "$DELETED_FILES" ]; then - echo "No deleted or renamed files found. Skipping check." - exit 0 - fi - - echo "Deleted or renamed files:" - echo "$DELETED_FILES" - - # Check if redirects.py has been updated - REDIRECTS_UPDATED=$(git diff --name-status ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep -q '^M\|^A' | grep 'redirects.py' && echo "yes" || echo "no") - - if [ "$REDIRECTS_UPDATED" == "no" ]; then - echo "::error::Files were deleted or renamed but redirects.py was not updated. Please add redirects for deleted/renamed files." - exit 1 - fi - - # Check if each deleted file has a redirect entry - MISSING_REDIRECTS=0 - for FILE in $DELETED_FILES; do - # Convert file path to URL path format (remove extension and adjust path) - URL_PATH=$(echo $FILE | sed 's/\.rst$//g' | sed 's/\.py$//g' | sed 's/\.ipynb$//g' | sed 's/^tutorials\///g') - - # Check if this path exists in redirects.py - if ! grep -q "\"$URL_PATH\"" tutorials/redirects.py; then - echo "::error::Missing redirect for deleted file: $FILE (URL path: $URL_PATH)" - MISSING_REDIRECTS=1 - fi - done - - if [ $MISSING_REDIRECTS -eq 1 ]; then - echo "::error::Please add redirects for all deleted/renamed files to redirects.py" - exit 1 - fi - - echo "All deleted/renamed files have proper redirects. Check passed!" - + chmod +x ./.github/scripts/check_redirects.sh + ./.github/scripts/check_redirects.sh + env: + BASE_BRANCH: ${{ github.base_ref }} + CURRENT_BRANCH: ${{ github.head_ref }} diff --git a/beginner_source/vt_tutorial.py b/beginner_source/vt_tutorial.py new file mode 100644 index 00000000000..777098be946 --- /dev/null +++ b/beginner_source/vt_tutorial.py @@ -0,0 +1,293 @@ +""" +Optimizing Vision Transformer Model for Deployment +================================================== + +`Jeff Tang `_, +`Geeta Chauhan `_ + +Vision Transformer models apply the cutting-edge attention-based +transformer models, introduced in Natural Language Processing to achieve +all kinds of the state of the art (SOTA) results, to Computer Vision +tasks. Facebook Data-efficient Image Transformers `DeiT `_ +is a Vision Transformer model trained on ImageNet for image +classification. + +In this tutorial, we will first cover what DeiT is and how to use it, +then go through the complete steps of scripting, quantizing, optimizing, +and using the model in iOS and Android apps. We will also compare the +performance of quantized, optimized and non-quantized, non-optimized +models, and show the benefits of applying quantization and optimization +to the model along the steps. + +""" + + + +############################################################################### +# What is DeiT +# --------------------- +# +# Convolutional Neural Networks (CNNs) have been the main models for image +# classification since deep learning took off in 2012, but CNNs typically +# require hundreds of millions of images for training to achieve the +# SOTA results. DeiT is a vision transformer model that requires a lot less +# data and computing resources for training to compete with the leading +# CNNs in performing image classification, which is made possible by two +# key components of of DeiT: +# +# - Data augmentation that simulates training on a much larger dataset; +# - Native distillation that allows the transformer network to learn from +# a CNN’s output. +# +# DeiT shows that Transformers can be successfully applied to computer +# vision tasks, with limited access to data and resources. For more +# details on DeiT, see the `repo `_ +# and `paper `_. +# + + +###################################################################### +# Classifying Images with DeiT +# ------------------------------- +# +# Follow the ``README.md`` at the DeiT repository for detailed information on how to +# classify images using DeiT, or for a quick test, first install the +# required packages: +# +# .. code-block:: python +# +# pip install torch torchvision timm pandas requests + +####################################################### +# To run in Google Colab, install dependencies by running the following command: +# +# .. code-block:: python +# +# !pip install timm pandas requests + +############################# +# then run the script below: + +from PIL import Image +import torch +import timm +import requests +import torchvision.transforms as transforms +from timm.data.constants import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD + +print(torch.__version__) +# should be 1.8.0 + + +model = torch.hub.load('facebookresearch/deit:main', 'deit_base_patch16_224', pretrained=True) +model.eval() + +transform = transforms.Compose([ + transforms.Resize(256, interpolation=3), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD), +]) + +img = Image.open(requests.get("https://raw.githubusercontent.com/pytorch/ios-demo-app/master/HelloWorld/HelloWorld/HelloWorld/image.png", stream=True).raw) +img = transform(img)[None,] +out = model(img) +clsidx = torch.argmax(out) +print(clsidx.item()) + + +###################################################################### +# The output should be 269, which, according to the ImageNet list of class +# index to `labels file `_, maps to ``timber +# wolf, grey wolf, gray wolf, Canis lupus``. +# +# Now that we have verified that we can use the DeiT model to classify +# images, let’s see how to modify the model so it can run on iOS and +# Android apps. +# + + +###################################################################### +# Scripting DeiT +# ---------------------- +# To use the model on mobile, we first need to script the +# model. See the `Script and Optimize recipe `_ for a +# quick overview. Run the code below to convert the DeiT model used in the +# previous step to the TorchScript format that can run on mobile. +# + + +model = torch.hub.load('facebookresearch/deit:main', 'deit_base_patch16_224', pretrained=True) +model.eval() +scripted_model = torch.jit.script(model) +scripted_model.save("fbdeit_scripted.pt") + + +###################################################################### +# The scripted model file ``fbdeit_scripted.pt`` of size about 346MB is +# generated. +# + + +###################################################################### +# Quantizing DeiT +# --------------------- +# To reduce the trained model size significantly while +# keeping the inference accuracy about the same, quantization can be +# applied to the model. Thanks to the transformer model used in DeiT, we +# can easily apply dynamic-quantization to the model, because dynamic +# quantization works best for LSTM and transformer models (see `here `_ +# for more details). +# +# Now run the code below: +# + +# Use 'x86' for server inference (the old 'fbgemm' is still available but 'x86' is the recommended default) and ``qnnpack`` for mobile inference. +backend = "x86" # replaced with ``qnnpack`` causing much worse inference speed for quantized model on this notebook +model.qconfig = torch.quantization.get_default_qconfig(backend) +torch.backends.quantized.engine = backend + +quantized_model = torch.quantization.quantize_dynamic(model, qconfig_spec={torch.nn.Linear}, dtype=torch.qint8) +scripted_quantized_model = torch.jit.script(quantized_model) +scripted_quantized_model.save("fbdeit_scripted_quantized.pt") + + +###################################################################### +# This generates the scripted and quantized version of the model +# ``fbdeit_quantized_scripted.pt``, with size about 89MB, a 74% reduction of +# the non-quantized model size of 346MB! +# + +###################################################################### +# You can use the ``scripted_quantized_model`` to generate the same +# inference result: +# + +out = scripted_quantized_model(img) +clsidx = torch.argmax(out) +print(clsidx.item()) +# The same output 269 should be printed + +###################################################################### +# Optimizing DeiT +# --------------------- +# The final step before using the quantized and scripted +# model on mobile is to optimize it: +# + +from torch.utils.mobile_optimizer import optimize_for_mobile +optimized_scripted_quantized_model = optimize_for_mobile(scripted_quantized_model) +optimized_scripted_quantized_model.save("fbdeit_optimized_scripted_quantized.pt") + + +###################################################################### +# The generated ``fbdeit_optimized_scripted_quantized.pt`` file has about the +# same size as the quantized, scripted, but non-optimized model. The +# inference result remains the same. +# + + + +out = optimized_scripted_quantized_model(img) +clsidx = torch.argmax(out) +print(clsidx.item()) +# Again, the same output 269 should be printed + + +###################################################################### +# Using Lite Interpreter +# ------------------------ +# +# To see how much model size reduction and inference speed up the Lite +# Interpreter can result in, let’s create the lite version of the model. +# + +optimized_scripted_quantized_model._save_for_lite_interpreter("fbdeit_optimized_scripted_quantized_lite.ptl") +ptl = torch.jit.load("fbdeit_optimized_scripted_quantized_lite.ptl") + + +###################################################################### +# Although the lite model size is comparable to the non-lite version, when +# running the lite version on mobile, the inference speed up is expected. +# + + +###################################################################### +# Comparing Inference Speed +# --------------------------- +# +# To see how the inference speed differs for the four models - the +# original model, the scripted model, the quantized-and-scripted model, +# the optimized-quantized-and-scripted model - run the code below: +# + +with torch.autograd.profiler.profile(use_cuda=False) as prof1: + out = model(img) +with torch.autograd.profiler.profile(use_cuda=False) as prof2: + out = scripted_model(img) +with torch.autograd.profiler.profile(use_cuda=False) as prof3: + out = scripted_quantized_model(img) +with torch.autograd.profiler.profile(use_cuda=False) as prof4: + out = optimized_scripted_quantized_model(img) +with torch.autograd.profiler.profile(use_cuda=False) as prof5: + out = ptl(img) + +print("original model: {:.2f}ms".format(prof1.self_cpu_time_total/1000)) +print("scripted model: {:.2f}ms".format(prof2.self_cpu_time_total/1000)) +print("scripted & quantized model: {:.2f}ms".format(prof3.self_cpu_time_total/1000)) +print("scripted & quantized & optimized model: {:.2f}ms".format(prof4.self_cpu_time_total/1000)) +print("lite model: {:.2f}ms".format(prof5.self_cpu_time_total/1000)) + +###################################################################### +# The results running on a Google Colab are: +# +# .. code-block:: sh +# +# original model: 1236.69ms +# scripted model: 1226.72ms +# scripted & quantized model: 593.19ms +# scripted & quantized & optimized model: 598.01ms +# lite model: 600.72ms +# + + +###################################################################### +# The following results summarize the inference time taken by each model +# and the percentage reduction of each model relative to the original +# model. +# + +import pandas as pd +import numpy as np + +df = pd.DataFrame({'Model': ['original model','scripted model', 'scripted & quantized model', 'scripted & quantized & optimized model', 'lite model']}) +df = pd.concat([df, pd.DataFrame([ + ["{:.2f}ms".format(prof1.self_cpu_time_total/1000), "0%"], + ["{:.2f}ms".format(prof2.self_cpu_time_total/1000), + "{:.2f}%".format((prof1.self_cpu_time_total-prof2.self_cpu_time_total)/prof1.self_cpu_time_total*100)], + ["{:.2f}ms".format(prof3.self_cpu_time_total/1000), + "{:.2f}%".format((prof1.self_cpu_time_total-prof3.self_cpu_time_total)/prof1.self_cpu_time_total*100)], + ["{:.2f}ms".format(prof4.self_cpu_time_total/1000), + "{:.2f}%".format((prof1.self_cpu_time_total-prof4.self_cpu_time_total)/prof1.self_cpu_time_total*100)], + ["{:.2f}ms".format(prof5.self_cpu_time_total/1000), + "{:.2f}%".format((prof1.self_cpu_time_total-prof5.self_cpu_time_total)/prof1.self_cpu_time_total*100)]], + columns=['Inference Time', 'Reduction'])], axis=1) + +print(df) + +""" + Model Inference Time Reduction +0 original model 1236.69ms 0% +1 scripted model 1226.72ms 0.81% +2 scripted & quantized model 593.19ms 52.03% +3 scripted & quantized & optimized model 598.01ms 51.64% +4 lite model 600.72ms 51.43% +""" + +###################################################################### +# Learn More +# ~~~~~~~~~~~~~~~~~ +# +# - `Facebook Data-efficient Image Transformers `__ +# - `Vision Transformer with ImageNet and MNIST on iOS `__ +# - `Vision Transformer with ImageNet and MNIST on Android `__ From 23b845131b4b66971ae7254f16369336d1f7685e Mon Sep 17 00:00:00 2001 From: Svetlana Karslioglu Date: Thu, 26 Jun 2025 09:46:58 -0700 Subject: [PATCH 3/4] Update --- .github/workflows/check-redirects.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-redirects.yml b/.github/workflows/check-redirects.yml index 942fa3df942..380e3989bf4 100644 --- a/.github/workflows/check-redirects.yml +++ b/.github/workflows/check-redirects.yml @@ -3,9 +3,9 @@ name: Check Redirects for Deleted or Renamed Files on: pull_request: paths: - - '**/*.rst' - - '**/*.py' - - '**/*.md' + - '*/**/*.rst' + - '*/**/*.py' + - '*/**/*.md' jobs: check-redirects: From 4b0012c57509183fb76fea574b7745af5b35938a Mon Sep 17 00:00:00 2001 From: Svetlana Karslioglu Date: Thu, 26 Jun 2025 10:29:53 -0700 Subject: [PATCH 4/4] Update --- .github/scripts/check_redirects.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/scripts/check_redirects.sh b/.github/scripts/check_redirects.sh index c3009e519c9..6aa31819820 100755 --- a/.github/scripts/check_redirects.sh +++ b/.github/scripts/check_redirects.sh @@ -7,9 +7,7 @@ fi # Get list of deleted or renamed files in this branch compared to base -DELETED_FILES=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH --diff-filter=DR | grep -E '\.(rst|py|md)$' | grep -| awk '{print $2}' | grep -E '\.(rst|py|md)$' | grep -v 'redirects.py') - +DELETED_FILES=$(git diff --name-status $BASE_BRANCH $CURRENT_BRANCH --diff-filter=DR | awk '{print $2}' | grep -E '\.(rst|py|md)$' | grep -v 'redirects.py') # Check if any deleted or renamed files were found if [ -z "$DELETED_FILES" ]; then echo "No deleted or renamed files found. Skipping check." @@ -31,9 +29,9 @@ fi MISSING_REDIRECTS=0 for FILE in $DELETED_FILES; do # Convert file path to URL path format (remove extension and adjust path) - REDIRECT_PATH=$(echo $FILE | sed -E 's/(.+)_source\/(.+)\.(py|rst|md|ipynb)$/\1\/\2.html/') + REDIRECT_PATH=$(echo $FILE | sed -E 's/(.+)_source\/(.+)\.(py|rst|md)$/\1\/\2.html/') - # Check if this path exists in redirects.py as a key (without checking the target) + # Check if this path exists in redirects.py as a key. We don't check for values. if ! grep -q "\"$REDIRECT_PATH\":" redirects.py; then echo "ERROR: Missing redirect for deleted file: $FILE (should have entry for \"$REDIRECT_PATH\")" MISSING_REDIRECTS=1