mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-16 21:00:14 +00:00
801 lines
238 KiB
Text
801 lines
238 KiB
Text
|
|
{
|
||
|
|
"cells": [
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "c6b4f765",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# Quantization\n",
|
||
|
|
"\n",
|
||
|
|
"The notebooks compare quantization types."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "9333e48c",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## One matrix\n",
|
||
|
|
"\n",
|
||
|
|
"Taken from [MobileNet](https://github.com/onnx/models/tree/main/vision/classification/mobilenet)."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 1,
|
||
|
|
"id": "e26ddb92",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"download 'mobilenetv2-12.onnx'\n",
|
||
|
|
"done\n",
|
||
|
|
"model size 13964571 bytes\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"import os\n",
|
||
|
|
"import urllib\n",
|
||
|
|
"\n",
|
||
|
|
"url = \"https://github.com/onnx/models/raw/main/vision/classification/mobilenet/model/mobilenetv2-12.onnx\"\n",
|
||
|
|
"destination = \"mobilenetv2-12.onnx\"\n",
|
||
|
|
"\n",
|
||
|
|
"if not os.path.exists(destination) or os.stat(destination).st_size < 10000:\n",
|
||
|
|
" print(f\"download {destination!r}\")\n",
|
||
|
|
" g = urllib.request.urlopen(url)\n",
|
||
|
|
" with open(destination, \"wb\") as f:\n",
|
||
|
|
" f.write(g.read())\n",
|
||
|
|
" print(\"done\")\n",
|
||
|
|
"else:\n",
|
||
|
|
" print(f\"already downloaded {destination!r}\")\n",
|
||
|
|
"print(f\"model size {os.stat(destination).st_size} bytes\")"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 2,
|
||
|
|
"id": "f75c988a",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"model size: 13964571\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"from onnx import load\n",
|
||
|
|
"\n",
|
||
|
|
"with open(destination, \"rb\") as f:\n",
|
||
|
|
" onx = load(f)\n",
|
||
|
|
" print(f\"model size: {len(onx.SerializeToString())}\")"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "d8581d42",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"Let's take one of the biggest matrix of coefficients:"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 3,
|
||
|
|
"id": "358217f6",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"(614421, '616')\n",
|
||
|
|
"(614421, '619')\n",
|
||
|
|
"(1228821, '625')\n",
|
||
|
|
"(1638421, '628')\n",
|
||
|
|
"(5120034, 'classifier.1.weight')\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"initializers = []\n",
|
||
|
|
"for init in onx.graph.initializer:\n",
|
||
|
|
" initializers.append((len(init.SerializeToString()), init.name, init))\n",
|
||
|
|
"\n",
|
||
|
|
"initializers.sort()\n",
|
||
|
|
"\n",
|
||
|
|
"for init in initializers[-5:]:\n",
|
||
|
|
" print(init[:2])"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 86,
|
||
|
|
"id": "3cd9fc33",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"((160, 960, 1, 1), dtype('float32'))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 86,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"from onnx.numpy_helper import to_array\n",
|
||
|
|
"\n",
|
||
|
|
"coef = to_array(initializers[-5][-1])\n",
|
||
|
|
"coef.shape, coef.dtype"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "b044ce26",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Distributions"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 87,
|
||
|
|
"id": "374652c6",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 1000x400 with 2 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"import matplotlib.pyplot as plt\n",
|
||
|
|
"\n",
|
||
|
|
"cf = coef.ravel()\n",
|
||
|
|
"cf01 = cf[(cf >= 0) & (cf <= 0.001)]\n",
|
||
|
|
"\n",
|
||
|
|
"fig, axs = plt.subplots(1, 2, figsize=(10, 4))\n",
|
||
|
|
"axs[0].hist(cf, bins=2048)\n",
|
||
|
|
"axs[0].set_title(\n",
|
||
|
|
" f\"Coefficients Distribution\\nwith {cf.size} éléments\"\n",
|
||
|
|
")\n",
|
||
|
|
"axs[1].hist(cf01, bins=2048)\n",
|
||
|
|
"axs[1].set_title(f\"Same distribution between 0 et {cf01.max():.4f}\\n{cf01.size} éléments\");"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "083b75c0",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"Distribution of float 8."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 88,
|
||
|
|
"id": "544a61de",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"254"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 88,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"import numpy\n",
|
||
|
|
"from onnx.numpy_helper import float8e4m3_to_float32\n",
|
||
|
|
"\n",
|
||
|
|
"float8 = [float8e4m3_to_float32(i) for i in range(0, 256)]\n",
|
||
|
|
"no_nan8 = [f for f in float8 if not numpy.isnan(f)]\n",
|
||
|
|
"len(no_nan8)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 89,
|
||
|
|
"id": "217b5762",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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lfDx8cGuXbtKXZ9nnnkGL774olZb69atIZPJcOzYMaktNjYWMpkMp0+fBlD8Hio3NzecPHkSP/74o7R/f/S4nZubi9DQUNSvXx+1atXCwIEDcf369VJzLLyEOT09Hf369YONjQ1cXFywdu1aAA8vwXzuuedQq1YtNG7cGNu3by/Wx59//okhQ4agbt26sLa2RocOHfDNN99oxRQeT2NiYjB79my4uLjA2tpaOhYdOHAAvXr1gp2dHaytrdG1a1f8+uuvpeZfyJDvLI9+3yg8bi9fvhwbNmxA06ZNoVAo0L59exw6dEhrXrVajZCQEDRs2BAKhQINGjTAgAEDDLrPjSoGC6pqrvB+nJIuvTt58iT69euH3NxczJ8/HytWrED//v2lnc3TTz+N+fPnA3h4lmHr1q3YunUrunTpIvVx8+ZN9O7dG15eXoiKikL37t1LzOudd97BN998g7feeguTJk1CQkICAgIC8M8//xi1fobkVpQQAv3798eqVavQq1cvrFy5Es2bN8f06dMRGhpaLP6XX37BuHHjMGzYMCxduhT37t3DoEGDcPPmzRLz+ueff9CtWzds3boVI0aMwLJly2BnZ4dRo0Zh9erVUu5bt26Fg4MDvLy8pNzr169frL/69etj69at8PT0RMOGDaXYp59+WufyT548ic6dO+P333/HjBkzMGfOHKSlpaFbt244cOCAFPfnn38iLi4O/fr1w8qVKzF9+nQcP34cXbt2RUZGhknbGIB0MB49ejRSU1Nx+fJlxMbGYv369Zg0aVKJl+UVdePGjWKvwgNkUVOmTEH37t2LnUnS5eWXX8bVq1e1itHt27ejR48exb5UFZWTk4MbN27gwoULWLVqFb799lv06NGjWFx+fn6xnO/cuVMsztbWFlOnTsXXX3+NI0eOlJo3ET2exo0bIyUlBSdOnCg1dv369WjcuDFmzZqFFStWwNXVFePGjZMKgaLOnz+Pl19+GS+88AIiIyPx999/44UXXsC2bdswdepU/N///R/mzZuHCxcu4KWXXtL6MefkyZPo0KEDTp8+jZkzZ2LFihWoVasWgoKC8NVXX5WYY+fOnfHLL79I72/duoWTJ0/CwsICP//8s9T+888/o379+nqPF1FRUWjYsCE8PT2l/fvbb7+tFTNx4kT8/vvviIiIwBtvvIGvv/4aEyZMKHU7Ag/3ib1794arqyuWLl0KNzc3TJgwAZs3b0avXr3g4+ODJUuWoHbt2hg5ciTS0tKkeTMzM9GxY0fs3bsX48aNwzvvvIN79+6hf//+OrfPggUL8M033+DNN9/EokWLIJfL8cMPP6BLly7QaDSIiIjAokWLkJWVheeeew4HDx40aB0e5zvL9u3bsWzZMrz22mtYuHAhLl68iBdffBH379+XYgYNGoSvvvoKISEhWLduHSZNmoTbt28jPT3doPyoAgh6om3atEkAEIcOHdIbY2dnJ9q1aye9j4iIEEU/GqtWrRIAxPXr1/X2cejQIQFAbNq0qdi0rl27CgAiOjpa57SuXbtK7/ft2ycACBcXF6HRaKT2zz77TAAQq1evltoaN24sgoODS+2zpNyCg4NF48aNpfdxcXECgFi4cKFW3ODBg4VMJhPnz5+X2gAIuVyu1fb7778LAGLNmjXFllVUVFSUACA++eQTqS0vL0/
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 1000x400 with 2 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"p = 3\n",
|
||
|
|
"gauss = numpy.random.normal(size=len(no_nan8) * 20)\n",
|
||
|
|
"scale1 = numpy.std(no_nan8) / numpy.std(gauss)\n",
|
||
|
|
"scalep = numpy.std(no_nan8) / numpy.std(gauss**p)\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"fig, axs = plt.subplots(1, 2, figsize=(10, 4))\n",
|
||
|
|
"axs[0].hist(float8, bins=50, alpha=0.5, label=\"f8\", density=True)\n",
|
||
|
|
"axs[0].hist(gauss * scale1, bins=50, alpha=0.5, label=\"N\", density=True)\n",
|
||
|
|
"axs[0].hist(gauss**p * scalep, bins=50, alpha=0.5, label=f\"N^{p}\", density=True)\n",
|
||
|
|
"axs[0].set_xlim([-200, 200])\n",
|
||
|
|
"axs[0].set_title(\"Distribution of float 8 E4M3FN\")\n",
|
||
|
|
"axs[0].legend()\n",
|
||
|
|
"\n",
|
||
|
|
"axs[1].hist(float8, bins=2000, alpha=0.5, label=\"f8\", density=True)\n",
|
||
|
|
"axs[1].hist(gauss * scale1, bins=2000, alpha=0.5, label=\"N\", density=True)\n",
|
||
|
|
"axs[1].hist(gauss**p * scalep, bins=2000, alpha=0.5, label=f\"N^{p}\", density=True)\n",
|
||
|
|
"axs[1].set_xlim([-50, 50])\n",
|
||
|
|
"axs[1].set_title(\"Same with more bins\")\n",
|
||
|
|
"axs[1].legend();"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "cbbf27bc",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"Curve `N^3` is gaussian at power 3. It was added to show that E4M3FN distribution is closer to $X^3$ than $X$ ($X$ is gaussian)."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 90,
|
||
|
|
"id": "a64efc70",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"(0.004002655570437662, -0.0)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 90,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"scale_f8p, zero_f8p = estimation_quantization_scale(coef, method=\"power\")\n",
|
||
|
|
"scale_f8p, zero_f8p"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "0c029522",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Scale estimation\n",
|
||
|
|
"\n",
|
||
|
|
"Very basic:\n",
|
||
|
|
"\n",
|
||
|
|
"* ratio of standard deviation for float 8\n",
|
||
|
|
"* quantile at 5% for uint 8"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 91,
|
||
|
|
"id": "61dc7741",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"(0.0009081294882681465, -0.0)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 91,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"from onnx import TensorProto\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"def estimation_quantization_scale(\n",
|
||
|
|
" coef: numpy.array, to: int = TensorProto.FLOAT8E4M3FN, method: str = \"naive\"\n",
|
||
|
|
") -> tuple[float, float]:\n",
|
||
|
|
" \"\"\"\n",
|
||
|
|
" Estimates the scale parameter for the quantization to float 8 assuming\n",
|
||
|
|
" the distribution of the coefficients is gaussian.\n",
|
||
|
|
" \"\"\"\n",
|
||
|
|
" if to == TensorProto.FLOAT8E4M3FN:\n",
|
||
|
|
" float8 = [float8e4m3_to_float32(i) for i in range(0, 256)]\n",
|
||
|
|
" quant_float = [f for f in float8 if not numpy.isnan(f)]\n",
|
||
|
|
" if method == \"naive\":\n",
|
||
|
|
" std_coef = numpy.std(coef.ravel())\n",
|
||
|
|
" std_quant = numpy.std(numpy.array(quant_float, dtype=numpy.float32))\n",
|
||
|
|
" elif method == \"power\":\n",
|
||
|
|
" cr = coef.ravel()\n",
|
||
|
|
" ca = numpy.abs(cr)\n",
|
||
|
|
" std_coef = numpy.std(ca ** (1.0 / 3.0) * cr / ca)\n",
|
||
|
|
" std_quant = numpy.std(numpy.array(quant_float, dtype=numpy.float32))\n",
|
||
|
|
" else:\n",
|
||
|
|
" raise ValueError(f\"Unexpected quantization method {method!r}.\")\n",
|
||
|
|
" zero = 0.0\n",
|
||
|
|
" scale = std_quant / std_coef\n",
|
||
|
|
" elif to == TensorProto.UINT8:\n",
|
||
|
|
" uint8 = [i for i in range(0, 256)]\n",
|
||
|
|
" qu = numpy.quantile(coef.ravel(), [1 - 0.99999, 0.99999])\n",
|
||
|
|
" scale = 255 / (qu[1] - qu[0])\n",
|
||
|
|
" zero = qu[0] * scale\n",
|
||
|
|
" else:\n",
|
||
|
|
" raise ValueError(f\"Unexpected quantization type for to={to}.\")\n",
|
||
|
|
"\n",
|
||
|
|
" return 1.0 / scale, -zero\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"scale_f8, zero_f8 = estimation_quantization_scale(coef)\n",
|
||
|
|
"scale_f8, zero_f8"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 92,
|
||
|
|
"id": "2bfef061",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"(0.004002655570437662, -0.0)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 92,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"scale_f8p, zero_f8p = estimation_quantization_scale(coef, method=\"power\")\n",
|
||
|
|
"scale_f8p, zero_f8p"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 93,
|
||
|
|
"id": "e86fa67a",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"(0.003963413028773201, 131.88381712385316)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 93,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"scale_u8, zero_u8 = estimation_quantization_scale(coef, to=TensorProto.UINT8)\n",
|
||
|
|
"scale_u8, zero_u8"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "13ce5145",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## QDQ\n",
|
||
|
|
"\n",
|
||
|
|
"Let's compare the square loss with two operators [QuantizeLinear](https://onnx.ai/onnx/operators/onnx__QuantizeLinear.html) + [DequantizeLinear](https://onnx.ai/onnx/operators/onnx__DequantizeLinear.html) ~ Identity."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 94,
|
||
|
|
"id": "04cd02c0",
|
||
|
|
"metadata": {
|
||
|
|
"scrolled": false
|
||
|
|
},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"array([ 0.05448777, 0.06538533, -0.00590284, ..., 0.01997885,\n",
|
||
|
|
" 0.00590284, 0.21795107], dtype=float32)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 94,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"from onnx.helper import (\n",
|
||
|
|
" make_node,\n",
|
||
|
|
" make_graph,\n",
|
||
|
|
" make_model,\n",
|
||
|
|
" make_tensor_value_info,\n",
|
||
|
|
" make_operatorsetid,\n",
|
||
|
|
" make_tensor,\n",
|
||
|
|
")\n",
|
||
|
|
"from onnx.reference import ReferenceEvaluator\n",
|
||
|
|
"\n",
|
||
|
|
"X = make_tensor_value_info(\"X\", TensorProto.FLOAT, [None])\n",
|
||
|
|
"Scale = make_tensor_value_info(\"Scale\", TensorProto.FLOAT, [1])\n",
|
||
|
|
"Y = make_tensor_value_info(\"Y\", TensorProto.FLOAT, [None])\n",
|
||
|
|
"\n",
|
||
|
|
"model_f8 = make_model(\n",
|
||
|
|
" make_graph(\n",
|
||
|
|
" [\n",
|
||
|
|
" make_node(\n",
|
||
|
|
" \"Constant\",\n",
|
||
|
|
" [],\n",
|
||
|
|
" [\"Zero\"],\n",
|
||
|
|
" value=make_tensor(\"Zero\", TensorProto.FLOAT8E4M3FN, [1], [0.0]),\n",
|
||
|
|
" ),\n",
|
||
|
|
" make_node(\"QuantizeLinear\", [\"X\", \"Scale\", \"Zero\"], [\"Q\"], axis=0),\n",
|
||
|
|
" make_node(\"DequantizeLinear\", [\"Q\", \"Scale\"], [\"Y\"], axis=0),\n",
|
||
|
|
" ],\n",
|
||
|
|
" \"quf8\",\n",
|
||
|
|
" [X, Scale],\n",
|
||
|
|
" [Y],\n",
|
||
|
|
" ),\n",
|
||
|
|
" opset_imports=[make_operatorsetid(\"\", 19)],\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"ref_f8 = ReferenceEvaluator(model_f8)\n",
|
||
|
|
"qu_f8 = ref_f8.run(\n",
|
||
|
|
" None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale_f8], dtype=numpy.float32)}\n",
|
||
|
|
")[0]\n",
|
||
|
|
"qu_f8"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 95,
|
||
|
|
"id": "459cf5fd",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"array([ 0.05603718, 0.0720478 , -0.00600398, ..., 0.02001328,\n",
|
||
|
|
" 0.00550365, 0.20813808], dtype=float32)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 95,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"qu_f8p = ref_f8.run(\n",
|
||
|
|
" None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale_f8p], dtype=numpy.float32)}\n",
|
||
|
|
")[0]\n",
|
||
|
|
"qu_f8p"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 96,
|
||
|
|
"id": "95fe22fe",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"array([ 0.05548779, 0.06737802, -0.00396341, ..., 0.01981707,\n",
|
||
|
|
" 0.00396341, 0.2140243 ], dtype=float32)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 96,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"model_u8 = make_model(\n",
|
||
|
|
" make_graph(\n",
|
||
|
|
" [\n",
|
||
|
|
" make_node(\n",
|
||
|
|
" \"Constant\",\n",
|
||
|
|
" [],\n",
|
||
|
|
" [\"Zero\"],\n",
|
||
|
|
" value=make_tensor(\"Zero\", TensorProto.UINT8, [1], [int(zero_u8)]),\n",
|
||
|
|
" ),\n",
|
||
|
|
" make_node(\"QuantizeLinear\", [\"X\", \"Scale\", \"Zero\"], [\"Q\"], axis=0),\n",
|
||
|
|
" make_node(\"DequantizeLinear\", [\"Q\", \"Scale\", \"Zero\"], [\"Y\"], axis=0),\n",
|
||
|
|
" ],\n",
|
||
|
|
" \"quu8\",\n",
|
||
|
|
" [X, Scale],\n",
|
||
|
|
" [Y],\n",
|
||
|
|
" ),\n",
|
||
|
|
" opset_imports=[make_operatorsetid(\"\", 19)],\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"ref_u8 = ReferenceEvaluator(model_u8)\n",
|
||
|
|
"qu_u8 = ref_u8.run(\n",
|
||
|
|
" None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale_u8], dtype=numpy.float32)}\n",
|
||
|
|
")[0]\n",
|
||
|
|
"qu_u8"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 97,
|
||
|
|
"id": "e9e49f1b",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"(6.497171816517831e-06, 6.141178007996629e-06, 3.0187591841210397e-06)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 97,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"err_f8 = ((coef.ravel() - qu_f8) ** 2).sum() ** 0.5 / coef.size\n",
|
||
|
|
"err_f8p = ((coef.ravel() - qu_f8p) ** 2).sum() ** 0.5 / coef.size\n",
|
||
|
|
"err_u8 = ((coef.ravel() - qu_u8) ** 2).sum() ** 0.5 / coef.size\n",
|
||
|
|
"err_f8, err_f8p, err_u8"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "797aac3e",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"Plots"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 98,
|
||
|
|
"id": "ee4b9887",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 1200x1200 with 12 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"fig, axs = plt.subplots(4, 3, figsize=(12, 12), sharey=True, sharex=True)\n",
|
||
|
|
"for i, bins in [(0, 64), (1, 128), (2, 256), (3, 512)]:\n",
|
||
|
|
" axs[i, 0].set_ylabel(f\"bins={bins}\")\n",
|
||
|
|
" axs[i, 0].hist(coef.ravel(), bins=bins, density=True, label=\"coef\", alpha=0.5)\n",
|
||
|
|
" axs[i, 0].hist(qu_f8, bins=bins, alpha=0.5, label=\"qdq_f8\", density=True)\n",
|
||
|
|
" axs[i, 0].legend()\n",
|
||
|
|
" axs[i, 0].set_title(f\"QDQ E4M3FN (same) - err={err_f8:1.3g}\")\n",
|
||
|
|
"\n",
|
||
|
|
" axs[i, 1].hist(coef.ravel(), bins=bins, density=True, label=\"coef\", alpha=0.5)\n",
|
||
|
|
" axs[i, 1].hist(qu_f8p, bins=bins, alpha=0.5, label=\"qdq_f8\", density=True)\n",
|
||
|
|
" axs[i, 1].legend()\n",
|
||
|
|
" axs[i, 1].set_title(f\"QDQ E4M3FN (p3) - err={err_f8p:1.3g}\")\n",
|
||
|
|
"\n",
|
||
|
|
" axs[i, 2].hist(coef.ravel(), bins=bins, density=True, label=\"coef\", alpha=0.5)\n",
|
||
|
|
" axs[i, 2].hist(qu_u8, bins=bins, alpha=0.5, label=\"qdq_u8\", density=True)\n",
|
||
|
|
" axs[i, 2].legend()\n",
|
||
|
|
" axs[i, 2].set_title(f\"QDQ uint 8 - err={err_u8:1.3g}\");"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "8b9b6aa7",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Other scales"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 103,
|
||
|
|
"id": "1efabcbe",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stderr",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"100%|██████████████████████████████████████████████████████████████████████████████████| 10/10 [00:08<00:00, 1.15it/s]\n"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/html": [
|
||
|
|
"<div>\n",
|
||
|
|
"<style scoped>\n",
|
||
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
||
|
|
" vertical-align: middle;\n",
|
||
|
|
" }\n",
|
||
|
|
"\n",
|
||
|
|
" .dataframe tbody tr th {\n",
|
||
|
|
" vertical-align: top;\n",
|
||
|
|
" }\n",
|
||
|
|
"\n",
|
||
|
|
" .dataframe thead th {\n",
|
||
|
|
" text-align: right;\n",
|
||
|
|
" }\n",
|
||
|
|
"</style>\n",
|
||
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
||
|
|
" <thead>\n",
|
||
|
|
" <tr style=\"text-align: right;\">\n",
|
||
|
|
" <th></th>\n",
|
||
|
|
" <th>scale</th>\n",
|
||
|
|
" <th>err</th>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" </thead>\n",
|
||
|
|
" <tbody>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>0</th>\n",
|
||
|
|
" <td>0.000147</td>\n",
|
||
|
|
" <td>0.122887</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>1</th>\n",
|
||
|
|
" <td>0.000440</td>\n",
|
||
|
|
" <td>0.025486</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>2</th>\n",
|
||
|
|
" <td>0.000733</td>\n",
|
||
|
|
" <td>0.007755</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>3</th>\n",
|
||
|
|
" <td>0.001027</td>\n",
|
||
|
|
" <td>0.006265</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>4</th>\n",
|
||
|
|
" <td>0.001320</td>\n",
|
||
|
|
" <td>0.006142</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>5</th>\n",
|
||
|
|
" <td>0.001614</td>\n",
|
||
|
|
" <td>0.006165</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>6</th>\n",
|
||
|
|
" <td>0.001907</td>\n",
|
||
|
|
" <td>0.006151</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>7</th>\n",
|
||
|
|
" <td>0.002200</td>\n",
|
||
|
|
" <td>0.006154</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>8</th>\n",
|
||
|
|
" <td>0.002494</td>\n",
|
||
|
|
" <td>0.006152</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" <tr>\n",
|
||
|
|
" <th>9</th>\n",
|
||
|
|
" <td>0.002787</td>\n",
|
||
|
|
" <td>0.006161</td>\n",
|
||
|
|
" </tr>\n",
|
||
|
|
" </tbody>\n",
|
||
|
|
"</table>\n",
|
||
|
|
"</div>"
|
||
|
|
],
|
||
|
|
"text/plain": [
|
||
|
|
" scale err\n",
|
||
|
|
"0 0.000147 0.122887\n",
|
||
|
|
"1 0.000440 0.025486\n",
|
||
|
|
"2 0.000733 0.007755\n",
|
||
|
|
"3 0.001027 0.006265\n",
|
||
|
|
"4 0.001320 0.006142\n",
|
||
|
|
"5 0.001614 0.006165\n",
|
||
|
|
"6 0.001907 0.006151\n",
|
||
|
|
"7 0.002200 0.006154\n",
|
||
|
|
"8 0.002494 0.006152\n",
|
||
|
|
"9 0.002787 0.006161"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 103,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"from pandas import DataFrame\n",
|
||
|
|
"from tqdm import tqdm\n",
|
||
|
|
"\n",
|
||
|
|
"a = 0.00014669707383747942\n",
|
||
|
|
"h = 0.00014669707383747942 * 2\n",
|
||
|
|
"\n",
|
||
|
|
"data = []\n",
|
||
|
|
"for scale in tqdm([a + h * i for i in range(10)]):\n",
|
||
|
|
" got = ref_f8.run(\n",
|
||
|
|
" None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale], dtype=numpy.float32)}\n",
|
||
|
|
" )[0]\n",
|
||
|
|
" err = ((coef.ravel() - got) ** 2).sum() ** 0.5 / coef.size\n",
|
||
|
|
" obs = dict(scale=scale, err=err*1000)\n",
|
||
|
|
" data.append(obs)\n",
|
||
|
|
" \n",
|
||
|
|
"df = DataFrame(data)\n",
|
||
|
|
"df"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 105,
|
||
|
|
"id": "53fbc33d",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 640x480 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"df.plot(x=\"scale\", y=\"err\", logy=True);"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": null,
|
||
|
|
"id": "e7e555ce",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": []
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"metadata": {
|
||
|
|
"kernelspec": {
|
||
|
|
"display_name": "Python 3 (ipykernel)",
|
||
|
|
"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.11.4"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nbformat": 4,
|
||
|
|
"nbformat_minor": 5
|
||
|
|
}
|