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، بنوع بياناتها الأصلي. تصل المخرجات العائمة كما هي؛ وتصل المخرجات الصحيحة مُكمَّمة.

7.15.3. الحساب المُكمَّم

تلجأ المفكِّكات المشحونة جميعها إلى المساعِدات نفسها في ml.utils، وعادةً ما يريد المفكِّك المخصص النمط ذاته: ترفع quantize() عتبة عائمة إلى الفضاء المُكمَّم للنموذج، وتُرشّح threshold() دون فكّ تكميم الموتر بأكمله، وتعمل dequantize() مرة واحدة على الناجين. تتوفر sigmoid() و logit() للشبكات التي تكون قنوات ناتجها لوغيتات ما قبل السيغمويد (كواشف MediaPipe هي الحالة النموذجية).

بالنسبة للنماذج ذات المخرجات العائمة -- رؤوس الانحدار، أو النماذج بطبقة فكّ تكميم نهائية مدمجة -- تمرّر مساعِدات التكميم القيم دون تغيير، فيعمل كود المعالج اللاحق نفسه مع أي من نوعَي البيانات دون معالجة حالة خاصة.

7.15.4. القيمة المُعادة

أيّاً كان ما يعيده الكائن القابل للاستدعاء فهو ما تعيده predict(). بالنسبة للمفكِّكات التي تُصدر مربعات، يقضي العرف بدفع المرشحين عبر NMS وإعادة قوائمه لكل فئة -- شكل الاستدعاء الذي يوثّقه كبت غير الحد الأقصى ويبنيه شرح YOLOv8 المفصّل في سياقه. لأي شيء آخر، أعِد ما يجده التطبيق ملائماً: ndarray واحد، أو سلسلة تسمية، أو صف (class, score, embedding)، أو قاموس.