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

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

Tất cả mô hình hình ảnh xuất bản trên Mô hình Kaggle đều đã được điền sẵ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à tệp liên kết.

Siêu dữ liệu của mô hình được xác định trong metadata_schema.fbs, tệp FlatBuffer. Như trong Hình 1, tệp này được lưu trữ trong trường siêu dữ liệu của giản đồ mô hình TFLite, bên dưới tên là "TFLITE_METADATA". Một số mô hình có thể đi kèm với các tệp 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 tệp ZIP bằng cách sử dụng chế độ"nối" 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 đây. Hãy xem bài viết Đóng gói các tệp được liên kết để biết thêm thông tin.

Hãy xem hướng dẫn dưới đây về cách điền sẵn, trực quan hoá và đọc siêu dữ liệu.

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

Trước khi thêm siêu dữ liệu vào mô hình, bạn 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 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ó 3 phần siêu dữ liệu của mô hình trong giản đồ:

  1. Thông tin về mô hình – Nội dung 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. Hãy xem ModelMetadata.
    1. Thông tin đầu vào – Nội dung mô tả về các dữ liệu đầu vào và quy trình xử lý trước cần thiết, chẳng hạn như chuẩn hoá. Hãy xem phần SubGraphMetadata.input_tensor_metadata.
      1. Thông tin đầu ra – Nội dung mô tả đầu ra và quy trình xử lý hậu kỳ cần thiết, chẳng hạn như ánh xạ đến nhãn. Hãy xem phần SubGraphMetadata.output_tensor_metadata.

Vì TensorFlow Lite chỉ hỗ trợ một đồ thị con tại thời điểm này, nên trình tạo mã TensorFlow Litetính năng Liên kết học máy của Android Studio 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 của TensorFlow Lite cho dữ liệu đầu vào và đầu ra không được thiết kế 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. Không quan trọng chức năng của mô hình, miễn là kiểu dữ liệu đầu vào và đầu ra bao gồm các kiểu sau hoặc kết hợp các giá trị sau, thì mô hình đó được siêu dữ liệu TensorFlow Lite hỗ trợ:

  • Tính năng – 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 RGB và thang màu xám.
  • Hộp giới hạn – Hộp giới hạn hình chữ nhật. Giản đồ hỗ trợ nhiều lược đồ đánh số.

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

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

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

Thông tin về tệp liên kết có thể được ghi lại trong siêu dữ liệu. Tuỳ thuộc vào loại tệp và vị trí đính kèm tệp (ví dụ: ModelMetadata, SubGraphMetadataTensorMetadata), trình tạo mã Android TensorFlow Lite có thể tự động áp dụng quy trình xử lý trước/sau tương ứng cho đối tượng. Hãy xem mục <Codegen Usage> của mỗi loại tệp liên kết trong giản đồ để biết thêm thông tin chi tiết.

Tham số chuẩn hoá và lượng tử hoá

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

Lượng tử hoá mô hình là một kỹ thuật cho phép giảm độ chính xác biểu thị của trọng số và có thể kích hoạt cả việc lưu trữ và tính toán (không bắt buộc).

Về mặt tiền xử lý và hậu xử lý, chuẩn hoá và lượng tử hoá là hai bước độc lập. Dưới đây là các chi tiết.

Chuẩn hoá Lượng tử hoá

Ví dụ về các giá trị tham số của hình ảnh đầu vào trong MobileNet lần lượt cho các mô hình số thực và số lượng.
Mô hình số thực:
- trung bình: 127,5
- std: 127,5
Mô hình lượng tử:
- trung bình: 127,5
- std: 127,5
Mô hình số thực:
– zeroPoint: 0
- tỷ lệ: 1.0
Mô hình lượng tử:
- zeroPoint: 128.0
- tỷ lệ:0.0078125f




Khi nào nên gọi?


Đầu vào: Nếu dữ liệu đầu vào được chuẩn hoá 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 hoá tương ứng.
Đầu ra: dữ liệu đầu ra sẽ không được chuẩn hoá nói chung.
Mô hình số thực không cần lượng tử hoá.
Mô hình được lượng tử hoá có thể hoặc không cần lượng tử hoá trong quá trình xử lý trước/sau. Điều này phụ thuộc vào loại dữ liệu của các tensor đầu vào/đầu ra.
– tensor độ chính xác đơn: không cần lượng tử hoá 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ử hoá 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 / scale + zeroPoint
Khử lượng tử cho đầu ra:
f = (q - zeroPoint) * tỷ lệ

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

[1] API Java TensorFlow LiteAPI C++ cho TensorFlow Lite.
[2] Thư viện trình 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, đôi khi, quá trình chuẩn hoá và lượng tử hoá sẽ bị bỏ qua. Bạn có thể làm như vậy khi giá trị pixel nằm trong khoảng [0, 255]. Nhưng nhìn chung, bạn phải luôn xử lý dữ liệu theo các tham số chuẩn hoá và lượng tử hoá nếu có.

Ví dụ

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

Phân loại hình ảnh

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

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ố kỹ thuật của mô hình như this 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ụ về phân loại hình ảnh để minh hoạ các thành phần chính.

Tìm hiểu sâu ví dụ về cách 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 một 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 cho bạn biết cách mô tả chữ ký đầu vào và đầu ra của mô hình. Các trình tạo mã tự động có thể sử dụng siêu dữ liệu này để tạo mã trước và sau xử lý. Cách 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()

Nhập hình ảnh

Hình ảnh là một loại dữ liệu đầu vào phổ biến cho công nghệ học máy. Siêu dữ liệu của TensorFlow Lite hỗ trợ các thông tin như hệ màu và thông tin tiền xử lý, chẳng hạn như chuẩn hoá. 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 tự động suy ra.

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 của nhãn

Bạn có thể liên kết nhãn tới một tensor đầu ra thông qua một tệp 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 Vùng đệm phẳng siêu dữ liệu

Đoạn mã sau đây kết hợp thông tin về 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 kết vào mô hình

Sau khi tạo siêu dữ liệu Flatbuffers, 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 liên kết tuỳ ý vào mô hình thông qua load_associated_files. Tuy nhiên, bạn cần phải đóng gói ít nhất các tệp được ghi lại 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 hoá siêu dữ liệu

Bạn có thể sử dụng Netron để trực quan hoá siêu dữ liệu của mình, hoặc đọc siêu dữ liệu từ mô hình TensorFlow Lite thành đị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 Liên kết máy học của Android Studio.

Tạo phiên bản siêu dữ liệu

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

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

Giản đồ siêu dữ liệu được tạo phiên bản bằng số phiên bản ngữ nghĩa, chẳng hạn như MAJOR.MINOR.PATCH. Công cụ này theo dõi các thay đổi đối với giản đồ theo các quy tắc tại đây. Xem nhật ký trường được thêm sau phiên bản 1.0.0.

Nhận dạng tệp Flatbuffers

Việc tạo phiên bản ngữ nghĩa đảm bảo khả năng tương thích nếu tuân thủ các quy tắc, nhưng không ngụ ý rằng tính không tương thích thực sự. Khi tăng số MAJOR, đ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 tính năng nhận dạng tệp Flatbuffers, file_identifier để biểu thị khả năng tương thích thực sự của giản đồ siêu dữ liệu. Giá trị nhận dạng tệp dài chính xác 4 ký tự. Dữ liệu này được cố định theo một giản đồ siêu dữ liệu nhất định và người dùng không thể thay đổi. Nếu khả năng tương thích ngược của giản đồ siêu dữ liệu bị hỏng vì lý do nào đó, file_identifier sẽ tăng lên, ví dụ: từ "M001" thành "M002". File_identifier sẽ ít được thay đổi hơn nhiều so với siêu dữ liệu_phiên bản.

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

Phiên bản trình phân tích cú pháp siêu dữ liệu tối thiểu cần thiết 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ằng Flatbuffers) có thể đọc đầy đủ Bộ đệm siêu dữ liệu. Phiên bản thực sự 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 sẵn và là phiên bản tương thích nhỏ nhất được biểu thị bằng giá trị nhận dạng tệp. Phiên bản tối thiểu cần thiết của trình phân tích cú pháp siêu dữ liệu được MetadataPopulator tự động điền khi siêu dữ liệu được điền vào mô hình TFLite. Hãy 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 tối thiểu cần thiết của trình phân tích cú pháp siêu dữ liệu.

Đọc siêu dữ liệu của mô hình

Thư viện Trình trích xuất siêu dữ liệu là một công cụ thuận tiện để đọc siêu dữ liệu và các tệp liên kết từ một mô hình trên nhiều nền tảng (xem phiên bản Javaphiên bản C++). Bạn có thể tạo 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 nhờ 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, bạn nên sử dụng TensorFlow Lite Metadata AAR (Siêu dữ liệu TensorFlow Lite) được lưu trữ tại MavenCentral. Tệp này chứa lớp MetadataExtractor, cũng như các liên kết Java của FlatBuffers cho giản đồ siêu dữ liệugiản đồ mô hình.

Bạn có thể chỉ định mã này trong các phần phụ thuộc build.gradle như sau:

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

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

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

public MetadataExtractor(ByteBuffer buffer);

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

Với giá trị nhận dạng tệp trùng khớ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ả giản đồ trước đây và trong tương lai do cơ chế chuyển tiếp và tương thích ngược của Flatbuffers. Tuy nhiên, các công cụ trích xuất siêu dữ liệu cũ không thể trích xuất các trường từ giản đồ trong tương lai. Phiên bản trình phân tích cú pháp tối thiểu cần thiết 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 siêu dữ liệu. Bạn có thể sử dụng phương thức sau để xác minh xem điều kiện phiên bản trình phân tích cú pháp tối thiểu cần thiết có được đáp ứng hay không:

public final boolean isMinimumParserVersionSatisfied();

Bạn có thể truyền dữ liệu vào mô hình không có siêu dữ liệu. Tuy nhiên, 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 hàm 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ù giản đồ mô hình TensorFlow Lite hỗ trợ nhiều đồ thị con, nhưng Trình thông dịch TFLite hiện chỉ hỗ trợ một đồ thị 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 các tệp được liên kết từ mô hình

Về cơ bản, mô hình TensorFlow Lite có siêu dữ liệu và các tệp liên kết là một tệp zip có thể giải nén bằng các công cụ zip phổ biến để lấy các tệp liên quan. Ví dụ: bạn có thể giải nén mobilenet_v1_0.75_160_quantized và giải nén 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, hãy chuyển tên tệp vào phương thức MetadataExtractor.getAssociatedFile:

public InputStream getAssociatedFile(String fileName);

Tương tự, trong C++, bạn có thể thực hiện việc này bằng phương thức ModelMetadataExtractor::GetAssociatedFile:

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