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)، أو قاموس.