Streamlit + Bedrock SDXL 로 GPU 없이 이미지 생성하기
2024년 02월 05일 작성TL;DR
코드는 여기1
시작하며
얼마전에 M1 맥북에서 SDXL-Turbo 모델을 사용해서 이미지를 생성하는 방법을 소개 했었다.2
이 방법도 나쁘지 않지만, 도커랑 이것저것 띄운 M1 16GB 맥북에게는 상당히 부담스러운 작업이었다.
좀 더 가벼운 환경을 위해, Amazon Bedrock SDXL 을 통해 로컬에서 이미지를 생성하는 방법을 소개한다.
Streamlit
원래 생성형 AI 프로젝트 데모를 UI 로 보여줄 때 가장 많이 사용하는 라이브러리는 Gradio 일 것이다. Streamlit 은 원래 데이터 분석 결과물을 보여주기 위한 라이브러리이지만, 최근에 서드파티 컴포넌트를 지원하면서 생성형 AI 프로젝트에도 많이 사용하는 것 같다.
이 정도로 간단한 예제는 둘 중 뭘 써도 상관없지만, 개인적으로는 Streamlit 이 Gradio 보다 약간 더 예쁘고 데이터 분석 결과물을 같이 보여주기에도 좋아서 자주 사용한다.
streamlit 은 pip 로 설치하고 이후,
$ pip install streamlit
CLI 로 파이썬 모듈을 실행할 수 있다.
$ streamlit run app.py
Bedrock SDXL
Amazon Bedrock 에는 SDXL 0.8 과 1.0 두 버전을 지원한다. 0.8은 없다고 생각하면 된다. 1.0 버 전을 사용하자.
또한 현재 Amazon Bedrock 은 서울 리전에서는 지원되지 않으므로, 여기서는 us-east-1 리전을 사용한다. (이와 별개로 g5 인스턴스가 서울리전에 할당실패가 자주 일어 나므로, 생성형 AI 를 파인튜닝한다면 us-east-1 에서 학습을 하고 서울 리전으로 모델을 복사하는 것이 좋다.)
SDXL 을 사용하기 위해서는 먼저 Amazon Bedrock 에서 모델을 활성화해야 한다. 웹 콘솔 의 i Model access 페이지에서 Manage model access
버튼을 클릭한다.
그리고 SDXL 1.0 모델을 선택하고 Save changes
버튼을 클릭한다.
위의 과정은 마켓플레이스에서 모델을 구독하는 과정을 대신해주는 거라고 생각하면 된다.
사실 이 후부터는 웹 콘솔의 Playground 에서 모델을 생성할 수도 있지만 streamlit 을 통하면 훨씬 재미있는 것들을 많이 할 수 있다.
Streamlit + Bedrock SDXL
전체 코드는 여기1 에서 확인할 수 있고, 해당 코드는 다양한 언어로 된 프롬프트를 지원하는 Amazon Bedrock SDXL 기반 UI 를 제공하는 예제이다.
Amazon Bedrock SDXL 은 한글 프롬프트를 인식하지 못한다. 그래서 한글로 된 프롬프트를 사용하려면 적절히 영어로 번역해줘야 한다.
Amazon Bedrock 의 Claude 를 통해 번역을 할수도 있겠지만, Amazon Translate 를 사용해서 번역하는 것이 더 비용효율적이므로 여기서는 Amazon Translate 를 사용한다.
streamlit 특성상 코드가 매우 직관적이고 간단하다. 따라서 여기서는 특이한 부분 한두개만 소개하고 넘어간다.
Amazon Translate 로 다국어 번역하기
영어가 아닌 글자가 포함되어 있을 때만 번역을 하도록 만들었다. 소스 언어를 auto
로 하면 자동으로 언어를 인식해서 번역해준다.
...
pattern = re.compile(r'[^a-zA-Z0-9 ,.]+')
# if text does contains only English letters, return as is
if not pattern.search(text):
print('text is in English')
return text
else:
L = []
for t in text.split(', '):
response = self.client.translate_text(
Text=t.strip(),
SourceLanguageCode="auto",
TargetLanguageCode=target_language,
)
L.append(response.get("TranslatedText", ""))
return ', '.join(filter(None, L))
글로벌 네거티브 프롬프트 사용하기
civit.ai2 같은 서비스에서 다양한 프롬프트와 네거티브 프롬프트를 찾을 수 있다.
프롬프트는 엄청 다양하기 때문에 글로벌 프롬프트라고 부를만한 내용이 없지만, 네거티브 프롬프트는 어느정도 통용되는 내용이 있다.
여기서는 다음과 같이 잘 알려진 공용 네거티브 프롬프트를 사용했다.
image = None
with st.spinner("Generating image based on prompt"):
image = sdxl.generate_image_from_prompt(
prompt=prompt,
negative_prompts=[
'ugly,', 'tiling,', 'poorly', 'drawn', 'hands,',
'poorly', 'drawn', 'feet,', 'poorly', 'drawn',
'face,', 'out', 'of', 'frame,', 'extra', 'limbs,',
'disfigured,', 'deformed,', 'body', 'out', 'of',
'frame,', 'bad', 'anatomy,', 'watermark,', 'signature,',
'cut', 'off,', 'low', 'contrast,', 'underexposed,',
'overexposed,', 'bad', 'art,', 'beginner,', 'amateur,',
'distorted', 'face',
],
)
st.success("Generated stable diffusion model")
if image:
st.image(image)
테스트
이제 streamlit 을 실행하고,
$ streamlit run app.py
웹브라우저에서 http://localhost:8501
로 접속하면 다음과 같은 화면을 볼 수 있다.
왼쪽 사이드바에서 원하는 프롬프트를 선택해보거나, 아무 언어로 프롬프트를 직접 입력해보자.
한글예제
...
source: 검은색 대리석 벽과 타일로 구성된 럭셔리한 화장실
translated: Luxurious bathroom with black marble walls and tiles
일본어예제
...
source: 黒い大理石の壁とタイルで構成された豪華なトイレ
translated: Luxurious toilet with black marble walls and tiles
마치며
위에 이미지들의 하단은 캡쳐하는 과정에서 잘린 것이다. 원본은 깨끗하게 바닥까지 내려가는 이미지이다.