Lượng tử hóa sau đào tạo

Lượng tử hóa sau đào tạo là một kỹ thuật chuyển đổi có thể giảm kích thước mô hình đồng thời cải thiện độ trễ của bộ tăng tốc phần cứng và CPU mà không làm giảm độ chính xác của mô hình. Bạn có thể định lượng mô hình TensorFlow float đã được đào tạo khi chuyển đổi nó sang định dạng TensorFlow Lite bằng cách sử dụng TensorFlow Lite Converter .

Phương pháp tối ưu hóa

Có một số tùy chọn lượng tử hóa sau đào tạo để bạn lựa chọn. Dưới đây là bảng tóm tắt các lựa chọn và lợi ích mà chúng mang lại:

Kỹ thuật Những lợi ích Phần cứng
Lượng tử hóa phạm vi động Nhỏ hơn gấp 4 lần, tăng tốc gấp 2-3 lần CPU
Lượng tử hóa số nguyên đầy đủ Nhỏ hơn gấp 4 lần, tăng tốc gấp 3 lần CPU, Edge TPU, Vi điều khiển
Lượng tử hóa Float16 Nhỏ hơn gấp 2 lần, tăng tốc GPU CPU, GPU

Cây quyết định sau đây có thể giúp xác định phương pháp lượng tử hóa sau đào tạo nào là tốt nhất cho trường hợp sử dụng của bạn:

tùy chọn tối ưu hóa sau đào tạo

Lượng tử hóa phạm vi động

Lượng tử hóa phạm vi động là điểm bắt đầu được đề xuất vì nó giúp giảm mức sử dụng bộ nhớ và tính toán nhanh hơn mà bạn không cần phải cung cấp tập dữ liệu đại diện để hiệu chỉnh. Kiểu lượng tử hóa này chỉ lượng tử hóa tĩnh các trọng số từ dấu phẩy động sang số nguyên tại thời điểm chuyển đổi, cung cấp độ chính xác 8 bit:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

Để giảm thêm độ trễ trong quá trình suy luận, các toán tử "phạm vi động" tự động định lượng các kích hoạt dựa trên phạm vi của chúng thành 8 bit và thực hiện các phép tính với trọng số và kích hoạt 8 bit. Sự tối ưu hóa này cung cấp độ trễ gần với các suy luận điểm cố định hoàn toàn. Tuy nhiên, kết quả đầu ra vẫn được lưu trữ bằng cách sử dụng dấu phẩy động nên tốc độ tăng lên của các thao tác trên phạm vi động sẽ thấp hơn so với tính toán điểm cố định đầy đủ.

Lượng tử hóa số nguyên đầy đủ

Bạn có thể nhận được những cải tiến hơn nữa về độ trễ, giảm mức sử dụng bộ nhớ cao nhất và khả năng tương thích với các thiết bị phần cứng hoặc bộ tăng tốc chỉ có số nguyên bằng cách đảm bảo tất cả toán học mô hình đều được lượng tử hóa số nguyên.

Để lượng tử hóa số nguyên đầy đủ, bạn cần hiệu chỉnh hoặc ước tính phạm vi, tức là (tối thiểu, tối đa) của tất cả các tensor dấu phẩy động trong mô hình. Không giống như các tensor không đổi như trọng số và độ lệch, các tensor biến đổi như đầu vào mô hình, kích hoạt (đầu ra của các lớp trung gian) và đầu ra mô hình không thể được hiệu chỉnh trừ khi chúng ta chạy một vài chu kỳ suy luận. Do đó, bộ chuyển đổi yêu cầu một tập dữ liệu đại diện để hiệu chỉnh chúng. Tập dữ liệu này có thể là một tập hợp con nhỏ (khoảng ~ 100-500 mẫu) của dữ liệu huấn luyện hoặc xác thực. Hãy tham khảo hàm đại representative_dataset() bên dưới.

Từ phiên bản TensorFlow 2.7, bạn có thể chỉ định tập dữ liệu đại diện thông qua chữ ký như ví dụ sau:

def representative_dataset():
  for data in dataset:
    yield {
      "image": data.image,
      "bias": data.bias,
    }

Nếu có nhiều hơn một chữ ký trong mô hình TensorFlow nhất định, bạn có thể chỉ định nhiều tập dữ liệu bằng cách chỉ định các khóa chữ ký:

def representative_dataset():
  # Feed data set for the "encode" signature.
  for data in encode_signature_dataset:
    yield (
      "encode", {
        "image": data.image,
        "bias": data.bias,
      }
    )

  # Feed data set for the "decode" signature.
  for data in decode_signature_dataset:
    yield (
      "decode", {
        "image": data.image,
        "hint": data.hint,
      },
    )

Bạn có thể tạo tập dữ liệu đại diện bằng cách cung cấp danh sách tensor đầu vào:

def representative_dataset():
  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
    yield [tf.dtypes.cast(data, tf.float32)]

Kể từ phiên bản TensorFlow 2.7, chúng tôi khuyên bạn nên sử dụng cách tiếp cận dựa trên chữ ký thay vì cách tiếp cận dựa trên danh sách tensor đầu vào vì thứ tự tensor đầu vào có thể dễ dàng bị đảo lộn.

Đối với mục đích thử nghiệm, bạn có thể sử dụng tập dữ liệu giả như sau:

def representative_dataset():
    for _ in range(100):
      data = np.random.rand(1, 244, 244, 3)
      yield [data.astype(np.float32)]
 

Số nguyên với dự phòng float (sử dụng đầu vào/đầu ra float mặc định)

Để lượng tử hóa toàn bộ số nguyên của một mô hình nhưng sử dụng toán tử float khi chúng không triển khai số nguyên (để đảm bảo quá trình chuyển đổi diễn ra suôn sẻ), hãy làm theo các bước sau:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
tflite_quant_model = converter.convert()

Chỉ số nguyên

Tạo các mô hình chỉ số nguyên là trường hợp sử dụng phổ biến của TensorFlow Lite dành cho Bộ vi điều khiểnTPU Coral Edge .

Ngoài ra, để đảm bảo khả năng tương thích với các thiết bị chỉ có số nguyên (chẳng hạn như bộ vi điều khiển 8 bit) và bộ tăng tốc (chẳng hạn như Coral Edge TPU), bạn có thể thực thi lượng tử hóa số nguyên đầy đủ cho tất cả các hoạt động bao gồm đầu vào và đầu ra, bằng cách làm theo các bước sau:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8
tflite_quant_model = converter.convert()

Lượng tử hóa Float16

Bạn có thể giảm kích thước của mô hình dấu phẩy động bằng cách lượng tử hóa các trọng số thành float16, tiêu chuẩn IEEE cho số dấu phẩy động 16 bit. Để kích hoạt lượng tử hóa trọng số float16, hãy làm theo các bước sau:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()

Ưu điểm của lượng tử hóa float16 như sau:

  • Nó làm giảm kích thước mô hình tới một nửa (vì tất cả trọng lượng trở thành một nửa kích thước ban đầu của chúng).
  • Nó gây ra sự mất mát tối thiểu về độ chính xác.
  • Nó hỗ trợ một số đại biểu (ví dụ: đại biểu GPU) có thể hoạt động trực tiếp trên dữ liệu float16, dẫn đến việc thực thi nhanh hơn so với tính toán float32.

Những nhược điểm của lượng tử hóa float16 như sau:

  • Nó không làm giảm độ trễ nhiều như lượng tử hóa toán học điểm cố định.
  • Theo mặc định, mô hình lượng tử hóa float16 sẽ "khử lượng tử" các giá trị trọng số thành float32 khi chạy trên CPU. (Lưu ý rằng đại biểu GPU sẽ không thực hiện quá trình khử lượng tử này vì nó có thể hoạt động trên dữ liệu float16.)

Chỉ số nguyên: kích hoạt 16 bit với trọng số 8 bit (thử nghiệm)

Đây là một sơ đồ lượng tử hóa thử nghiệm. Nó tương tự như sơ đồ "chỉ số nguyên", nhưng kích hoạt được lượng tử hóa dựa trên phạm vi của chúng đến 16 bit, trọng số được lượng tử hóa theo số nguyên 8 bit và độ lệch được lượng tử hóa thành số nguyên 64 bit. Điều này còn được gọi là lượng tử hóa 16x8.

Ưu điểm chính của việc lượng tử hóa này là nó có thể cải thiện độ chính xác một cách đáng kể nhưng chỉ tăng nhẹ kích thước mô hình.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]
tflite_quant_model = converter.convert()

Nếu một số toán tử trong mô hình không hỗ trợ lượng tử hóa 16x8 thì mô hình vẫn có thể được lượng tử hóa nhưng các toán tử không được hỗ trợ vẫn ở trạng thái thả nổi. Tùy chọn sau nên được thêm vào target_spec để cho phép điều này.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
tf.lite.OpsSet.TFLITE_BUILTINS]
tflite_quant_model = converter.convert()

Ví dụ về các trường hợp sử dụng trong đó các cải tiến về độ chính xác được cung cấp bởi sơ đồ lượng tử hóa này bao gồm:

  • giải pháp tối ưu,
  • xử lý tín hiệu âm thanh như khử tiếng ồn và định dạng chùm tia,
  • khử nhiễu hình ảnh,
  • Tái tạo HDR từ một hình ảnh duy nhất.

Nhược điểm của lượng tử hóa này là:

  • Hiện tại suy luận chậm hơn đáng kể so với số nguyên đầy đủ 8 bit do thiếu triển khai hạt nhân được tối ưu hóa.
  • Hiện tại nó không tương thích với các đại biểu TFLite được tăng tốc phần cứng hiện có.

Hướng dẫn về chế độ lượng tử hóa này có thể được tìm thấy ở đây .

Độ chính xác của mô hình

Vì các trọng số được lượng tử hóa sau quá trình đào tạo nên có thể bị mất độ chính xác, đặc biệt đối với các mạng nhỏ hơn. Các mô hình lượng tử hóa đầy đủ được đào tạo trước được cung cấp cho các mạng cụ thể trên TensorFlow Hub . Điều quan trọng là phải kiểm tra tính chính xác của mô hình lượng tử hóa để xác minh rằng bất kỳ sự suy giảm nào về độ chính xác đều nằm trong giới hạn chấp nhận được. Có các công cụ để đánh giá độ chính xác của mô hình TensorFlow Lite .

Ngoài ra, nếu độ chính xác giảm quá cao, hãy cân nhắc sử dụng phương pháp đào tạo nhận biết lượng tử hóa . Tuy nhiên, làm như vậy đòi hỏi phải sửa đổi trong quá trình đào tạo mô hình để thêm các nút lượng tử hóa giả, trong khi các kỹ thuật lượng tử hóa sau đào tạo trên trang này sử dụng mô hình được đào tạo trước hiện có.

Biểu diễn cho tensor lượng tử hóa

Lượng tử hóa 8 bit xấp xỉ các giá trị dấu phẩy động bằng công thức sau.

\[real\_value = (int8\_value - zero\_point) \times scale\]

Việc biểu diễn có hai phần chính:

  • Trọng số trên mỗi trục (còn gọi là trên mỗi kênh) hoặc trên mỗi tenxơ được biểu thị bằng các giá trị bù của int8 hai trong phạm vi [-127, 127] với điểm 0 bằng 0.

  • Kích hoạt/đầu vào trên mỗi tensor được biểu thị bằng các giá trị bù hai của int8 trong phạm vi [-128, 127], với điểm 0 trong phạm vi [-128, 127].

Để có cái nhìn chi tiết về sơ đồ lượng tử hóa của chúng tôi, vui lòng xem thông số lượng tử hóa của chúng tôi. Các nhà cung cấp phần cứng muốn kết nối với giao diện đại biểu của TensorFlow Lite được khuyến khích triển khai sơ đồ lượng tử hóa được mô tả ở đó.