chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Waiting to run
Docker Image CI / build-ubuntu2004 (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,749 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import datetime\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import time\n",
|
||||
"import collections\n",
|
||||
"\n",
|
||||
"import torch\n",
|
||||
"import torch.utils.data\n",
|
||||
"from torch import nn\n",
|
||||
"\n",
|
||||
"from tqdm import tqdm\n",
|
||||
"\n",
|
||||
"import torchvision\n",
|
||||
"from torchvision import transforms\n",
|
||||
"\n",
|
||||
"from pytorch_quantization import nn as quant_nn\n",
|
||||
"from pytorch_quantization import calib\n",
|
||||
"from pytorch_quantization.tensor_quant import QuantDescriptor\n",
|
||||
"\n",
|
||||
"from absl import logging\n",
|
||||
"logging.set_verbosity(logging.FATAL) # Disable logging as they are too noisy in notebook\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# For simplicity, import train and eval functions from the train script from torchvision instead of copything them here\n",
|
||||
"# Download torchvision from https://github.com/pytorch/vision\n",
|
||||
"sys.path.append(\"/raid/skyw/models/torchvision/references/classification/\")\n",
|
||||
"from train import evaluate, train_one_epoch, load_data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Set default QuantDescriptor to use histogram based calibration for activation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"quant_desc_input = QuantDescriptor(calib_method='histogram')\n",
|
||||
"quant_nn.QuantConv2d.set_default_quant_desc_input(quant_desc_input)\n",
|
||||
"quant_nn.QuantLinear.set_default_quant_desc_input(quant_desc_input)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Initialize quantized modules"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from pytorch_quantization import quant_modules\n",
|
||||
"quant_modules.initialize()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Create model with pretrained weight"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"ResNet(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)\n",
|
||||
" (layer1): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (layer2): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (3): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (layer3): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (3): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (4): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (5): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (layer4): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))\n",
|
||||
" (fc): QuantLinear(\n",
|
||||
" in_features=2048, out_features=1000, bias=True\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator quant)\n",
|
||||
" )\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"model = torchvision.models.resnet50(pretrained=True, progress=False)\n",
|
||||
"model.cuda()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Create data loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Loading data\n",
|
||||
"Loading training data\n",
|
||||
"Took 3.580507755279541\n",
|
||||
"Loading validation data\n",
|
||||
"Creating data loaders\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data_path = \"/raid/data/imagenet/imagenet_pytorch\"\n",
|
||||
"batch_size = 512\n",
|
||||
"\n",
|
||||
"traindir = os.path.join(data_path, 'train')\n",
|
||||
"valdir = os.path.join(data_path, 'val')\n",
|
||||
"_args = collections.namedtuple('mock_args', ['model', 'distributed', 'cache_dataset'])\n",
|
||||
"dataset, dataset_test, train_sampler, test_sampler = load_data(traindir, valdir, _args(model='resnet50', distributed=False, cache_dataset=False))\n",
|
||||
"\n",
|
||||
"data_loader = torch.utils.data.DataLoader(\n",
|
||||
" dataset, batch_size=batch_size,\n",
|
||||
" sampler=train_sampler, num_workers=4, pin_memory=True)\n",
|
||||
"\n",
|
||||
"data_loader_test = torch.utils.data.DataLoader(\n",
|
||||
" dataset_test, batch_size=batch_size,\n",
|
||||
" sampler=test_sampler, num_workers=4, pin_memory=True)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Calibrate the model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def collect_stats(model, data_loader, num_batches):\n",
|
||||
" \"\"\"Feed data to the network and collect statistic\"\"\"\n",
|
||||
"\n",
|
||||
" # Enable calibrators\n",
|
||||
" for name, module in model.named_modules():\n",
|
||||
" if isinstance(module, quant_nn.TensorQuantizer):\n",
|
||||
" if module._calibrator is not None:\n",
|
||||
" module.disable_quant()\n",
|
||||
" module.enable_calib()\n",
|
||||
" else:\n",
|
||||
" module.disable()\n",
|
||||
"\n",
|
||||
" for i, (image, _) in tqdm(enumerate(data_loader), total=num_batches):\n",
|
||||
" model(image.cuda())\n",
|
||||
" if i >= num_batches:\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" # Disable calibrators\n",
|
||||
" for name, module in model.named_modules():\n",
|
||||
" if isinstance(module, quant_nn.TensorQuantizer):\n",
|
||||
" if module._calibrator is not None:\n",
|
||||
" module.enable_quant()\n",
|
||||
" module.disable_calib()\n",
|
||||
" else:\n",
|
||||
" module.enable()\n",
|
||||
" \n",
|
||||
"def compute_amax(model, **kwargs):\n",
|
||||
" # Load calib result\n",
|
||||
" for name, module in model.named_modules():\n",
|
||||
" if isinstance(module, quant_nn.TensorQuantizer):\n",
|
||||
" if module._calibrator is not None:\n",
|
||||
" if isinstance(module._calibrator, calib.MaxCalibrator):\n",
|
||||
" module.load_calib_amax()\n",
|
||||
" else:\n",
|
||||
" module.load_calib_amax(**kwargs)\n",
|
||||
"# print(F\"{name:40}: {module}\")\n",
|
||||
" model.cuda()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"100%|██████████| 2/2 [04:50<00:00, 111.13s/it]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# It is a bit slow since we collect histograms on CPU\n",
|
||||
"with torch.no_grad():\n",
|
||||
" collect_stats(model, data_loader, num_batches=2)\n",
|
||||
" compute_amax(model, method=\"percentile\", percentile=99.99)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Now evaluate the calibrated model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Test: [ 0/98] eta: 0:05:53 loss: 0.5656 (0.5656) acc1: 85.7422 (85.7422) acc5: 96.0938 (96.0938) time: 3.6079 data: 2.8152 max mem: 5880\n",
|
||||
"Test: [20/98] eta: 0:01:07 loss: 0.6741 (0.6825) acc1: 82.8125 (82.4219) acc5: 95.8984 (95.7682) time: 0.7343 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [40/98] eta: 0:00:46 loss: 0.6995 (0.7157) acc1: 80.0781 (81.4024) acc5: 96.0938 (95.7412) time: 0.7226 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [60/98] eta: 0:00:29 loss: 1.1064 (0.8590) acc1: 71.4844 (78.2627) acc5: 91.0156 (94.1150) time: 0.7259 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [80/98] eta: 0:00:13 loss: 1.1220 (0.9372) acc1: 72.4609 (76.7072) acc5: 89.6484 (93.1375) time: 0.7220 data: 0.0002 max mem: 5882\n",
|
||||
"Test: Total time: 0:01:13\n",
|
||||
" * Acc@1 76.138 Acc@5 92.916\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"criterion = nn.CrossEntropyLoss()\n",
|
||||
"with torch.no_grad():\n",
|
||||
" evaluate(model, criterion, data_loader_test, device=\"cuda\", print_freq=20)\n",
|
||||
" \n",
|
||||
"# Save the model\n",
|
||||
"torch.save(model.state_dict(), \"/tmp/quant_resnet50-calibrated.pth\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## We can also try different calibrations and see which one works the best"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Test: [ 0/98] eta: 0:05:27 loss: 0.6037 (0.6037) acc1: 84.9609 (84.9609) acc5: 95.3125 (95.3125) time: 3.3411 data: 2.6190 max mem: 5882\n",
|
||||
"Test: [20/98] eta: 0:01:06 loss: 0.6760 (0.7041) acc1: 81.2500 (81.7522) acc5: 95.7031 (95.4892) time: 0.7243 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [40/98] eta: 0:00:45 loss: 0.7241 (0.7351) acc1: 79.1016 (80.7784) acc5: 95.8984 (95.4459) time: 0.7243 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [60/98] eta: 0:00:29 loss: 1.1162 (0.8793) acc1: 71.4844 (77.6383) acc5: 90.8203 (93.7948) time: 0.7204 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [80/98] eta: 0:00:13 loss: 1.1498 (0.9603) acc1: 71.4844 (76.0368) acc5: 89.4531 (92.7156) time: 0.7164 data: 0.0002 max mem: 5882\n",
|
||||
"Test: Total time: 0:01:12\n",
|
||||
" * Acc@1 75.438 Acc@5 92.486\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with torch.no_grad():\n",
|
||||
" compute_amax(model, method=\"percentile\", percentile=99.9)\n",
|
||||
" evaluate(model, criterion, data_loader_test, device=\"cuda\", print_freq=20)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"mse calibration\n",
|
||||
"Test: [ 0/98] eta: 0:06:34 loss: 0.5700 (0.5700) acc1: 85.1562 (85.1562) acc5: 96.2891 (96.2891) time: 4.0243 data: 3.3231 max mem: 5882\n",
|
||||
"Test: [20/98] eta: 0:01:08 loss: 0.6758 (0.6838) acc1: 82.8125 (82.5707) acc5: 96.0938 (95.7868) time: 0.7204 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [40/98] eta: 0:00:46 loss: 0.7047 (0.7163) acc1: 80.2734 (81.4834) acc5: 96.2891 (95.7746) time: 0.7178 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [60/98] eta: 0:00:29 loss: 1.1127 (0.8585) acc1: 71.0938 (78.3395) acc5: 90.8203 (94.1278) time: 0.7192 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [80/98] eta: 0:00:13 loss: 1.1261 (0.9367) acc1: 72.6562 (76.7530) acc5: 89.8438 (93.1785) time: 0.7176 data: 0.0002 max mem: 5882\n",
|
||||
"Test: Total time: 0:01:13\n",
|
||||
" * Acc@1 76.186 Acc@5 92.926\n",
|
||||
"entropy calibration\n",
|
||||
"Test: [ 0/98] eta: 0:05:28 loss: 0.5648 (0.5648) acc1: 85.3516 (85.3516) acc5: 96.0938 (96.0938) time: 3.3558 data: 2.6268 max mem: 5882\n",
|
||||
"Test: [20/98] eta: 0:01:05 loss: 0.6724 (0.6815) acc1: 82.8125 (82.5428) acc5: 95.8984 (95.7589) time: 0.7196 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [40/98] eta: 0:00:45 loss: 0.7090 (0.7149) acc1: 80.6641 (81.4929) acc5: 96.0938 (95.7269) time: 0.7214 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [60/98] eta: 0:00:29 loss: 1.1077 (0.8571) acc1: 72.0703 (78.3779) acc5: 90.6250 (94.0798) time: 0.7198 data: 0.0002 max mem: 5882\n",
|
||||
"Test: [80/98] eta: 0:00:13 loss: 1.1253 (0.9356) acc1: 72.2656 (76.7626) acc5: 90.0391 (93.1231) time: 0.7192 data: 0.0002 max mem: 5882\n",
|
||||
"Test: Total time: 0:01:12\n",
|
||||
" * Acc@1 76.206 Acc@5 92.900\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with torch.no_grad():\n",
|
||||
" for method in [\"mse\", \"entropy\"]:\n",
|
||||
" print(F\"{method} calibration\")\n",
|
||||
" compute_amax(model, method=method)\n",
|
||||
" evaluate(model, criterion, data_loader_test, device=\"cuda\", print_freq=20)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,605 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Following the calibrate_quant_resnet50 example, now we fine tune the model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"WARNING: Logging before flag parsing goes to stderr.\n",
|
||||
"W0608 21:25:39.018203 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n",
|
||||
"W0608 21:25:39.019082 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n",
|
||||
"W0608 21:25:39.019555 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n",
|
||||
"W0608 21:25:39.020030 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n",
|
||||
"W0608 21:25:39.020492 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n",
|
||||
"W0608 21:25:39.020947 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n",
|
||||
"W0608 21:25:39.021392 140228493526848 tensor_quant.py:96] Meaning of axis has changed since v2.0. Make sure to update.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import datetime\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import torch\n",
|
||||
"import torch.utils.data\n",
|
||||
"from torch import nn\n",
|
||||
"\n",
|
||||
"from tqdm import tqdm\n",
|
||||
"\n",
|
||||
"import torchvision\n",
|
||||
"from torchvision import transforms\n",
|
||||
"\n",
|
||||
"from pytorch_quantization import nn as quant_nn\n",
|
||||
"from pytorch_quantization import calib\n",
|
||||
"from pytorch_quantization.tensor_quant import QuantDescriptor\n",
|
||||
"\n",
|
||||
"from absl import logging\n",
|
||||
"logging.set_verbosity(logging.FATAL) # Disable logging as they are too noisy in notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# For simplicity, import train and eval functions from the train script from torchvision instead of copything them here\n",
|
||||
"sys.path.append(\"/raid/skyw/models/torchvision/references/classification/\")\n",
|
||||
"from train import evaluate, train_one_epoch, load_data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"QuantResNet(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=2.6387 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.7817](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)\n",
|
||||
" (layer1): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=2.9730 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.7266](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.0971 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.4679](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3318 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3936](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=2.9730 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.9879](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.4872 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.2618](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.0466 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0564, 0.5201](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5106 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.2946](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5250 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0533, 0.1921](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9980 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0810, 0.2856](64) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.6532 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0197, 0.2752](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (layer2): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5499 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0670, 0.3532](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1606 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0694, 0.2993](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1425 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3917](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5499 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.5662](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.4626 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0370, 0.2522](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.8304 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0142, 0.2998](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1722 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3038](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.4864 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0653, 0.2383](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9450 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0646, 0.2556](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.8535 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0162, 0.3522](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (3): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5229 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0648, 0.2814](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9247 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0595, 0.2210](128) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9747 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0127, 0.2956](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (layer3): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5941 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0842, 0.3425](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3565 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0544, 0.2008](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.0293 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3212](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.5941 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3460](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3305 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0407, 0.2942](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9844 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0432, 0.2634](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9333 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.4969](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3388 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0469, 0.2715](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.8617 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0397, 0.2100](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.7507 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3538](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (3): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3554 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0553, 0.2390](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9257 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0455, 0.2792](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.8117 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0000, 0.3126](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (4): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.4199 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0598, 0.2722](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.9274 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0459, 0.1919](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.8702 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0160, 0.3161](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (5): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.4258 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0618, 0.3995](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.2256 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0498, 0.2236](256) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3560 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0180, 0.3288](1024) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (layer4): Sequential(\n",
|
||||
" (0): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3915 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0744, 0.3415](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1571 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0432, 0.3993](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1295 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0198, 0.3546](2048) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" (downsample): Sequential(\n",
|
||||
" (0): QuantConv2d(\n",
|
||||
" 1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.3915 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0197, 0.6413](2048) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (1): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (1): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=3.9348 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0482, 0.7003](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1277 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0379, 0.2257](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=0.8992 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0211, 0.2427](2048) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" (2): Bottleneck(\n",
|
||||
" (conv1): QuantConv2d(\n",
|
||||
" 2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=5.2181 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0601, 0.4541](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv2): QuantConv2d(\n",
|
||||
" 512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.2051 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0338, 0.1416](512) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (conv3): QuantConv2d(\n",
|
||||
" 512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=1.1045 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.0119, 0.2798](2048) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
" (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
|
||||
" (relu): ReLU(inplace=True)\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
" (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))\n",
|
||||
" (fc): QuantLinear(\n",
|
||||
" in_features=2048, out_features=1000, bias=True\n",
|
||||
" (_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=5.5345 calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" (_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=[0.1716, 0.7371](1000) calibrator=MaxCalibrator(track_amax=False) quant)\n",
|
||||
" )\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from pytorch_quantization import quant_modules\n",
|
||||
"quant_modules.initialize()\n",
|
||||
"\n",
|
||||
"# Create and load the calibrated model\n",
|
||||
"model = torchvision.models.resnet50()\n",
|
||||
"model.load_state_dict(torch.load(\"/tmp/quant_resnet50-calibrated.pth\"))\n",
|
||||
"model.cuda()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"data_path = \"/raid/data/imagenet/imagenet_pytorch\"\n",
|
||||
"\n",
|
||||
"traindir = os.path.join(data_path, 'train')\n",
|
||||
"valdir = os.path.join(data_path, 'val')\n",
|
||||
"dataset, dataset_test, train_sampler, test_sampler = load_data(traindir, valdir, False, False)\n",
|
||||
"\n",
|
||||
"data_loader = torch.utils.data.DataLoader(\n",
|
||||
" dataset, batch_size=256,\n",
|
||||
" sampler=train_sampler, num_workers=4, pin_memory=True)\n",
|
||||
"\n",
|
||||
"data_loader_test = torch.utils.data.DataLoader(\n",
|
||||
" dataset_test, batch_size=256,\n",
|
||||
" sampler=test_sampler, num_workers=4, pin_memory=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Quantized fine tuning\n",
|
||||
"Let's fine tune the model with fake quantization. We only fine tune for 1 epoch as an example."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"criterion = nn.CrossEntropyLoss()\n",
|
||||
"optimizer = torch.optim.SGD(model.parameters(), lr=0.0001)\n",
|
||||
"lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.1)\n",
|
||||
"\n",
|
||||
"data_loader = torch.utils.data.DataLoader(\n",
|
||||
" dataset, batch_size=128,\n",
|
||||
" sampler=train_sampler, num_workers=16, pin_memory=True)\n",
|
||||
"\n",
|
||||
"# Training takes about one and half hour per epoch on single V100\n",
|
||||
"train_one_epoch(model, criterion, optimizer, data_loader, \"cuda\", 0, 100)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Evaluate the fine tuned model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Test: [ 0/196] eta: 0:09:36 loss: 0.4680 (0.4680) acc1: 85.9375 (85.9375) acc5: 98.0469 (98.0469) time: 2.9406 data: 2.1852 max mem: 16096\n",
|
||||
"Test: [ 10/196] eta: 0:01:58 loss: 0.6694 (0.6522) acc1: 83.2031 (82.9545) acc5: 96.0938 (96.1293) time: 0.6346 data: 0.1988 max mem: 16096\n",
|
||||
"Test: [ 20/196] eta: 0:01:30 loss: 0.6738 (0.6733) acc1: 82.0312 (82.4777) acc5: 95.7031 (95.7961) time: 0.3928 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 30/196] eta: 0:01:18 loss: 0.6219 (0.6322) acc1: 84.3750 (83.9718) acc5: 95.7031 (96.0181) time: 0.3859 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 40/196] eta: 0:01:10 loss: 0.6801 (0.6750) acc1: 81.6406 (82.5934) acc5: 95.7031 (95.9604) time: 0.3861 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 50/196] eta: 0:01:04 loss: 0.6937 (0.6724) acc1: 80.0781 (82.3529) acc5: 96.8750 (96.0938) time: 0.3834 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 60/196] eta: 0:00:58 loss: 0.7149 (0.6849) acc1: 80.0781 (81.9864) acc5: 96.4844 (96.1066) time: 0.3854 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 70/196] eta: 0:00:53 loss: 0.6616 (0.6716) acc1: 80.8594 (82.2843) acc5: 96.4844 (96.1983) time: 0.3859 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 80/196] eta: 0:00:48 loss: 0.6510 (0.6968) acc1: 81.2500 (81.7467) acc5: 95.7031 (95.9201) time: 0.3860 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [ 90/196] eta: 0:00:44 loss: 0.9469 (0.7444) acc1: 76.1719 (80.6834) acc5: 92.5781 (95.4370) time: 0.3868 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [100/196] eta: 0:00:39 loss: 1.1594 (0.7964) acc1: 70.7031 (79.5521) acc5: 90.6250 (94.8755) time: 0.3864 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [110/196] eta: 0:00:35 loss: 1.1594 (0.8214) acc1: 72.2656 (79.0365) acc5: 91.4062 (94.6298) time: 0.3836 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [120/196] eta: 0:00:31 loss: 0.9820 (0.8389) acc1: 76.1719 (78.7771) acc5: 92.1875 (94.3634) time: 0.3856 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [130/196] eta: 0:00:26 loss: 1.0825 (0.8705) acc1: 72.6562 (77.9610) acc5: 91.4062 (94.0303) time: 0.3866 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [140/196] eta: 0:00:22 loss: 1.1088 (0.8889) acc1: 72.2656 (77.6125) acc5: 91.4062 (93.8137) time: 0.3879 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [150/196] eta: 0:00:18 loss: 1.1069 (0.9059) acc1: 73.0469 (77.2998) acc5: 91.0156 (93.5586) time: 0.3914 data: 0.0002 max mem: 16096\n",
|
||||
"Test: [160/196] eta: 0:00:14 loss: 1.1360 (0.9197) acc1: 73.0469 (77.0380) acc5: 90.2344 (93.3472) time: 0.3898 data: 0.0002 max mem: 16096\n",
|
||||
"Test: [170/196] eta: 0:00:10 loss: 1.2171 (0.9371) acc1: 71.8750 (76.6265) acc5: 89.8438 (93.1721) time: 0.3845 data: 0.0002 max mem: 16096\n",
|
||||
"Test: [180/196] eta: 0:00:06 loss: 1.2493 (0.9527) acc1: 68.7500 (76.2992) acc5: 90.2344 (93.0205) time: 0.3815 data: 0.0001 max mem: 16096\n",
|
||||
"Test: [190/196] eta: 0:00:02 loss: 1.0816 (0.9511) acc1: 71.4844 (76.3089) acc5: 92.1875 (93.0465) time: 0.3736 data: 0.0001 max mem: 16096\n",
|
||||
"Test: Total time: 0:01:17\n",
|
||||
" * Acc@1 76.426 Acc@5 93.080\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"with torch.no_grad():\n",
|
||||
" evaluate(model, criterion, data_loader_test, device=\"cuda\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"After only 1 epoch of quantized fine tuning, top-1 improved from ~76.1 to 76.426. Train longer with lr anealing can improve accuracy further"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,657 @@
|
||||
#
|
||||
# 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 datetime
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import argparse
|
||||
import warnings
|
||||
import collections
|
||||
|
||||
import subprocess
|
||||
|
||||
import torch
|
||||
import torch.utils.data
|
||||
|
||||
from collections import namedtuple
|
||||
from torch import nn
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
import torchvision
|
||||
from torchvision import transforms
|
||||
from torch.hub import load_state_dict_from_url
|
||||
|
||||
from pytorch_quantization import nn as quant_nn
|
||||
from pytorch_quantization import calib
|
||||
from pytorch_quantization.tensor_quant import QuantDescriptor
|
||||
from pytorch_quantization import quant_modules
|
||||
|
||||
import onnxruntime
|
||||
import numpy as np
|
||||
import models.classification as models
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
# The following path assumes running in nvcr.io/nvidia/pytorch:20.08-py3
|
||||
sys.path.insert(0, "/opt/pytorch/vision/references/classification/")
|
||||
|
||||
# Import functions from torchvision reference
|
||||
try:
|
||||
from train import evaluate, train_one_epoch, load_data, utils
|
||||
except Exception as e:
|
||||
raise ModuleNotFoundError(
|
||||
"Add https://github.com/pytorch/vision/blob/master/references/classification/ to PYTHONPATH")
|
||||
|
||||
|
||||
def get_parser():
|
||||
"""
|
||||
Creates an argument parser.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='Classification quantization flow script')
|
||||
|
||||
parser.add_argument('--data-dir', '-d', type=str, help='input data folder', required=True)
|
||||
parser.add_argument('--model-name', '-m', default='resnet50', help='model name: default resnet50')
|
||||
parser.add_argument('--disable-pcq',
|
||||
'-dpcq',
|
||||
action="store_true",
|
||||
help='disable per-channel quantization for weights')
|
||||
parser.add_argument('--out-dir', '-o', default='/tmp', help='output folder: default /tmp')
|
||||
parser.add_argument('--print-freq', '-pf', type=int, default=20, help='evaluation print frequency: default 20')
|
||||
parser.add_argument('--threshold',
|
||||
'-t',
|
||||
type=float,
|
||||
default=-1.0,
|
||||
help='top1 accuracy threshold (less than 0.0 means no comparison): default -1.0')
|
||||
|
||||
parser.add_argument('--fp16', action="store_true", help="Enable FP16 model training, evaluation and export")
|
||||
|
||||
parser.add_argument('--batch-size-train', type=int, default=128, help='batch size for training: default 128')
|
||||
parser.add_argument('--batch-size-test', type=int, default=128, help='batch size for testing: default 128')
|
||||
parser.add_argument('--batch-size-onnx', type=int, default=1, help='batch size for onnx: default 1')
|
||||
|
||||
parser.add_argument('--seed', type=int, default=12345, help='random seed: default 12345')
|
||||
|
||||
checkpoint = parser.add_mutually_exclusive_group(required=True)
|
||||
checkpoint.add_argument('--ckpt-path', default='', type=str, help='path to latest checkpoint (default: none)')
|
||||
checkpoint.add_argument('--ckpt-url', default='', type=str, help='url to latest checkpoint (default: none)')
|
||||
checkpoint.add_argument('--pretrained', action="store_true")
|
||||
|
||||
parser.add_argument('--num-calib-batch',
|
||||
default=4,
|
||||
type=int,
|
||||
help='Number of batches for calibration. 0 will disable calibration. (default: 4)')
|
||||
parser.add_argument('--num-finetune-epochs',
|
||||
default=0,
|
||||
type=int,
|
||||
help='Number of epochs to fine tune. 0 will disable fine tune. (default: 0)')
|
||||
parser.add_argument('--calibrator', type=str, choices=["max", "histogram"], default="max")
|
||||
parser.add_argument('--percentile', nargs='+', type=float, default=[99.9, 99.99, 99.999, 99.9999])
|
||||
parser.add_argument('--sensitivity', action="store_true", help="Build sensitivity profile")
|
||||
parser.add_argument('--evaluate-onnx', action="store_true", help="Evaluate exported ONNX")
|
||||
parser.add_argument('--evaluate-trt', action="store_true", help="Export and evaluate TRT")
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def prepare_model(model_name,
|
||||
data_dir,
|
||||
per_channel_quantization,
|
||||
batch_size_train,
|
||||
batch_size_test,
|
||||
batch_size_onnx,
|
||||
calibrator,
|
||||
pretrained=True,
|
||||
ckpt_path=None,
|
||||
ckpt_url=None,
|
||||
fp16=False):
|
||||
"""
|
||||
Prepare the model for the classification flow.
|
||||
Arguments:
|
||||
model_name: name to use when accessing torchvision model dictionary
|
||||
data_dir: directory with train and val subdirs prepared "imagenet style"
|
||||
per_channel_quantization: iff true use per channel quantization for weights
|
||||
note that this isn't currently supported in ONNX-RT/Pytorch
|
||||
batch_size_train: batch size to use when training
|
||||
batch_size_test: batch size to use when testing in Pytorch
|
||||
batch_size_onnx: batch size to use when testing with ONNX-RT
|
||||
calibrator: calibration type to use (max/histogram)
|
||||
|
||||
pretrained: if true a pretrained model will be loaded from torchvision
|
||||
ckpt_path: path to load a model checkpoint from, if not pretrained
|
||||
ckpt_url: url to download a model checkpoint from, if not pretrained and no path was given
|
||||
* at least one of {pretrained, path, url} must be valid
|
||||
|
||||
The method returns a the following list:
|
||||
[
|
||||
Model object,
|
||||
data loader for training,
|
||||
data loader for Pytorch testing,
|
||||
data loader for onnx testing
|
||||
]
|
||||
"""
|
||||
# Use 'spawn' to avoid CUDA reinitialization with forked subprocess
|
||||
torch.multiprocessing.set_start_method('spawn')
|
||||
|
||||
## Initialize quantization, model and data loaders
|
||||
if per_channel_quantization:
|
||||
quant_desc_input = QuantDescriptor(calib_method=calibrator)
|
||||
quant_nn.QuantConv2d.set_default_quant_desc_input(quant_desc_input)
|
||||
quant_nn.QuantLinear.set_default_quant_desc_input(quant_desc_input)
|
||||
else:
|
||||
## Force per tensor quantization for onnx runtime
|
||||
quant_desc_input = QuantDescriptor(calib_method=calibrator, axis=None)
|
||||
quant_nn.QuantConv2d.set_default_quant_desc_input(quant_desc_input)
|
||||
quant_nn.QuantConvTranspose2d.set_default_quant_desc_input(quant_desc_input)
|
||||
quant_nn.QuantLinear.set_default_quant_desc_input(quant_desc_input)
|
||||
|
||||
quant_desc_weight = QuantDescriptor(calib_method=calibrator, axis=None)
|
||||
quant_nn.QuantConv2d.set_default_quant_desc_weight(quant_desc_weight)
|
||||
quant_nn.QuantConvTranspose2d.set_default_quant_desc_weight(quant_desc_weight)
|
||||
quant_nn.QuantLinear.set_default_quant_desc_weight(quant_desc_weight)
|
||||
|
||||
if model_name in models.__dict__:
|
||||
model = models.__dict__[model_name](pretrained=pretrained, quantize=True)
|
||||
else:
|
||||
quant_modules.initialize()
|
||||
model = torchvision.models.__dict__[model_name](pretrained=pretrained)
|
||||
quant_modules.deactivate()
|
||||
|
||||
if not pretrained:
|
||||
if ckpt_path:
|
||||
checkpoint = torch.load(ckpt_path)
|
||||
else:
|
||||
checkpoint = load_state_dict_from_url(ckpt_url)
|
||||
if 'state_dict' in checkpoint.keys():
|
||||
checkpoint = checkpoint['state_dict']
|
||||
elif 'model' in checkpoint.keys():
|
||||
checkpoint = checkpoint['model']
|
||||
model.load_state_dict(checkpoint)
|
||||
model.eval()
|
||||
model.cuda()
|
||||
|
||||
if fp16:
|
||||
model = model.half()
|
||||
|
||||
## Prepare the data loaders
|
||||
traindir = os.path.join(data_dir, 'train')
|
||||
valdir = os.path.join(data_dir, 'val')
|
||||
_args = collections.namedtuple("mock_args", [
|
||||
"model", "distributed", "cache_dataset", "val_resize_size", "val_crop_size", "train_crop_size", "interpolation",
|
||||
"ra_magnitude", "augmix_severity", "weights", "backend", "use_v2"
|
||||
])
|
||||
dataset, dataset_test, train_sampler, test_sampler = load_data(
|
||||
traindir, valdir,
|
||||
_args(model=model_name,
|
||||
distributed=False,
|
||||
cache_dataset=False,
|
||||
val_resize_size=256,
|
||||
val_crop_size=224,
|
||||
train_crop_size=224,
|
||||
interpolation="bilinear",
|
||||
ra_magnitude=9,
|
||||
augmix_severity=3,
|
||||
weights=None,
|
||||
backend="pil",
|
||||
use_v2=False))
|
||||
|
||||
data_loader_train = torch.utils.data.DataLoader(dataset,
|
||||
batch_size=batch_size_train,
|
||||
sampler=train_sampler,
|
||||
num_workers=4,
|
||||
pin_memory=True)
|
||||
|
||||
data_loader_test = torch.utils.data.DataLoader(dataset_test,
|
||||
batch_size=batch_size_test,
|
||||
sampler=test_sampler,
|
||||
num_workers=4,
|
||||
pin_memory=True)
|
||||
|
||||
data_loader_onnx = torch.utils.data.DataLoader(dataset_test,
|
||||
batch_size=batch_size_onnx,
|
||||
sampler=test_sampler,
|
||||
num_workers=4,
|
||||
pin_memory=True)
|
||||
|
||||
return model, data_loader_train, data_loader_test, data_loader_onnx
|
||||
|
||||
|
||||
def main(cmdline_args):
|
||||
parser = get_parser()
|
||||
args = parser.parse_args(cmdline_args)
|
||||
print(parser.description)
|
||||
print(args)
|
||||
|
||||
torch.manual_seed(args.seed)
|
||||
np.random.seed(args.seed)
|
||||
|
||||
## Prepare the pretrained model and data loaders
|
||||
model, data_loader_train, data_loader_test, data_loader_onnx = prepare_model(
|
||||
args.model_name, args.data_dir, not args.disable_pcq, args.batch_size_train, args.batch_size_test,
|
||||
args.batch_size_onnx, args.calibrator, args.pretrained, args.ckpt_path, args.ckpt_url, args.fp16)
|
||||
|
||||
## Initial accuracy evaluation
|
||||
CrossEntropy = nn.CrossEntropyLoss()
|
||||
|
||||
# nn.CrossEntropyLoss expects float inputs
|
||||
def criterion(output, target):
|
||||
return CrossEntropy(output.float(), target)
|
||||
|
||||
with torch.no_grad():
|
||||
print('Initial evaluation:')
|
||||
top1_initial = evaluate(model, criterion, data_loader_test, device="cuda", print_freq=args.print_freq)
|
||||
|
||||
## Calibrate the model
|
||||
with torch.no_grad():
|
||||
calibrate_model(model=model,
|
||||
model_name=args.model_name,
|
||||
data_loader=data_loader_train,
|
||||
num_calib_batch=args.num_calib_batch,
|
||||
calibrator=args.calibrator,
|
||||
hist_percentile=args.percentile,
|
||||
out_dir=args.out_dir)
|
||||
|
||||
## Evaluate after calibration
|
||||
if args.num_calib_batch > 0:
|
||||
with torch.no_grad():
|
||||
print('Calibration evaluation:')
|
||||
top1_calibrated = evaluate(model, criterion, data_loader_test, device="cuda", print_freq=args.print_freq)
|
||||
else:
|
||||
top1_calibrated = -1.0
|
||||
|
||||
## Build sensitivy profile
|
||||
if args.sensitivity:
|
||||
build_sensitivity_profile(model, criterion, data_loader_test)
|
||||
|
||||
## Finetune the model
|
||||
criterion = nn.CrossEntropyLoss()
|
||||
optimizer = torch.optim.SGD(model.parameters(), lr=0.0001)
|
||||
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, args.num_finetune_epochs)
|
||||
for epoch in range(args.num_finetune_epochs):
|
||||
# Training a single epch
|
||||
if "print_freq" in inspect.signature(train_one_epoch).parameters:
|
||||
train_one_epoch(model, criterion, optimizer, data_loader_train, "cuda", 0, 100)
|
||||
else:
|
||||
_args = collections.namedtuple("mock_args",
|
||||
["print_freq", "clip_grad_norm", "model_ema_steps", "lr_warmup_epochs"])
|
||||
train_one_epoch(model, criterion, optimizer, data_loader_train, "cuda", 0,
|
||||
_args(print_freq=100, clip_grad_norm=None, model_ema_steps=32, lr_warmup_epochs=0))
|
||||
lr_scheduler.step()
|
||||
|
||||
if args.num_finetune_epochs > 0:
|
||||
## Evaluate after finetuning
|
||||
with torch.no_grad():
|
||||
print('Finetune evaluation:')
|
||||
top1_finetuned = evaluate(model, criterion, data_loader_test, device="cuda")
|
||||
else:
|
||||
top1_finetuned = -1.0
|
||||
|
||||
## Export to ONNX
|
||||
onnx_filename = args.out_dir + '/' + args.model_name + ".onnx"
|
||||
top1_onnx = -1.0
|
||||
if args.evaluate_onnx and export_onnx(model, onnx_filename, args.batch_size_onnx, not args.disable_pcq):
|
||||
## Validate ONNX and evaluate
|
||||
top1_onnx = evaluate_onnx(onnx_filename, data_loader_onnx, criterion, args.print_freq)
|
||||
|
||||
trt_filename = args.out_dir + '/' + args.model_name + ".trt"
|
||||
top1_trt = -1.0
|
||||
if args.evaluate_trt and export_trt(model, trt_filename, args.batch_size_onnx, args.fp16):
|
||||
## Validate TRT and evaluate
|
||||
top1_trt = evaluate_trt(trt_filename, data_loader_onnx, criterion, args.print_freq)
|
||||
|
||||
## Print summary
|
||||
print("Accuracy summary:")
|
||||
table = PrettyTable(['Stage', 'Top1'])
|
||||
table.align['Stage'] = "l"
|
||||
table.add_row(['Initial', "{:.2f}".format(top1_initial)])
|
||||
table.add_row(['Calibrated', "{:.2f}".format(top1_calibrated)])
|
||||
table.add_row(['Finetuned', "{:.2f}".format(top1_finetuned)])
|
||||
table.add_row(['ONNX', "{:.2f}".format(top1_onnx)])
|
||||
if args.evaluate_trt:
|
||||
table.add_row(['TRT', "{:.2f}".format(top1_trt)])
|
||||
print(table)
|
||||
|
||||
## Compare results
|
||||
if args.threshold >= 0.0:
|
||||
if args.evaluate_onnx and top1_onnx < 0.0:
|
||||
print("Failed to export/evaluate ONNX!")
|
||||
return 1
|
||||
if args.evaluate_trt and top1_trt < 0.0:
|
||||
print("Failed to export/evaluate TRT!")
|
||||
return 1
|
||||
if args.num_finetune_epochs > 0:
|
||||
if top1_finetuned >= (top1_onnx - args.threshold):
|
||||
print("Accuracy threshold was met!")
|
||||
else:
|
||||
print("Accuracy threshold was missed!")
|
||||
return 1
|
||||
|
||||
if args.evaluate_trt and top1_finetuned >= (top1_trt - args.threshold):
|
||||
print("TRT Accuracy threshold was met!")
|
||||
elif args.evaluate_trt:
|
||||
print("TRT Accuracy threshold was missed!")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def evaluate_onnx(onnx_filename, data_loader, criterion, print_freq):
|
||||
"""Evaluate accuracy on the given ONNX file using the provided data loader and criterion.
|
||||
The method returns the average top-1 accuracy on the given dataset.
|
||||
"""
|
||||
print("Loading ONNX file: ", onnx_filename)
|
||||
ort_session = onnxruntime.InferenceSession(onnx_filename, providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
|
||||
with torch.no_grad():
|
||||
metric_logger = utils.MetricLogger(delimiter=" ")
|
||||
header = 'Test:'
|
||||
with torch.no_grad():
|
||||
for image, target in metric_logger.log_every(data_loader, print_freq, header):
|
||||
image = image.to("cpu", non_blocking=True)
|
||||
image_data = np.array(image)
|
||||
input_data = image_data
|
||||
|
||||
# run the data through onnx runtime instead of torch model
|
||||
input_name = ort_session.get_inputs()[0].name
|
||||
raw_result = ort_session.run([], {input_name: input_data})
|
||||
output = torch.tensor((raw_result[0])).float()
|
||||
|
||||
loss = criterion(output, target)
|
||||
acc1, acc5 = utils.accuracy(output, target, topk=(1, 5))
|
||||
batch_size = image.shape[0]
|
||||
metric_logger.update(loss=loss.item())
|
||||
metric_logger.meters['acc1'].update(acc1.item(), n=batch_size)
|
||||
metric_logger.meters['acc5'].update(acc5.item(), n=batch_size)
|
||||
# gather the stats from all processes
|
||||
metric_logger.synchronize_between_processes()
|
||||
|
||||
print(' ONNXRuntime: Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f}'.format(top1=metric_logger.acc1,
|
||||
top5=metric_logger.acc5))
|
||||
return metric_logger.acc1.global_avg
|
||||
|
||||
|
||||
def evaluate_trt(trt_filename, data_loader, criterion, print_freq):
|
||||
print("Loading TRT file: ", trt_filename)
|
||||
|
||||
import pycuda.driver as cuda
|
||||
try:
|
||||
import pycuda.autoprimaryctx
|
||||
except ModuleNotFoundError:
|
||||
import pycuda.autoinit
|
||||
|
||||
import tensorrt as trt
|
||||
|
||||
TRT_LOGGER = trt.Logger()
|
||||
|
||||
TRT_tensor = namedtuple('TRT_tensor', ['binding_idx', 'shape', 'dtype', 'device_memory', 'host_memory'])
|
||||
|
||||
def load_engine(engine_file_path):
|
||||
assert os.path.exists(engine_file_path)
|
||||
print("Reading engine from file {}".format(engine_file_path))
|
||||
with open(engine_file_path, "rb") as f, trt.Runtime(TRT_LOGGER) as runtime:
|
||||
return runtime.deserialize_cuda_engine(f.read())
|
||||
|
||||
def setup_context(engine):
|
||||
return engine.create_execution_context()
|
||||
|
||||
def allocate_buffers(engine, context):
|
||||
|
||||
# Allocate host and device buffers
|
||||
bindings = []
|
||||
inputs = {}
|
||||
outputs = {}
|
||||
for binding_idx in range(engine.num_bindings):
|
||||
binding = engine.get_tensor_name(binding_idx)
|
||||
shape = tuple(context.get_tensor_shape(binding))
|
||||
|
||||
size = trt.volume(context.get_tensor_shape(binding))
|
||||
dtype = np.dtype(trt.nptype(engine.get_tensor_dtype(binding)))
|
||||
|
||||
device_memory = cuda.mem_alloc(size * dtype.itemsize)
|
||||
bindings.append(int(device_memory))
|
||||
|
||||
if engine.get_tensor_mode(binding) == trt.TensorIOMode.INPUT:
|
||||
inputs[binding] = TRT_tensor(binding_idx, shape, dtype, device_memory, None)
|
||||
else:
|
||||
host_memory = cuda.pagelocked_empty(size, dtype)
|
||||
outputs[binding] = TRT_tensor(binding_idx, shape, dtype, device_memory, host_memory)
|
||||
|
||||
stream = cuda.Stream()
|
||||
return bindings, inputs, outputs, stream
|
||||
|
||||
def infer(batch, context, bindings, inputs, outputs, stream):
|
||||
|
||||
# Transfer input data to the GPU.
|
||||
for name, trt_in_t in inputs.items():
|
||||
buffer = np.ascontiguousarray(batch[name])
|
||||
cuda.memcpy_htod_async(trt_in_t.device_memory, buffer, stream)
|
||||
|
||||
# Run inference
|
||||
context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
|
||||
|
||||
# Transfer predictions back from the GPU.
|
||||
for _, trt_out_t in outputs.items():
|
||||
cuda.memcpy_dtoh_async(trt_out_t.host_memory, trt_out_t.device_memory, stream)
|
||||
|
||||
# Synchronize the stream
|
||||
stream.synchronize()
|
||||
|
||||
return {k: torch.tensor(v.host_memory).reshape(v.shape) for k, v in outputs.items()}
|
||||
|
||||
engine = load_engine(trt_filename)
|
||||
context = setup_context(engine)
|
||||
bindings, inputs, outputs, stream = allocate_buffers(engine, context)
|
||||
|
||||
with torch.no_grad():
|
||||
metric_logger = utils.MetricLogger(delimiter=" ")
|
||||
header = 'Test:'
|
||||
with torch.no_grad():
|
||||
for image, target in metric_logger.log_every(data_loader, print_freq, header):
|
||||
image = image.to("cpu", non_blocking=True)
|
||||
image_data = np.array(image)
|
||||
|
||||
output = infer({"input": image_data}, context, bindings, inputs, outputs, stream)["output"].float()
|
||||
|
||||
loss = criterion(output, target)
|
||||
acc1, acc5 = utils.accuracy(output, target, topk=(1, 5))
|
||||
batch_size = image.shape[0]
|
||||
metric_logger.update(loss=loss.item())
|
||||
metric_logger.meters['acc1'].update(acc1.item(), n=batch_size)
|
||||
metric_logger.meters['acc5'].update(acc5.item(), n=batch_size)
|
||||
# gather the stats from all processes
|
||||
metric_logger.synchronize_between_processes()
|
||||
|
||||
print(' TRTRuntime: Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f}'.format(top1=metric_logger.acc1,
|
||||
top5=metric_logger.acc5))
|
||||
return metric_logger.acc1.global_avg
|
||||
|
||||
|
||||
def _export_onnx(model, dummy_input, onnx_filename, opset_version):
|
||||
try:
|
||||
if "enable_onnx_checker" in inspect.signature(torch.onnx.export).parameters:
|
||||
torch.onnx.export(model,
|
||||
dummy_input,
|
||||
onnx_filename,
|
||||
verbose=False,
|
||||
input_names=["input"],
|
||||
output_names=["output"],
|
||||
opset_version=opset_version,
|
||||
enable_onnx_checker=False,
|
||||
do_constant_folding=True)
|
||||
else:
|
||||
torch.onnx.export(model,
|
||||
dummy_input,
|
||||
onnx_filename,
|
||||
verbose=False,
|
||||
input_names=["input"],
|
||||
output_names=["output"],
|
||||
opset_version=opset_version,
|
||||
do_constant_folding=True)
|
||||
except ValueError:
|
||||
print("Failed to export to ONNX")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def export_onnx(model, onnx_filename, batch_onnx, per_channel_quantization):
|
||||
model.eval()
|
||||
|
||||
if per_channel_quantization:
|
||||
opset_version = 13
|
||||
else:
|
||||
opset_version = 12
|
||||
|
||||
# Export ONNX for multiple batch sizes
|
||||
print("Creating ONNX file: " + onnx_filename)
|
||||
dummy_input = torch.randn(batch_onnx, 3, 224, 224, device='cuda') #TODO: switch input dims by model
|
||||
return _export_onnx(model, dummy_input, onnx_filename, opset_version)
|
||||
|
||||
|
||||
def export_trt(model, trt_filename, batch_trt, fp16=False):
|
||||
model.eval()
|
||||
|
||||
# Export TRT for multiple batch sizes
|
||||
print("Creating TRT file: " + trt_filename)
|
||||
dummy_input = torch.randn(batch_trt, 3, 224, 224, device='cuda') #TODO: switch input dims by model
|
||||
|
||||
OPSET = 17
|
||||
onnx_filename = trt_filename.replace(".trt", ".onnx")
|
||||
|
||||
if not _export_onnx(model, dummy_input, onnx_filename, OPSET):
|
||||
return False
|
||||
|
||||
trt_cmd = f"trtexec --onnx={onnx_filename} --saveEngine={trt_filename} --int8"
|
||||
|
||||
if fp16:
|
||||
trt_cmd += " --fp16"
|
||||
|
||||
print(trt_cmd)
|
||||
try:
|
||||
trt_stdout = subprocess.check_output(trt_cmd, shell=True).decode("utf-8")
|
||||
except:
|
||||
print("Failed to export to TRT")
|
||||
return False
|
||||
|
||||
print(trt_stdout)
|
||||
return 'PASSED' in trt_stdout
|
||||
|
||||
|
||||
def calibrate_model(model, model_name, data_loader, num_calib_batch, calibrator, hist_percentile, out_dir):
|
||||
"""
|
||||
Feed data to the network and calibrate.
|
||||
Arguments:
|
||||
model: classification model
|
||||
model_name: name to use when creating state files
|
||||
data_loader: calibration data set
|
||||
num_calib_batch: amount of calibration passes to perform
|
||||
calibrator: type of calibration to use (max/histogram)
|
||||
hist_percentile: percentiles to be used for historgram calibration
|
||||
out_dir: dir to save state files in
|
||||
"""
|
||||
|
||||
if num_calib_batch > 0:
|
||||
print("Calibrating model")
|
||||
with torch.no_grad():
|
||||
collect_stats(model, data_loader, num_calib_batch)
|
||||
|
||||
if not calibrator == "histogram":
|
||||
compute_amax(model, method="max")
|
||||
calib_output = os.path.join(out_dir, F"{model_name}-max-{num_calib_batch*data_loader.batch_size}.pth")
|
||||
torch.save(model.state_dict(), calib_output)
|
||||
else:
|
||||
for percentile in hist_percentile:
|
||||
print(F"{percentile} percentile calibration")
|
||||
compute_amax(model, method="percentile")
|
||||
calib_output = os.path.join(
|
||||
out_dir, F"{model_name}-percentile-{percentile}-{num_calib_batch*data_loader.batch_size}.pth")
|
||||
torch.save(model.state_dict(), calib_output)
|
||||
|
||||
for method in ["mse", "entropy"]:
|
||||
print(F"{method} calibration")
|
||||
compute_amax(model, method=method)
|
||||
calib_output = os.path.join(out_dir,
|
||||
F"{model_name}-{method}-{num_calib_batch*data_loader.batch_size}.pth")
|
||||
torch.save(model.state_dict(), calib_output)
|
||||
|
||||
|
||||
def collect_stats(model, data_loader, num_batches):
|
||||
"""Feed data to the network and collect statistics"""
|
||||
# Enable calibrators
|
||||
for name, module in model.named_modules():
|
||||
if isinstance(module, quant_nn.TensorQuantizer):
|
||||
if module._calibrator is not None:
|
||||
module.disable_quant()
|
||||
module.enable_calib()
|
||||
else:
|
||||
module.disable()
|
||||
|
||||
# Feed data to the network for collecting stats
|
||||
for i, (image, _) in tqdm(enumerate(data_loader), total=num_batches):
|
||||
model(image.cuda())
|
||||
if i >= num_batches:
|
||||
break
|
||||
|
||||
# Disable calibrators
|
||||
for name, module in model.named_modules():
|
||||
if isinstance(module, quant_nn.TensorQuantizer):
|
||||
if module._calibrator is not None:
|
||||
module.enable_quant()
|
||||
module.disable_calib()
|
||||
else:
|
||||
module.enable()
|
||||
|
||||
|
||||
def compute_amax(model, **kwargs):
|
||||
# Load calib result
|
||||
for name, module in model.named_modules():
|
||||
if isinstance(module, quant_nn.TensorQuantizer):
|
||||
if module._calibrator is not None:
|
||||
if isinstance(module._calibrator, calib.MaxCalibrator):
|
||||
module.load_calib_amax()
|
||||
else:
|
||||
module.load_calib_amax(**kwargs)
|
||||
print(F"{name:40}: {module}")
|
||||
model.cuda()
|
||||
|
||||
|
||||
def build_sensitivity_profile(model, criterion, data_loader_test):
|
||||
quant_layer_names = []
|
||||
for name, module in model.named_modules():
|
||||
if name.endswith("_quantizer"):
|
||||
module.disable()
|
||||
layer_name = name.replace("._input_quantizer", "").replace("._weight_quantizer", "")
|
||||
if layer_name not in quant_layer_names:
|
||||
quant_layer_names.append(layer_name)
|
||||
for i, quant_layer in enumerate(quant_layer_names):
|
||||
print("Enable", quant_layer)
|
||||
for name, module in model.named_modules():
|
||||
if name.endswith("_quantizer") and quant_layer in name:
|
||||
module.enable()
|
||||
print(F"{name:40}: {module}")
|
||||
with torch.no_grad():
|
||||
evaluate(model, criterion, data_loader_test, device="cuda")
|
||||
for name, module in model.named_modules():
|
||||
if name.endswith("_quantizer") and quant_layer in name:
|
||||
module.disable()
|
||||
print(F"{name:40}: {module}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
res = main(sys.argv[1:])
|
||||
exit(res)
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
from . import classification
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
from .resnet import *
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# BSD 3-Clause License
|
||||
#
|
||||
# Copyright (c) Soumith Chintala 2016,
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import torch
|
||||
from torch import Tensor
|
||||
import torch.nn as nn
|
||||
from torch.hub import load_state_dict_from_url
|
||||
from typing import Type, Any, Callable, Union, List, Optional
|
||||
from pytorch_quantization import quant_modules
|
||||
from pytorch_quantization import nn as quant_nn
|
||||
|
||||
__all__ = [
|
||||
'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d',
|
||||
'wide_resnet50_2', 'wide_resnet101_2'
|
||||
]
|
||||
|
||||
model_urls = {
|
||||
'resnet18': 'https://download.pytorch.org/models/resnet18-f37072fd.pth',
|
||||
'resnet34': 'https://download.pytorch.org/models/resnet34-b627a593.pth',
|
||||
'resnet50': 'https://download.pytorch.org/models/resnet50-0676ba61.pth',
|
||||
'resnet101': 'https://download.pytorch.org/models/resnet101-63fe2227.pth',
|
||||
'resnet152': 'https://download.pytorch.org/models/resnet152-394f9c45.pth',
|
||||
'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
|
||||
'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
|
||||
'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
|
||||
'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
|
||||
}
|
||||
|
||||
|
||||
def conv3x3(in_planes: int,
|
||||
out_planes: int,
|
||||
stride: int = 1,
|
||||
groups: int = 1,
|
||||
dilation: int = 1,
|
||||
quantize: bool = False) -> nn.Conv2d:
|
||||
"""3x3 convolution with padding"""
|
||||
if quantize:
|
||||
return quant_nn.QuantConv2d(in_planes,
|
||||
out_planes,
|
||||
kernel_size=3,
|
||||
stride=stride,
|
||||
padding=dilation,
|
||||
groups=groups,
|
||||
bias=False,
|
||||
dilation=dilation)
|
||||
else:
|
||||
return nn.Conv2d(in_planes,
|
||||
out_planes,
|
||||
kernel_size=3,
|
||||
stride=stride,
|
||||
padding=dilation,
|
||||
groups=groups,
|
||||
bias=False,
|
||||
dilation=dilation)
|
||||
|
||||
|
||||
def conv1x1(in_planes: int, out_planes: int, stride: int = 1, quantize: bool = False) -> nn.Conv2d:
|
||||
"""1x1 convolution"""
|
||||
if quantize:
|
||||
return quant_nn.QuantConv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
|
||||
else:
|
||||
return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
|
||||
|
||||
|
||||
class BasicBlock(nn.Module):
|
||||
expansion: int = 1
|
||||
|
||||
def __init__(self,
|
||||
inplanes: int,
|
||||
planes: int,
|
||||
stride: int = 1,
|
||||
downsample: Optional[nn.Module] = None,
|
||||
groups: int = 1,
|
||||
base_width: int = 64,
|
||||
dilation: int = 1,
|
||||
norm_layer: Optional[Callable[..., nn.Module]] = None,
|
||||
quantize: bool = False) -> None:
|
||||
super(BasicBlock, self).__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2d
|
||||
if groups != 1 or base_width != 64:
|
||||
raise ValueError('BasicBlock only supports groups=1 and base_width=64')
|
||||
if dilation > 1:
|
||||
raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
|
||||
# Both self.conv1 and self.downsample layers downsample the input when stride != 1
|
||||
self.conv1 = conv3x3(inplanes, planes, stride, quantize=quantize)
|
||||
self.bn1 = norm_layer(planes)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.conv2 = conv3x3(planes, planes, quantize=quantize)
|
||||
self.bn2 = norm_layer(planes)
|
||||
self.downsample = downsample
|
||||
self.stride = stride
|
||||
self._quantize = quantize
|
||||
if self._quantize:
|
||||
self.residual_quantizer = quant_nn.TensorQuantizer(quant_nn.QuantConv2d.default_quant_desc_input)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
if self._quantize:
|
||||
out += self.residual_quantizer(identity)
|
||||
else:
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class Bottleneck(nn.Module):
|
||||
# Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
|
||||
# while original implementation places the stride at the first 1x1 convolution(self.conv1)
|
||||
# according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
|
||||
# This variant is also known as ResNet V1.5 and improves accuracy according to
|
||||
# https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
|
||||
|
||||
expansion: int = 4
|
||||
|
||||
def __init__(self,
|
||||
inplanes: int,
|
||||
planes: int,
|
||||
stride: int = 1,
|
||||
downsample: Optional[nn.Module] = None,
|
||||
groups: int = 1,
|
||||
base_width: int = 64,
|
||||
dilation: int = 1,
|
||||
norm_layer: Optional[Callable[..., nn.Module]] = None,
|
||||
quantize: bool = False) -> None:
|
||||
super(Bottleneck, self).__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2d
|
||||
width = int(planes * (base_width / 64.)) * groups
|
||||
# Both self.conv2 and self.downsample layers downsample the input when stride != 1
|
||||
self.conv1 = conv1x1(inplanes, width, quantize=quantize)
|
||||
self.bn1 = norm_layer(width)
|
||||
self.conv2 = conv3x3(width, width, stride, groups, dilation, quantize=quantize)
|
||||
self.bn2 = norm_layer(width)
|
||||
self.conv3 = conv1x1(width, planes * self.expansion, quantize=quantize)
|
||||
self.bn3 = norm_layer(planes * self.expansion)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.downsample = downsample
|
||||
self.stride = stride
|
||||
self._quantize = quantize
|
||||
if self._quantize:
|
||||
self.residual_quantizer = quant_nn.TensorQuantizer(quant_nn.QuantConv2d.default_quant_desc_input)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv3(out)
|
||||
out = self.bn3(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
if self._quantize:
|
||||
out += self.residual_quantizer(identity)
|
||||
else:
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class ResNet(nn.Module):
|
||||
|
||||
def __init__(self,
|
||||
block: Type[Union[BasicBlock, Bottleneck]],
|
||||
layers: List[int],
|
||||
quantize: bool = False,
|
||||
num_classes: int = 1000,
|
||||
zero_init_residual: bool = False,
|
||||
groups: int = 1,
|
||||
width_per_group: int = 64,
|
||||
replace_stride_with_dilation: Optional[List[bool]] = None,
|
||||
norm_layer: Optional[Callable[..., nn.Module]] = None) -> None:
|
||||
super(ResNet, self).__init__()
|
||||
self._quantize = quantize
|
||||
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2d
|
||||
self._norm_layer = norm_layer
|
||||
|
||||
self.inplanes = 64
|
||||
self.dilation = 1
|
||||
if replace_stride_with_dilation is None:
|
||||
# each element in the tuple indicates if we should replace
|
||||
# the 2x2 stride with a dilated convolution instead
|
||||
replace_stride_with_dilation = [False, False, False]
|
||||
if len(replace_stride_with_dilation) != 3:
|
||||
raise ValueError("replace_stride_with_dilation should be None "
|
||||
"or a 3-element tuple, got {}".format(replace_stride_with_dilation))
|
||||
self.groups = groups
|
||||
self.base_width = width_per_group
|
||||
|
||||
if quantize:
|
||||
self.conv1 = quant_nn.QuantConv2d(3,
|
||||
self.inplanes,
|
||||
kernel_size=7,
|
||||
stride=2,
|
||||
padding=3,
|
||||
bias=False)
|
||||
else:
|
||||
self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False)
|
||||
|
||||
self.bn1 = norm_layer(self.inplanes)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
|
||||
self.layer1 = self._make_layer(block, 64, layers[0], quantize=quantize)
|
||||
self.layer2 = self._make_layer(block,
|
||||
128,
|
||||
layers[1],
|
||||
stride=2,
|
||||
dilate=replace_stride_with_dilation[0],
|
||||
quantize=quantize)
|
||||
self.layer3 = self._make_layer(block,
|
||||
256,
|
||||
layers[2],
|
||||
stride=2,
|
||||
dilate=replace_stride_with_dilation[1],
|
||||
quantize=quantize)
|
||||
self.layer4 = self._make_layer(block,
|
||||
512,
|
||||
layers[3],
|
||||
stride=2,
|
||||
dilate=replace_stride_with_dilation[2],
|
||||
quantize=quantize)
|
||||
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
|
||||
|
||||
if quantize:
|
||||
self.fc = quant_nn.QuantLinear(512 * block.expansion, num_classes)
|
||||
else:
|
||||
self.fc = nn.Linear(512 * block.expansion, num_classes)
|
||||
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
|
||||
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
|
||||
nn.init.constant_(m.weight, 1)
|
||||
nn.init.constant_(m.bias, 0)
|
||||
|
||||
# Zero-initialize the last BN in each residual branch,
|
||||
# so that the residual branch starts with zeros, and each residual block behaves like an identity.
|
||||
# This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
|
||||
if zero_init_residual:
|
||||
for m in self.modules():
|
||||
if isinstance(m, Bottleneck):
|
||||
nn.init.constant_(m.bn3.weight, 0) # type: ignore[arg-type]
|
||||
elif isinstance(m, BasicBlock):
|
||||
nn.init.constant_(m.bn2.weight, 0) # type: ignore[arg-type]
|
||||
|
||||
def _make_layer(self,
|
||||
block: Type[Union[BasicBlock, Bottleneck]],
|
||||
planes: int,
|
||||
blocks: int,
|
||||
stride: int = 1,
|
||||
dilate: bool = False,
|
||||
quantize: bool = False) -> nn.Sequential:
|
||||
norm_layer = self._norm_layer
|
||||
downsample = None
|
||||
previous_dilation = self.dilation
|
||||
if dilate:
|
||||
self.dilation *= stride
|
||||
stride = 1
|
||||
if stride != 1 or self.inplanes != planes * block.expansion:
|
||||
downsample = nn.Sequential(
|
||||
conv1x1(self.inplanes, planes * block.expansion, stride, quantize=quantize),
|
||||
norm_layer(planes * block.expansion),
|
||||
)
|
||||
|
||||
layers = []
|
||||
layers.append(
|
||||
block(self.inplanes, planes, stride, downsample, self.groups, self.base_width, previous_dilation,
|
||||
norm_layer, self._quantize))
|
||||
self.inplanes = planes * block.expansion
|
||||
for _ in range(1, blocks):
|
||||
layers.append(
|
||||
block(self.inplanes,
|
||||
planes,
|
||||
groups=self.groups,
|
||||
base_width=self.base_width,
|
||||
dilation=self.dilation,
|
||||
norm_layer=norm_layer,
|
||||
quantize=quantize))
|
||||
|
||||
return nn.Sequential(*layers)
|
||||
|
||||
def _get_dtype(self):
|
||||
return self.conv1.weight.dtype
|
||||
|
||||
def _forward_impl(self, x: Tensor) -> Tensor:
|
||||
# See note [TorchScript super()]
|
||||
x = self.conv1(x)
|
||||
x = self.bn1(x)
|
||||
x = self.relu(x)
|
||||
x = self.maxpool(x)
|
||||
|
||||
x = self.layer1(x)
|
||||
x = self.layer2(x)
|
||||
x = self.layer3(x)
|
||||
x = self.layer4(x)
|
||||
|
||||
x = self.avgpool(x)
|
||||
x = torch.flatten(x, 1)
|
||||
x = self.fc(x)
|
||||
|
||||
return x
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
return self._forward_impl(x.to(self._get_dtype()))
|
||||
|
||||
|
||||
def _resnet(arch: str, block: Type[Union[BasicBlock, Bottleneck]], layers: List[int], pretrained: bool, progress: bool,
|
||||
quantize: bool, **kwargs: Any) -> ResNet:
|
||||
model = ResNet(block, layers, quantize, **kwargs)
|
||||
if pretrained:
|
||||
state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
|
||||
model.load_state_dict(state_dict)
|
||||
return model
|
||||
|
||||
|
||||
def resnet18(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNet-18 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def resnet34(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNet-34 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def resnet50(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNet-50 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def resnet101(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNet-101 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def resnet152(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNet-152 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def resnext50_32x4d(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNeXt-50 32x4d model from
|
||||
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width_per_group'] = 4
|
||||
return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def resnext101_32x8d(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""ResNeXt-101 32x8d model from
|
||||
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width_per_group'] = 8
|
||||
return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def wide_resnet50_2(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""Wide ResNet-50-2 model from
|
||||
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.
|
||||
|
||||
The model is the same as ResNet except for the bottleneck number of channels
|
||||
which is twice larger in every block. The number of channels in outer 1x1
|
||||
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
|
||||
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['width_per_group'] = 64 * 2
|
||||
return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], pretrained, progress, quantize, **kwargs)
|
||||
|
||||
|
||||
def wide_resnet101_2(pretrained: bool = False, progress: bool = True, quantize: bool = False, **kwargs: Any) -> ResNet:
|
||||
r"""Wide ResNet-101-2 model from
|
||||
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.
|
||||
|
||||
The model is the same as ResNet except for the bottleneck number of channels
|
||||
which is twice larger in every block. The number of channels in outer 1x1
|
||||
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
|
||||
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['width_per_group'] = 64 * 2
|
||||
return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], pretrained, progress, quantize, **kwargs)
|
||||
Reference in New Issue
Block a user