Kiểm tra lỗi lượng tử hóa bằng trình gỡ lỗi lượng tử hóa

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép Xem mô hình TF Hub

Mặc dù lượng tử hóa toàn bộ số nguyên cung cấp độ trễ và kích thước mô hình được cải thiện, nhưng mô hình lượng tử hóa không phải lúc nào cũng hoạt động như mong đợi. Thông thường, chất lượng mô hình (ví dụ: độ chính xác, mAP, WER) sẽ thấp hơn một chút so với mô hình float ban đầu. Tuy nhiên, có những trường hợp chất lượng mô hình có thể thấp hơn mong đợi của bạn hoặc tạo ra kết quả hoàn toàn sai.

Khi sự cố này xảy ra, thật khó và khó để tìm ra nguyên nhân gốc rễ của lỗi lượng tử hóa, và việc sửa lỗi lượng tử hóa thậm chí còn khó khăn hơn. Để hỗ trợ cho quá trình kiểm tra mô hình này, gỡ rối lượng tử có thể được sử dụng để xác định các lớp có vấn đề, và lượng tử hóa có chọn lọc có thể để lại những lớp có vấn đề trong phao để tính chính xác mô hình có thể được phục hồi với chi phí giảm được hưởng lợi từ lượng tử.

Trình gỡ lỗi lượng tử hóa

Trình gỡ lỗi lượng tử hóa giúp bạn có thể thực hiện phân tích chỉ số chất lượng lượng tử hóa trong mô hình hiện có. Trình gỡ lỗi lượng tử hóa có thể tự động hóa các quy trình cho mô hình đang chạy với bộ dữ liệu gỡ lỗi và thu thập các chỉ số chất lượng lượng tử hóa cho mỗi tensors.

Điều kiện tiên quyết

Nếu bạn đã có một đường dẫn để lượng tử hóa một mô hình, bạn có tất cả các phần cần thiết để chạy trình gỡ lỗi lượng tử hóa!

  • Mô hình lượng tử hóa
  • Bộ dữ liệu đại diện

Ngoài mô hình và dữ liệu, bạn sẽ cần sử dụng khung xử lý dữ liệu (ví dụ: gấu trúc, Google Trang tính) để phân tích kết quả đã xuất.

Thành lập

Phần này chuẩn bị thư viện, mô hình MobileNet v3 và tập dữ liệu thử nghiệm gồm 100 hình ảnh.

# 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

Boilerplates và trợ giúp

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%

Chúng ta có thể thấy rằng mô hình ban đầu có độ chính xác top 5 cao hơn nhiều đối với tập dữ liệu nhỏ của chúng tôi, trong khi mô hình lượng tử hóa có độ chính xác mất đi đáng kể.

Bước 1. Chuẩn bị trình gỡ lỗi

Cách dễ nhất để sử dụng các chương trình gỡ rối lượng tử là cung cấp tf.lite.TFLiteConverter mà bạn đã sử dụng để quantize mô hình.

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

Bước 2. Chạy trình gỡ lỗi và nhận kết quả

Khi bạn gọi QuantizationDebugger.run() , các chương trình gỡ rối đăng nhập sẽ khác nhau giữa tensors phao và tensors lượng tử cho vị trí op giống nhau, và xử lý chúng với số liệu cho trước.

debugger.run()

Các số liệu xử lý có thể được truy cập với QuantizationDebugger.layer_statistics , hoặc có thể được đổ vào một file văn bản ở định dạng CSV với 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

Đối với mỗi hàng trong các bãi chứa, tên op và chỉ số đến trước, tiếp theo là các thông số lượng tử và số liệu lỗi (bao gồm cả số liệu lỗi người dùng định nghĩa , nếu có). Tệp CSV kết quả có thể được sử dụng để chọn các lớp có vấn đề với số liệu lỗi lượng tử hóa lớn.

Với gấu trúc hoặc các thư viện xử lý dữ liệu khác, chúng tôi có thể kiểm tra các chỉ số lỗi chi tiết cho mỗi lớp.

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

Bước 3. Phân tích dữ liệu

Có nhiều cách khác nhau để phân tích kết quả. Đầu tiên, hãy thêm một số số liệu hữu ích có được từ kết quả đầu ra của trình gỡ lỗi. ( scale có nghĩa là yếu tố quy mô lượng tử cho mỗi tensor.)

  • Range ( 256 / scale )
  • RMSE / quy mô ( sqrt(mean_squared_error) / scale )

Các RMSE / scale gần 1 / sqrt(12) (~ 0,289) khi lượng tử phân phối tương tự như sự phân bố float gốc, cho thấy một mô hình lượng tử hóa tốt. Giá trị càng lớn thì càng có nhiều khả năng lớp không được lượng tử hóa tốt.

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

Có rất nhiều lớp với phạm vi rộng, và một số lớp có cao RMSE/scale giá trị. Hãy lấy các lớp có chỉ số lỗi cao.

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

Với các lớp này, bạn có thể thử lượng tử hóa có chọn lọc để xem liệu việc lượng tử hóa các lớp đó có cải thiện chất lượng mô hình hay không.

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

Ngoài ra, việc bỏ qua lượng tử hóa trong một vài lớp đầu tiên cũng giúp cải thiện chất lượng của mô hình lượng tử hóa.

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

Lượng tử hóa có chọn lọc

Lượng tử hóa chọn lọc bỏ qua quá trình lượng tử hóa đối với một số nút, do đó việc tính toán có thể xảy ra trong miền dấu phẩy động ban đầu. Khi bỏ qua các lớp chính xác, chúng ta có thể mong đợi một số phục hồi chất lượng mô hình với chi phí tăng độ trễ và kích thước mô hình.

Tuy nhiên, nếu bạn dự định chạy các mô hình lượng tử hóa trên các máy gia tốc chỉ sử dụng số nguyên (ví dụ: Hexagon DSP, EdgeTPU), lượng tử hóa có chọn lọc sẽ gây ra sự phân mảnh của mô hình và dẫn đến độ trễ suy luận chậm hơn chủ yếu do chi phí truyền dữ liệu giữa CPU và các máy gia tốc đó . Để tránh điều này, bạn có thể xem xét việc chạy lượng tử đào tạo ý thức để giữ tất cả các lớp trong khi vẫn giữ nguyên tính chính xác mô hình.

Tùy chọn Quantization debugger của chấp nhận denylisted_nodesdenylisted_ops tùy chọn cho việc bỏ qua lượng tử cho các lớp cụ thể, hoặc tất cả các trường hợp của ops cụ thể. Sử dụng suspected_layers chúng tôi chuẩn bị từ bước trước, chúng ta có thể sử dụng chương trình gỡ rối lượng tử để có được một mô hình chọn lọc lượng tử hóa.

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%

Độ chính xác vẫn thấp hơn so với mô hình float ban đầu, nhưng chúng tôi có cải tiến đáng chú ý từ toàn bộ mô hình lượng tử hóa bằng cách bỏ qua lượng tử hóa cho ~ 10 lớp trong tổng số 111 lớp.

Bạn cũng có thể cố gắng không lượng tử hóa tất cả các hoạt động trong cùng một lớp. Ví dụ, để bỏ qua lượng tử cho tất cả các ops bình, bạn có thể vượt qua MEAN để 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%

Với những kỹ thuật này, chúng tôi có thể cải thiện độ chính xác của mô hình MobileNet V3 đã lượng tử hóa. Tiếp theo, chúng ta sẽ khám phá các kỹ thuật nâng cao để cải thiện độ chính xác của mô hình hơn nữa.

Tập quán nâng cao

Với các tính năng sau, bạn có thể tùy chỉnh đường dẫn gỡ lỗi của mình trong tương lai.

Chỉ số tùy chỉnh

Theo mặc định, trình gỡ lỗi lượng tử hóa phát ra năm số liệu cho mỗi chênh lệch lượng tử float: kích thước tensor, độ lệch chuẩn, lỗi trung bình, lỗi tuyệt đối tối đa và lỗi bình phương trung bình. Bạn có thể thêm nhiều số liệu tùy chỉnh hơn bằng cách chuyển chúng đến các tùy chọn. Đối với mỗi số liệu, kết quả phải là một giá trị float duy nhất và số liệu thu được sẽ là giá trị trung bình của các chỉ số từ tất cả các ví dụ.

  • layer_debug_metrics : tính toán số liệu dựa trên diff cho mỗi đầu ra op từ phao và đầu ra op lượng tử.
  • layer_direct_compare_metrics : thay vì chỉ nhận được diff, điều này sẽ tính toán số liệu dựa trên phao liệu và tensors lượng tử, và các thông số lượng tử của nó (quy mô, không phẩy)
  • model_debug_metrics : chỉ được sử dụng khi float_model_(path|content) sẽ được chuyển cho các chương trình gỡ rối. Ngoài các chỉ số op-level, đầu ra của lớp cuối cùng được so sánh với đầu ra tham chiếu từ mô hình float ban đầu.
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()

Kết quả của model_debug_metrics có thể được nhìn thấy tách biệt khỏi debugger.model_statistics .

debugger.model_statistics
{'argmax_accuracy': 0.36}

Sử dụng API mlir_quantize (nội bộ) để truy cập các tính năng chuyên sâu

from tensorflow.lite.python import convert

Chế độ xác minh toàn bộ mô hình

Hành vi mặc định cho việc tạo mô hình gỡ lỗi là xác minh theo từng lớp. Trong chế độ này, đầu vào cho cặp op nổi và op lượng tử hóa là từ cùng một nguồn (op đã lượng tử hóa trước đó). Một chế độ khác là xác minh toàn bộ mô hình, trong đó mô hình float và lượng tử hóa được tách biệt. Chế độ này sẽ hữu ích để quan sát cách lỗi được truyền xuống mô hình. Để kích hoạt, enable_whole_model_verify=True để convert.mlir_quantize khi tạo mô hình debug bằng tay.

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

Lượng tử hóa có chọn lọc từ một mô hình đã được hiệu chỉnh

Bạn có thể trực tiếp gọi convert.mlir_quantize để có được những mô hình lượng tử chọn lọc từ mô hình đã hiệu chỉnh. Điều này sẽ đặc biệt hữu ích khi bạn muốn hiệu chỉnh mô hình một lần và thử nghiệm với các kết hợp danh sách từ chối khác nhau.

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%