Déployer Imagen dans Cloud Run

1. À propos de cet atelier de programmation

Dernière mise à jour:11/10/2024

Rédigé par Laurie White

Génération d'images

Soyons honnêtes, la génération d'images par les grands modèles de langage (LLM) peut être amusante. Bien entendu, il existe de nombreuses applications commerciales pour générer des images à partir d'une requête, allant de la publicité personnalisée aux présentations attrayantes. (Le site Web Google Cloud présente de nombreux cas d'utilisation spécifiques des entreprises qui utilisent les agents de création.) Toutefois, il peut être amusant de voir ce qui s'affiche lorsque vous demandez une image de "chiens verts heureux dans un champ".

Que vous soyez intéressé par la génération d'images pour des raisons professionnelles ou récréatives (ou les deux !), il existe des défis à relever entre l'utilisation d'un programme de génération d'images et son déploiement dans une application Web. Cet atelier vous aidera à relever ces défis.

Objectifs de l'atelier

Dans cet atelier de programmation, vous allez créer une application qui reçoit une invite de texte et renvoie une page Web avec une image générée à l'aide de cette invite.

Points abordés

Dans cet atelier, vous allez apprendre:

  • Utiliser Google Imagen pour créer des images à partir de requêtes textuelles dans des environnements de notebook
  • Difficultés liées au transfert du code Imagen d'un notebook vers une application Web
  • Déployer une application Cloud Run qui utilise Imagen pour générer des images
  • Inclure une image d'Imagen dans du code HTML

Cet atelier de programmation est consacré à Imagen et au déploiement. Les concepts et les blocs de codes non pertinents ne sont pas abordés, et vous sont fournis afin que vous puissiez simplement les copier et les coller.

Prérequis

Le code complet de cet atelier de programmation est disponible sur https://github.com/Annie29/imagen-deployment .

2. Activer les API

Sélectionnez un projet à utiliser pour cet atelier de programmation. Vous pouvez créer un nouveau projet pour supprimer plus facilement tout votre travail lorsque vous avez terminé.

Avant de pouvoir commencer à utiliser Imagen, vous devez activer certaines API.

  1. Accédez à Google Cloud Console.
  2. Accédez au tableau de bord Vertex AI.
  3. Sélectionnez "Activer toutes les API recommandées".

a8f336f7380a9eab.png

3. Explorer Google Imagen (facultatif)

Si vous connaissez déjà Imagen, vous pouvez ignorer cette section.

Avant d'essayer de créer une application Web qui utilise Imagen, il est utile de voir ce qu'Imagen peut faire. Heureusement, il existe un certain nombre de notebooks qui exécutent du code Imagen simple. Commençons par l'un d'eux.

  1. Accédez au notebook à l'adresse https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/getting-started/image_generation.ipynb .
  2. Sélectionnez "Ouvrir dans Colab" pour ouvrir le notebook sur le serveur de notebook de Google.
  3. Sélectionnez "Fichier -> Enregistrer une copie dans Drive" ou cliquez sur "Copier dans Drive" en haut de la page pour créer votre propre copie de ce notebook.
  4. Fermez la copie d'origine (juste pour éviter de travailler sur la mauvaise).
  5. Vous devez vous connecter à un environnement d'exécution en cliquant sur le bouton "Connecter" en haut à droite. 2afdc8fa660a89bd.png
  6. Commencez à travailler sur chacune des cellules du notebook.
  7. Pour exécuter une cellule, vous pouvez cliquer sur [] ou sur la flèche située à gauche de la cellule, ou utiliser l'option "Exécuter la sélection" dans le menu "Environnement d'exécution" (ou son raccourci): dfec032ef6c31296.png
  8. Lorsque vous redémarrez l'environnement d'exécution actuel, un message s'affiche indiquant que votre système a planté. Pas de panique. Ceci est normal.
  9. Vous devez authentifier votre environnement de notebook.
  10. Vous pouvez saisir l'ID de votre projet (et non son nom) et son emplacement (us-central1 fonctionne si vous n'avez pas défini d'emplacement) dans les champs situés à droite du code, et laisser Colab les insérer dans le code à votre place.
  11. Lorsque vous arrivez à "Générer une image", vous pouvez voir ce que Imagen peut faire. N'hésitez pas à modifier l'invite et à réexécuter la cellule pour voir la variété d'images que vous pouvez obtenir.
  12. À ce stade, vous devriez avoir une bonne idée de la façon dont Imagen peut créer des images à partir d'un notebook. N'hésitez pas à compléter ce notebook pour en savoir plus sur les paramètres d'image dès maintenant ou à un moment qui vous convient.

4. Commencer à créer une application Web pour afficher une image

Nous allons utiliser Python avec le framework Flask sur Cloud Run pour créer notre application.

Les applications Python Flask sont configurées dans un dossier comme suit:

app-folder
    templates
        template.html
        (etc.)
        anothertemplate.html
    main.py
    requirements.txt

Les modèles sont des fichiers contenant du code HTML, généralement avec des espaces réservés nommés dans lesquels le programme insère le texte généré. main.py est l'application du serveur Web elle-même, et requirements.txt est la liste de toutes les bibliothèques non standards utilisées par main.py.

L'application comporte deux pages : la première pour obtenir une invite et la seconde pour afficher l'image et permettre à l'utilisateur de saisir une autre invite.

Commencez par créer le framework du projet.

Créer la structure de fichiers

Cet atelier de programmation suppose que votre projet se trouve dans le dossier imageapp. Si vous utilisez un autre nom, veillez à modifier les commandes en conséquence.

Accédez à Cloud Shell en sélectionnant l'icône d'invite en haut à droite de l'écran.

28135f700c5b12b0.png

Vous pouvez gagner de l'espace de travail en déplaçant le shell dans un nouvel onglet à l'aide de la flèche en haut de la fenêtre du shell:

310422ac131813e1.png

Dans votre répertoire d'accueil dans Cloud Shell, créez le dossier imageapp, accédez-y, puis créez les dossiers templates. Vous pouvez le faire depuis la ligne de commande ou l'éditeur Cloud Shell.

Créer les modèles

L'application comporte deux pages : la première (que nous appellerons home.html) pour obtenir une invite et la seconde (que nous appellerons display.html) pour afficher l'image et permettre à l'utilisateur de saisir une autre invite.

Créez deux modèles à l'aide de l'éditeur Cloud Shell ou de l'éditeur Linux de votre choix. Dans le dossier imageapp/templates, créez la page initiale que l'utilisateur verra, home.html. Il utilise la variable prompt pour renvoyer la description saisie par l'utilisateur.

templates/home.html

<!DOCTYPE html>
<html>
   <head>
       <title>Let's draw a picture</title>
   </head>
   <body>
       <h1>Let's draw a picture</h1>
       <form  action="/" method="post" >
           <input type="text" id="prompt" name="prompt">
           <input type="submit" value="Send">
       </form>
   </body>
</html>

Créez ensuite display.html, qui affichera l'image. Notez que l'emplacement de l'image se trouve dans image_url.

templates/display.html

<!DOCTYPE html>
<html>
   <head>
       <title>Let's draw a picture</title>
   </head>
   <body>
       <h1>Let's draw a picture</h1>

       <div>
           <form  action="/" method="post" >
               <input type="text" id="prompt" name="prompt">
               <input type="submit" value="Send">
           </form>

           <p></p>
       </div>

       <div id="picture">
           <img id="pict" name="pict" alt="The created image" src="{{image_uri}}" style="width:100%;">
       </div>

   </body>
</html>

5. Démarrer le code

Vous devez créer le fichier requirements.txt pour vous assurer que toutes les bibliothèques dont votre programme a besoin sont disponibles. Pour l'instant, il vous suffit d'inclure flask dans le fichier requirements.txt.

Le fichier main.py contient le code qui traitera les requêtes Web. Nous n'avons à gérer que deux requêtes: une requête GET pour la page d'accueil et une requête POST qui envoie le formulaire décrivant l'image que nous souhaitons générer.

À l'aide de l'éditeur Cloud Shell ou de l'éditeur Linux de votre choix, créez le fichier main.py dans le dossier imageapp. Nous allons commencer par le squelette ci-dessous:

main.py

import flask

app = flask.Flask(__name__)

@app.route("/", methods=["GET"])
def home_page():
    return flask.render_template("home.html")

@app.route("/", methods=["POST"])
def display_image():
    # Code to get the prompt (called prompt) from the submitted form
    # Code to generate the image
    # Code to create a URL for the image (called image_url)

    return flask.render_template("display.html", prompt=prompt, image_url=image_url)

# Initialize the web server app when the code locally (Cloud Run handles it in that environment)
if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=8080)

En fait, c'est presque toute l'application. Il y a trois commentaires dans display_image qui doivent être étoffés avec du code Python, et c'est tout.

Commençons à remplir les parties manquantes. Flask permet de récupérer facilement l'invite. Ajoutez une ligne après le commentaire, comme illustré ci-dessous:

# Code to get the prompt (called prompt) from the submitted form
prompt = flask.request.form["prompt"]

Si vous souhaitez tester l'application maintenant, vous pouvez ajouter une ligne avant l'instruction return dans display_image pour attribuer une valeur à image_url (une URL valide pointant vers une image).

Par exemple : image_url="<your url here>"

Vous pouvez exécuter le programme localement à partir de Cloud Shell (à l'aide de la commande python main.py) et l'afficher en aperçu à l'aide de l'option "Preview on port 8080" (Prévisualiser sur le port 8080) en haut à droite de l'écran.

a80b4abd28cb7eed.png

Dans l'état actuel du programme, l'image de l'URL que vous avez fournie s'affiche toujours. Passons à la suite et voyons comment obtenir cette valeur à partir de l'application. Veillez à supprimer la ligne qui attribue une valeur statique à image_url.

6. Créer l'image

Google Cloud propose une API Python pour l'IA générative sur Vertex AI. Pour l'utiliser, nous devons ajouter une ligne l'important avec les autres importations en haut de notre programme:

from vertexai.vision_models import ImageGenerationModel

et incluez vertexai dans le fichier requirements.txt.

La documentation d'ImageGenerationModel explique comment l'utiliser. Nous allons créer un modèle, puis générer une image à partir de celui-ci, à partir d'une requête. Ajoutez du code à main.py pour la deuxième étape, qui consiste à créer l'image et à la stocker dans response:

# Code to generate the image
model = ImageGenerationModel.from_pretrained("imagegeneration@006")
response = model.generate_images(prompt=prompt)[0]

Vous pouvez créer jusqu'à quatre images à la fois, en fonction des paramètres envoyés à generate_images. La valeur renvoyée sera donc une liste de GeneratedImage, même si une seule image est renvoyée, comme dans ce cas.

Nous devons maintenant afficher l'image sur une page WWW. GeneratedImage dispose d'une méthode permettant de show l'image, mais elle ne fonctionne que dans un environnement de notebook. Il existe toutefois une méthode pour enregistrer l'image. Nous enregistrerons l'image et enverrons son URL lorsque nous génèrerons le modèle.

Cette opération est un peu délicate et peut être réalisée de différentes manières. Examinons l'une des approches les plus simples, étape par étape. (Vous trouverez une image des étapes ci-dessous si vous êtes plus visuel.)

Nous devons d'abord enregistrer l'image. Mais quel nom lui donner ? L'utilisation d'un nom statique peut entraîner des problèmes, car le programme peut être utilisé par plusieurs personnes en même temps. Nous pourrions créer des noms d'image distincts pour chaque utilisateur (avec un UUID, par exemple), mais il est plus simple d'utiliser la bibliothèque tempfile de Python, qui crée un fichier temporaire avec un nom unique. Le code ci-dessous crée un fichier temporaire, en obtient le nom et écrit la réponse de l'étape de génération d'image dans ce fichier temporaire. Nous ne l'insérerons pas encore dans notre code, car nous devons d'abord obtenir une URL.

with tempfile.NamedTemporaryFile("wb") as f:
    filename = f.name
    response.save(filename, include_generation_parameters=False)
    # process the saved file here, before it goes away

Il existe plusieurs façons de traiter le fichier enregistré, mais l'une des plus simples et des plus sûres consiste à utiliser une URL de données.

Les URL de données permettent d'envoyer les données réelles dans l'URL, et non seulement un chemin d'accès. La syntaxe d'une URL de données est la suivante:

data:[image/png][;base64],<data>

Pour obtenir l'encodage base64 de l'image, nous devons ouvrir le fichier enregistré par tempfile et le lire dans une variable. Oui, il s'agit d'une chaîne de grande taille, mais cela ne devrait pas poser de problème avec les navigateurs et les serveurs modernes. Nous utiliserons ensuite la bibliothèque base64 pour l'encoder en une chaîne que nous pourrons envoyer dans l'URL des données.

Le code final pour effectuer la troisième étape (créer l'URL) sera le suivant:

# Code to create a URL for the image (called image_url)
with tempfile.NamedTemporaryFile("wb") as f:
    filename = f.name
    response.save(filename, include_generation_parameters=False)
    # process the saved file here, before it goes away
    with open(filename, "rb") as image_file:
        binary_image = image_file.read()
        base64_image = base64.b64encode(binary_image).decode("utf-8")
        image_url = f"data:image/png;base64,{base64_image}"

Vous pouvez voir toutes ces étapes dans l'image ci-dessous:

268876579dc02376.png

Vous devez importer tempfile et base64 au début de votre programme.

import tempfile
import base64

Essayez d'exécuter votre programme à partir de Cloud Shell en vous assurant d'être dans le dossier avec main.py et en exécutant la commande suivante:

python main.py

Vous pouvez ensuite l'afficher en utilisant l'option "Preview on port 8080" (Prévisualiser sur le port 8080) en haut à droite de l'écran.

a80b4abd28cb7eed.png

7. Erreur courante

À un moment donné, vous remarquerez peut-être que lorsque vous exécutez le programme (lors des tests ou après l'avoir déployé), vous recevez un message semblable à celui-ci:

2366c3bba6273517.png

Cela est probablement dû à une requête qui enfreint les pratiques d'IA responsable de Google . Une requête aussi simple que "chatons jouant avec des balles colorées" peut entraîner ce problème. (Mais ne vous inquiétez pas, vous pouvez obtenir des images de "chatons jouant avec des jouets colorés".)

Pour résoudre cette erreur, nous allons ajouter du code pour intercepter l'exception générée lorsque nous essayons de générer l'image. Si c'est le cas, nous affichons à nouveau le modèle home.html avec un message.

Tout d'abord, ajoutons un élément div dans le modèle home.html après le premier formulaire qui s'affiche en cas d'erreur:

<!DOCTYPE html>
<html>
   <head>
       <title>Let's draw a picture</title>
   </head>
   <body>
       <h1>Let's draw a picture</h1>
       <form  action="/" method="post" >
           <input type="text" id="prompt" name="prompt">
           <input type="submit" value="Send">
       </form>
       {% if mistake %}
       <div id="warning">
       The prompt contains sensitive words that violate
       <a href=\"https://ai.google/responsibility/responsible-ai-practices\">
           Google's Responsible AI practices</a>.
       Try rephrasing the prompt."</div>

       {% endif %}

   </body>
</html>

Ajoutez ensuite du code dans main.py pour intercepter une éventuelle exception lors de l'appel du code generate_images dans display_image. En cas d'exception, le code affiche le modèle home.html avec un message.

# Code to generate the image
   model = ImageGenerationModel.from_pretrained("imagegeneration@006")
   try:
       response = model.generate_images(prompt=prompt)[0]   
   except:
       #  This is probably due to a questionable prompt
       return flask.render_template("home.html", warning=True)

Ce n'est pas la seule fonctionnalité d'IA responsable d'Imagen. Plusieurs fonctionnalités protègent la génération de personnes et d'enfants, ainsi que les filtres généraux sur les images. Pour en savoir plus, cliquez ici.

8. Déployer l'application sur le Web

Vous pouvez déployer l'application sur le Web à l'aide de la commande du dossier imageapp dans Cloud Shell. Veillez à utiliser votre ID de projet réel dans la commande.

gcloud run deploy imageapp \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --project your-project-id

Une réponse semblable à celle-ci doit s'afficher, vous indiquant où trouver votre application:

Service [imageapp] revision [imageapp-00001-t48] has been deployed and is serving 100 percent of traffic.
Service URL: https://imageapp-708208532564.us-central1.run.app```

9. Nettoyage

Bien que Cloud Run ne facture pas lorsque le service n'est pas utilisé, il se peut que des frais vous soient facturés pour le stockage de l'image de conteneur dans Artifact Registry. Vous pouvez supprimer votre dépôt ou votre projet Cloud pour éviter que des frais ne vous soient facturés. La suppression de votre projet Cloud arrête la facturation de toutes les ressources utilisées dans ce projet.

Pour supprimer votre dépôt d'images de conteneur:

gcloud artifacts repositories delete cloud-run-source-deploy \
  --location $REGION

Pour supprimer votre service Cloud Run:

gcloud run services delete imageapp \
  --platform managed \
  --region $REGION

Pour supprimer votre projet Google Cloud:

  1. Récupérez votre ID de projet actuel:
PROJECT_ID=$(gcloud config get-value core/project)
  1. Vérifiez qu'il s'agit bien du projet que vous souhaitez supprimer:
echo $PROJECT_ID
  1. Supprimez le projet :
gcloud projects delete $PROJECT_ID

10. Félicitations

Félicitations, vous avez créé une application Web qui affiche les images créées par Imagen. Comment pouvez-vous l'utiliser dans votre application ?

Et ensuite ?

Découvrez quelques-uns des ateliers de programmation...

Complément d'informations