안녕하세요! 오늘은 Nvidia의 최신 소프트웨어 기술 NIM(Nvidia Inference Microservices)에 대해 알아보겠습니다. 최근 AI 기술이 급속도로 발전하면서, 대형 언어 모델(LLMs)을 활용한 다양한 애플리케이션들이 등장하고 있는데요, 이러한 모델을 실제 환경에 배포하고 최적화하는 과정은 복잡하고 많은 시간과 비용이 소요됩니다. NIM은 생성 AI 모델의 배포를 단순화하고 최적화하여, 누구나 쉽게 AI 기술을 활용할 수 있도록 도와줍니다. 이번 블로그에서는 NIM이 무엇인지, 어떤 주요 기능을 제공하는지, 그리고 실제 애플리케이션 테스트 결과를 통해 NIM의 성능을 살펴보겠습니다.
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
NIM 개요
Nvidia Inference Microservices(NIM, 엔비디아 추론 마이크로서비스)는 Nvidia가 도입한 최신 소프트웨어 기술로, 추론 엔진, 표준 API 및 AI 모델 지원을 하나의 컨테이너에 패키징하여 사용자가 생성 AI 대형 언어 모델(LLMs)의 배포를 더욱 빠르고 효율적으로 활용할 수 있도록 합니다. 이 컨테이너는 클라우드, 서버리스 환경, 로컬 서버 등 다양한 환경에서 작동할 수 있으며, 생성 AI의 배포 및 관리에 필요한 모든 도구와 기술을 제공합니다.
NIM은 클라우드, 온프레미스, 로컬 워크스테이션 등 다양한 인프라에서 유연하게 배포 가능하며, 표준화된 API를 통해 손쉽게 AI 모델에 접근하고 애플리케이션을 개발할 수 있습니다. 언어 처리, 음성 인식, 비디오 처리, 헬스케어 등 도메인별 최적화된 모델을 제공하고, 최적화된 추론 엔진을 활용하여 성능을 극대화합니다.
- 어디서나 배포 가능: NIM은 클라우드, 온프레미스 데이터 센터, 로컬 워크스테이션 등 다양한 인프라 환경에서 유연하게 모델을 배포할 수 있습니다. 특히 NVIDIA 하드웨어 플랫폼에서 최적의 성능을 발휘하며, 사전 빌드된 컨테이너를 통해 손쉽게 배포가 가능합니다.
- 산업 표준 API 사용: NIM은 표준화된 API를 제공하여 개발자들이 쉽게 AI 모델에 접근하고 애플리케이션을 개발할 수 있게 합니다. 최소한의 코드 변경으로 AI 애플리케이션을 빠르게 업데이트할 수 있어, 신속한 통합과 확장이 가능합니다.
- 도메인별 최적화 모델 제공: NIM은 언어 처리, 음성 인식, 비디오 처리, 헬스케어 등 다양한 도메인에 특화된 최적화된 NVIDIA CUDA 라이브러리와 코드를 포함합니다. 이를 통해 도메인별 정확하고 관련성 높은 애플리케이션을 개발할 수 있습니다.
- 최적화된 추론 엔진 사용: NIM은 각 모델과 하드웨어 설정에 최적화된 추론 엔진을 활용하여 지연 시간과 처리량을 최적화합니다. 이는 대규모 추론 워크로드의 비용을 줄이고 사용자 경험을 향상시킵니다. 또한 사용자 지정 데이터 소스를 통해 모델의 정확도와 성능을 더욱 향상시킬 수 있습니다.
- 엔터프라이즈급 AI 지원: NIM은 엔터프라이즈급 기본 컨테이너를 기반으로 하여 엄격한 검증, 서비스 수준 계약(SLA) 지원, 정기적인 보안 업데이트 등을 제공합니다. 이를 통해 프로덕션 환경에서 효율적이고 확장 가능한 AI 애플리케이션을 배포할 수 있습니다.
- 다양한 AI 모델 지원: NIM은 커뮤니티 모델, NVIDIA AI Foundation 모델, 커스텀 AI 모델을 포함하여 다양한 AI 모델을 지원합니다. 이를 통해 언어, 비전, 음성, 이미지, 비디오, 약물 발견, 의료 영상 등 여러 도메인에서 AI 애플리케이션을 개발할 수 있습니다.
https://build.nvidia.com/explore/discover
NIM 주요 기능
NIM(엔비디아 추론 마이크로서비스)은 Nvidia의 GPU 가속 기술을 활용하여 인공지능(AI) 모델의 추론(inference) 작업을 수행하는 마이크로서비스로서, 각각의 서비스를 작은 독립적인 서비스로 나누어 개별적으로 배포하고 관리할 수 있도록 지원하며, 주요 기능은 다음과 같습니다:
- 컨테이너화된 마이크로서비스: NIM은 Nvidia GPU가 있는 모든 환경에서 실행될 수 있는 모델을 포함한 컨테이너 형태로 제공됩니다. 이는 클라우드, 로컬 서버, 서버리스 환경 등에서 유연하게 사용될 수 있습니다.
- 프리빌트 모델과 사용자 정의 데이터 지원: NIM은 사전 빌드된 모델을 제공하며, 사용자가 자신만의 데이터를 추가하여 맞춤형 AI 모델을 생성할 수 있도록 지원합니다. 이는 Retrieval Augmented Generation(RAG) 배포를 가속화하는 데 중요한 역할을 합니다.
- 높은 최적화 수준: NIM은 Tensor RT와 Triton Inference Server와 같은 Nvidia의 기존 추론 지원 도구들을 통합하여, 생성 AI 모델을 대규모로 운영하기 위한 최적의 환경을 제공합니다.
- RAG 지원: NIM은 RAG 배포 모델을 지원하여 데이터 검색과 통합을 최적화합니다. Nvidia NeMo Retriever 마이크로서비스를 통해 가속화된 데이터 검색을 가능하게 하여 높은 품질의 데이터를 빠르게 사용할 수 있습니다.
NIM 서비스는 다음과 같은 장점을 제공합니다:
- 확장성: - 마이크로서비스 아키텍처를 사용하여 서비스의 개별 구성 요소를 독립적으로 확장할 수 있습니다.
- 유연성: - 다양한 AI 모델과 프레임워크를 지원하며, 필요에 따라 쉽게 업데이트하거나 교체할 수 있습니다.
- 관리 용이성: - 각 마이크로서비스는 독립적으로 배포 및 관리되므로, 전체 시스템의 복잡성을 줄일 수 있습니다.
NIM의 구성 요소는 다음과 같습니다.
- 모델 서버: AI 모델을 호스팅 하고 추론 요청을 처리하는 서버입니다.
- API 게이트웨이: 외부 클라이언트가 추론 서비스를 호출할 수 있도록 API를 제공합니다.
- 로드 밸런서: 여러 인스턴스에 대한 추론 요청을 분산 처리하여 성능과 가용성을 높입니다.
- 모니터링 및 로깅: 서비스의 상태와 성능을 모니터링하고, 로그를 수집하여 문제를 진단하고 해결합니다.
이러한 구성 요소를 통해 Nvidia 추론 마이크로서비스는 다양한 AI 애플리케이션에서 효율적이고 확장 가능한 추론 서비스를 제공할 수 있습니다.
NIM 테스트
NIM의 실제 성능과 활용 가능성을 알아보기 위해 LLAMA3 70b 대화앱과 KOSMOS 이미지인식 앱 두 가지 애플리케이션을 테스트해 보았습니다:.
LLAMA3 70b 대화앱 테스트
LLAMA3 70b 대화앱은 NIM을 활용한 자연어 처리 애플리케이션입니다. 이 앱은 사용자와 실시간으로 대화하며, 다양한 질문에 대한 답변을 제공할 수 있습니다. NIM의 최적화된 추론 엔진을 통해, LLAMA3 대화앱은 빠르고 정확한 응답을 제공할 수 있습니다.
LLAMA3 70b 대화앱의 테스트방법은 다음과 같습니다. 이 블로그의 테스트 환경은 Windows 11 Pro(23H2), 파이썬 버전 3.11, 비주얼 스튜디오 코드(이하 VSCode) 1.89.1, CPU i9-13900H, 2.60 GHz, RAM 16GB, GPU RTX4060입니다.
1. 샘플코드 확인 및 API Key 생성: 아래 링크에서 LLAMA3 70b 대화앱 샘플코드를 확인하고 API Key를 생성합니다.
https://build.nvidia.com/meta/llama3-70b
2. 가상환경생성 및 의존성 설치: 아래 명령어로 VSCode에서 가상환경을 만들고 활성화한 후, 의존성을 설치합니다.
conda create -n nim python=3.11
conda activate nim
pip install aiohttp gradio
3. 코드작성: LLAMA3 70b 대화앱은 NIM 샘플코드를 기반으로 gradio 인터페이스 및 비동기 설정을 추가하여, 제가 여러 번의 디버그를 거쳐 작성하였으며, 코드사용 시 출처를 표시해 주세요.
import aiohttp
import asyncio
import gradio as gr
import json
# NVIDIA API 키 설정
api_key = "발급받은 API Key"
base_url = "https://integrate.api.nvidia.com/v1/chat/completions"
async def generate_response(user_input):
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"model": "meta/llama3-70b-instruct",
"messages": [{"role": "user", "content": user_input}],
"temperature": 0.5,
"top_p": 1.0,
"max_tokens": 1024,
"stream": True
}
async with aiohttp.ClientSession() as session:
async with session.post(base_url, json=payload, headers=headers) as response:
async for line in response.content:
if line:
decoded_line = line.decode("utf-8").strip()
if decoded_line.startswith("data: "):
data = decoded_line[len("data: "):]
if data.strip() == "[DONE]":
break
else:
json_data = json.loads(data)
if 'choices' in json_data and len(json_data['choices']) > 0:
delta = json_data['choices'][0]['delta']
if 'content' in delta:
yield delta['content']
def process_input(user_input):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
generator = generate_response(user_input)
response = ""
try:
while True:
partial = loop.run_until_complete(generator.__anext__())
response += partial
yield response
except StopAsyncIteration:
pass
iface = gr.Interface(
fn=process_input,
inputs=gr.Textbox(label="Enter your message:", lines=1, placeholder="Type a message and press Enter"),
outputs="text",
title="Chat with NVIDIA API",
description="Enter your message to chat with the NVIDIA API.",
live=False
)
if __name__ == "__main__":
iface.launch()
위 프로그램은 사용자가 Gradio 인터페이스를 통해 NVIDIA API와 상호작용할 수 있도록 하는 애플리케이션입니다. 프로그램의 동작 순서는 다음과 같습니다:
- 1. 프로그램이 실행되면 Gradio 인터페이스가 웹 브라우저에 표시됩니다.
- 2. 사용자는 텍스트 상자에 메시지를 입력하고 엔터 키를 눌러 제출합니다.
- 3. 사용자의 입력은 `process_input` 함수로 전달됩니다.
- 4. `process_input` 함수는 새로운 이벤트 루프를 생성하고, `generate_response` 비동기 함수를 실행합니다.
- 5. `generate_response` 함수는 NVIDIA API에 HTTP POST 요청을 보냅니다. 요청에는 사용자의 메시지와 모델 설정이 포함됩니다.
- 6. API 응답이 스트리밍 되기 시작하면, `generate_response` 함수는 응답 스트림을 읽고 각 줄을 처리하여 텍스트 데이터를 추출합니다.
- 7. 텍스트 데이터가 추출되면 `process_input` 함수로 전달됩니다.
- 8. `process_input` 함수는 스트리밍 된 텍스트 데이터를 연결하여 최종 응답을 생성하고, 이를 실시간으로 Gradio 인터페이스에 표시합니다.
- 9. 사용자는 Gradio 인터페이스에서 API의 응답을 확인할 수 있습니다.
NIM을 활용한 대화앱은 아래 동영상과 같이 지연 없이 빠르게 동작하는 것을 확인할 수 있었습니다.
llama3 70b 대화앱 |
KOSMOS 이미지인식 앱 테스트
KOSMOS 이미지인식 앱은 NIM을 활용한 이미지 인식 애플리케이션입니다. 이 앱은 이미지를 분석하여 객체를 식별하고, 해당 객체에 대한 정보를 제공할 수 있습니다. 마이크로소프트에서 개발한 KOSMOS-2 모델은 텍스트를 시각적 세계에 연결하여 이미지 내의 시각적 요소를 이해하고 추론할 수 있도록 설계된 다중모달 대형 언어 모델(MLLM)입니다.
https://build.nvidia.com/microsoft/microsoft-kosmos-2
이미지 인식앱의 코드도 NIM의 샘플코드를 바탕으로 제가 여러 번의 디버그를 거쳐 작성하였으며, 입력 이미지 크기조정과 이미지 설명 텍스트의 배경색 설정을 추가하였습니다. 코드사용 시에는 출처를 표시해 주세요.
import os
import base64
import requests
import gradio as gr
from PIL import Image
import matplotlib.pyplot as plt
from random import randint
api_key = "발급받은 API Key"
# Function to resize image if larger than a given size and reduce quality
def resize_image(image_path, max_size=(400, 400), quality=50):
image = Image.open(image_path)
if image.size[0] > max_size[0] or image.size[1] > max_size[1]:
image.thumbnail(max_size, Image.LANCZOS)
resized_path = "resized_" + os.path.basename(image_path).split('.')[0] + ".jpg"
image = image.convert("RGB") # Ensure image is in RGB mode for JPEG
image.save(resized_path, format="JPEG", quality=quality)
return resized_path
# Function to invoke NVIDIA API and get the response
def get_nvidia_response(image_path, api_key, prompt):
invoke_url = "https://ai.api.nvidia.com/v1/vlm/microsoft/kosmos-2"
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
# Print the length of the base64 string for debugging
print("Length of base64 string:", len(image_b64))
assert len(image_b64) < 180_000, \
"To upload larger images, use the assets API (see docs)"
headers = {
"Authorization": f"Bearer {api_key}",
"Accept": "application/json"
}
payload = {
"messages": [
{
"role": "user",
"content": f'{prompt} <img src="data:image/jpeg;base64,{image_b64}" />'
}
],
"max_tokens": 1024,
"temperature": 0.20,
"top_p": 0.20
}
response = requests.post(invoke_url, headers=headers, json=payload)
# Print response content for debugging
print("Response status code:", response.status_code)
print("Response content:", response.text)
try:
response_data = response.json()
except requests.exceptions.JSONDecodeError:
response_data = {"error": "Invalid JSON response"}
return response_data
# Function to plot image with bounding boxes
def plot_image_with_bboxes(image_path, bboxes, colors):
image = Image.open(image_path)
fig, ax = plt.subplots(1)
ax.imshow(image)
for bbox, color in zip(bboxes, colors):
x = bbox[0] * image.width
y = bbox[1] * image.height
width = (bbox[2] - bbox[0]) * image.width
height = (bbox[3] - bbox[1]) * image.height
rect = plt.Rectangle((x, y), width, height, linewidth=2, edgecolor=color, facecolor='none')
ax.add_patch(rect)
output_image_path = "output_image.jpg"
fig.savefig(output_image_path)
plt.close(fig)
return output_image_path
def process_image(image, prompt, api_key):
image_path = "uploaded_image.png"
image.save(image_path)
resized_image_path =resize_image(image_path)
response_data = get_nvidia_response(resized_image_path, api_key, prompt)
# Parse response from NVIDIA API
if 'choices' in response_data:
message_content = response_data['choices'][0]['message']['content']
entities = response_data['choices'][0]['message']['entities']
colors = {entity['phrase']: f"#{randint(0, 0xFFFFFF):06x}" for entity in entities}
bboxes = {entity['phrase']: entity['bboxes'] for entity in entities}
# Generate HTML with background colors for entities
html_content = message_content
for entity in entities:
phrase = entity['phrase']
color = colors[phrase]
html_content = html_content.replace(phrase, f'<span style="background-color:{color}">{phrase}</span>')
else:
message_content = response_data.get("error", "Sorry, I couldn't process the image.")
bboxes, colors = {}, {}
html_content = f"<p>{message_content}</p>"
# Plot image with bounding boxes
combined_bboxes = [bbox for bbox_list in bboxes.values() for bbox in bbox_list]
combined_colors = [colors[phrase] for phrase, bbox_list in bboxes.items() for bbox in bbox_list]
output_image_path = plot_image_with_bboxes(resized_image_path, combined_bboxes, combined_colors)
# Wrap the content in a div for styling
html_content = f"""
<div style="color:black; font-size:16px;">
{html_content}
</div>
"""
return output_image_path, html_content
# Gradio interface
api_key = "발급받은 API Key"
iface = gr.Interface(
fn=lambda image, prompt: process_image(image, prompt, api_key),
inputs=[
gr.Image(type="pil", label="Upload Image"),
gr.Textbox(placeholder="Enter a prompt", label="Prompt")
],
outputs=[
gr.Image(type="filepath", label="Image with Bounding Boxes"),
gr.HTML(label="Response Text")
],
title="Image Analysis with NVIDIA API",
description="Upload an image and get a description with bounding boxes from the NVIDIA API.",
theme="default" # Ensure the theme is set to default (light theme)
)
if __name__ == "__main__":
iface.launch(share=True)
위 코드의 실행결과 화면은 아래화면과 같습니다.
좌측에서 이미지를 선택하고 설명해 달라고 요청하면 아래 화면과 같이 이미지 설명 텍스트의 배경색과 일치하는 객체를 박스로 구분한 응답이 출력됩니다. 웹 페이지의 배경색은 색구분을 위해 밝은 색으로 변경하였습니다.
맺음말
오늘은 NVIDIA의 생성 AI 모델의 배포와 운영을 편리하게 해주는 기술, NIM에 대해서 알아보았습니다. NIM은 최적화된 추론 엔진과 유연한 배포 환경으로, 다양한 애플리케이션에서 AI 모델을 빠르고 효율적으로 활용할 수 있게 지원합니다. 블로그에서는 LLAMA3 대화앱과 KOSMOS 이미지인식 앱 테스트를 통해 NIM의 성능과 효율성을 확인해 보았습니다.
NVIDIA의 NIM을 사용해 본 후기는 다음과 같습니다.
- 누구나 다양한 NIM API를 통해 다양한 AI 모델을 인프라 없이 쉽게 구현할 수 있다.
- 대화앱과 KOSMOS 이미지 인식 앱의 로컬 구현은 NIM과 호환성 확인이 필요하다. (입력 이미지 크기, 비동기처리 등)
- NIM으로 구현할 수 있는 언어 모델에 Claude, DeepSeek, Gemini 모델은 빠져 있다.
오늘 블로그 내용은 여기까지입니다. 여러분도 한번 NIM을 이용해서 편리하게 AI 애플리케이션을 구현해 보시길 바라면서, 저는 다음 시간에 더 유익한 정보를 가지고 다시 찾아뵙겠습니다. 감사합니다.
2024.05.16 - [AI 도구] - NVIDIA ChatRTX 2024. 5월 최신 업데이트: 설치 및 사용 후기
'AI 도구' 카테고리의 다른 글
Ollama 모바일 앱 설정 가이드: 스마트폰으로 어디서나 AI 모델과 대화하기 (1) | 2024.06.10 |
---|---|
OpenRecall: 디지털 메모리를 기록하고, 검색하는 오픈소스 솔루션 (0) | 2024.06.09 |
⚡️🆓Lightning AI: 무료 GPU 클라우드 기반 AI 개발 플랫폼 Ollama 가이드 (2) | 2024.06.02 |
🌐✨Page Assist: Ollama 기반 웹 브라우저 AI Co-pilot 설치 및 사용법 (0) | 2024.05.30 |
LobeChat: AI 기반 대화 서비스 플랫폼 설치 및 활용 가이드 (1) | 2024.05.28 |