AI 체험존 인터페이스 구축 일지

석준·2024년 5월 14일
0

캡스톤디자인

목록 보기
9/9
post-thumbnail

지난 여름부터 캡스톤디자인 팀원 3명과 만들고 있는 AI 체험 웹서비스 "mAIt"가 드디어 윤곽을 드러냈다.

나는 총 3가지의 주요 기능 중 "이미지 변환" 부분을 담당했고, "InstructPix2Pix" 라는 딥러닝 모델을 Flask를 활용하여 서빙하였다. ( Flask로 InstructPix2Pix 모델 서빙하기 )

모델 inference time 개선, 백엔드 통합, 그리고 프론트엔드와 연결하는 과정에서 있었던 이슈들을 정리해 보았다.


모델 Inference Time 개선하기

약 500KB의 jpg 파일 1개를 변환하는 데 무려 20분이 소요된다는 문제점이 있었다.

캡스톤 디자인 전시회에서 실시간 시현이 필요하고, 더 나아가 서비스를 런칭한다면 이 정도의 소요 시간은 치명적이다.

값비싼 GPU 서버를 사용할 수 없는 현실 속에서 모델의 Inference Time 개선이 필요했다.

1. num_inference_steps 줄이기

num_inference_steps는 이미지 생성 과정 중에 수행할 추론 단계의 횟수를 결정하며, 높은 값을 넣을수록 일반적으로 더 정교하고 세밀한 결과를 얻을 수 있지만, 계산 비용이 많이 든다는 단점이 있다.

num_inference_steps가 8일 때 가장 좋은 퀄리티의 사진이 나왔지만, 시간을 줄이기 위해 추론의 횟수를 줄여 보았다.

다음은 7로 줄였을 때의 소요 시간과 퀄리티 비교이다.


num_inference_steps: 8 -> 18분 49초

num_inference_steps: 7 -> 15분 24초

시간은 3분 25초 줄어들었고, 결과물의 퀄리티는 확연히 떨어졌다.

줄어드는 시간 대비 결과물이 좋지 않아서 적절한 해결책이 될 수 없었다.


2. 사진 자체의 용량 낮추기

사진 용량에 따라 추론 시간이 달랐다.

num_inference_steps 8을 기준으로 500KB에서는 20분, 200KB에서는 10분, 50KB에서는 8분이 걸렸다.

따라서 퀄리티에 많은 영향을 주지 않는 선에서 자체적으로 사진의 품질을 낮추는 코드를 추가했다.

import PIL

def save_image(image, folder, quality=None):
    unique_filename = str(uuid.uuid4()) + '.jpg'
    file_path = os.path.join(app.config[folder], unique_filename)
    if quality is not None:
        image.save(file_path, quality=quality)
    else:
        image.save(file_path)
    return file_path
    
uploaded_image_path = save_image(load_image(file), 'UPLOAD_FOLDER', quality=50)

Python Imaging Library (PIL)의 Image 클래스를 사용하여 사진을 서버에 임시로 저장한다.

이때, image.save()의 quality 매개변수를 통해 쉽게 사진의 퀄리티를 조절할 수 있다.

디폴트 값이 75%이므로, 나는 50%까지 퀄리티를 낮추도록 조정했다.

500KB의 jpg 파일 기준으로 소요 시간은 약 5분이 줄어들었고, 결과물의 퀄리티는 육안으로 비교했을 때 거의 차이가 없을 정도였다.

따라서, 이 방법을 채택했다.


성능을 낮추는 방식으로 Inference Time을 줄이긴 했지만 하드웨어의 개선이 필요하다고 느꼈다.

CPU 성능이 두 배 정도 차이 나는 다른 친구의 랩탑에서 같은 사진을 변환해 본 결과 10분에서 3분으로 확연하게 시간이 줄어들었다.

가능하다면 GPU를 탑재한 서버를 구하는 것이 좋을 것 같다...


백엔드 통합 및 프론트엔드와 연결

프론트엔드 담당 팀원이 구성한 React 기반의 페이지에 Flask를 연결하기 위해 약간의 수정이 필요했다.

먼저, "이미지 변환", "맞춤형 뉴스", "챗봇"을 3명이 각자 구현했기 때문에 하나의 파일에서 배포하기 위해 합치는 것이 필요했다.

후술하겠지만, 이 과정에서 어려움이 많았는데 특히 챗봇을 연결할 때 많은 에러 메시지와 직면했다.

1. 결과 이미지 전달 및 표시

이미지 변환 결과 이미지를 어떻게 전달하고 표시할지 고민이 많았다.

나는 모델이 생성한 이미지를 서버에 저장한 다음, URL을 생성하여 프론트에 반환하고 결과 페이지로 넘어감과 동시에 URL을 통해 결과 이미지를 보여주는 방식을 구상했다.

따라서, 백엔드에서 넘겨준 URL을 받으면 그 URL과 함께 결과 페이지로 넘어가야 했다.

기존에 Link 컴포넌트로 구현되어 있던 페이지 이동을 useNavigate 컴포넌트를 사용하여 쉽게 수정할 수 있었다.

  const handleSubmit = async () => {
    setIsLoading(true);

    const formData = new FormData();
    formData.append('file', image);
    formData.append('prompt', concept.toString());
  
    try {
      const response = await fetch('http://localhost:50/ImageConversion', {
        method: 'POST',
        body: formData,
      });
      const result = await response.json();

      navigate('/Pages/Generator/Output', { state: { imageUrl: result.image_url } });

이미지 변환하기 버튼을 누르면 handleSubmit 함수가 호출이 되고 file, propt를 POST 방식으로 전송한다.

결과 이미지의 URL이 반환되면 navigate()를 사용하여 페이지를 이동함과 동시에 state에 URL을 담아서 해당 페이지로 넘겨준다.

그러면 위와 같이 사진이 표시된다! 다운로드 기능도 추가해서 사용자가 쉽게 사진을 다운로드 할 수 있게 하였다.

2. CORS 오류

Access to fetch at 'http://localhost:50/message' from origin
'http://localhost:3000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the
requested resource. If an opaque response serves your needs,
set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

챗봇을 프론트와 연결하는 도중에 위와 같은 에러메시지를 받았다.

CORS라는 용어를 처음 들어봐서 구글링을 통해 찾아보았다.

CORS(Cross-Origin Resource Sharing)는 웹 브라우저에서 실행되는 스크립트가 다른 도메인의 자원에 접근할 수 있는 권한을 부여하는 보안 기능이라고 한다.

from flask_cors import CORS

CORS(app)

위의 코드로 간단히 해결할 수 있었지만 CORS에 대해서 더 자세히 알아볼 필요가 있을 것 같다.

다음 포스팅으로 CORS에 대해 공부하고 정리해 보겠다.

3. POST 요청 오류

챗봇에서 메시지를 전송했을 때 답을 주지 않고 다음과 같이 에러 메시지를 주었다.

POST http://localhost:50/message 500 (INTERNAL SERVER ERROR)

message 함수 내부에서 발생한 예외로 인해 오류가 발생했다고 가정하고 다음과 같이 try-except 블록을 사용하여 단계별로 예외처리를 강화했다.

    try:
        response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=conversation
        )
    except Exception as e:
        return jsonify({'error': f'OpenAI API 호출 중 오류 발생: {str(e)}'}), 500

그때, openai.ChatCompletion.create 호출 부분에서 오류를 반환했다.

File "C:\Users\82102\Desktop\image_editing\serving.py", line 169, in message
response = openai.ChatCompletion.create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\82102\Desktop\image_editing.venv\Lib\site-packages\openai\lib_old_api.py", line 39, in call
enai-python for the API.
You can run openai migrate to automatically upgrade your codebase to use the 1.0.0 interface.
Alternatively, you can pin your installation to the old version, e.g. pip install openai==0.28
A detailed migration guide is available here: https://github.com/openai/openai-python/discussions/742

OpenAI의 Python SDK의 구버전을 사용하고 있으며, 이를 최신 버전으로 업그레이드해야 한다고 친절하게 알려주었다.

그러나, Windows에서는 OpenAI의 마이그레이션 CLI 도구를 사용할 수 없기 때문에 pip install openai==0.28 명령어를 사용하여 수동설치 하는 것으로 문제를 해결했다.


현재 프론트와 백엔드를 로컬에서 연결하는 데 성공했고 디테일한 수정을 계속 진행하고 있다.

또한, GPU가 탑재된 컴퓨터에서 Docker를 사용하여 배포할 예정이다.

끝까지 마무리 잘 해보자!

profile
ERICA SW 19

0개의 댓글