Déployer Imagen dans Cloud Run

1. À propos de cet atelier de programmation

Dernière mise à jour : 11 octobre 2024

Auteur : Laurie White

Génération d'images

Soyons honnêtes, la génération d'images par de grands modèles de langage (LLM) peut être amusante. Bien sûr, il existe de nombreuses applications professionnelles pour générer des images à partir d'un prompt, allant de la publicité personnalisée aux présentations attrayantes. (Le site Web Google Cloud présente de nombreuses utilisations spécifiques d'entreprises qui utilisent des agents créatifs.) Toutefois, voir les résultats lorsque vous demandez une image de "chiens verts joyeux dans un champ" peut être assez amusant.

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

Objectifs de l'atelier

Dans cet atelier de programmation, vous allez créer une application qui prendra un prompt textuel et renverra une page Web avec une image générée à l'aide de ce prompt.

Points abordés

Dans cet atelier, vous apprendrez à :

  • utiliser Google Imagen pour créer des images à partir de prompts textuels dans des environnements de notebook ;
  • découvrir les difficultés liées au déplacement 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 axé sur Imagen et le 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.

Ce dont vous avez besoin

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 projet pour faciliter la suppression de tout votre travail une fois terminé.

Avant de 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 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 donc par l'un d'eux.

  1. Accédez au notebook sur https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/getting-started/image_generation.ipynb .
  2. Sélectionnez "Ouvrir dans Colab" pour ouvrir le notebook dans 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 dans la mauvaise copie).
  5. Vous devez vous connecter à un environnement d'exécution en cliquant sur le bouton "Connecter" en haut à droite. 2afdc8fa660a89bd.png
  6. Commencez à parcourir chacune des cellules du notebook.
  7. Pour exécuter une cellule, vous pouvez cliquer sur [] ou sur la flèche à gauche de la cellule, ou utiliser l'option "Exécuter la sélection" du menu "Environnement d'exécution" (ou son raccourci) : dfec032ef6c31296.png
  8. Lorsque vous redémarrez l'environnement d'exécution actuel, un message indiquant que votre système a planté s'affiche. 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 cases à droite du code, et Colab les insérera dans le code pour vous.
  11. Lorsque vous arrivez à "Générer une image", vous avez la possibilité de voir ce qu'Imagen peut faire. N'hésitez pas à modifier le prompt 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 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 du texte généré. main.py est l'application de serveur Web elle-même, et requirements.txt est une liste de toutes les bibliothèques non standards utilisées par main.py.

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

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 à mettre à jour les commandes de manière appropriée.

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

28135f700c5b12b0.png

Vous pouvez disposer de plus d'espace pour travailler si vous déplacez le shell vers 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 à partir de la ligne de commande ou de l'éditeur Cloud Shell.

Créer les modèles

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

À l'aide de l'éditeur Cloud Shell ou de l'éditeur Linux de votre choix, créez deux modèles. Dans le dossier imageapp/templates, créez la page initiale que l'utilisateur verra, home.html. Elle 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 trouvera 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, incluez simplement flask dans le fichier requirements.txt.

Le fichier main.py contient le code qui traitera les requêtes Web. Nous n'avons que deux requêtes à gérer : une requête GET pour la page d'accueil et une requête POST qui envoie le formulaire décrivant l'image que nous voulons 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, il s'agit presque de l'application complète. Il existe trois commentaires dans display_image qui doivent être complétés avec du code Python, et c'est tout.

Commençons à remplir ces parties manquantes. Flask facilite la récupération du prompt. Ajoutez une ligne après le commentaire, comme indiqué 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 qui pointe 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 le prévisualiser à l'aide de l'option "Prévisualiser sur le port 8080" en haut à droite de l'écran.

a80b4abd28cb7eed.png

Dans l'état actuel du programme, l'image s'affiche toujours dans l'URL que vous avez fournie. 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 dispose d'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 inclure vertexai dans le fichier requirements.txt.

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

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

Jusqu'à quatre images peuvent être créées à 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. La GeneratedImage dispose d'une méthode pour show l'image, mais elle ne fonctionne que dans un environnement de notebook. Cependant, il existe une méthode pour enregistrer l'image. Nous allons enregistrer l'image et envoyer l'URL de l'image enregistrée lorsque nous afficherons le modèle.

C'est un peu délicat, et il existe de nombreuses façons de procéder. Examinons l'une des approches les plus simples, étape par étape. (Vous trouverez une image des étapes ci-dessous si vous apprenez mieux en voyant les choses.)

Nous devons d'abord enregistrer l'image. Mais comment l'appeler ? L'utilisation d'un nom statique peut poser problème, car le programme peut être utilisé par de nombreuses personnes en même temps. Bien que nous puissions créer des noms d'image distincts pour chaque utilisateur (avec quelque chose comme UUID), une méthode plus simple consiste à utiliser la bibliothèque tempfile de Python, qui créera un fichier temporaire avec un nom unique. Le code ci-dessous crée un fichier temporaire, obtient son nom et écrit la réponse de l'étape de génération d'image dans le fichier temporaire. Nous ne l'entrerons 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 pas seulement un chemin d'accès à celles-ci. 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 longue chaîne, 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 dans une chaîne que nous pourrons envoyer dans l'URL de 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 que vous vous trouvez dans le dossier contenant main.py et en exécutant la commande :

python main.py

Vous pouvez ensuite le prévisualiser à l'aide de l'option "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 d'un test ou après son déploiement), vous recevez un message semblable à celui-ci :

2366c3bba6273517.png

Cela est très probablement dû à un prompt qui enfreint les pratiques de Responsible AI de Google . Un prompt aussi simple que "chatons jouant avec des balles colorées" peut provoquer 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 qui est générée lorsque nous tentons de générer l'image. Si une exception se produit, nous afficherons à nouveau le modèle home.html, avec un message.

Tout d'abord, ajoutons un div dans le modèle home.html après le premier formulaire qui s'affichera 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>

Ensuite, ajoutez 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 affichera 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)

Il ne s'agit pas de la seule fonctionnalité de Responsible AI d'Imagen. Un certain nombre de fonctionnalités protègent la génération de personnes et d'enfants, ainsi que des 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 l'ID de votre projet dans la commande.

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

Un résultat semblable à celui-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 afin d'éviter que des frais ne vous soient facturés. La suppression de votre projet Google Cloud arrête la facturation de toutes les ressources utilisées dans ce projet.

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

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 l'ID de votre projet actuel :
PROJECT_ID=$(gcloud config get-value core/project)
  1. Assurez-vous qu'il s'agit 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 des images créées par Imagen. Comment l'utiliser dans votre application ?

Et ensuite ?

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

Complément d'informations