كيفية تحويل نموذج Keras SavedModel إلى تطبيق ويب يعمل داخل المتصفح

دقائق القراءة: 8

مقدمة: لماذا تحويل نموذج التعلم الآلي إلى تطبيق ويب؟

إذا كنت تطوّر نماذج تعلم آلي باستخدام Python وKeras، فغالباً وصلت إلى مرحلة تريد فيها نقل النموذج من بيئة التدريب إلى منتج حقيقي يمكن للمستخدمين التفاعل معه بسهولة. وهنا تظهر أهمية تحويل نموذج Keras SavedModel إلى تطبيق ويب يعمل مباشرة داخل المتصفح.

هذا الأسلوب يتيح لك تشغيل النموذج دون الحاجة إلى تثبيت برامج إضافية لدى المستخدم، كما يجعله متاحاً على الهواتف وأجهزة الحاسوب والأجهزة اللوحية عبر واجهة موحدة وسهلة الاستخدام. والأهم من ذلك أنه يقرّب نموذجك من الاستخدام العملي بدلاً من بقائه محصوراً داخل بيئة التطوير.

تحويل نموذج تعلم آلي من كيراس إلى تطبيق ويب يعمل داخل المتصفح

ما هو نموذج Keras SavedModel؟

نموذج Keras يتكوّن عادةً من عدة عناصر رئيسية:

  • بنية الشبكة العصبية.
  • الأوزان weights.
  • إعدادات المُحسّن optimizer ودالة الخسارة.

وعند حفظ النموذج بالصيغة الافتراضية SavedModel، يتم تخزين معلومات البنية والخسارة والمُحسّن داخل الملف saved_model.pb، بينما تُحفظ الأوزان داخل مجلد variables. وتمتاز هذه الصيغة بأنها مناسبة لحفظ النماذج، بما فيها النماذج التي تحتوي على عناصر مخصّصة custom objects، بأقل قدر من التعقيد.

كيف تدرّب نموذجاً إذا لم تكن تملك GPU؟

واحدة من أكثر البيئات شيوعاً بين المطورين والباحثين هي Google Colab. فهي توفّر بيئة شبيهة بـ Jupyter Notebook مع إمكانية الوصول المجاني إلى وحدات معالجة الرسوميات لفترات تدريب مناسبة، ما يجعلها خياراً عملياً لمن يريد تدريب نموذج أولي أو متوسط الحجم دون تجهيزات محلية قوية.

لذلك، حتى لو لم تمتلك جهازاً مزوداً بـ GPU، يمكنك بناء نموذجك وتدريبه ثم تصديره لاحقاً إلى الويب.

لماذا لا نكتفي ببناء النموذج مباشرة باستخدام TensorFlow.js؟

قد يبدو من المنطقي تطوير كل شيء بلغة JavaScript من البداية، لكن هذا ليس دائماً الخيار الأفضل. إذا كنت قد استثمرت وقتاً طويلاً في تدريب نموذجك باستخدام Keras على بيانات كبيرة، فمن غير العملي إعادة كتابة البنية بالكامل ثم إعادة التدريب من الصفر فقط لكي يعمل داخل المتصفح.

لذلك، تكون عملية التحويل هي الحل المثالي: تحتفظ بعملك السابق كما هو، ثم تنقل النموذج إلى صيغة متوافقة مع الويب.

نظرة عامة على خطوات التحويل إلى تطبيق ويب

في هذا المثال، سنعتمد على نموذج CNN بسيط لاكتشاف المشاعر من الصور، ويصنّف سبع حالات: السعادة، الحزن، الحياد، الغضب، المفاجأة، الخوف، والاشمئزاز. ولتشغيله داخل المتصفح، نحتاج عادة إلى المرور بالمراحل التالية:

  1. تحويل نموذج Keras SavedModel إلى صيغة TensorFlow.js Layers.
  2. تحميل النموذج في JavaScript باستخدام أسلوب Promises وasync/await.
  3. قراءة صورة يرفعها المستخدم.
  4. تنفيذ المعالجة المسبقة preprocessing للصورة.
  5. تشغيل الاستدلال inference داخل المتصفح وعرض النتائج في واجهة الاستخدام.

مخطط يوضح خطوات تحويل نموذج كيراس إلى تطبيق ويب باستخدام TensorFlow.js

كيفية تحويل Keras SavedModel إلى صيغة TensorFlow.js Layers

لكي يصبح النموذج قابلاً للاستخدام داخل المتصفح، يجب تحويله إلى الصيغة التي يفهمها TensorFlow.js. ويمكن تنفيذ ذلك باستخدام أداة tensorflowjs_converter أو عبر واجهة Python API.

عملياً، قد تواجه بعض البيئات مشكلات مع الأداة المباشرة، خصوصاً عند التعامل مع مسارات ملفات تحتوي على فراغات مثل مسارات Google Drive داخل Google Colab. في هذه الحالة، يكون استخدام واجهة Python أكثر استقراراً في كثير من الأحيان.

بعد نجاح التحويل، ستحصل عادة على:

  • ملف model.json ويحتوي على بنية النموذج.
  • ملفات ثنائية binary للأوزان.

كود تحويل نموذج SavedModel إلى صيغة TensorFlow.js Layers

متى يكون التحويل هو الخيار الأفضل؟

التحويل مناسب جداً إذا كان النموذج قد تم تدريبه مسبقاً بكفاءة، وتريد فقط نقله إلى الواجهة الأمامية دون إعادة التدريب أو إعادة البناء بلغة مختلفة.

تحميل النموذج في المتصفح باستخدام JavaScript

تُعد مكتبة TensorFlow.js خياراً أساسياً لتشغيل نماذج التعلم الآلي داخل المتصفح أو عبر Node.js. وفي المشاريع البسيطة أو المتوسطة، يكفي غالباً تضمين المكتبة من خلال وسم script.

<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>

بعد تضمين المكتبة، يمكن تحميل النموذج من نقطة وصول HTTP أو HTTPS، وهو الخيار الأنسب عند استضافة الملفات على خدمة مثل Firebase Hosting.

const model = await tf.loadLayersModel('model.json');

فهم دور Promises وasync/await

عند تحميل ملف النموذج من الخادم، لا تصل البيانات فوراً. ولهذا تعتمد JavaScript على مفهوم Promise، وهو تمثيل لقيمة ستصبح متاحة لاحقاً عند اكتمال العملية.

وباستخدام async/await يصبح الكود أكثر وضوحاً وأسهل في الصيانة. فالكلمة await تجعل التنفيذ ينتظر نتيجة العملية غير المتزامنة، بينما تُعرّف الدالة التي تحتويها باستخدام async.

إنشاء واجهة لرفع الصور من المستخدم

لكي يتفاعل المستخدم مع النموذج، نحتاج إلى حقل رفع ملفات وزر لبدء التنبؤ. يمكن تنفيذ ذلك بعناصر HTML بسيطة كما يلي:

<div class="container" id="tray">
  <div id="uploadFile" class="custombutton">
    <i class="fa fa-file" style="font-size:25px;color:#1ab5e3"></i>
    <br/><br/>
    <input type="file" name="fileupload" accept="image/*" onchange="display(event)">
  </div>
  <div class="custombutton">
    <i class="fa fa-bar-chart" style="font-size:25px;color:#1ab5e3"></i>
    <br/><br/>
    <input type="button" name="predict" onclick="predict_emotion()" value="PREDICT">
  </div>
</div>

واجهة رفع صورة وتشغيل التنبؤ في تطبيق ويب يعتمد على نموذج تعلم آلي

كيفية قراءة الصورة المعروضة داخل الصفحة

بعد أن يرفع المستخدم صورة، يمكن الوصول إليها وعرضها فوراً باستخدام URL.createObjectURL(). هذه الطريقة مفيدة لأنها تنشئ رابطاً مؤقتاً للملف المحلي دون الحاجة إلى رفعه إلى الخادم أولاً.

let input_image = document.getElementById("input_image");
input_image.src = URL.createObjectURL(event.target.files[0]);
document.getElementById("input_image_container").style.display = "block";
<div id="input_image_container">
  <img src="#" id="input_image" style="top:5vh;">
</div>

وبعد الرفع، تظهر الصورة للمستخدم داخل الواجهة، ما يمنحه تأكيداً بصرياً قبل تنفيذ التنبؤ.

عرض الصورة التي رفعها المستخدم داخل تطبيق الويب قبل تنفيذ التنبؤ

المعالجة المسبقة للصورة قبل الاستدلال

هذه الخطوة تعتمد على طبيعة النموذج نفسه. فلا توجد معالجة موحدة لكل المشاريع، بل يجب أن تطابق تماماً ما تم أثناء التدريب. في هذا المثال، كانت العملية بسيطة وشملت:

  • تغيير الحجم إلى 48×48.
  • تحويل الصورة إلى تدرّج رمادي باستخدام المتوسط.
  • تحويل القيم إلى نوع float.
  • إعادة تشكيل البيانات إلى الصيغة (1,48,48,1).
  • تطبيع القيم بالقسمة على 255.0.
// Preprocessing steps
/*
(1) Resize to 48*48
(2) Convert to grayscale using simple mean
(3) Convert to float
(4) Reshape to (1,48,48,1)
(5) Normalize by dividing by 255.0
*/
let step1 = tf.browser.fromPixels(input)
  .resizeNearestNeighbor([48, 48])
  .mean(2)
  .toFloat()
  .expandDims(0)
  .expandDims(-1)
  .div(255.0)

من الضروري جداً أن تتطابق هذه الخطوات مع إعدادات التدريب؛ لأن أي اختلاف في شكل الإدخال أو مقياس القيم قد يؤدي إلى نتائج ضعيفة أو غير منطقية.

تنفيذ الاستدلال داخل المتصفح وعرض النتائج

بعد تجهيز الصورة، يمكن إرسالها إلى النموذج عبر الدالة model.predict(). وتكون النتيجة في هذا المثال مصفوفة احتمالات تمثل المشاعر السبع. ثم تُعرض القيم في واجهة مرئية لتسهيل فهمها من قبل المستخدم.

pred = model.predict(step1)
pred.data().then((data) => {
  console.log(data)
  output = document.getElementById("output_chart")
  output.innerHTML = ""
  max_val = -1
  max_val_index = -1
  for (let i = 0; i < data.length; i++) {
    style_text = "width: " + data[i] * 150 + "px; height: 25px; position:relative; margin-top: 3vh; background-color: violet; "
    output.innerHTML += "<div style='" + style_text + "'></div>"
    if (data[i] > max_val) {
      max_val = data[i]
      max_val_index = i
    }
  }
  EMOTION_DETECTED = emotions[max_val_index]
  document.getElementsByClassName("output_screen")[0].style.display = "flex";
  document.getElementById("output_text").innerHTML = "";
  document.getElementById("output_text").innerHTML = "<p>Emotions and corresponding scaled up probability</p><p>Emotion detected: " + EMOTION_DETECTED + "(" + (max_val * 100).toFixed(2) + "% probability)</p>"
})

الفكرة هنا أن واجهة المستخدم لا تكتفي بعرض النتيجة النهائية فقط، بل تعرض أيضاً توزيع الاحتمالات، وهو أمر مفيد جداً لشرح سلوك النموذج وتحسين قابلية التفسير.

الكود النهائي لتشغيل التطبيق

كود JavaScript الكامل

// Display image uploaded by user
function display(event) {
  let input_image = document.getElementById("input_image")
  input_image.src = URL.createObjectURL(event.target.files[0]);
  document.getElementById("input_image_container").style.display = "block";
}

// Predict emotion and display output
async function predict_emotion() {
  let input = document.getElementById("input_image");

  // Preprocessing steps
  /*
  (1) Resize to 48*48
  (2) Convert to grayscale using simple mean
  (3) Convert to float
  (4) Reshape to (1,48,48,1)
  (5) Normalize by dividing by 255.0
  */
  let step1 = tf.browser.fromPixels(input).resizeNearestNeighbor([48, 48]).mean(2).toFloat().expandDims(0).expandDims(-1).div(255.0)

  const model = await tf.loadLayersModel('model.json');
  pred = model.predict(step1)
  pred.print()
  console.log("End of predict function")

  // This array is encoded with index i = corresponding emotion.
  // In dataset, 0 = Angry, 1 = Disgust, 2 = Fear, 3 = Happy, 4 = Sad, 5 = Surprise and 6 = Neutral
  emotions = ["Angry", "Disgust", "Fear", "Happy", "Sad", "Surprise", "Neutral"]

  // At which index in tensor we get the largest value?
  pred.data().then((data) => {
    console.log(data)
    output = document.getElementById("output_chart")
    output.innerHTML = ""
    max_val = -1
    max_val_index = -1

    for (let i = 0; i < data.length; i++) {
      style_text = "width: " + data[i] * 150 + "px; height: 25px; position:relative; margin-top: 3vh; background-color: violet; "
      output.innerHTML += "<div style='" + style_text + "'></div>"
      if (data[i] > max_val) {
        max_val = data[i]
        max_val_index = i
      }
    }

    EMOTION_DETECTED = emotions[max_val_index]
    document.getElementsByClassName("output_screen")[0].style.display = "flex";
    document.getElementById("output_text").innerHTML = ""
    document.getElementById("output_text").innerHTML = "<p>Emotions and corresponding scaled up probability</p><p>Emotion detected: " + EMOTION_DETECTED + " (" + (max_val * 100).toFixed(2) + "% probability)</p>"
  })
}

بنية HTML النهائية

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  <link rel="stylesheet" type="text/css" href="styles/page_styling.css">
</head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
<body>
  <div id="input_image_container">
    <img src="#" id="input_image" style="top:5vh;">
  </div>

  <div class="container" id="tray">
    <div id="uploadFile" class="custombutton">
      <i class="fa fa-file" style="font-size:25px;color:#1ab5e3"></i>
      <br/><br/>
      <input type="file" name="fileupload" accept="image/*" onchange="display(event)">
    </div>

    <div class="custombutton">
      <i class="fa fa-bar-chart" style="font-size:25px;color:#1ab5e3"></i>
      <br/><br/>
      <input type="button" name="predict" onclick="predict_emotion()" value="PREDICT">
    </div>
  </div>

  <div class="container output_screen">
    <div id="emotion_tags">
      <ul>
        <li>Angry</li>
        <li>Disgust</li>
        <li>Fear</li>
        <li>Happy</li>
        <li>Sad</li>
        <li>Surprise</li>
        <li>Neutral</li>
      </ul>
    </div>

    <div id="output_chart"></div>
    <div id="output_text"></div>
  </div>

  <script src="scripts/script.js"></script>
</body>
</html>

نتائج التنبؤ بالمشاعر داخل واجهة التطبيق في المتصفح

نصائح عملية لتحسين جودة التطبيق قبل النشر

  • حمّل النموذج مرة واحدة فقط عند فتح الصفحة بدلاً من إعادة تحميله عند كل عملية تنبؤ.
  • أضف رسالة انتظار أثناء جلب model.json وملفات الأوزان لتحسين تجربة المستخدم.
  • تحقق من نوع الملف المرفوع وحجمه قبل المعالجة.
  • استخدم try/catch لمعالجة أخطاء التحميل أو التنبؤ.
  • راعِ الأداء على الهواتف، خصوصاً إذا كان النموذج كبيراً أو المعالجة كثيفة.

ما الذي تعلّمناه من هذه العملية؟

تحويل نموذج Keras SavedModel إلى تطبيق ويب ليس مجرد خطوة تقنية، بل هو انتقال من مرحلة التجربة إلى مرحلة الاستخدام الفعلي. لقد مررنا في هذا الدليل عبر أهم النقاط الأساسية: تحويل الصيغة، تحميل النموذج، استقبال الصورة من المستخدم، تنفيذ المعالجة المسبقة، ثم عرض ناتج الاستدلال داخل واجهة مرئية واضحة.

هذه المنهجية تصلح ليس فقط لاكتشاف المشاعر، بل أيضاً لتطبيقات كثيرة مثل تصنيف الصور، كشف العناصر، التعرف على الأنماط، أو أي نموذج يمكن تبسيط مدخلاته ومخرجاته ليعمل بكفاءة في المتصفح.

تطبيقات تعلم آلي تعمل داخل المتصفح بعد تحويل نموذج كيراس إلى الويب

الخلاصة التقنية

من الناحية التقنية، يُعد الجمع بين Keras وTensorFlow.js حلاً عملياً جداً لمن يريد الاستفادة من قوة التدريب في Python مع سهولة النشر في الويب. أفضل ممارسة هنا هي الحفاظ على تطابق المعالجة المسبقة بين التدريب والاستدلال، وتقليل حجم النموذج قدر الإمكان، وتحميله بكفاءة من استضافة موثوقة. إذا طُبقت هذه العناصر بعناية، فستحصل على تطبيق سريع، سهل الاستخدام، وقابل للتوسع بشكل ممتاز.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *