Thêm siêu dữ liệu vào các mô hình TensorFlow Lite

Siêu dữ liệu TensorFlow Lite cung cấp tiêu chuẩn cho mô tả mô hình. Siêu dữ liệu là nguồn kiến ​​thức quan trọng về chức năng của mô hình và thông tin đầu vào/đầu ra của nó. Siêu dữ liệu bao gồm cả

Tất cả các mô hình hình ảnh được xuất bản trên TensorFlow Hub đều đã được điền siêu dữ liệu.

Mô hình có định dạng siêu dữ liệu

model_with_metadata
Hình 1. Mô hình TFLite với siêu dữ liệu và các tệp liên quan.

Siêu dữ liệu mô hình được xác định trong siêu dữ liệu_schema.fbs , một tệp FlatBuffer . Như được hiển thị trong Hình 1, nó được lưu trữ trong trường siêu dữ liệu của lược đồ mô hình TFLite , dưới tên "TFLITE_METADATA" . Một số kiểu máy có thể đi kèm với các tệp được liên kết, chẳng hạn như tệp nhãn phân loại . Các tệp này được nối vào cuối tệp mô hình gốc dưới dạng ZIP bằng chế độ "chắp thêm" ZipFile (chế độ 'a' ). Trình thông dịch TFLite có thể sử dụng định dạng tệp mới theo cách tương tự như trước. Xem Đóng gói các tệp liên quan để biết thêm thông tin.

Xem hướng dẫn bên dưới về cách điền, trực quan hóa và đọc siêu dữ liệu.

Thiết lập các công cụ siêu dữ liệu

Trước khi thêm siêu dữ liệu vào mô hình của mình, bạn sẽ cần thiết lập môi trường lập trình Python để chạy TensorFlow. Có hướng dẫn chi tiết về cách thiết lập tính năng này tại đây .

Sau khi thiết lập môi trường lập trình Python, bạn sẽ cần cài đặt thêm công cụ:

pip install tflite-support

Công cụ siêu dữ liệu TensorFlow Lite hỗ trợ Python 3.

Thêm siêu dữ liệu bằng API Flatbuffers Python

Có ba phần của siêu dữ liệu mô hình trong lược đồ :

  1. Thông tin về mô hình - Mô tả tổng thể về mô hình cũng như các mục như điều khoản cấp phép. Xem ModelMetadata .
  2. Thông tin đầu vào - Mô tả các đầu vào và yêu cầu xử lý trước, chẳng hạn như chuẩn hóa. Xem SubGraphMetadata.input_tensor_metadata .
  3. Thông tin đầu ra - Mô tả đầu ra và yêu cầu xử lý hậu kỳ, chẳng hạn như ánh xạ tới nhãn. Xem SubGraphMetadata.output_tensor_metadata .

Vì TensorFlow Lite chỉ hỗ trợ một sơ đồ con tại thời điểm này nên trình tạo mã TensorFlow Litetính năng Android Studio ML Binding sẽ sử dụng ModelMetadata.nameModelMetadata.description , thay vì SubGraphMetadata.nameSubGraphMetadata.description , khi hiển thị siêu dữ liệu và tạo mã.

Các loại đầu vào / đầu ra được hỗ trợ

Siêu dữ liệu TensorFlow Lite cho đầu vào và đầu ra không được thiết kế dành cho các loại mô hình cụ thể mà thay vào đó là các loại đầu vào và đầu ra. Chức năng của mô hình không quan trọng, miễn là loại đầu vào và đầu ra bao gồm các loại sau hoặc kết hợp các loại sau, thì mô hình đó được siêu dữ liệu TensorFlow Lite hỗ trợ:

  • Tính năng - Các số là số nguyên không dấu hoặc float32.
  • Hình ảnh - Siêu dữ liệu hiện hỗ trợ hình ảnh thang độ xám và RGB.
  • Hộp đóng bìa - Hộp đóng khung hình chữ nhật. Lược đồ này hỗ trợ nhiều sơ đồ đánh số khác nhau .

Đóng gói các tập tin liên quan

Các mô hình TensorFlow Lite có thể đi kèm với các tệp liên quan khác nhau. Ví dụ: các mô hình ngôn ngữ tự nhiên thường có các tệp từ vựng ánh xạ các phần từ thành ID từ; mô hình phân loại có thể có các tệp nhãn cho biết danh mục đối tượng. Nếu không có các tệp liên quan (nếu có), mô hình sẽ không hoạt động tốt.

Giờ đây, các tệp được liên kết có thể được gói cùng với mô hình thông qua thư viện siêu dữ liệu Python. Mô hình TensorFlow Lite mới trở thành một tệp zip chứa cả mô hình và các tệp được liên kết. Nó có thể được giải nén bằng các công cụ zip thông thường. Định dạng mô hình mới này tiếp tục sử dụng cùng một phần mở rộng tệp, .tflite . Nó tương thích với khung và Trình thông dịch TFLite hiện có. Xem Đóng gói siêu dữ liệu và các tệp liên quan vào mô hình để biết thêm chi tiết.

Thông tin tệp liên quan có thể được ghi lại trong siêu dữ liệu. Tùy thuộc vào loại tệp và nơi tệp được đính kèm (ví dụ: ModelMetadata , SubGraphMetadataTensorMetadata ), trình tạo mã Android TensorFlow Lite có thể tự động áp dụng quá trình xử lý trước/sau tương ứng cho đối tượng. Xem phần <Cách sử dụng Codegen> của từng loại tệp liên kết trong lược đồ để biết thêm chi tiết.

Các tham số chuẩn hóa và lượng tử hóa

Chuẩn hóa là một kỹ thuật tiền xử lý dữ liệu phổ biến trong học máy. Mục tiêu của việc chuẩn hóa là thay đổi các giá trị về một thang đo chung mà không làm sai lệch sự khác biệt trong phạm vi giá trị.

Lượng tử hóa mô hình là một kỹ thuật cho phép giảm sự biểu diễn chính xác của trọng số và tùy chọn kích hoạt cho cả lưu trữ và tính toán.

Xét về mặt tiền xử lý và hậu xử lý, chuẩn hóa và lượng tử hóa là hai bước độc lập. Đây là những thông tin chi tiết.

Chuẩn hóa Lượng tử hóa

Một ví dụ về các giá trị tham số của hình ảnh đầu vào trong MobileNet tương ứng cho các mô hình float và quant.
Mô hình phao :
- trung bình: 127,5
- tiêu chuẩn: 127,5
Mô hình lượng tử :
- trung bình: 127,5
- tiêu chuẩn: 127,5
Mô hình phao :
- Điểm 0: 0
- tỷ lệ: 1.0
Mô hình lượng tử :
- Điểm 0: 128.0
- tỷ lệ: 0,0078125f




Khi nào nên triệu tập?


Đầu vào : Nếu dữ liệu đầu vào được chuẩn hóa trong quá trình huấn luyện thì dữ liệu đầu vào của suy luận cần được chuẩn hóa tương ứng.
Đầu ra : dữ liệu đầu ra nói chung sẽ không được chuẩn hóa.
Các mô hình float không cần lượng tử hóa.
Mô hình lượng tử hóa có thể cần hoặc không cần lượng tử hóa trong quá trình xử lý trước/sau. Nó phụ thuộc vào kiểu dữ liệu của tensor đầu vào/đầu ra.
- tensor float: không cần lượng tử hóa trong quá trình xử lý trước/sau. Quant op và dequant op được đưa vào biểu đồ mô hình.
- tensor int8/uint8: cần lượng tử hóa trong quá trình xử lý trước/sau.


Công thức


normalized_input = (đầu vào - trung bình) / std
Định lượng cho đầu vào :
q = f / thang đo + điểm không
Dequantize cho đầu ra :
f = (q - zeroPoint) * thang đo

Thông số ở đâu
Được người tạo mô hình điền và lưu trữ trong siêu dữ liệu mô hình, dưới dạng NormalizationOptions Được điền tự động bởi trình chuyển đổi TFLite và được lưu trữ trong tệp mô hình tflite.
Làm thế nào để có được các thông số? Thông qua API MetadataExtractor [2] Thông qua API TFLite Tensor [1] hoặc thông qua API MetadataExtractor [2]
Các mô hình float và quant có chia sẻ cùng một giá trị không? Có, mô hình float và quant có cùng tham số Chuẩn hóa Không, mô hình float không cần lượng tử hóa.
Trình tạo mã TFLite hoặc liên kết Android Studio ML có tự động tạo mã đó trong quá trình xử lý dữ liệu không?
Đúng

Đúng

[1] API Java TensorFlow LiteAPI TensorFlow Lite C++ .
[2] Thư viện trích xuất siêu dữ liệu

Khi xử lý dữ liệu hình ảnh cho các mô hình uint8, việc chuẩn hóa và lượng tử hóa đôi khi bị bỏ qua. Bạn có thể làm như vậy khi giá trị pixel nằm trong phạm vi [0, 255]. Nhưng nói chung, bạn phải luôn xử lý dữ liệu theo các tham số chuẩn hóa và lượng tử hóa khi có thể.

Thư viện tác vụ TensorFlow Lite có thể xử lý việc chuẩn hóa cho bạn nếu bạn thiết lập NormalizationOptions trong siêu dữ liệu. Quá trình lượng tử hóa và giải lượng tử luôn được đóng gói.

Ví dụ

Bạn có thể tìm thấy các ví dụ về cách điền siêu dữ liệu cho các loại mô hình khác nhau tại đây:

Phân loại hình ảnh

Tải tập lệnh xuống tại đây , tập lệnh này sẽ điền siêu dữ liệu vào mobilenet_v1_0.75_160_quantized.tflite . Chạy tập lệnh như thế này:

python ./metadata_writer_for_image_classifier.py \
    --model_file=./model_without_metadata/mobilenet_v1_0.75_160_quantized.tflite \
    --label_file=./model_without_metadata/labels.txt \
    --export_directory=model_with_metadata

Để điền siêu dữ liệu cho các mô hình phân loại hình ảnh khác, hãy thêm thông số mô hình như thế này vào tập lệnh. Phần còn lại của hướng dẫn này sẽ nêu bật một số phần chính trong ví dụ phân loại hình ảnh để minh họa các yếu tố chính.

Đi sâu vào ví dụ phân loại hình ảnh

Thông tin mẫu

Siêu dữ liệu bắt đầu bằng cách tạo thông tin mô hình mới:

from tflite_support import flatbuffers
from tflite_support import metadata as _metadata
from tflite_support import metadata_schema_py_generated as _metadata_fb

""" ... """
"""Creates the metadata for an image classifier."""

# Creates model info.
model_meta = _metadata_fb.ModelMetadataT()
model_meta.name = "MobileNetV1 image classifier"
model_meta.description = ("Identify the most prominent object in the "
                          "image from a set of 1,001 categories such as "
                          "trees, animals, food, vehicles, person etc.")
model_meta.version = "v1"
model_meta.author = "TensorFlow"
model_meta.license = ("Apache License. Version 2.0 "
                      "http://www.apache.org/licenses/LICENSE-2.0.")

Thông tin đầu vào/đầu ra

Phần này chỉ cho bạn cách mô tả chữ ký đầu vào và đầu ra của mô hình. Siêu dữ liệu này có thể được sử dụng bởi các trình tạo mã tự động để tạo mã trước và sau xử lý. Để tạo thông tin đầu vào hoặc đầu ra về một tensor:

# Creates input info.
input_meta = _metadata_fb.TensorMetadataT()

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()

Đầu vào hình ảnh

Hình ảnh là loại đầu vào phổ biến cho máy học. Siêu dữ liệu TensorFlow Lite hỗ trợ thông tin như không gian màu và thông tin tiền xử lý như chuẩn hóa. Kích thước của hình ảnh không yêu cầu thông số kỹ thuật thủ công vì nó đã được cung cấp bởi hình dạng của tensor đầu vào và có thể được suy ra tự động.

input_meta.name = "image"
input_meta.description = (
    "Input image to be classified. The expected image is {0} x {1}, with "
    "three channels (red, blue, and green) per pixel. Each value in the "
    "tensor is a single byte between 0 and 255.".format(160, 160))
input_meta.content = _metadata_fb.ContentT()
input_meta.content.contentProperties = _metadata_fb.ImagePropertiesT()
input_meta.content.contentProperties.colorSpace = (
    _metadata_fb.ColorSpaceType.RGB)
input_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.ImageProperties)
input_normalization = _metadata_fb.ProcessUnitT()
input_normalization.optionsType = (
    _metadata_fb.ProcessUnitOptions.NormalizationOptions)
input_normalization.options = _metadata_fb.NormalizationOptionsT()
input_normalization.options.mean = [127.5]
input_normalization.options.std = [127.5]
input_meta.processUnits = [input_normalization]
input_stats = _metadata_fb.StatsT()
input_stats.max = [255]
input_stats.min = [0]
input_meta.stats = input_stats

Đầu ra nhãn

Nhãn có thể được ánh xạ tới một tensor đầu ra thông qua một tệp được liên kết bằng cách sử dụng TENSOR_AXIS_LABELS .

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()
output_meta.name = "probability"
output_meta.description = "Probabilities of the 1001 labels respectively."
output_meta.content = _metadata_fb.ContentT()
output_meta.content.content_properties = _metadata_fb.FeaturePropertiesT()
output_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.FeatureProperties)
output_stats = _metadata_fb.StatsT()
output_stats.max = [1.0]
output_stats.min = [0.0]
output_meta.stats = output_stats
label_file = _metadata_fb.AssociatedFileT()
label_file.name = os.path.basename("your_path_to_label_file")
label_file.description = "Labels for objects that the model can recognize."
label_file.type = _metadata_fb.AssociatedFileType.TENSOR_AXIS_LABELS
output_meta.associatedFiles = [label_file]

Tạo bộ đệm phẳng siêu dữ liệu

Đoạn mã sau kết hợp thông tin mô hình với thông tin đầu vào và đầu ra:

# Creates subgraph info.
subgraph = _metadata_fb.SubGraphMetadataT()
subgraph.inputTensorMetadata = [input_meta]
subgraph.outputTensorMetadata = [output_meta]
model_meta.subgraphMetadata = [subgraph]

b = flatbuffers.Builder(0)
b.Finish(
    model_meta.Pack(b),
    _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
metadata_buf = b.Output()

Đóng gói siêu dữ liệu và các tệp liên quan vào mô hình

Khi siêu dữ liệu Flatbuffers được tạo, siêu dữ liệu và tệp nhãn sẽ được ghi vào tệp TFLite thông qua phương thức populate :

populator = _metadata.MetadataPopulator.with_model_file(model_file)
populator.load_metadata_buffer(metadata_buf)
populator.load_associated_files(["your_path_to_label_file"])
populator.populate()

Bạn có thể đóng gói bao nhiêu tệp được liên kết vào mô hình tùy thích thông qua load_associated_files . Tuy nhiên, cần phải đóng gói ít nhất những tệp được ghi trong siêu dữ liệu. Trong ví dụ này, việc đóng gói tệp nhãn là bắt buộc.

Trực quan hóa siêu dữ liệu

Bạn có thể sử dụng Netron để trực quan hóa siêu dữ liệu của mình hoặc bạn có thể đọc siêu dữ liệu từ mô hình TensorFlow Lite sang định dạng json bằng MetadataDisplayer :

displayer = _metadata.MetadataDisplayer.with_model_file(export_model_path)
export_json_file = os.path.join(FLAGS.export_directory,
                                os.path.splitext(model_basename)[0] + ".json")
json_file = displayer.get_metadata_json()
# Optional: write out the metadata as a json file
with open(export_json_file, "w") as f:
  f.write(json_file)

Android Studio cũng hỗ trợ hiển thị siêu dữ liệu thông qua tính năng Android Studio ML Binding .

Phiên bản siêu dữ liệu

Lược đồ siêu dữ liệu được phiên bản cả theo số phiên bản Ngữ nghĩa, theo dõi các thay đổi của tệp lược đồ và bằng nhận dạng tệp Flatbuffers, cho biết khả năng tương thích của phiên bản thực.

Số phiên bản ngữ nghĩa

Lược đồ siêu dữ liệu được phiên bản theo số phiên bản Ngữ nghĩa , chẳng hạn như MAJOR.MINOR.PATCH. Nó theo dõi những thay đổi của lược đồ theo các quy tắc ở đây . Xem lịch sử các trường được thêm sau phiên bản 1.0.0 .

Nhận dạng tệp Flatbuffers

Phiên bản ngữ nghĩa đảm bảo tính tương thích nếu tuân theo các quy tắc, nhưng nó không ngụ ý tính không tương thích thực sự. Khi tăng số CHÍNH, điều đó không nhất thiết có nghĩa là khả năng tương thích ngược bị hỏng. Do đó, chúng tôi sử dụng nhận dạng tệp Flatbuffers , file_identifier , để biểu thị tính tương thích thực sự của lược đồ siêu dữ liệu. Mã định danh tệp dài chính xác 4 ký tự. Nó được cố định theo một lược đồ siêu dữ liệu nhất định và người dùng không thể thay đổi. Nếu vì lý do nào đó, khả năng tương thích ngược của lược đồ siêu dữ liệu bị phá vỡ, thì file_identifier sẽ tăng lên, chẳng hạn như từ “M001” thành “M002”. File_identifier dự kiến ​​sẽ được thay đổi ít thường xuyên hơn siêu dữ liệu_version.

Phiên bản trình phân tích cú pháp siêu dữ liệu cần thiết tối thiểu

Phiên bản trình phân tích cú pháp siêu dữ liệu cần thiết tối thiểu là phiên bản tối thiểu của trình phân tích cú pháp siêu dữ liệu (mã được tạo bởi Flatbuffers) có thể đọc đầy đủ siêu dữ liệu Flatbuffers. Phiên bản này thực tế là số phiên bản lớn nhất trong số các phiên bản của tất cả các trường được điền và là phiên bản tương thích nhỏ nhất được chỉ định bởi mã định danh tệp. Phiên bản trình phân tích cú pháp siêu dữ liệu cần thiết tối thiểu được MetadataPopulator tự động điền khi siêu dữ liệu được đưa vào mô hình TFLite. Xem trình trích xuất siêu dữ liệu để biết thêm thông tin về cách sử dụng phiên bản trình phân tích cú pháp siêu dữ liệu cần thiết tối thiểu.

Đọc siêu dữ liệu từ các mô hình

Thư viện Trình trích xuất siêu dữ liệu là công cụ thuận tiện để đọc siêu dữ liệu và các tệp liên quan từ một mô hình trên các nền tảng khác nhau (xem phiên bản Javaphiên bản C++ ). Bạn có thể xây dựng công cụ trích xuất siêu dữ liệu của riêng mình bằng các ngôn ngữ khác bằng thư viện Flatbuffers.

Đọc siêu dữ liệu trong Java

Để sử dụng thư viện Trình trích xuất siêu dữ liệu trong ứng dụng Android của bạn, chúng tôi khuyên bạn nên sử dụng AAR siêu dữ liệu TensorFlow Lite được lưu trữ tại MavenCentral . Nó chứa lớp MetadataExtractor , cũng như các ràng buộc Java FlatBuffers cho lược đồ siêu dữ liệulược đồ mô hình .

Bạn có thể chỉ định điều này trong phần phụ thuộc build.gradle của mình như sau:

dependencies {
    implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}

Để sử dụng ảnh chụp nhanh hàng đêm, hãy đảm bảo rằng bạn đã thêm kho lưu trữ ảnh chụp nhanh Sonatype .

Bạn có thể khởi tạo một đối tượng MetadataExtractor bằng ByteBuffer trỏ đến mô hình:

public MetadataExtractor(ByteBuffer buffer);

ByteBuffer phải không thay đổi trong suốt thời gian tồn tại của đối tượng MetadataExtractor . Quá trình khởi tạo có thể không thành công nếu mã định danh tệp Flatbuffers của siêu dữ liệu mô hình không khớp với mã định danh của trình phân tích cú pháp siêu dữ liệu. Xem phiên bản siêu dữ liệu để biết thêm thông tin.

Với các mã định danh tệp phù hợp, trình trích xuất siêu dữ liệu sẽ đọc thành công siêu dữ liệu được tạo từ tất cả lược đồ trong quá khứ và tương lai nhờ cơ chế tương thích tiến và lùi của Flatbuffers. Tuy nhiên, các trường từ lược đồ trong tương lai không thể được trích xuất bằng trình trích xuất siêu dữ liệu cũ hơn. Phiên bản trình phân tích cú pháp cần thiết tối thiểu của siêu dữ liệu cho biết phiên bản tối thiểu của trình phân tích cú pháp siêu dữ liệu có thể đọc đầy đủ Bộ đệm phẳng siêu dữ liệu. Bạn có thể sử dụng phương pháp sau để xác minh xem điều kiện phiên bản trình phân tích cú pháp cần thiết tối thiểu có được đáp ứng hay không:

public final boolean isMinimumParserVersionSatisfied();

Được phép chuyển vào một mô hình không có siêu dữ liệu. Tuy nhiên, việc gọi các phương thức đọc từ siêu dữ liệu sẽ gây ra lỗi thời gian chạy. Bạn có thể kiểm tra xem một mô hình có siêu dữ liệu hay không bằng cách gọi phương thức hasMetadata :

public boolean hasMetadata();

MetadataExtractor cung cấp các chức năng thuận tiện để bạn lấy siêu dữ liệu của tensor đầu vào/đầu ra. Ví dụ,

public int getInputTensorCount();
public TensorMetadata getInputTensorMetadata(int inputIndex);
public QuantizationParams getInputTensorQuantizationParams(int inputIndex);
public int[] getInputTensorShape(int inputIndex);
public int getoutputTensorCount();
public TensorMetadata getoutputTensorMetadata(int inputIndex);
public QuantizationParams getoutputTensorQuantizationParams(int inputIndex);
public int[] getoutputTensorShape(int inputIndex);

Mặc dù lược đồ mô hình TensorFlow Lite hỗ trợ nhiều sơ đồ con, Trình thông dịch TFLite hiện chỉ hỗ trợ một sơ đồ con duy nhất. Do đó, MetadataExtractor bỏ qua chỉ mục đồ thị con làm đối số đầu vào trong các phương thức của nó.

Đọc các tập tin liên quan từ các mô hình

Mô hình TensorFlow Lite với siêu dữ liệu và các tệp được liên kết về cơ bản là một tệp zip có thể được giải nén bằng các công cụ zip phổ biến để lấy các tệp được liên kết. Ví dụ: bạn có thể giải nén mobilenet_v1_0.75_160_quantized và trích xuất tệp nhãn trong mô hình như sau:

$ unzip mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
Archive:  mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
 extracting: labels.txt

Bạn cũng có thể đọc các tệp liên quan thông qua thư viện Trình trích xuất siêu dữ liệu.

Trong Java, chuyển tên tệp vào phương thức MetadataExtractor.getAssociatedFile :

public InputStream getAssociatedFile(String fileName);

Tương tự, trong C++, điều này có thể được thực hiện bằng phương thức ModelMetadataExtractor::GetAssociatedFile :

tflite::support::StatusOr<absl::string_view> GetAssociatedFile(
      const std::string& filename) const;