Stable Diffusion 모델을 이용하면 텍스트를 이용하여 창조적인 이미지를 생성할 수 있습니다. Amazon에서는 SageMaker JumpStart을 이용하여 머신러닝(ML)을 쉽게 사용할 수 있도록 사전학습(pre-trained)된 모델을 제공하고 있는데, 2022년 10월 부터 Stable Diffusion 모델을 추가적으로 제공하고 있습니다. 이를 통해 Stable Diffusion 이미지를 쉽게 생성할 수 있으며, 즉시 Serving할 수 있도록 SageMaker Endpoint도 제공합니다. SageMaker Endpoint는 트래픽이 증가할 때는 자동으로 Scale out 하므로, 트래픽 변동이 심할때에도 효율적으로 인프라를 유지할 수 있으며 IAM 기반의 강화된 보안을 제공하고 있습니다.
Stable Diffusion Keywords에서는 keywords에 따른 Stable Diffusion의 결과를 볼 수 있습니다.
"The Legend of Zelda landscape atmospheric, hyper realistic, 8k, epic composition, cinematic, octane render, artstation landscape vista photography by Carr Clifton & Galen Rowell, 16K resolution, Landscape veduta photo by Dustin Lefevre & tdraw, 8k resolution, detailed landscape painting by Ivan Shishkin, DeviantArt, Flickr, rendered in Enscape, Miyazaki, Nausicaa Ghibli, Breath of The Wild, 4k detailed post processing, artstation, rendering by octane, unreal engine"
SageMaker Endpoint로 JumpStart에서 제공한 Stable Diffusion 이미지 생성을 요청할 때 얻어진 응답(Response)은 아래와 같습니다. JSON 응답에는 "generated_image" 필드로 이미지의 RGB 정보를 전달합니다. 이를 클라이언트에서 활용하기 위해서는 이미지 포맷으로 변경하여야 합니다. 또한, SageMaker Endpoint로 Stable Diffusion 이미지 생성을 요청(Request)할 때에는 IAM 인증을 하여야 하므로, 클라이언트는 민감한 정보인 IAM Credential을 가지고 있어야 하고, AWS SDK를 통해 API 요청을 수행하여야 합니다. 따라서 웹브라우저 또는 모바일앱에서는 IAM 인증 기반의 서비스를 제공하기 어렵습니다. 이와 같은 이유로 본 게시글에서는 SageMaker Endpoint에 대한 IAM 인증 및 이미지 파일 변환을 위해 API Gateway와 Lambda를 사용합니다.
{
"generated_image": [
[[221,145,108],[237,141,98],[249,154,111],..]
...
],
"prompt": "{
predictions":[{
"prompt": "astronaut on a horse",
"width": 768,
"height": 512,
"num_images_per_prompt": 1,
"num_inference_steps": 50,
"guidance_scale": 7.5
}]
}
}
전체적인 Architecture는 아래와 같습니다. SageMaker는 JumpStart로 제공되는 Stable Diffusion 모델을 가지고 있어서 입력된 텍스트로 부터 이미지를 생성할 수 있습니다. Lambda는 IAM 인증을 통해 SageMaker Endpoint로 사용자가 전달한 텍스트 정보를 전달하고, 생성된 이미지의 정보를 image map 형태로 얻습니다. 사용자가 쉽게 사용할 수 있도록 image map은 S3에 JPEG 포맷으로 저장되는데, CloudFront 도메인 정보를 활용하여 이미지에 대한 URL을 생성합니다. API Gateway는 사용자의 요청을 Restful API로 받아서 Lambda에 사용자의 요청을 전달하고, Lambda가 생성한 URL 이미지 정보를 사용자에게 응답으로 전달합니다. 전체 서비스들의 배포는 AWS CDK를 이용하고, docker container 이미지는 ECR로 관리합니다.
Lambda에서 Sagemaker Endpoint로 추론(Inference) 요청시에 아래와 같이 "ContentType"과 "Accept"을 지정하여야 합니다.
"ContentType": "application/json",
"Accept": "application/json",
이때 Request의 Body에는 아래 포맷으로 Stable Diffusion에 필요한 정보를 전달합니다. width, height로 이미지의 크기를 지정하는데 8로 나눌 수 있어야 합니다. num_images_per_prompt은 한번에 생성되는 이미지의 갯수이고, num_inference_steps는 이미지 생성시 denoising 단계를 의미하는데 숫자를 높이면 더 높은 품질의 이미지를 얻을 수 있습니다. guidance_scale은 prompt에 가까운 정도를 표현합니다.
{
predictions":[{
"prompt": "astronaut on a horse",
"width": 768,
"height": 512,
"num_images_per_prompt": 1,
"num_inference_steps": 50,
"guidance_scale": 7.5
}]
}
lambda_function.py에서는 아래와 같이 요청을 수행합니다. Python의 boto3을 이용해 SageMaker Endpoint에 요청(request)을 전달하는데, ContentType은 "application/json"이고, Accept 헤더로는 "Accept='application/json" 또는 "Accept='application/json;jpeg"을 사용할 수 있습니다.
import boto3
runtime = boto3.Session().client('sagemaker-runtime')
response = runtime.invoke_endpoint(EndpointName=endpoint, ContentType='application/json', Accept='application/json;jpeg', Body=json.dumps(payload))
SageMaker Endpoint에 query시에 Accept을 "application/json"으로 하는 경우에 RGB로 된 text데이터가 내려옵니다. 이미지 데이터는 JSON의 "Body"와 "generated_image"로 부터 추출한 후에, PIL(pillow)과 numpy 라이브러리를 사용하여 S3에 저장할수 있는 바이너리 이미지 데이터로 변환합니다. 이때 lambda_function.py의 코드는 아래와 같습니다.
from PIL import Image
import numpy as np
def parse_response(query_response):
response_dict = json.loads(query_response)
return response_dict["generated_images"], response_dict["prompt"]
response_payload = response['Body'].read().decode('utf-8')
generated_image, prompt = parse_response(response_payload)
image = Image.fromarray(np.uint8(generated_images[0]))
buffer = io.BytesIO()
image.save(buffer, "jpeg")
buffer.seek(0)
s3 = boto3.client('s3')
s3.upload_fileobj(buffer, mybucket, mykey, ExtraArgs={ "ContentType": "image/jpeg"})
그런데, Lambda에서 pillow, numpy 라이브러리를 "pip install --target=[lambda 폴더] pillow numpy"와 같이 설치한 후 압축해서 올리면 layer를 추가하여야 하므로, docker container를 이용하여 pillow, numpy와 같은 라이브러리를 사용할 수 있도록 합니다. 이때의 Dockerfile의 예는 아래와 같습니다.
FROM amazon/aws-lambda-python:3.8
RUN pip3 install --upgrade pip
RUN python -m pip install joblib awsiotsdk
RUN pip install numpy pillow
WORKDIR /var/task/lambda
COPY lambda_function.py /var/task
COPY . .
CMD ["lambda_function.lambda_handler"]
Accept헤더를 "application/json;jpeg"로 설정하면 SageMaker Endpoint가 base64로 encoding된 JPEG 이미지를 전달합니다. 따라서 base64 decoding 후에 인메모리 바이너리 스트림으로 변경하여 S3로 업로드합니다.
response_payload = response['Body'].read().decode('utf-8')
generated_image, prompt = parse_response(response_payload)
import base64
img_str = base64.b64decode(generated_image)
buffer = io.BytesIO(img_str)
s3.upload_fileobj(buffer, mybucket, mykey, ExtraArgs={"ContentType": "image/jpeg"})
CDK 배포 준비에서는 CDK로 S3, Lambda, API Gateway, CloudFront를 배포하는 방법을 설명합니다.
Stable Diffusion Endpoint 생성에 따라 SageMaker JumpStart에서 Stable Diffusion Endpoint 생성합니다.
추론을 위한 인프라에는 API Gateway, S3, Lambda, CloudFront가 있으며, AWS CDK로 배포합니다. 상세한 배포정보는 cdk-stable-diffusion-stack.ts을 참조합니다. Cloud9을 생성하기 위하여 Cloud9 console에서 Create environment를 선택한 후에 아래처럼 Name을 입력합니다. 여기서는 "Stabel Diffusion"이라고 입력하였습니다. 이후 나머지는 모두 그대로 유지하고 [Create]를 선택합니다.
Cloud9이 생성된 후에 [Open]을 선택하여 진입한 후 아래처럼 터미널을 실행합니다.
이후 아래와 같이 관련 코드를 다운로드 합니다.
git clone https://github.com/kyopark2014/stable-diffusion-api-server
인프라 생성시 SageMaker의 Endpoint 정보가 필요하므로, 아래와 같이 좌측 파일탐색기에서 "cdk-stable-diffusion/lib/cdk-stable-diffusion-stack.ts"를 선택하여 이전 단계에서 복사한 Endpoint의 이름을 수정합니다.
CDK 폴더(cdk-stable-diffusion)로 이동하여 "aws-cdk-lib"와 "path" 라이브러리를 npm으로 설치합니다. 여기서, "aws-cdk-lib"은 CDK 2.0 라이브러리를 의미합니다.
cd cdk-stable-diffusion && npm install aws-cdk-lib path
아래 명령어로 전체 인프라를 설치합니다.
cdk deploy
CDK로 인프라 설치가 완료되면 아래와 같이 설치된 인프라의 정보를 알 수 있습니다. 여기서 appUrl은 Browser에서 query문을 이용해 API를 호출할때 사용할 수 있고, curlUrl은 shell에서 테스트 할 때 사용합니다.
실제 예는 아래와 같습니다.
CdkStableDiffusionStack.WebUrl = https://1r9dqh4f37.execute-api.ap-northeast-2.amazonaws.com/dev/text2image?prompt=astronaut
CdkStableDiffusionStack.curlUrl = curl -X POST https://1r9dqh4f37.execute-api.ap-northeast-2.amazonaws.com/dev/text2image -H "Content-Type: application/json" -d '{"text":"astronaut on a horse"}'
Browser에서 접속하는 방법은 아래와 같습니다. prompt에 쿼리할 문장을 입력합니다.
https://1r9dqh4f37.execute-api.ap-northeast-2.amazonaws.com/dev/text2image?prompt=astronaut on a horse
이때의 결과는 아래와 같습니다.
curl 명령어로 아래와 같이 실행할 수 있습니다.
curl -X POST https://1r9dqh4f37.execute-api.ap-northeast-2.amazonaws.com/dev/text2image -H "Content-Type: application/json" -d '{"text":"astronaut on a horse"}'
추론에 대한 결과의 예입니다. "body"에 추론의 결과로 생성된 이미지의 URL이 있습니다.
{"statusCode": 200, "body": "https://d283dvdglbetjo.cloudfront.net/img_20230208-014926"}
아래와 같이 POST 방식을 선택하고 URL을 입력합니다.
[Body] - [raw] 에서 JSON 형태로 입력합니다.
{
"text": "astronaut on a horse"
}
[Headers]에 아래와 같이 Conten-Type으로 application/json을 추가합니다.
이후 [Sent]를 선택하면 아래와 같은 결과를 얻습니다.
아래와 같이 입력하는 텍스트를 변경하면서 결과를 확인하여 보았습니다.
- ukrainian girl with blue and yellow clothes near big ruined building, concept art, trending on artstation, highly detailed, intricate, sharp focus, digital art, 8 k
- a portrait of a korean woman that is a representation of korean culture, buenos aires, fantasy, intricate, highly detailed, digital painting, artstation, concept art, smooth, sharp focus, illustration, art by artgerm and greg rutkowski and alphonse mucha
- "I see trees of green Red roses too. I see them bloom for me and you. And I think to myself. What a wonderful world" (Louis Armstrong's What a Wonderful World song!)
a young blonde male jedi with short hair standing still looking at the sunset concept art by Doug Chiang cinematic, realistic painting, high definition, concept art, portait image, path tracing, serene landscape, high quality, highly detailed, 8K, soft colors, warm colors, turbulent sea, high coherence, anatomically correct, hyperrealistic, concept art, defined face, five fingers, symmetrical
the eye of the storm, atmospheric, hyper realistic, 8k, epic composition, cinematic, octane render, artstation landscape vista photography by Carr Clifton & Galen Rowell, 16K resolution, Landscape veduta photo by Dustin Lefevre & tdraw, 8k resolution, detailed landscape painting by Ivan Shishkin, DeviantArt, Flickr, rendered in Enscape, Miyazaki, Nausicaa Ghibli, Breath of The Wild, 4k detailed post processing, artstation, rendering by octane!
Generate images from text with the stable diffusion model on Amazon SageMaker JumpStart
Amazon SageMaker JumpStart로 사전 구축된 모델과 기계 학습 솔루션 액세스 단순화
Introduction to JumpStart - Text to Image
SageMaker Endpoint (Single Model Endpoint)
Build and automatize the management of your Sagemaker Studio Users using AWS CDK
Deploying SageMaker Endpoints With CloudFormation