はじめに
GPUパフォーマンスの必要な StableDuffusion をGPUクラウドを利用して動かしたので、その備忘録。
ここでは Serverlessエンドポイント作成 → APIキー払い出し → 導通確認 → APIキーを利用した javascript作成 までの手順をまとめる。
対象読者:
- GPUを安価に使って、画像生成や SLM 等を実践してみたい
使用サービス、価格について
-
GPUクラウドサービス:Runpod ( https://www.runpod.io/ )
PodsとServerlessのサービスあり(他にもあり)-
Pods (GPU 自体の時間貸し):
- RTX4090クラスで $0.49/hr ~ ※73.5円/時間(1$=150円)
-
Serverless(GPU の実行時間貸し)
- RTX4090クラスで $0.00031/sec ~ ※0.0465円/秒(1$=150円)
今回は画像生成時のみ GPU を利用するので Serverlessを選択
※1画像を1分で作るとしておおよそ3円 -
Pods (GPU 自体の時間貸し):
-
支払:クレジット払
事前にチャージが必要 $10~
Serverless Endpointの作成
-
メニューバーから「Serverless」を選択すると下記画面に変わる
-
「+New Endpoint」でEndpointを自作・展開することもできるが、今回は「Browse hub」で作成済テンプレートより選択。
-
各項目について(変更後は「Save Endpoint」で保存)
API Key の発行
導通確認
-
curlにてエンドポイント呼び出しの書式は以下の通り
- your_endpoint_name: Serverless Endpoint 作成の項目で作成したものを使用
- your_api_key: API key の発行の項目で作成したものを使用
bashcurl -X POST https://api.runpod.ai/v2/your_endpoint_id/run \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer your_api_key' \ -d '{"input":{"prompt":"Your prompt"}}'
-
curlが実行できる環境でコマンドを入力すると、正常の場合は imageを含んだ大きいJSONデータが返却される
bash# curl -X POST https://api.runpod.ai/v2/your_endpoint_id/runsync \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer your_api_key' \ -d '{"input":{"prompt":"Your prompt"}}' {"delayTime":1045,"executionTime":2345,"id":"sync-55406c11-237c-4e5f-a502-81a7854d303c-e1","output":{"images": ~省略~"}
APIキーを利用した javascript作成
-
以下の html ファイルを作成する
ファイル名はtest.htmlとかでよい
const apiUrlとconst apiKey の行については前述の通りRunpod_Serveless_test.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>RunPod Serverless+Stable Diffusionによる画像生成</title> <style> body { font-family: sans-serif; line-height: 1.6; } input, button { font-size: 1em; padding: 4px; margin: 5px 0; width: 100%; max-width: 500px; } label { display: block; margin-top: 1em; } #resultImage { max-width: 512px; display: block; margin: 1em 0; } #responseArea { white-space: pre-wrap; background: #f0f0f0; padding: 1em; border: 1px solid #ccc; max-width: 700px; overflow-x: auto; } </style> </head> <body> <h2>🎨 Runpod Serverless+Stable Diffusionによる画像生成</h2> <label>Prompt: <input type="text" id="promptInput" value="a cute cat sitting on a sofa"> </label> <label>Negative prompt: <input type="text" id="negPromptInput" value="low quality, blurry, bad anatomy"> </label> <label>Steps: <input type="number" id="stepsInput" value="20" min="1" max="100"> </label> <button onclick="generateImage()">画像生成</button> <img id="resultImage" style="display: none;"> <div id="responseArea">画像とAPIレスポンスがここに表示されます</div> <script> async function generateImage() { const prompt = document.getElementById("promptInput").value; const negPrompt = document.getElementById("negPromptInput").value; const steps = parseInt(document.getElementById("stepsInput").value); const resultImage = document.getElementById("resultImage"); const responseArea = document.getElementById("responseArea"); resultImage.style.display = "none"; responseArea.textContent = "⏳ APIレスポンス待機中..."; // 以下の2行はセキュアに管理すること const apiUrl = "https://api.runpod.ai/v2/your_endpoint_id/runsync"; const apiKey = "your_api_key"; const payload = { input: { prompt: prompt, negative_prompt: negPrompt, steps: steps } }; try { const response = await fetch(apiUrl, { method: "POST", headers: { "Authorization": "Bearer " + apiKey, "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); const imageB64 = result.output?.images?.[0]; if (imageB64) { resultImage.src = "data:image/png;base64," + imageB64; resultImage.style.display = "block"; } responseArea.textContent = JSON.stringify(result, null, 2); } catch (error) { responseArea.textContent = "❌ エラー: " + error; } } </script> </body> </html>
参考