Créer un modèle de Machine Learning dans un environnement de développement est une chose. Pouvoir rendre son utilisation accessible à tous via une application avec une interface graphique en est une autre. Dans cet article, nous découvrirons comment déployer un modèle de Machine Learning sur  les appareils mobiles, à la fois Android et IOS, ceci grace aux Bots Telegram et un hébergement gratuit sur Héroku.

Mais bien avant, je vous invite à regarder la démo de mon bot de détection de masque de protection ici, et à l'essayer aussi, pourquoi pas ;-). Vous serez bientôt en mesure de le reproduire vous-mêmes en quelques minutes.

Mais d'abord pourquoi ai-je réalisé ce projet et comment ce bot de détection de masque peut-il être utile?

Inspiration

J'ai eu l'idée de ce projet quand j'ai vu ce tweet d'Uber, présentant leur fonction de vérification de masque pour les conducteurs et les passagers:

Tweet de Uber

Eh bien, je voulais faire de même et reproduire l'expérience utilisateur, c'est-à-dire prendre une photo dans une application et avoir une réponse de détection de masque.


Malheureusement, comme la plupart des Data Scientists et Machine Learning Engineer, je n'ai pas de compétences en création d'applications mobiles. J'ai pensé à apprendre Flutter afin de pouvoir déployer sur IOS et Android, mais bon, j'ai déjà une longue liste de compétences à apprendre sur mon backlog.

J'ai découvert plus tard qu'on peut créer des bots sur Telegram gratuitement et comme Telegram est disponible sur toutes les plates-formes mobiles ainsi que sur Windows, Mac et Linux, il pourrait être utilisé pour servir des modèles de Deep Learning.

Alors, de quoi avons-nous besoin pour ce projet?

  • Données: images de personnes portant des masques et de personnes ne portant pas de masques
  • Modèle: nous utiliserons Fastai v2 pour entrainer un modèle en tirant parti du Transfert Learning
  • Compte Telegram: évidemment
  • Un compte Heroku: pour l'hébergement

Commençons!!!

Données

Je n'ai pas eu à créer un ensemble de données à partir de zéro. J'ai trouvé ce dépôt par Prajna Bhandary sur Github. Elle a déjà fait le travail. Vous pouvez trouver les données dans le dossier "experiments". 690 images de personnes portant un masque se trouvent dans un dossier nommé "with_mask" et 686 images de personnes ne portant pas de masque dans un dossier nommé "without_mask". C'est tout ce dont nous avons besoin pour entrainer un modèle.

Entrainement d'un modèle avec Fastai v2

J'ai récemment commencé à apprendre fastai avec le livre "Deep Learning for Coders". C'était donc l'occasion de mettre en pratique mes compétences. De plus, le Transfert Learning avec fastai v2 se fait en juste 5 ou 6 lignes de code. Mais j'aurais pu le faire aussi avec Tensorflow 2.0 et obtenir les mêmes résultats.


Installons fastai. Il est recommandé de le faire dans un environnement conda. Installez également fastbook pour obtenir des fichiers utilitaires:

conda install -c fastai -c pytorch fastai
pip install -Uqq fastbook

Ouvrez un jupyter notebook et importons tout ce dont on a besoin:

import fastbook
fastbook.setup_book()
from fastbook import *
from fastai.vision.all import *

Lien du chemin où se trouve le dossier data:

path = Path("../data")

Il est temps de créer un Dataloader. C'est aussi simple que ça. Le datablock obtiendra les images, en utilisera 20% pour la validation, obtiendra les "labels" simplement en prenant le nom du répertoire parent et redimensionnera toutes les images à 128 * 128 * 3:

mask = DataBlock(
    blocks=(ImageBlock, CategoryBlock), 
    get_items=get_image_files, 
    splitter=RandomSplitter(valid_pct=0.2, seed=42),
    get_y=parent_label,
    item_tfms=Resize(128))

Jetons un coup d'oeil à quelques images dans le set de validation:

dls = mask.dataloaders(path)
dls.valid.show_batch(max_n=10, nrows=2)
Quelques images de notre dataset de détection de masques

Nous pouvons déjà remarquer que certaines images ont été créées en ajoutant simplement un masque aux visages des gens. Bon à savoir.


Nous pouvons maintenant ajouter quelques étapes d'augmentation de données et créer notre modèle avec du Transfert Learning en utilisant un resnet18:

mask = mask.new(
    item_tfms=RandomResizedCrop(224, min_scale=0.5),
    batch_tfms=aug_transforms())
dls = mask.dataloaders(path)
learn = cnn_learner(dls, resnet18, metrics=error_rate)
learn.fine_tune(4)
Entrainement du modèle

Et juste comme ça, en seulement 2 minutes sur ma machine locale, nous avons une précision de 99%. Comme c'est incroyable! Regardons la matrice de confusion:

Matrice de confusion

Seulement 2 cas de personnes sans masque classées à tort comme portant un masque. Nous pouvons exporter ce modèle et commencer à écrire du code pour notre bot.

learn.export("model.pkl")

Bot Telegram pour notre modèle

C'est la partie intéressante, et c'est étonnamment si simple. Pour créer un bot sur Telegram, recherchez BotFather sur Telegram, envoyez cette commande: /newbot et il vous demandera le nom de votre bot et son nom d'utilisateur. Une fois ces étapes terminées, vous obtiendrez un lien pour accéder à votre bot et un jeton qui sera utilisé dans le code pour interagir avec celui-ci.


Quelque chose ceci :

BotFather

Accédez à votre éditeur de code préféré, Pycharm dans mon cas, et écrivons le script du bot.
Nous utiliserons la bibliothèque python-telegram-bot. Installer avec:

pip install python-telegram-bot

Import des bibliothèques avec fastai pour le chargement du modèle:

import logging
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
from fastai.vision.all import load_learner

Tous les bots Télégram doivent définir une fonction pour les commandes spéciales /start et /help.

def start(update, context):
    update.message.reply_text(
        "Bot by @kevindegila on Twitter \n\n "
        "EN : Just send me a photo of you and I will tell you if you're wearing a mask 😏 \n"
        "FR : Envoie moi une photo de toi et je te dirai si tu portes un masque 😏"
    )


def help_command(update, context):
    update.message.reply_text('My only purpose is to tell you if you are wearing a mask. Send a photo')

Comme vous pouvez le voir, ces fonctions prennent un "update" et un "context" en entrée et envoient du texte au bot à l'aide de la fonction update.message.reply_text ().
Une instance de la classe Updater reçoit les commandes et les messages saisis par les utilisateurs, les transmet à un dispatcher qui donne les messages à différents handlers:

def main():
    updater = Updater(token="token", use_context=True)
    dp = updater.dispatcher
    
    dp.add_handler(CommandHandler("start", start))
    dp.add_handler(CommandHandler("help", help_command))
    
    updater.start_polling()
    updater.idle()
    
    
if __name__ == '__main__':
    main()

À cette étape, vous pouvez démarer votre bot en exécutant le script et envoyer un message pour les commandes spéciales.


Ajoutons la fonction de détection de masque. Nous allons définir une fonction pour charger notre modèle, une autre fonction pour quand nous recevons des images des utilisateurs, et passer cette fonction à un handler de messages avec des filtres pour les images:

def load_model():
    global model
    model = load_learner('model/model.pkl')
    print('Model loaded')
    
    
def detect_mask(update, context):
    user = update.message.from_user
    photo_file = update.message.photo[-1].get_file()
    photo_file.download('user_photo.jpg')
    
    label = model.predict('user_photo.jpg')[0]
    if label == "with_mask":
        update.message.reply_text(
            "EN: Looks like you are wearing a mask 😷. I hope you don't forget it when going out!😉 \n\n"
            "FR: On dirait que tu portes un masque 😷, J'espère que tu ne l'oublies pas quand tu sors! 😉"
        )
    else:
        update.message.reply_text(
            "EN: Looks like you are not wearing a mask 😷. Please wear one and stay safe 🙄\n\n"
            "FR: On dirait que tu ne portes pas un masque 😷. S'il te plait, va en porter un. Fais attention 🙄"
        )

Vous pouvez voir comment nous téléchargeons les images et les transmettons à notre modèle et obtenons le label avec label = model.predict ('user_photo.jpg') [0]. Nous envoyons simplement différents messages en fonction du label prédit.


Notre fonction main ressemble maintenant à ceci:

def main():
    load_model()
    updater = Updater(token="token", use_context=True)
    dp = updater.dispatcher
    dp.add_handler(CommandHandler("start", start))
    dp.add_handler(CommandHandler("help", help_command))

    dp.add_handler(MessageHandler(Filters.photo, detect_mask))

    updater.start_polling()
    updater.idle()

C'est tout pour notre bot. Tout est prêt et cela devrait fonctionner sur votre ordinateur portable.
Maintenant, Déployons le gratuitement sur heroku.

Déploiement de bot Télégram sur Heroku

Rendez-vous sur https://www.heroku.com/ et inscrivez-vous si vous n'avez pas encore de compte. La deuxième étape consiste à aller sur votre https://dashboard.heroku.com/ pour créer une nouvelle application en cliquant sur le  bouton new:

Creation d'application sur Heroku

Une fois votre application créée, vous devez créer 3 fichiers spéciaux dans le dossier de votre projet:

  • Un fichier nommé Procfile pour indiquer à Heroku comment exécuter votre code:
worker: python main.py
  • Un fichier nommé runtime.txt pour indiquer à Heroku quelle version de Python installer:
python-3.7.0
  • Un fichier nommé requirements.txt pour dire à heroku d'installer certaines bibliothèques. Ici, nous installons la version cpu de Pytorch pour éviter de dépasser la taille du slug de 500 Mb sur Heroku. Assurez-vous de fixer fastai sur la même version avec laquelle vous avez entrainé votre modèle:
python-telegram-bot
-f https://download.pytorch.org/whl/torch_stable.html
fastai==2.0.13
torch==1.6.0+cpu
torchvision==0.7.0+cpu

Il vous suffit maintenant de suivre les étapes suivantes pour que votre bot soit déployé et disponible à tout moment:

  • Créez un dépôt et Faites un commit de tous vos fichiers
  • Entrez la commande heroku login pour vous connecter à votre compte Heroku
  • Ajoutez heroku en tant que dépôt distant avec heroku git: remote -a app_name avec app_name étant le nom de votre application sur heroku
  • Déployez en uploadant votre code vers Heroku avec: git push heroku master

C'est tout. Vous pouvez vérifier si tout fonctionne en testant sur Télégram et en voyant les journaux avec heroku logs - tail.

Quelques considérations sur l'éthique


Voici quelques éléments à prendre en compte lors de la création d'un projet comme celui-ci:

  • À propos du modèle: Reconnaît-il le masque sur toutes les couleurs de peau, sur tous les genres? Vous devez vérifier les biais avant de déployer ce type de modèle.
  • À propos du bot: devrait-il enregistrer les images des utilisateurs? Ont-ils accepté la collecte de leurs données? Dans mon cas, je ne garde pas d'images pour ce bot. Si je le faisais, je dépasserais de toute façon la taille de slug.

Pour plus d'informations sur l'éthique dans l'IA, consultez ce cours par fast.ai: https://ethics.fast.ai/

Conclusion

Dans ce projet, nous avons créé un bot Télégram qui peut dire si l'utilisateur porte un masque sur sa photo ou non. Nous avons entrainé le modèle avec fastai v2 et en utilisant le Transfert Learning. Le bot a été créé à l'aide de la bibliothèque  python-telegram-bot et nous avons déployé notre bot sur Heroku afin que notre bot puisse être disponible à tout moment.


Si vous avez lu ceci jusqu'à la fin, je vous encourage à le partager.  Vous pouvez regarder le tutoriel vidéo sur ma chaîne Youtube et rejoindre mon serveur discord si vous avez des questions: https://discord.gg/sHE5exZ


Les commentaires et les questions sont également les bienvenus sur Twitter à kevindegila.