將 Imagen 部署至 Cloud Run

1. 程式碼研究室簡介

上次更新時間:2024 年 10 月 11 日

撰文:Laurie White

圖像生成

老實說,由大型語言模型 (LLM) 產生的圖片可能很有趣。當然,許多業務應用程式都會根據提示產生圖片,從客製廣告到吸引人的簡報皆是如此。(Google Cloud 網站上有許多使用 Creative Agent 的具體用途。)不過,當你要求「田野中快樂的綠色狗狗」圖片時,看到的結果可能會很有趣。

無論您是出於工作或休閒 (或兩者皆是) 而有興趣使用圖像生成功能,在使用圖像生成程式和將其部署至網路應用程式之間,都會遇到一些挑戰。本研究室將協助您克服這些挑戰。

建構項目

在本程式碼研究室中,您將建構一個應用程式,該應用程式會接收文字提示,並傳回網頁,其中包含使用該提示產生的圖片。

課程內容

本實驗室的內容包括:

  • 如何在筆記本環境中使用 Google Imagen 根據文字提示建立圖像
  • 將 Imagen 程式碼從 Notebook 移至 Web 應用程式時遇到的困難
  • 如何部署使用 Imagen 產生圖片的 Cloud Run 應用程式
  • 如何在 HTML 中加入 Imagen 圖片

本程式碼研究室著重於 Imagen 和部署作業。我們不會對與本主題無關的概念和程式碼多做介紹,但會事先準備好這些程式碼區塊,屆時您只要複製及貼上即可。

軟硬體需求

您可以在 https://github.com/Annie29/imagen-deployment 中找到本程式碼研究室的完整程式碼。

2. 啟用 API

選取要用於本程式碼研究室的專案。建議您建立新專案,以便在完成後輕鬆移除所有工作。

您必須先啟用某些 API,才能開始使用 Imagen。

  1. 前往 Google Cloud 控制台。
  2. 前往 Vertex AI 資訊主頁。
  3. 選取「啟用所有建議的 API」

a8f336f7380a9eab.png

3. 探索 Google Imagen (選用)

如果您熟悉 Imagen,可以略過本節。

在嘗試建立使用 Imagen 的網頁應用程式之前,先瞭解 Imagen 的功能會很有幫助。幸運的是,有許多可執行簡單 Imagen 程式碼的 Notebook,因此我們先從其中一個開始吧。

  1. 前往 https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/getting-started/image_generation.ipynb 查看 Notebook。
  2. 選取「在 Colab 中開啟」,即可在 Google 的筆記本伺服器中開啟筆記本。
  3. 選取「檔案」->「在雲端硬碟中儲存副本」,或是點選頁面頂端的「複製到雲端硬碟」,即可建立這個筆記本的副本。
  4. 關閉原始副本 (避免在錯誤的副本上工作)。
  5. 您必須按一下右上方的「連線」按鈕,才能連線至執行階段。2afdc8fa660a89bd.png
  6. 開始執行筆記本中的每個儲存格。
  7. 如要執行儲存格,請點選儲存格左側的 [] 或箭頭,或是使用「執行時間」選單中的「執行所選項目」選項 (或捷徑):dfec032ef6c31296.png
  8. 重新啟動目前的執行階段時,您會收到系統當機的訊息。別緊張,這是正常情況。
  9. 您必須驗證筆記本環境。
  10. 您可以在程式碼右側的方塊中輸入專案 ID (不是名稱) 和位置 (如果未設定位置,則可使用 us-central1),讓 Colab 在程式碼中插入這些資訊。
  11. 當您看到「產生圖片」時,就能瞭解 Imagen 的功能。您可以隨意變更提示,並重新執行單元格,查看可產生的各種圖片。
  12. 到目前為止,您應該已瞭解 Imagen 如何從筆記本建立圖片。歡迎您現在或在方便時完成這個 Notebook,進一步瞭解圖片參數。

4. 開始建構網路應用程式,以便顯示圖片

我們會使用 Python 在 Cloud Run 上使用 Flask 架構建構應用程式。

Python Flask 應用程式會在以下資料夾中設定:

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

範本是包含 HTML 的檔案,通常會在其中加入名為「預留位置」的元素,讓程式插入產生的文字。main.py 是網路伺服器應用程式本身,而 requirements.txt 則是 main.py 使用的所有非標準程式庫清單。

應用程式會有兩個頁面:第一個頁面用於取得提示,第二個頁面則用於顯示圖片,並讓使用者輸入另一個提示。

首先建立專案架構。

建立檔案結構

本程式碼研究室假設您的專案位於 imageapp 資料夾中。如果您使用其他名稱,請務必視情況更新指令。

選取畫面右上方的提示圖示,即可進入 Cloud Shell。

28135f700c5b12b0.png

您可以使用殼層視窗頂端的箭頭,將殼層移至新分頁,這樣就能有更多空間進行作業:

310422ac131813e1.png

在 Cloud Shell 的主目錄中建立 imageapp 資料夾,然後切換至該資料夾並建立 templates 資料夾。您可以透過指令列或 Cloud Shell 編輯器執行這項操作。

建立範本

應用程式會有兩個頁面:第一個頁面 (我們稱為 home.html) 會顯示提示,第二個頁面 (我們稱為 display.html) 則會顯示圖片,並允許使用者輸入其他提示。

使用 Cloud Shell 編輯器或您選擇的 Linux 編輯器,建立兩個範本。在 imageapp/templates 資料夾中建立使用者會看到的初始網頁 home.html。這個函式會使用變數 prompt 傳回使用者輸入的說明。

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>

接著建立 display.html,用於顯示圖片。請注意,圖片的位置會在 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. 開始編寫程式碼

您必須建立檔案 requirements.txt,確保程式所需的所有程式庫皆可使用。目前只需在 requirements.txt 檔案中加入 flask

main.py 檔案包含用來處理網頁要求的程式碼。我們只需要處理兩個要求:首頁的 GET 要求,以及提交表單的 POST 要求,說明我們要產生的圖片。

使用 Cloud Shell 編輯器或您選擇的 Linux 編輯器,在 imageapp 資料夾中建立 main.py 檔案。我們先從以下骨架開始:

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)

其實,這幾乎就是整個應用程式。display_image 中有三個註解需要使用 Python 程式碼加以充實,這就是全部了。

我們開始填入缺漏的部分。Flask 可讓您輕鬆擷取提示。在註解後方新增一行,如下所示:

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

如果您現在想測試應用程式,可以在 display_image 中的 return 陳述式前方新增一行,為 image_url 提供值 (指向圖片的有效網址)。

例如:image_url="<your url here>"

您可以透過 Cloud Shell 在本機上執行程式 (使用指令 python main.py),然後使用畫面右上方的「透過以下通訊埠預覽:8080」預覽程式。

a80b4abd28cb7eed.png

在目前的程式中,您一律會在您提供的網址中看到圖片。接下來,我們來看看如何從應用程式取得該值。請務必移除為 image_url 提供靜態值的程式碼行。

6. 建立圖片

Google Cloud 提供 Vertex AI 生成式 AI 的 Python API。如要使用它,我們必須在程式頂端附近新增一行匯入指令,並與其他匯入指令一起匯入:

from vertexai.vision_models import ImageGenerationModel

並在 requirements.txt 檔案中加入 vertexai

如要瞭解如何使用 ImageGenerationModel,請參閱相關說明文件。我們會建立模型,然後根據提示生成圖片。在 main.py 中新增程式碼,用於第二個步驟,建立圖片並儲存在 response 中:

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

一次最多可建立 4 張圖片,具體取決於傳送至 generate_images 的參數,因此傳回的值會是 GeneratedImage 的清單,即使只傳回一張圖片也一樣。

接下來,我們需要在 WWW 網頁上顯示圖片。GeneratedImage 確實有方法可將圖片 show,但只能在 Notebook 環境中使用。不過,我們有方法儲存圖片。我們會在算繪範本時儲存圖片,並傳送已儲存圖片的網址。

這項操作有點複雜,而且有很多種方法。我們將逐步介紹其中一種較簡單的方法。(如果您是視覺型學習者,請參考下方步驟的圖片)。

首先,我們需要儲存圖片。但要取什麼名稱呢?使用靜態名稱可能會發生問題,因為許多人可能會同時使用該程式。雖然我們可以為每位使用者建立個別的圖片名稱 (使用 UUID 之類的內容),但更簡單的方法是使用 Python 的 tempfile 程式庫,這個程式庫會建立具有不重複名稱的暫存檔案。以下程式碼會建立暫存檔、取得其名稱,並將圖片產生步驟的回應寫入暫存檔。我們還不會在程式碼中輸入這個值,因為我們需要先取得網址。

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

處理已儲存檔案的方式有很多種,但最簡單且最安全的方法之一,就是使用資料網址

資料網址可讓您透過網址傳送實際資料,而非僅傳送資料路徑。資料網址的語法如下:

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

如要取得圖片的 base64 編碼,我們需要開啟 tempfile 儲存的檔案,並將檔案讀取至變數。是的,這會是一個很大的字串,但在現代瀏覽器和伺服器中應該沒問題。接著,我們會使用 base64 程式庫將其編碼為字串,以便透過資料網址傳送。

我們要執行第三個步驟 (建立網址) 的最終程式碼如下:

# 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}"

您可以在下圖中查看所有步驟:

268876579dc02376.png

您必須在程式開頭匯入 tempfile 和 base64。

import tempfile
import base64

請嘗試透過 Cloud Shell 執行程式,確認您位於 main.py 資料夾中,然後執行下列指令:

python main.py

接著,您可以使用畫面右上方的「透過以下通訊埠預覽:8080」預覽應用程式。

a80b4abd28cb7eed.png

7. 常見錯誤

您可能會發現,在執行程式 (測試期間或部署後) 時,會收到類似下方的訊息:

2366c3bba6273517.png

這很可能是因為提示違反 Google 負責任的 AI 技術做法。只要是「小貓咪玩彩色球」這類簡單的提示,就可能導致這個問題。(不過別擔心,你可以取得「小貓玩彩色玩具」的圖片)。

為了處理這個錯誤,我們會新增程式碼,擷取嘗試產生圖片時發生的例外狀況。如果有,我們會再次轉譯 home.html 範本,並顯示訊息。

首先,請在 home.html 範本中,在第一個表單後方新增 div,以便在發生錯誤時顯示:

<!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>

接著,請在 main.py 中新增程式碼,以便在 display_image 中呼叫 generate_images 程式碼時,擷取可能的例外狀況。如果發生例外狀況,程式碼會轉譯含有訊息的 home.html 範本。

# 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)

這並非 Imagen 唯一的 Responsible AI 功能。我們提供多項功能,可保護人物和兒童的世代,以及圖片上的一般濾鏡。如要進一步瞭解這些功能,請參閱本文

8. 將應用程式部署至網路

您可以使用 Cloud Shell 中 imageapp 資料夾中的指令,將應用程式部署至網路。請務必在指令中使用實際的專案 ID。

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

您應該會看到類似以下的回應,說明應用程式的位置:

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. 清除

不使用服務時,Cloud Run 不會收費,但您可能仍須針對已儲存於 Artifact Registry 中的容器映像檔,支付儲存費用。您可以刪除儲存庫或 Cloud 專案,以免產生費用。刪除 Cloud 專案後,系統就會停止對專案使用的所有資源收取費用。

刪除容器映像檔存放區:

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

如何刪除 Cloud Run 服務:

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

如何刪除 Google Cloud 專案:

  1. 擷取目前的專案 ID:
PROJECT_ID=$(gcloud config get-value core/project)
  1. 確認這是您要刪除的專案:
echo $PROJECT_ID
  1. 刪除專案:
gcloud projects delete $PROJECT_ID

10. 恭喜

恭喜,您已成功建構網頁應用程式,可顯示由 Imagen 建立的圖片。如何在應用程式中使用這項功能?

後續步驟

查看一些程式碼研究室…

其他資訊