chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:55 +08:00
commit c8a779b1bb
1887 changed files with 3245738 additions and 0 deletions
@@ -0,0 +1,43 @@
## About
This script presents a QAT end-to-end workflow (TF2-to-ONNX) for [Inception models](https://keras.io/api/applications/inceptionv3/) in `tf.keras.applications`.
### Contents
[Requirements](#requirements) • [Workflow](#workflow) • [Results](#results)
## Requirements
Install base requirements and prepare data. Please refer to [examples' README](../README.md).
## Workflow
### Step 1: Model Quantization and Fine-tuning
> Similar to [ResNet](../resnet): different model and different input pre-processing.
Please run the following to quantize, fine-tune, and save the final graph in SavedModel format (checkpoints are also saved).
```sh
python run_qat_workflow.py
```
### Step 2: Conversion to ONNX
Step 1 already does the conversion from SavedModel to ONNX automatically. For manual steps, please see step 3 in [EfficientNet's README](../efficientnet_b0/README.md).
### Step 3: TensorRT Deployment
Please refer to the [examples' README](../README.md).
## Results
Results obtained on NVIDIA's A100 GPU and TensorRT 8.4.2.4 (GA Update 1).
### Inception-v3
| Model | TF (%) | TF latency (ms, bs=1) | TRT(%) | TRT latency (ms, bs=1) |
|----------|--------|-----------------------|--------|------------------------|
| Baseline | 77.86 | 9.01 | 77.86 | 1.39 |
| PTQ | - | - | 77.73 | 0.82 |
| **QAT** | 78.11 | 101.97 | 78.08 | 0.82 |
### Notes
- Optimization: MaxPool needs to be quantized to trigger horizontal fusion in Concat layer.
- QAT fine-tuning hyper-params:
- Optimizer: `piecewise_sgd`, `lr_schedule=[(1.0, 1), (0.1, 2), (0.01, 7)]` (default)
- Hyper-parameters: `bs=64, ep=10, lr=0.001, steps_per_epoch=500`
- PTQ calibration: `bs=64`.
@@ -0,0 +1,178 @@
#
# SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
import tensorflow as tf
from tensorflow_quantization.quantize import quantize_model
from tensorflow_quantization.utils import convert_saved_model_to_onnx
from tensorflow_quantization.custom_qdq_cases import InceptionQDQCase
from examples.utils import ensure_dir, get_tfkeras_model
from examples.data.data_loader import load_data
from examples.utils_finetuning import (
get_finetuned_weights_dirname,
fine_tune,
compile_model,
)
import gc
import numpy as np
import random
import sys
import logging
MODEL_NAME = "inception_v3" # Options=[inception_v3]
HYPERPARAMS = {
# ################ Data loading ################
"tfrecord_data_dir": "/media/Data/imagenet_data/tf_records",
"batch_size": 64,
"train_data_size": None, # Only for `tfrecord`. If None, consider all data, otherwise, consider subset.
"val_data_size": None, # Only for `tfrecord`. If None, consider all data, otherwise, consider subset.
# ############## Fine-tuning ##################
"epochs": 10,
"steps_per_epoch": 500, # 500, # 'None' if you want to use the default number of steps. If you use this, make sure the number of steps is <= the number of shards (total number of samples / batch_size). Otherwise, an error will occur.
"base_lr": 0.001, # 0.0001
"optimizer": "piecewise_sgd", # Options={sgd, piecewise_sgd, adam}
"save_root_dir": "./weights/{}".format(
MODEL_NAME
), # DIR is updated to reflect hyperparams
# ############## Enable/disable tasks ##################
"finetune_qat_model": True, # If True, finetune QAT model. Otherwise, just quantize and load weights if existent.
"rewrite_weights_qat_finetuning": True, # If True, rewrites existing fine-tuned weights. Otherwise, just load weights if they exist.
"evaluate_baseline_model": True,
"evaluate_qat_model": True,
"save_baseline_model": True,
"seed": 42,
}
# Set seed for reproducible results
os.environ["PYTHONHASHSEED"] = str(HYPERPARAMS["seed"])
random.seed(HYPERPARAMS["seed"])
np.random.seed(HYPERPARAMS["seed"])
tf.random.set_seed(HYPERPARAMS["seed"])
# Create logger and save to out.log
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)
def main():
# ------------- Initial settings -------------
# Create directory to save the fine-tuned weights + add relevant hyperparameters in the name
qat_save_finetuned_weights = get_finetuned_weights_dirname(HYPERPARAMS)
ensure_dir(qat_save_finetuned_weights)
# Add terminal and file handlers to logger
output_file_handler = logging.FileHandler(
os.path.join(qat_save_finetuned_weights, "out.log"), mode="w"
)
stdout_handler = logging.StreamHandler(sys.stdout)
LOGGER.addHandler(output_file_handler)
LOGGER.addHandler(stdout_handler)
# Load data
train_batches, val_batches = load_data(HYPERPARAMS, model_name=MODEL_NAME)
# ------------- Baseline model -------------
LOGGER.info("------------- Baseline model -------------")
# Instantiate Baseline model
model = get_tfkeras_model(model_name=MODEL_NAME)
if HYPERPARAMS["evaluate_baseline_model"]:
# Compile model (needed to evaluate model)
compile_model(model)
_, baseline_model_accuracy = model.evaluate(val_batches)
LOGGER.info("Baseline val accuracy: {}".format(baseline_model_accuracy))
if HYPERPARAMS["save_baseline_model"]:
tf.keras.models.save_model(
model, os.path.join(HYPERPARAMS["save_root_dir"], "saved_model_baseline")
)
convert_saved_model_to_onnx(
saved_model_dir=os.path.join(
HYPERPARAMS["save_root_dir"], "saved_model_baseline"
),
onnx_model_path=os.path.join(
HYPERPARAMS["save_root_dir"], "model_baseline.onnx"
),
)
# ------------- QAT model -------------
# Quantize model
LOGGER.info("\n------------- QAT model -------------")
q_model = quantize_model(model, custom_qdq_cases=[InceptionQDQCase()])
# q_model = quantize_model(model)
finetuned_qat_weights_path = os.path.join(
qat_save_finetuned_weights, "checkpoints_best"
)
# Performs fine-tuning if `rewrite` is enabled or if fine-tuned weights don't exist yet
# (1st time fine-tuning model).
if HYPERPARAMS["finetune_qat_model"] and (
HYPERPARAMS["rewrite_weights_qat_finetuning"]
or not os.path.exists(finetuned_qat_weights_path)
):
# Fine-tuning + saving new checkpoints
LOGGER.info("\nFine-tuning model...")
fine_tune(
q_model,
train_batches,
val_batches,
qat_save_finetuned_weights,
HYPERPARAMS,
LOGGER,
)
LOGGER.info("Fine-tuning done!")
# Loads best weights if they exist
if os.path.exists(finetuned_qat_weights_path + ".index"):
LOGGER.info("Loading fine-tuned weights...")
q_model.load_weights(finetuned_qat_weights_path).expect_partial()
LOGGER.info("Loaded complete!")
compile_model(q_model)
if HYPERPARAMS["evaluate_qat_model"]:
LOGGER.info("\nEvaluating QAT model...")
_, qat_model_accuracy = q_model.evaluate(val_batches)
LOGGER.info("QAT val accuracy: {}".format(qat_model_accuracy))
# Save quantized model
LOGGER.info("\nSaving QAT model")
tf.keras.models.save_model(
q_model, os.path.join(qat_save_finetuned_weights, "saved_model")
)
# Clear GPU and invoke Garbage Collector to avoid script ending during ONNX conversion
tf.keras.backend.clear_session()
gc.collect()
del model
del q_model
# Convert SavedModel to ONNX
LOGGER.info("\nONNX conversion...")
convert_saved_model_to_onnx(
saved_model_dir=os.path.join(qat_save_finetuned_weights, "saved_model"),
onnx_model_path=os.path.join(qat_save_finetuned_weights, "model.onnx"),
)
if __name__ == "__main__":
main()
@@ -0,0 +1,61 @@
#
# SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import tensorflow as tf
from tensorflow_quantization.custom_qdq_cases import InceptionQDQCase
from examples.utils import get_tfkeras_model
from tests.onnx_graph_qdq_validator import validate_quantized_model
from tensorflow_quantization.utils import CreateAssetsFolders
from tensorflow_quantization.quantize import LayerConfig
import pytest
# Create a directory to save test models
test_assets = CreateAssetsFolders("test_qdq_node_placement")
EXPECTED_QDQ_INSERTION = [
LayerConfig(name="Conv2D", is_keras_class=True),
LayerConfig(name="Dense", is_keras_class=True),
LayerConfig(name="DepthwiseConv2D", is_keras_class=True),
LayerConfig(
name="AveragePooling2D", is_keras_class=True, quantize_weight=False
),
LayerConfig(
name="GlobalAveragePooling2D", is_keras_class=True, quantize_weight=False
)
]
def test_inceptionv3_quantize_full():
"""
Inception-v3: Full model quantization
"""
this_function_name = sys._getframe().f_code.co_name
# Instantiate Baseline model
nn_model_original = get_tfkeras_model(model_name="inception_v3")
custom_qdq_cases = [InceptionQDQCase()]
q_model, validated = validate_quantized_model(
test_assets, nn_model_original, test_name=this_function_name,
custom_qdq_cases=custom_qdq_cases,
expected_qdq_insertion=EXPECTED_QDQ_INSERTION
)
assert validated, "ONNX QDQ validation for full network quantization failed!"
# necessary to clear model layer names from the memory
tf.keras.backend.clear_session()