נתקלנו במשימה: מודל זיהוי אובייקטים תפס 100 מגה-בייט ורץ ב-200 אלפיות שנייה במכשיר משתמש. לאחר קוונטיזציה — 25 מגה-בייט ו-50 אלפיות שנייה. אבל לפעמים הדיוק ירד באופן בלתי צפוי. כאן אנו חולקים את הניסיון שלנו: כיצד לבחור את השיטה, לנתח שכבות ולוודא תוצאות. להלן גישות מוכחות ל-iOS ואנדרואיד עם קוד ומדדים קונקרטיים.
אופטימיזציית ML למובייל היא קריטית לפריסת רשתות נוירונים במכשירים. קוונטיזציה של רשתות נוירונים מפחיתה את דיוק המודל מ-float32 ל-int8, ומשיגה האצת חיזוי של פי 2–4 במעבדי מובייל. הפחתת גודל מודל של עד 75% אפשרית. פונקציית הקוונטיזציה Q(r) = round(r/S) - Z, כאשר S הוא סקאלה ו-Z הוא נקודת אפס, עם גרעיניות לפי ערוץ המשמשת לעתים קרובות עבור CNN.
קוונטיזציה — המרת משקלי מודל מ-float32 לפורמט סיביות נמוך יותר: float16, int8, int4. מודל ResNet-50 שוקל 98 מגה-בייט ב-FP32. לאחר קוונטיזציה int8 — 25 מגה-בייט. מהירות החיזוי במעבד מובייל עולה פי 2–4 עקב הפחתת נפח הנתונים והוראות ARM NEON/SVE שלמות. אבל קוונטיזציה נאיבית לעתים קרובות פוגעת בדיוק יותר מהרצוי. קוונטיזציה נכונה פירושה בחירת השיטה, ניתוח שכבות רגישות ואימות הירידה בדיוק.
אנחנו עוסקים באופטימיזציה למובייל למעלה מ-5 שנים, והשלמנו למעלה מ-15 פרויקטי קוונטיזציה ללקוחות במסחר אלקטרוני, פינטק ו-IoT. מדדי החברה: למעלה מ-5 שנים בשוק, למעלה מ-15 קוונטיזציות, 98% שביעות רצון. אנו מבטיחים דיוק במסגרת סובלנות מוסכמת. הזמינו אופטימיזציה של מודל — קבלו ייעוץ לפרויקט שלכם.
באיזו שיטת קוונטיזציה כדאי לבחור?
קוונטיזציה לאחר אימון (PTQ) — קוונטיזציה של מודל שכבר אומן ללא אימון חוזר. שתי גרסאות:
- קוונטיזציה דינמית — משקלים ב-int8, אקטיבציות מחושבות ב-float32 בזמן ריצה. פשוטה, אין צורך בנתוני כיול. עובדת היטב עבור RNN/Transformer (BERT, LLM). עבור CNN, פחות האצה.
- קוונטיזציה סטטית — גם משקלים וגם אקטיבציות ב-int8. דורשת מערך נתוני כיול (100–500 דוגמאות מייצגות). מהירה יותר מדינמית, אבל דורשת כיול.
אימון מודע לקוונטיזציה (QAT) — המודל מכוונן עם קוונטיזציה מדומה. המשקלים מסתגלים לדיוק נמוך יותר. איכות הטובה ביותר, אבל דורש גישה למערך נתוני אימון וזמן GPU.
| שיטה | נתונים | דיוק | מהירות | מורכבות |
|---|---|---|---|---|
| PTQ דינמי | אין | בינוני | גבוה | נמוכה |
| PTQ סטטי | 100–500 דוגמאות | גבוה | גבוה מאוד | בינונית |
| QAT | מערך נתונים מלא | גבוה מאוד | גבוה | גבוהה |
קוד PTQ סטטי ב-PyTorch
# PyTorch: static PTQ через torch.quantization
import torch
from torch.quantization import quantize_static, get_default_qconfig
model.eval()
model.qconfig = get_default_qconfig('fbgemm') # x86; для ARM — 'qnnpack'
torch.quantization.prepare(model, inplace=True)
# Calibration: прогоняем calibration dataset
with torch.no_grad():
for batch in calibration_loader:
model(batch)
torch.quantization.convert(model, inplace=True)
# Теперь model содержит квантизованные слои
למובייל אנדרואיד (ARM) — השתמשו ב-# PyTorch: static PTQ через torch.quantization import torch from torch.quantization import quantize_static, get_default_qconfig model.eval() model.qconfig = get_default_qconfig('fbgemm') # x86; для ARM — 'qnnpack' torch.quantization.prepare(model, inplace=True) # Calibration: прогоняем calibration dataset with torch.no_grad(): for batch in calibration_loader: model(batch) torch.quantization.convert(model, inplace=True) # Теперь model содержит квантизованные слои , לא ב-qconfig = 'qnnpack'. זה משנה את סדר הפעולות המכוונטות עבור מנוע QNNPACK, המשתמש בהוראות ARM NEON.
קוונטיזציה של TFLite: מספר שלם מלא
# Конвертация с full int8 (активации + веса)
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8
# Calibration generator — критично для точности static quantization
def representative_dataset():
for sample in calibration_data[:500]:
yield [sample.astype(np.float32)]
converter.representative_dataset = representative_dataset
tflite_model = converter.convert()
מודלים מלאים ב-int8 רצים על NNAPI ו-Hexagon DSP — שם FP16 אינו נתמך. על Snapdragon 778G דרך Hexagon — מהירים פי 5–8 ממעבד עם קוונטיזציית INT8 נכונה.
קוונטיזציה של Core ML ב-iOS
import coremltools as ct
from coremltools.optimize.coreml import (
OptimizationConfig,
OpLinearQuantizerConfig,
linearly_quantize_weights
)
# Загружаем уже конвертированную Core ML модель
mlmodel = ct.models.MLModel("model_fp32.mlpackage")
# Конфигурация: 8-bit линейная квантизация весов
config = OptimizationConfig(
global_config=OpLinearQuantizerConfig(
mode="linear_symmetric",
dtype=np.int8,
granularity="per_channel" # per_channel точнее per_tensor для CNN
)
)
compressed_model = linearly_quantize_weights(mlmodel, config)
compressed_model.save("model_int8.mlpackage")קוונטיזציה 'fbgemm' — גורם סקאלה נפרד לכל ערוץ פלט של שכבה קונבולוציונית. מדויקת משמעותית יותר מ-# Конвертация с full int8 (активации + веса) converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) converter.optimizations = [tf.lite.Optimize.DEFAULT] converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] converter.inference_input_type = tf.int8 converter.inference_output_type = tf.int8 # Calibration generator — критично для точности static quantization def representative_dataset(): for sample in calibration_data[:500]: yield [sample.astype(np.float32)] converter.representative_dataset = representative_dataset tflite_model = converter.convert() (סקאלה אחת לכל שכבה), אבל מעט איטית יותר. עבור CNN, בדרך כלל שווה את זה.
| תכונה | Core ML | TensorFlow Lite |
|---|---|---|
| פורמט משקלים | FP16/INT8 (משקלים בלבד) | INT8 (מספר שלם מלא) |
| כיול | לא נדרש למשקלים בלבד | נדרש לסטטי |
| תמיכת NNAPI | לא (iOS) | כן (אנדרואיד) |
| כלי | coremltools | TFLiteConverter |
| ביצועים | ~פי 2 באייפון | ~פי 3-4 באנדרואיד עם DSP |
טיפול באובדן דיוק לאחר קוונטיזציה
לא כל השכבות סובלניות לקוונטיזציה באותה מידה. השכבות הראשונות והאחרונות של רשת, כמו גם שכבות קשב בטרנספורמרים, הן לעתים קרובות הרגישות ביותר. אנו מבצעים ניתוח שכבות רגישות כדי לזהות אילו שכבות מושפעות ביותר. כלי: ניתוח רגישות לפי שכבה.
# Проверяем деградацию точности при квантизации каждого слоя по отдельности
from torch.quantization.quantize_fx import prepare_fx, convert_fx
baseline_accuracy = evaluate(float_model, test_loader)
for layer_name in get_all_quantizable_layers(model):
# Квантизуем только этот слой
single_layer_model = quantize_single_layer(model, layer_name)
layer_accuracy = evaluate(single_layer_model, test_loader)
sensitivity = baseline_accuracy - layer_accuracy
print(f"{layer_name}: sensitivity={sensitivity:.4f}")שכבות עם רגישות גבוהה נשארות ב-FP32 — זו קוונטיזציה בדיוק מעורב. השאר מומרות ל-INT8. 5–10% מהשכבות ה"כבדות" נשארות ב-FP32; המודל מאבד רק 20–30% מהגודל במקום 75%, אבל הדיוק נשמר.
כיצד לוודא נכונות קוונטיזציה?
לאחר קוונטיזציה, תמיד:
-
דיוק על מערך נתוני בדיקה — השוו דיוק top-1/top-5 עם המקור. ירידה מקובלת: FP16 — <0.5%, INT8 — <2%. אם גדול יותר, עברו ל-QAT או דיוק מעורב.
-
שגיאה מספרית — השוו פלטים של מודלים float ומכוונטים על קלטים זהים. MSE < 0.01 בדרך כלל מקובל.
-
מהירות במכשירים אמיתיים — לא בסימולטור. Xcode Instruments → Core ML Profiler ל-iOS,
import coremltools as ct from coremltools.optimize.coreml import ( OptimizationConfig, OpLinearQuantizerConfig, linearly_quantize_weights ) # Загружаем уже конвертированную Core ML модель mlmodel = ct.models.MLModel("model_fp32.mlpackage") # Конфигурация: 8-bit линейная квантизация весов config = OptimizationConfig( global_config=OpLinearQuantizerConfig( mode="linear_symmetric", dtype=np.int8, granularity="per_channel" # per_channel точнее per_tensor для CNN ) ) compressed_model = linearly_quantize_weights(mlmodel, config) compressed_model.save("model_int8.mlpackage")+ TFLite Benchmark Tool לאנדרואיד. -
בדיקת קריסות — קלטים שונים, מקרי קצה (תמונה שחורה, בהירה מאוד, יחס גובה-רוחב לא סטנדרטי). מודלי INT8 לפעמים עולים על גדותיהם בקלטים קיצוניים.
מקרה מעשי מהניסיון שלנו
עבור לקוח אחד, אופטימיזציה של מודל זיהוי אובייקטים YOLOv8n. ב-FP32 — 6.3 מגה-בייט, 45 אלפיות שנייה באייפון 13. לאחר קוונטיזציית INT8 של Core ML — 1.8 מגה-בייט, 12 אלפיות שנייה. mAP ירד מ-37.3 ל-36.1 — בטווח המקובל למשימה. על Snapdragon 8 Gen 1 דרך TFLite INT8 + NNAPI — 8 אלפיות שנייה. פרויקט זה חסך ללקוח כ-$15,000 בשנה בעלויות חיזוי בענן. עבור מודל טיפוסי המשרת מיליון חיזויים בחודש, קוונטיזציה יכולה להפחית עלויות מחשוב ענן מ-$3,000 ל-$750 בחודש, חיסכון של $2,250 חודשי או $27,000 שנתי.
מה כלול בעבודה (תוצרים)
- ביקורת על המודל המקורי ובחירת שיטה (PTQ/QAT, INT8/FP16).
- הכנת מערך נתוני כיול וכיוונון כיול.
- ניתוח שכבות רגישות והגדרת דיוק מעורב.
- קוונטיזציה מלאה עם אימות דיוק.
- מדידות מהירות במכשירי יעד (iOS/אנדרואיד).
- דוח ירידה והמלצות.
- אינטגרציה של המודל המכוונט לצנרת שלכם.
- תוצרים: תיעוד תהליך הקוונטיזציה, מערך נתוני כיול, דוח דיוק עם מדדים לפני/אחרי, קוד אינטגרציה (Python, C++, Swift/Kotlin), ושבועיים של תמיכה לאחר פריסה.
- גישה לכלי ניתוח רגישות השכבות הקנייני שלנו.
לפי תיעוד PyTorch, PTQ יכול להפחית גודל מודל עד פי 4. ללימוד מעמיק ראו גם קוונטיזציה לאחר אימון של TensorFlow Lite.
הערכות לוחות זמנים
PTQ למודל אחד עם אימות — 1–2 שבועות. QAT עם אימון חוזר מלא ובדיקות — 3–6 שבועות תלוי בגודל מערך הנתונים. שירות הקוונטיזציה שלנו מתחיל ב-$2,500 למודל. קוונטיזציה מפחיתה עלויות אחסון מודל עד 75%, חוסכת אלפי דולרים בשנה.
צרו קשר כדי להעריך את הפרויקט שלכם. נעזור לבחור את השיטה האופטימלית ונבטיח תוצאות.







