7.15. Написання власного постпроцесора¶
Коли каталог не охоплює модель – дослідницьку мережу з нестандартним розташуванням виходу, модифікацію існуючої архітектури, тензор, семантична інтерпретація якого специфічна для застосунку – застосунок надає власний постпроцесор. Протокол простий: викликаний об’єкт, що приймає (model, inputs, outputs) і повертає те, що застосунок очікує від predict().
Звичайна форма – клас з __call__
class MyPostprocessor:
def __init__(self, threshold=0.5):
self.threshold = threshold
def __call__(self, model, inputs, outputs):
...
return result
Проста функція теж підходить – рушій лише перевіряє, чи є об’єкт викликаним.
7.15.1. Підключення¶
Два місця для прив’язки. Аргумент postprocess= у конструкторі прив’язує виклик для кожного виклику predict() моделі:
model = ml.Model("/rom/my_model.tflite",
postprocess=MyPostprocessor())
Щоб перевизначити прив’язку для одного виклику – замінити декодери без перезавантаження моделі – передайте callback= безпосередньо до predict:
result = model.predict([img], callback=MyOtherPostprocessor())
Сигнатура виклику однакова в обох випадках.
7.15.2. Що отримує виклик¶
model– екземплярModel, корисний для параметрів квантування (output_scale,output_zero_point,output_dtype) та вхідних розмірів (input_shape).inputs– список вхідних даних, переданих застосунком доpredict(). Перший елемент зазвичай є прив’язаним екземпляромNormalization; його атрибутroi– це те, щоNMSочікує для перепроєктування рамок назад у оригінальне зображення.outputs– необроблені вихідні тензори у вигляді списку об’єктівndarray, у їхньому нативному dtype. Виходи з плаваючою комою надходять як є; цілочисельні виходи надходять квантованими.
7.15.3. Квантована арифметика¶
Усі вбудовані декодери використовують ті самі допоміжні функції з ml.utils, і власний декодер зазвичай потребує того самого шаблону: quantize() підіймає поріг з плаваючою комою до квантованого простору моделі, threshold() фільтрує без деквантизації всього тензора, а dequantize() запускається один раз на відібраних значеннях. sigmoid() та logit() доступні для мереж, у яких вихідні канали є логітами до сигмоїди (детектори MediaPipe – канонічний випадок).
Для моделей з виходами у плаваючій комі – регресійні голови, моделі з фінальним шаром деквантизації – допоміжні функції квантування проходять без змін, тому той самий код постпроцесора працює з будь-яким dtype без спеціальних умов.
7.15.4. Повернуте значення¶
Те, що повертає виклик, є тим, що повертає predict(). Для декодерів, що видають рамки, прийнято передавати кандидатів через NMS і повертати його списки по класах – форма виклику, яку документує немаксимальне пригнічення і яку будує розбір YOLOv8 у контексті. Для всього іншого повертайте те, що є зручним для застосунку: один ndarray, рядок мітки, кортеж (class, score, embedding), словник.