소이뉴스

인공지능의 활용 - 나만을 위한 맞춤형 서비스

7thfloor 2023. 7. 21. 15:23

본 글은 소이넷에서 발행하는 뉴스레터 메일인 소이뉴스에 게재했던 내용을 담고 있습니다.

메일 구독을 원하시는 분은 구독링크를 통해 신청해 주세요.

 

AI 서비스, 너무 멀게 느껴지지 않으신가요?

공개되어 있는 AI 모델들은 많지만 이를 이용해서 브라우저나 모바일 폰에서

실제로 동작하는 것을 보려면 이것저것 고민해야 할 것들이 많이 있죠?

이럴 때 간단하게 활용할 수 있는 팁을 소개해 드릴게요.

 


SoyNet을 이용한 초간단 AI 웹앱 만드는 방법


 

Gradio는 뭔가요?

 

Gradio는 머신러닝이나 Data Science를 위한 데모나 웹 앱을 빌드하는 데 사용되는 오픈소스 Python 라이브러리입니다. 덕분에 웹 개발과 관련된 상세 지식이 없더라도 짧은 python 코드만으로도 데모나 기능 확인을 위한 웹 앱을 손쉽게 만들 수 있습니다. Gradio에 대한 상세한 내용은 여기를 참조하세요.

 

SoyNet은 어떤 역할을 하나요?

 

Gradio는 웹앱을 위한 틀을 제공할 뿐 실제 AI 서비스를 위해서는 딥러닝 모델의 추론 코드가 필요한데 이번 예시에서는 SoyNet으로 최적화된 Yolov5s 모델을 이용해서 '간단한 객체 감지기 웹앱'을 만들어 볼 생각입니다. 물론 소이넷의 Model Market 상에 등록된 다른 다양한 모델들을 이용해도 됩니다.

개인적인 생각으론, SoyNet을 사용할 경우, 딥러닝 모델 세부 코드를 다룰 필요가 없기 때문에 Gradio의 컨셉과 잘 맞아 떨어진다고 할 수 있겠습니다. ^^

 

만들어진 결과물은 어떤 모양인가요?

 

Gradio를 이용하면 본 예제처럼 이미지 뿐만 아니라 텍스트나 기타 다른 데이터 형태를 이용한 웹앱도 다양하게 만들 수 있습니다. 여기서는 가장 간단한 형태의 구현 예시만 보여 드리는 것이 목표라 다른 예는 향후 새로운 뉴스레터에서 소개해 드릴게요. 화면 좌측이 입력, 우측이 추론 결과가 표시되는 형태인데 흠... 역시 SoyNet이 적용되어 그런지 빠르군요... ^^;

 

 

 

만드는 과정이 복잡할 것 같은데 그렇지 않나요?

 

웹 앱, 특히나 인공지능 모델을 이용한 웹 앱의 경우는 구현하는 것이 쉽지 않습니다. 기본적으로 다뤄야 하는 기술과 S/W, 언어 등이 제각각이기 때문이죠. 하지만 Gradio와 SoyNet의 조합은 이런 복잡한 과정을 단순화시켜 줍니다.

모델의 다운로드에서부터 진행하는 과정은 블로그에 간단하게 소개되어 있으니 꼭 한번 읽어보시기 바랍니다.

 

이렇게 만들려면 코드가 많이 복잡하지 않나요?

 

그렇지 않습니다. SoyNet이나 Gradio 둘 다 단순함을 추구하기 때문입니다.

SoyNet은 딥러닝 모델 구조와 실행의 복잡함, Gradio는 웹 앱 개발 코드의 복잡함을 없애줍니다. 우리는 그걸 이용해서 만드는 것이죠.

 

그럼 실제 사용되는 코드를 보여주시겠어요?

 

실제 사용되는 코드는 아래와 같습니다. SoyNet 핸들의 초기값 설정하는 부분과 추론결과로 감지된 물체에 박스 그리는 작업 등을 제외하고는 십여줄 남짓 밖에 안 됩니다. (볼드체 참조)

 

import cv2 as cv
import sys
import numpy as np
import gradio as gr

sys.path.append('../')

from include.SoyNet import *

from utils.ClassName import COCO_80
class_names = COCO_80()

# gradio interface에서 사용할 fucntion 정의 
def predict(img):
    resized_img = cv.resize(img, (input_width, input_height))

    # 추론결과 output 데이터 형식정의
    data_type = np.dtype([("x1", c_float), ("y1", c_float), ("x2", c_float), ("y2", c_float),
                            ("obj_id", c_int), ("prob", c_float)])
    output = np.zeros(batch_size * nms_count, dtype=data_type)

    # SoyNet을 이용한 객체감지 추론
    feedData(handle, resized_img)
    inference(handle)
    getOutput(handle, output)

    # 감지결과 화면 표시
    threshold = 0.6
    for n_idx in range(nms_count):
        x1, y1, x2, y2, obj_id, prob = output[n_idx]
        if prob > threshold:
            x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
            cv.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
            cv.putText(img, class_names[obj_id], (x1, y1 - 3), 1, 1.5, (255, 0, 0), 1, cv.LINE_AA)
    return img

if __name__ == "__main__":
    # SoyNet 핸들 생성을 위한 초기값 설정 
    engine_serialize = 0  

    batch_size = 1
    region_count = 1000
    nms_count = 100
    class_count = len(class_names)
    input_height, input_width = 720, 1280
    model_size = 640

    model_name = "yolov5s"
    cfg_file = "../models/Yolov5-6.1-s/configs/{}.cfg".format(model_name)
    weight_file = "../models/Yolov5-6.1-s/weights/{}.weights".format(model_name)
    engine_file = "../models/Yolov5-6.1-s/engines/{}.bin".format(model_name)
    log_file = "../models/Yolov5-6.1-s/logs/{}.log".format(model_name)

    extend_param = \
        "MODEL_NAME={} BATCH_SIZE={} ENGINE_SERIALIZE={} CLASS_COUNT={} NMS_COUNT={} REGION_COUNT={} " \
        "INPUT_SIZE={},{} MODEL_SIZE={},{} " \
        "WEIGHT_FILE={} ENGINE_FILE={} LOG_FILE={}".format(
            model_name, batch_size, engine_serialize, class_count, nms_count, region_count,
            input_height, input_width, model_size, model_size,
            weight_file, engine_file, log_file
        )

    # SoyNet 핸들 생성
    handle = initSoyNet(cfg_file, extend_param)

    # Gradio Interface 생성
    demo = gr.Interface(
        fn=predict,
        inputs="image",
        outputs="image",
        title='SoyNet gradio Demo',
        description='This is gradio demo using SoyNet inference engine.',
        examples=['examples/NY_01.png','examples/NY_02.png'],
    )
    try:
        demo.launch()
    except KeyboardInterrupt:
        # SoyNet 핸들 해제
        freeSoyNet(handle)

 

객체감지 말고 다른 모델에도 적용해 보고 싶은데 가능한가요?

 

샘플로 Gradio를 적용한 사례를 몇 가지 더 소개합니다. 모델에 따라 입출력을 처리하는 방식만 약간씩 다를 뿐 전반적으로 Gradio를 사용하는 방식을 동일합니다 .

 

Gradio 외에는 이렇게 할 수 있는 방법이 없나요?

 

Gradio 외에도 Streamlit 등과 같은 라이브러리들이 공개되어 있습니다. 하지만 이런 것들이 적은 코드로 손쉽게 만들 수 있도록 해 주는 도구이다 보니 상용 서비스나 어플리케이션 용보다는 데모나 PoC 용으로 활용하는 편이 더 좋지 않을까 싶습니다. 물론 그건 응용해서 사용하는 개발자의 역량에 달려 있겠죠? ^^