Memeriksa Kesalahan Kuantisasi dengan Debugger Kuantisasi

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan Lihat model TF Hub

Meskipun kuantisasi bilangan bulat penuh memberikan ukuran dan latensi model yang ditingkatkan, model terkuantisasi tidak akan selalu berfungsi seperti yang diharapkan. Biasanya diharapkan kualitas model (misalnya akurasi, mAP, WER) sedikit lebih rendah dari model float asli. Namun, ada kasus di mana kualitas model bisa di bawah harapan Anda atau menghasilkan hasil yang benar-benar salah.

Ketika masalah ini terjadi, sulit dan menyakitkan untuk menemukan akar penyebab kesalahan kuantisasi, dan bahkan lebih sulit untuk memperbaiki kesalahan kuantisasi. Untuk membantu proses pemeriksaan model ini, kuantisasi debugger dapat digunakan untuk mengidentifikasi lapisan bermasalah, dan kuantisasi selektif dapat meninggalkan mereka lapisan bermasalah dalam mengapung sehingga akurasi model dapat dipulihkan pada biaya manfaat berkurang dari kuantisasi.

Debugger Kuantisasi

Debugger kuantisasi memungkinkan untuk melakukan analisis metrik kualitas kuantisasi dalam model yang ada. Debugger kuantisasi dapat mengotomatiskan proses untuk menjalankan model dengan set data debug, dan mengumpulkan metrik kualitas kuantisasi untuk setiap tensor.

Prasyarat

Jika Anda sudah memiliki saluran untuk mengkuantisasi model, Anda memiliki semua bagian yang diperlukan untuk menjalankan debugger kuantisasi!

  • Model untuk dikuantisasi
  • kumpulan data representatif

Selain model dan data, Anda perlu menggunakan kerangka pemrosesan data (misalnya panda, Google Spreadsheet) untuk menganalisis hasil yang diekspor.

Mempersiapkan

Bagian ini menyiapkan pustaka, model MobileNet v3, dan kumpulan data uji 100 gambar.

# Quantization debugger is available from TensorFlow 2.7.0
pip uninstall -y tensorflow
pip install tf-nightly
pip install tensorflow_datasets --upgrade  # imagenet_v2 needs latest checksum
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf
import tensorflow_datasets as tfds
import tensorflow_hub as hub

Boilerplate dan pembantu

2021-10-30 11:57:45.262002: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmp_3ry7zon/assets
INFO:tensorflow:Assets written to: /tmp/tmp_3ry7zon/assets
2021-10-30 11:57:52.134354: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:57:52.134407: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
test_ds = ds.map(lambda data: (data['image'], data['label'] + 1)).batch(16)
loss, acc = model.evaluate(test_ds)
print(f'Top-5 accuracy (float): {acc * 100:.2f}%')
7/7 [==============================] - 6s 33ms/step - loss: 88.6092 - sparse_top_k_categorical_accuracy: 11.7143
Top-5 accuracy (float): 1171.43%
eval_tflite(quantized_model, ds)
Top-5 accuracy (quantized): 51.00%

Kita dapat melihat bahwa model asli memiliki akurasi top-5 yang jauh lebih tinggi untuk kumpulan data kecil kami, sedangkan model terkuantisasi memiliki kehilangan akurasi yang signifikan.

Langkah 1. Persiapan debugger

Cara termudah untuk menggunakan debugger kuantisasi adalah untuk memberikan tf.lite.TFLiteConverter bahwa Anda telah menggunakan untuk quantize model.

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset(ds)

# my_debug_dataset should have the same format as my_representative_dataset
debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter, debug_dataset=representative_dataset(ds))
INFO:tensorflow:Assets written to: /tmp/tmpoa_5gejn/assets
INFO:tensorflow:Assets written to: /tmp/tmpoa_5gejn/assets
2021-10-30 11:58:34.006052: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:58:34.006103: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0

Langkah 2. Jalankan debugger dan dapatkan hasilnya

Ketika Anda memanggil QuantizationDebugger.run() , debugger akan log perbedaan antara tensor float dan tensor terkuantisasi untuk lokasi op yang sama, dan proses mereka dengan metrik yang diberikan.

debugger.run()

Metrik yang diproses dapat diakses dengan QuantizationDebugger.layer_statistics , atau dapat dibuang ke file teks dalam format CSV dengan QuantizationDebugger.layer_statistics_dump() .

RESULTS_FILE = '/tmp/debugger_results.csv'
with open(RESULTS_FILE, 'w') as f:
  debugger.layer_statistics_dump(f)
head /tmp/debugger_results.csv

Untuk setiap baris di dump, nama op dan indeks datang pertama, diikuti oleh parameter kuantisasi dan metrik kesalahan (termasuk user-defined metrik kesalahan , jika ada). File CSV yang dihasilkan dapat digunakan untuk memilih lapisan bermasalah dengan metrik kesalahan kuantisasi yang besar.

Dengan panda atau pustaka pemrosesan data lainnya, kami dapat memeriksa metrik kesalahan per-lapisan yang terperinci.

layer_stats = pd.read_csv(RESULTS_FILE)
layer_stats.head()

Langkah 3. Analisis data

Ada berbagai cara untuk menganalisis hasilnya. Pertama, mari tambahkan beberapa metrik berguna yang diturunkan dari keluaran debugger. ( scale berarti faktor skala kuantisasi untuk setiap tensor.)

  • Range ( 256 / scale )
  • RMSE / skala ( sqrt(mean_squared_error) / scale )

The RMSE / scale dekat 1 / sqrt(12) (~ 0,289) ketika terkuantisasi distribusi mirip dengan distribusi mengapung asli, menunjukkan baik model yang dikuantisasi. Semakin besar nilainya, semakin besar kemungkinan lapisan tidak terkuantisasi dengan baik.

layer_stats['range'] = 255.0 * layer_stats['scale']
layer_stats['rmse/scale'] = layer_stats.apply(
    lambda row: np.sqrt(row['mean_squared_error']) / row['scale'], axis=1)
layer_stats[['op_name', 'range', 'rmse/scale']].head()
plt.figure(figsize=(15, 5))
ax1 = plt.subplot(121)
ax1.bar(np.arange(len(layer_stats)), layer_stats['range'])
ax1.set_ylabel('range')
ax2 = plt.subplot(122)
ax2.bar(np.arange(len(layer_stats)), layer_stats['rmse/scale'])
ax2.set_ylabel('rmse/scale')
plt.show()

png

Ada banyak lapisan dengan kisaran luas, dan beberapa lapisan yang memiliki tinggi RMSE/scale nilai-nilai. Mari dapatkan lapisan dengan metrik kesalahan tinggi.

layer_stats[layer_stats['rmse/scale'] > 0.7][[
    'op_name', 'range', 'rmse/scale', 'tensor_name'
]]

Dengan lapisan ini, Anda dapat mencoba kuantisasi selektif untuk melihat apakah tidak mengkuantisasi lapisan tersebut meningkatkan kualitas model.

suspected_layers = list(
    layer_stats[layer_stats['rmse/scale'] > 0.7]['tensor_name'])

Selain itu, melewatkan kuantisasi untuk beberapa lapisan pertama juga membantu meningkatkan kualitas model terkuantisasi.

suspected_layers.extend(list(layer_stats[:5]['tensor_name']))

Kuantisasi Selektif

Kuantisasi selektif melewatkan kuantisasi untuk beberapa node, sehingga perhitungan dapat terjadi di domain titik-mengambang asli. Ketika lapisan yang benar dilewati, kita dapat mengharapkan beberapa pemulihan kualitas model dengan mengorbankan peningkatan latensi dan ukuran model.

Namun, jika Anda berencana untuk menjalankan model terkuantisasi pada akselerator khusus bilangan bulat (mis. Hexagon DSP, EdgeTPU), kuantisasi selektif akan menyebabkan fragmentasi model dan akan menghasilkan latensi inferensi yang lebih lambat yang terutama disebabkan oleh biaya transfer data antara CPU dan akselerator tersebut . Untuk mencegah hal ini, Anda dapat mempertimbangkan menjalankan kuantisasi pelatihan sadar untuk menjaga semua lapisan dalam bilangan bulat sambil menjaga akurasi model.

Opsi kuantisasi debugger ini menerima denylisted_nodes dan denylisted_ops pilihan untuk melewatkan kuantisasi untuk lapisan tertentu, atau semua contoh ops tertentu. Menggunakan suspected_layers kami dibuat dari langkah sebelumnya, kita dapat menggunakan kuantisasi debugger untuk mendapatkan model selektif dikuantisasi.

debug_options = tf.lite.experimental.QuantizationDebugOptions(
    denylisted_nodes=suspected_layers)
debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter,
    debug_dataset=representative_dataset(ds),
    debug_options=debug_options)
INFO:tensorflow:Assets written to: /tmp/tmpqqc57uli/assets
INFO:tensorflow:Assets written to: /tmp/tmpqqc57uli/assets
2021-10-30 11:59:13.603355: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:59:13.603400: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
selective_quantized_model = debugger.get_nondebug_quantized_model()
eval_tflite(selective_quantized_model, ds)
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
Top-5 accuracy (quantized): 64.00%

Akurasinya masih lebih rendah dibandingkan dengan model float asli, tetapi kami memiliki peningkatan penting dari keseluruhan model terkuantisasi dengan melewatkan kuantisasi untuk ~10 lapisan dari 111 lapisan.

Anda juga dapat mencoba untuk tidak mengkuantisasi semua operasi di kelas yang sama. Misalnya, untuk melewati kuantisasi untuk semua ops berarti, Anda dapat melewati MEAN ke denylisted_ops .

debug_options = tf.lite.experimental.QuantizationDebugOptions(
    denylisted_ops=['MEAN'])
debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter,
    debug_dataset=representative_dataset(ds),
    debug_options=debug_options)
INFO:tensorflow:Assets written to: /tmp/tmpxltlornb/assets
INFO:tensorflow:Assets written to: /tmp/tmpxltlornb/assets
2021-10-30 11:59:44.677473: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:59:44.677519: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
selective_quantized_model = debugger.get_nondebug_quantized_model()
eval_tflite(selective_quantized_model, ds)
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
Top-5 accuracy (quantized): 54.00%

Dengan teknik ini, kami dapat meningkatkan akurasi model MobileNet V3 terkuantisasi. Selanjutnya kita akan mengeksplorasi teknik lanjutan untuk meningkatkan akurasi model lebih jauh lagi.

Penggunaan lanjutan

Dengan fitur berikut, Anda dapat menyesuaikan lebih lanjut saluran debugging Anda.

Metrik khusus

Secara default, debugger kuantisasi memancarkan lima metrik untuk setiap perbedaan float-quant: ukuran tensor, deviasi standar, kesalahan rata-rata, kesalahan absolut maks, dan kesalahan kuadrat rata-rata. Anda dapat menambahkan lebih banyak metrik khusus dengan meneruskannya ke opsi. Untuk setiap metrik, hasilnya harus berupa nilai mengambang tunggal dan metrik yang dihasilkan akan menjadi metrik rata-rata dari semua contoh.

  • layer_debug_metrics : menghitung metrik berdasarkan diff untuk setiap op output dari float dan output op terkuantisasi.
  • layer_direct_compare_metrics : daripada mendapatkan diff saja, ini akan menghitung metrik berdasarkan mengambang baku dan tensor terkuantisasi, dan parameter kuantisasi nya (skala, titik nol)
  • model_debug_metrics : hanya digunakan ketika float_model_(path|content) dilewatkan ke debugger. Selain metrik level-op, output lapisan akhir dibandingkan dengan output referensi dari model float asli.
debug_options = tf.lite.experimental.QuantizationDebugOptions(
    layer_debug_metrics={
        'mean_abs_error': (lambda diff: np.mean(np.abs(diff)))
    },
    layer_direct_compare_metrics={
        'correlation':
            lambda f, q, s, zp: (np.corrcoef(f.flatten(),
                                             (q.flatten() - zp) / s)[0, 1])
    },
    model_debug_metrics={
        'argmax_accuracy': (lambda f, q: np.mean(np.argmax(f) == np.argmax(q)))
    })

debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter,
    debug_dataset=representative_dataset(ds),
    debug_options=debug_options)
INFO:tensorflow:Assets written to: /tmp/tmpm7cb9qcd/assets
INFO:tensorflow:Assets written to: /tmp/tmpm7cb9qcd/assets
2021-10-30 12:00:18.502193: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 12:00:18.502238: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
INFO:tensorflow:Assets written to: /tmp/tmpzkg3ny_8/assets
INFO:tensorflow:Assets written to: /tmp/tmpzkg3ny_8/assets
2021-10-30 12:00:28.401195: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 12:00:28.401241: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
debugger.run()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/numpy/lib/function_base.py:2691: RuntimeWarning: invalid value encountered in true_divide
  c /= stddev[:, None]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/numpy/lib/function_base.py:2692: RuntimeWarning: invalid value encountered in true_divide
  c /= stddev[None, :]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/lite/tools/optimize/debugging/python/debugger.py:382: RuntimeWarning: Mean of empty slice
  metrics[metric_name] = np.nanmean(metrics[metric_name])
CUSTOM_RESULTS_FILE = '/tmp/debugger_results.csv'
with open(CUSTOM_RESULTS_FILE, 'w') as f:
  debugger.layer_statistics_dump(f)

custom_layer_stats = pd.read_csv(CUSTOM_RESULTS_FILE)
custom_layer_stats[['op_name', 'mean_abs_error', 'correlation']].tail()

Hasil model_debug_metrics dapat secara terpisah dilihat dari debugger.model_statistics .

debugger.model_statistics
{'argmax_accuracy': 0.36}

Menggunakan (internal) mlir_quantize API untuk mengakses fitur mendalam

from tensorflow.lite.python import convert

Seluruh mode verifikasi model

Perilaku default untuk pembuatan model debug adalah verifikasi per-lapisan. Dalam mode ini, input untuk pasangan op float dan kuantisasi berasal dari sumber yang sama (op terkuantisasi sebelumnya). Mode lainnya adalah verifikasi seluruh model, di mana model float dan quantize dipisahkan. Mode ini akan berguna untuk mengamati bagaimana kesalahan disebarkan ke bawah model. Untuk mengaktifkan, enable_whole_model_verify=True untuk convert.mlir_quantize sementara menghasilkan model men-debug secara manual.

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.representative_dataset = representative_dataset(ds)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter._experimental_calibrate_only = True
calibrated_model = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmp2oa0sp06/assets
INFO:tensorflow:Assets written to: /tmp/tmp2oa0sp06/assets
2021-10-30 12:01:33.233118: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 12:01:33.233171: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
# Note that enable_numeric_verify and enable_whole_model_verify are set.
quantized_model = convert.mlir_quantize(
    calibrated_model,
    enable_numeric_verify=True,
    enable_whole_model_verify=True)
debugger = tf.lite.experimental.QuantizationDebugger(
    quant_debug_model_content=quantized_model,
    debug_dataset=representative_dataset(ds))
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0

Kuantisasi selektif dari model yang sudah dikalibrasi

Anda dapat langsung menghubungi convert.mlir_quantize untuk mendapatkan model terkuantisasi selektif dari model yang sudah dikalibrasi. Ini akan sangat berguna ketika Anda ingin mengkalibrasi model sekali, dan bereksperimen dengan berbagai kombinasi daftar yang ditolak.

selective_quantized_model = convert.mlir_quantize(
    calibrated_model, denylisted_nodes=suspected_layers)
eval_tflite(selective_quantized_model, ds)
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
Top-5 accuracy (quantized): 64.00%