درب وشغل Tensorflow Lite على تطبيق Flutter

تدريب نموذج الآلة وتشغيلة على تطبيق Flutter بإستخدام Google Colab و TensorFlow Lite

كثير من التطبيقات في الوقت الحالي تعتمد على تعلم الآلة والذكاء الاصطناعي وبعض منها يكون هذا المودل على Backend، لكن في ظل التطور المستمر للأجهزة والأنظمة بالإمكان تشغيل بعض هذه النماذج علي الجهاز مباشرة. في هذه التدوينة سنتعرف على كيفية بناء النموذج وايضًا إضافتة للتطبيق الخاص بنا في Flutter. سنقوم في هذا الدرس باستخدام dataset لتحديد نوع التمر من خلال التقاط صورة او من خلال معرض الصور. تم الاستعانة بالداتاست من Kaggle من هنا.

سيتكون الدرس من قسمين:
  • القسم الأول : تدريب النموذج على Google Colab او على جهازك الشحصي.
  • القسم الثاني : اضافة النموذج المُدرب الى تطبيق Flutter.

إنشاء نموذج الآلة:

سنقوم بإستخدام tensorflow للقيام بهذه المهمة.

هي مكتبة مجانية ومفتوحة المصدر للتعلم الآلة والذكاء الاصطناعي. يمكن استخدامه عبر مجموعة من المهام ولكن يركز بشكل خاص على تدريب واستدلال الشبكات العصبية العميقة.

https://www.tensorflow.org/install
تجهيز البيانات للتدريب:

حتى نقوم البدء في عملية التدريب نحتاج الى بعض الإجراءات القبلية pre-propccessing، كتغيير حجم الصورة وتحديد الـbatch size ايضًا تقليل حجم الصور.

استخدمت في هذا الدرس Google Colab يمكنك القيام بنفس المهام علي جهازك.

IMAGE_SIZE = 224 # حجم الصورة
BATCH_SIZE = 64 # عددالصور التي نريد تغذيةج الشبكات العصبية بها

datagen = tf.keras.preprocessing.image.ImageDataGenerator( # تجهيز الصور
    rescale = 1./255, # تقليل حجم الصور لتقليل وقت التدريب
    validation_split=0.2 # بشكل عام اي تدريب يكون هناك جزء للتدريب وجزء للاختبار، ايضا يفضل اضافة جزئية للتأكيد وتكون جزء من داتاست التدريب لقياس آداء النموذج
)

train_generator = datagen.flow_from_directory( # تدريب النموذج
    base_dir, # مسار الصور
    target_size=(IMAGE_SIZE, IMAGE_SIZE),  # تحويل حجم الصور
    batch_size = BATCH_SIZE, # عدد الصور التي تدخل الي الشبكة العصبية مع كل دورة
    subset='training' # الاسم
)
val_generator = datagen.flow_from_directory(  # فاعلية النموذج
    base_dir,  # مسار الصور
    target_size=(IMAGE_SIZE, IMAGE_SIZE), # تغيير حجم الصور
    batch_size=BATCH_SIZE, # عدد الصور في كل دورة
    subset='validation'
)
# تلاحظ في المخرجات لدينا 1329 صورة و 9 كلاسات في التدريب ولدينا في ال"فاعلية" 329 صورة
تجهيز واستخراج Labels.txt:

هذه الخطوة مهمة لتطبيق Flutter من خلالها نستطيع تحديد نوع التمر المرفق من الصورة او الكاميرا الخاصة بالجهاز.

print(train_generator.class_indices)
labels = '\n'.join(sorted(train_generator.class_indices.keys()))
with open('labels.txt', 'w') as f:
    f.write(labels)
بناء الشبكة العصبية:

سنقوم بإستخدام MobileNetV2 وهو نموذج مُدرب سابقًا يُقدم آداء ممتاز على الأجهزة، يقدم هذا النموذج CNN تم تدريبها على ImageNet هذا يوفر علينا عناد التدريب نرة أُخرى، لكن اذا أردت إعادة التدريب فهذا ممكن ايضا.

تقدم MobileNetv2 العديد من الخيارات والبراميترز التي يمكنك التلاعب بها بما يتناسب مع الغرض من النموذج. يمكنك قراءة المزيد من هنا

# سنستخدم model تم تدريبة يسمي MobileNetV2 يقدم آداء ممتاز على الأجهزة 
IMG_SHAPE = (IMAGE_SIZE, IMAGE_SIZE, 3) # الصور تتكون دائما من طول وعرض وايضًا قنوات للألوان RGB
base_model = tf.keras.applications.MobileNetV2( 
    input_shape=IMG_SHAPE,
    include_top=False, # نريد استخدام المُدرب مسبقًا، لا نريد هنا إعادة تدريب النموذج، هنا 
    weights='imagenet' # pre-training on ImageNet
)
طبقات الشبكة العصبية
base_model.trainable=False 
model = tf.keras.Sequential([ 
  base_model,
  tf.keras.layers.Conv2D(9,3, activation = 'relu'),
  tf.keras.layers.Dropout(0.2), 
  tf.keras.layers.GlobalAveragePooling2D(), 
  tf.keras.layers.Dense(9, activation='softmax')
])

الشبكة العصبية عبارة عن مجموعة من الطبقات، يمكن الإضافة عليها او الحذف منها، في المثال الخاص بنا قمنا بإضافة مجموعة من الطبقات سنتعرف عليها بإيجاز كالآتي:

  • بدايةً قمنا بإيقاف الشبكة من التعلم وتحديث weght الخاص بها. كما ذكرنا سابقًا.
  • اضفنا convolution kernel يقوم بإدخال layer كمدخلات ويقوم برعادة tensor. نلاحظ ايضًا وجود activation function ، هناك أكثر من نوع للهذه الفنكشن يمكنك القراد عنها من هذا الكتاب.
  • قمنا بإضافة Dropout وهو ببساطة لتجنب Overfitting خلال عملية التدريب.
  • قمنا بحساب متوسط ​​قيمة جميع القيم عبر المصفوفة بأكملها لكل من قنوات الإدخال٫
  • قمنا باضافة Dense وعدد الكلاسات لدينا 9 واضفنا softmax كـactiviation function
تكوين النموذج للتدريب:

هذه الخطوة مُباشرة الى حدٍ ما، نحتاج فقط فيها الى تحديد optimizer الذي نريد استخدامة. هناك العديد من optimizer التي يمكن استخدامها مع Deep Learning ولكن الأكثر شعبية هو Adam

model.compile(
    optimizer=tf.keras.optimizers.Adam(), 
    loss='categorical_crossentropy', 
    metrics=['accuracy']
)
تدريب النموذج
epochs = 10 
history = model.fit(
    train_generator, 
    epochs = epochs, 
    validation_data=val_generator
)

كلما زاد عدد epochs تزيد فعالية النموذج ولكن قد يكون Overfitting، يجب الأخذ في عين الاعتبار ان اداء النموذج العالي ربما لايكون الأجود.

مالفرق بين Batch و Epochs ؟

فكر في batch كأنه for-loop على عينة وحدة او مجموعة عينات، Epochs هو ايضًا for-loop على كامل الداتاست خلال هذه loop هناك loop داخلية تمثل Batch. يمكنك القراءة أكثر عن هذا الموضوع من هنا

Dive into Deep Learning
حفظ النموذج:

الآن بعد التدريب سنقوم بحفظ النموذج واستخدامة في تطبيق Flutter لتحديد نوع التمر من خلال الصورة

saved_model_dir = ''
tf.saved_model.save(model, saved_model_dir) 
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) 
tflite_model = converter.convert() 
with open('model.tflite', 'wb') as f: 
  f.write(tflite_model)

تطبيق Flutter

في هذا الجزء سنقوم بإنشاء تطبيق flutter لتفريق أنواع التمور من خلال أخذ الصورة من معرض الصور٫ ستتم التجربة على الأندرويد والأيفون.

إنشـاء مشـروع جديـد

انشئ مشروع جديد وسنقوم بإضافة الباكج التالية للمشروع.

# A Flutter plugin for accessing TensorFlow Lite API.
flutter pub add flutter_tflite
# flutter pub add image_picker
flutter pub add image_picker
واجهة المستخدم

واجهة المستخدم عبارة عن Column في داخلة صورة و Text، بالاضافة الى Float Action Button.

Scaffold(
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _image == null
                ? Container(
                    height: 300,
                    width: 300,
                    decoration: BoxDecoration(
                      color: Colors.amber.shade300,
                      borderRadius: BorderRadius.circular(20),
                    ),
                    child: const Icon(
                      Icons.image,
                      color: Colors.white,
                      size: 100,
                    ),
                  )
                : Container(
                    height: 300,
                    width: 300,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(20),
                      image: DecorationImage(
                        image: FileImage(_image!),
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
            const SizedBox(height: 20),
            _output != null
                ? Text(
                    "${_output![0]["label"]}",
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 20,
                    ),
                  )
                : Container(),

            Divider(
              color: Colors.brown.shade900,
              thickness: 2,
              indent: 20,
              endIndent: 20,
            ),
            // confidence prediction precentage %
            if (_output != null)
              Text(
                '${(_output?[0]['confidence'] as double).toStringAsFixed(2)}',
                style: Theme.of(context).textTheme.headline4,
              ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          var output = await pickImage();
        },
        tooltip: 'Pick Image',
        child: const Icon(Icons.photo_library),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
اضافة صورة:

إضافة صورة باستخدام باكج Image Picker مباشرة وسهلة

  // pick image from gallery
  Future pickImage() async {
    final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
    if (image == null) return null;
    setState(() {
      _image = File(image.path);
      classifyImage(_image);
    });
  }
تحميل النموذج (model) :

باستخدام باكج flutter_tflite سنقوم بتحميل model في التطبيق ولكن قبل كل شئ نحتاج إضافة assets النموذج و labels.txt.

الآن سنقوم بتعديل ملف android حتى نقوم بتفعيل بعض الخيارات، android/app/build.gradle

  aaptOptions {
        noCompress 'tflite'
        noCompress 'lite'
    }

تحميل model في التطبيق

  Future loadModel() async {
    await Tflite.loadModel(
      model: "assets/model.tflite",
      labels: "assets/labels.txt",
    );
  }

لتحميل النموذج model سنقوم باستدعاء

  • initState : من خلال هذه الدالة سنقوم بتحميل الـmodel
  @override
  void initState() {
    loadModel();
    super.initState();
  }
  • dispose : اذا اغلقت الشاشة سنقوم باغلاق النموذج
@override
  void dispose() {
    Tflite.close();
    super.dispose();
  }
تحديد نوع التمر:

يقدم باكج flutter_tflite العديد من خدمات Tensorflow lite ولكن في هذا الدرس سيكون تركيزنا علي runModelOnImage٫

 Future classifyImage(File? image) async {
    var output = await Tflite.runModelOnImage(
      path: image!.path,
      imageMean: 127.5,
      imageStd: 127.5,
      numResults: 2,
      threshold: 0.05,
      asynch: true,
    );
    setState(() {
      _output = output;
    });
  }
  • path : مسار الصورة.
  • imageMean و Imagestd للنورملايزيشن.
  • numResults : عدد النتائج الراجعة من model، نعلم ان النموذج يعتمد على confidence كلما كان أعلى كان أقرب.
تشغيل التطبيق:

عند تشغيل التطبيق ستقوم بإختيار صورة وسيعيد النتائج بناءً على ماتم تعلمه خلال عملية التدريب. التطبيق سيعمل على Android IOS، هذا الباكج لا يدعم web حتى الآن.


ختامًا.

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

اترك ردّاً

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

أوافق على سياسة الخصوصية*