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 deployCDK๋ก ์ธํ๋ผ ์ค์น๊ฐ ์๋ฃ๋๋ฉด ์๋์ ๊ฐ์ด ์ค์น๋ ์ธํ๋ผ์ ์ ๋ณด๋ฅผ ์ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์ 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














