Gemma3 1bをLambdaにデプロイしてみた
Gemma3 1b を Lambda にデプロイしてみた
はじめに
最近、Google が公開した LLM「Gemma 3」、なんと DeepSeek 1.5b より小さく、Gemma3 1b もあったので、AWS Lambda にデプロイして実際に使ってみることにしました。Gemma 3 は比較的軽量でありながら高性能なモデルで、特に 1B パラメータのバージョンはクラウド環境でも手軽に利用できます。今回はその実装過程と結果について共有します。
環境構築
まず、AWS SAM(Serverless Application Model)を使用して Lambda 関数をデプロイする環境を準備しました。SAM はサーバーレスアプリケーションの構築とデプロイを簡素化するフレームワークです。
プロジェクトの構成は以下の通りです:
- FastAPI を使用したバックエンド
- Hugging Face からのモデルダウンロード
- AWS Lambda へのデプロイ
ディレクトリ構成:
.
├── app
│ ├── Dockerfile
│ ├── __init__.py
│ ├── app.py
│ ├── models
│ │ └── gemma
│ │ ├── added_tokens.json
│ │ ├── config.json
│ │ ├── generation_config.json
│ │ ├── model.safetensors
│ │ ├── special_tokens_map.json
│ │ ├── tokenizer.json
│ │ ├── tokenizer.model
│ │ └── tokenizer_config.json
│ ├── requirements.txt
│ └── templates
│ └── chat.html
├── download_model.py
├── samconfig.toml
└── template.yaml
モデルのローカルにダウンロードする
まずは Gemma3 1b をローカルに持ってきます。
Access Tokensにて、READ
の権限があるアクセストークを発行し、
huggingface-cli login
で認証を解決した上、python3 download_model.py
を実行します。
huggingface-cli
のセットアップ手順は割愛します。
from huggingface_hub import snapshot_download
model_id = "google/gemma-3-1b-it"
snapshot_download(
repo_id=model_id,
local_dir="./app/models/gemma",
ignore_patterns=["*.md", "*.h5"]
)
print(f"Model files downloaded to ./app/models/gemma")
)
このスクリプトを実行すると、モデルファイルがローカルの./app/models/gemma
ディレクトリにダウンロードされます。
アプリケーションの実装
FastAPI を使用して API エンドポイントを実装しました。主な機能は:
- テキスト生成 API
- シンプルな Web ページ
✴︎ Lambda function URL でデプロイし、通常の Response を template に返す形なので、Lambda 環境では streaming が効かず改善は必要
import os
import torch
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import StreamingResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from mangum import Mangum
from pydantic import BaseModel
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
import json
from threading import Thread
app = FastAPI()
templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "templates"))
# Select device
DEVICE = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using device: {DEVICE}")
# Load model
MODEL_DIR = "./models/gemma" if os.path.exists("./models/gemma") else "/var/task/models/gemma"
print(f"Loading model from {MODEL_DIR}...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR, local_files_only=True)
model = AutoModelForCausalLM.from_pretrained(
MODEL_DIR,
local_files_only=True,
torch_dtype=torch.float32,
device_map=DEVICE
)
class PromptRequest(BaseModel):
prompt: str
@app.get("/", response_class=HTMLResponse)
async def chat_page(request: Request):
return templates.TemplateResponse("chat.html", {"request": request})
@app.post("/generate/stream")
async def generate_text_stream(request: PromptRequest):
try:
messages = [{"role": "user", "content": request.prompt}]
prompt = tokenizer.apply_chat_template(messages, tokenize=False)
inputs = tokenizer(prompt, return_tensors="pt").to(DEVICE)
def generate():
streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
generation_kwargs = dict(
**inputs,
streamer=streamer,
max_new_tokens=5000,
temperature=0.6,
do_sample=True,
pad_token_id=tokenizer.pad_token_id
)
thread = Thread(target=model.generate, kwargs=generation_kwargs)
thread.start()
for text in streamer:
yield f"data: {json.dumps({'text': text})}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream"
)
except Exception as e:
print(f"Generation error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
lambda_handler = Mangum(app)
Docker コンテナの設定
Lambda で実行するための Docker コンテナを設定しました:
イメージサイズは 2GB ほどあるので改善余地はあります。
FROM public.ecr.aws/lambda/python:3.12-arm64
COPY app.py requirements.txt ./
RUN microdnf install -y git && \
pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt && \
mkdir -p /var/task/templates
COPY ./templates /var/task/templates
COPY ./models/gemma ./models/gemma
CMD ["app.lambda_handler"]
ARM64 アーキテクチャを使用することで、コスト効率の良い Graviton3 プロセッサを利用できます。
SAM テンプレートの設定
AWS SAM のテンプレートファイルでは、Lambda 関数のリソース設定を行いました:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
Sample SAM Template for sam-gemma
Globals:
Function:
Timeout: 900
MemorySize: 10240
Resources:
LambdaFunction:
Type: AWS::Serverless::Function
Metadata:
Dockerfile: Dockerfile
DockerContext: ./app
DockerTag: python3.12-v1
Properties:
PackageType: Image
Architectures:
- arm64
Policies:
- AWSLambdaRole
- AWSLambdaBasicExecutionRole
- Statement:
Effect: Allow
Action:
- iam:PassRole
Resource: "*"
特に注目すべき点は:
- メモリサイズを 10GB に設定(モデルの読み込みに必要)
- タイムアウトを 900 秒(15 分)に設定
- ARM64 アーキテクチャの指定
Web ページ
雑に FastAPI のテンプレート機能を使いました。
ソースコード
デプロイと実行結果
sam build
とsam deploy
コマンドを使用して Lambda 関数をデプロイしました。デプロイ後 Lambda の管理画面にて Function URL の設定をし、そこからブラウザからアクセスできるようになります。
パフォーマンスと制限
Gemma 3 1b モデルは Lambda の 10GB 環境でも十分に動作しますが、いくつかの制限があります:
- コールドスタート時間がかなり長い(モデルのロードに時間がかかる)
- 推論速度はローカル環境より遅い(ただ一度コールドスタートが済ませばそこまで遅くはないが)
- 長時間の処理では Lambda のタイムアウト制限に注意が必要
- 1b なのでまともな回答やタスクの実施などは期待できない
まとめ
以上で AWS Lambda に Gemma3 1b をデプロイすることができました。
まだ実用レベルではないですが、まだまだ改善できる余地はあるので、今後 Lambda での LLM 利用は期待しています。
Discussion