본문 바로가기

Computer Science/NVIDIA

NVIDIA NIM 소개 및 실습

안녕하세요. 진또배기입니다.

오늘은 지난 NVIDIA GTC 2024에서 나온 개념인 NIM에 대해 소개해보고 실습해보는 시간을 가져보겠습니다.

NVIDIA GTC 2024 NIM소개 영상

(1:17:21부터 NIM에 대한 설명)

https://www.youtube.com/watch?v=Y2F8yisiS6E

 


1. NVIDIA NIM이란?

NIM이란 Nvidia Inference Microservice줄임말로 AI 모델 배포를 가속화하는 쿠버네티스 기반 마이크로서비스 세트입니다.

 

사전 구축된 컨테이너와 Helm chart, 각 종 산업에 표준화된 API, 해당 도메인에 특화된 코드, 최적화된 추론엔진등이  NIM이라고 하는 곳에 한데 모아놨다, 말아놨다고 이해하시면 되겠습니다. 따라서 이 말아놓은 NIM을 사용해서 원하는 업종에서 단 몇 줄의 코드만으로 엔터프라이즈급 AI 애플리케이션을 빠르게 구축할 수 있습니다.

NIM을 사용하기 위한 기본적인 요건은 NVIDIA GPU가 필수적입니다.

 

 

NIM은 이렇게 많이 엔비디아가 사전에 각 영역별로 다 잘 말아 놨습니다. 그래서 LLM, 이미지, Optimization 여러 영역에 걸쳐져 있는 모델별로 님을 다운받으실 수 있습니다. AI모델 하나당 님 하나로 생각을 하면 되겠습니다.


**Helm 차트란? 

쿠버네티스를 활용하기 위해서는 가장 먼저 yaml 파일을 작성해야하는데, yaml파일 작성이 여간 귀찮은 것이 아닙니다...아래와 같은 yaml파일을 여러 개 관리하는 것은 처음이야 괜찮겠지만 지루한 작업의 연속입니다.

yaml파일 예시

따라서 어플리케이션을 쉽게 배포할 수 있기위해 Helm-chart를 활용해 yaml파일을 관리합니다. helm-chart은 yaml 파일을 묶음으로 구성됩니다.
Helm 차트란 Kubernetes 클러스터에 애플리케이션을 쉽게 배포하고 관리하기 위해 개발된 Kubernetes 용 패키지 매니저입니다.
Helm Repository로부터 Helm chart를 가져와 리소스들을 생성합니다. yaml파일을 수정하고 싶다면 원하는 환경 변수만 수정한 뒤, upgrade를 통해 적용 가능합니다.



2. NVIDIA NIM Hands-on

앞으로 보여드릴 Hands-On은 이 중 일부분인 Mistral-7B에 대해서 작업한 결과물을 보여드리겠습니다.

1) 실습환경 구성하기

실습환경은 다음과 같습니다.

Google Colab(Google Drive + Docker + Linux + Google Cloud) + T4 GPU + Jupyter notebook

RunTime -> Change Runtime type 클릭


2) 검색 부분 작성

사전준비가 완료되었으면 Google Colab의 Jupyter notebook에서 NIM을 활용하여 문서기반 Chat-GPT를 만들어보기 위한 스크립트를 짜봅시다.

각 코드에 대한 설명은 주석으로 달아놓았습니다.

!pip install langchain_nvidia_ai_endpoints #언어모델 인터페이스인 Langchain 패키지를 설치합니다
!pip install langchain-community langchain-text-splitters faiss-gpu #밀집 벡터의 효율적인 유사도 검색과 클러스터링을 위한 faiss라이브러리 설치
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings, ChatNVIDIA # NVIDIA AI 엔드포인트 패키지에서 제공하는 클래스 불러오기
  • langchain_nvidia_ai_endpoints: NVIDIA의 AI 모델을 사용한 임베딩 생성 및 대화 기능을 제공하는 패키지입니다.
  • langchain-community: 다양한 언어 모델을 연결하고 활용하기 위한 커뮤니티 지원 패키지입니다.
  • langchain-text-splitters: 텍스트를 분할하여 조각으로 만드는 도구를 제공합니다.
  • faiss-gpu: Facebook AI에서 개발한 빠른 유사성 검색 및 클러스터링 라이브러리로, GPU 가속을 지원합니다.
  • NVIDIAEmbeddings: NVIDIA의 AI 모델을 사용하여 텍스트 임베딩을 생성하는 클래스입니다,
  • ChatNVIDIA: NVIDIA의 AI 모델을 사용하여 대화형 AI 기능을 제공하는 클래스입니다.

 

from langchain_community.document_loaders import WebBaseLoader #웹 기반 로더 가져오기
loader = WebBaseLoader("https://docs.nvidia.com/deploy/nvml-api/group__NvLink.html") #다른 URL을 가져와도 됨.
docs = loader.load()#문서를 호출
  • WebBaseLoader: 웹에서 문서를 로드하는 데 사용되는 클래스입니다.
  • loader는 WebBaseLoader의 인스턴스이어야 하며, 이를 통해 웹에서 문서를 불러옵니다.

 

위 코드에서 URL을 입력하였는데요. 저는 NVIDIA의 공식 블로그에서 NvLink에 대해 설명하는 URL을 입력했습니다. 다른 URL을 입력하고 싶다면, 그러셔도 됩니다.

https://developer.nvidia.com/blog/mastering-llm-techniques-inference-optimization/

from google.colab import userdata
import os
os.environ['NVIDIA_API_KEY'] = userdata.get('NVIDIA_API_KEY')
  • Google Colab의 사용자 데이터에서 NVIDIA API 키를 가져오기 위해 사용하였습니다.
  • NVIDIA AI 엔드포인트에 접근하기 위해 필요한 인증 키를 설정합니다.

 

위 코드에서는 저는 매개변수를 활용해 NVIDIA API Key를 불러왔습니다. 이 API Key는 아래 링크에서 얻을 수 있는데요. 링크에서 회원가입 후 무료로 주는 1000 Credit으로 실습을 진행해 볼 수 있습니다!

URL Link: https://build.nvidia.com/explore/discover

 

Try NVIDIA NIM APIs

Experience the leading models to build enterprise generative AI apps now.

build.nvidia.com

** NVIDIA NIM API Key얻기

위 사진과 같이, Reasoning 카테고리에서 Mixtral-8x7b-instruct-v0.1을 클릭해줍니다.

이후 나오는 창에서 "Get API Key"를 클릭합니다.

이후, 위와 같이 나오는 창에서 "Generate Key"를 클릭해 API Key를 얻습니다.

Google Colab의 보안 비밀 키에 Access할 수 있도록 "값" 부분에 API Key를 입력해줍니다. 여기서 "이름"부분과 코드의 매개변수는 반드시 일치해야합니다.

embeddings = NVIDIAEmbeddings() 
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter #텍스트 분할기 라이브러리
  • NVIDIA AI 모델을 사용하여 텍스트 임베딩 생성합니다.
  • NVIDIAEmbeddings 클래스의 인스턴스를 생성하여 텍스트 데이터를 벡터 형식으로 변환하는 데 사용합니다.
  • FAISS 벡터 스토어 및 텍스트 분할기 클래스를 불러옵니다.
  • FAISS: 벡터 검색 및 클러스터링을 위해 사용되는 고성능 라이브러리입니다.
  • RecursiveCharacterTextSplitter: 텍스트를 지정된 크기와 중첩으로 분할하는 도구입니다.

 

 

text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)#chunk size 지정, 권장하는 방식임.
documents = text_splitter.split_documents(docs)#문서가 텍스트 분할기를 전달하여 올바를 문서를 전달하는 문서를 뱉어냄
  • chunk_size: 각 텍스트 조각의 최대 길이
  • chunk_overlap: 분할된 조각들 사이의 중복 길이
  • WebBaseLoader로 로드된 문서를 텍스트 조각으로 분할하여 처리합니다.

 

 

documents[0] #이 코드를 실행하면 URL의 첫번째 항목(보통 목록이나 제목, 콘텐츠 항목, 메타데이터)을 가져옴

문서의 첫번째([0])항목을 불러와서 제가 잘 하고 있는지 확인해봅니다.

위 코드를 실행하면 아래와 같이 첫 번째 항목의 결과가 나옵니다.

vector = FAISS.from_documents(documents, embeddings)#이 벡터에 문서와 임베딩을 전달하는 역할
retriever = vector.as_retriever()#검색 변수 생성

 

  • FAISS는 빠른 벡터 검색을 위해 사용되며, 생성된 임베딩을 기반으로 문서를 저장합니다.
  • 생성된 FAISS 벡터 스토어에서 데이터를 검색할 수 있는 검색기를 만듭니다.

검색 변수 생성까지 끝났다면 검색 부분 코딩은 끝났습니다. 우리가 지금까지 딥러닝이나 AI모듈을 쓴 것이 있었나요? 없었죠? 우리는 NIM의 API key만 불러왔습니다. 이제부터는 생성부분 코딩을 해주도록 합시다.

 


3) 생성부분 작성

# LangChain의 ChatPromptTemplate과 StrOutputParser 모듈을 가져옴
from langchain_core.prompts import ChatPromptTemplate#채팅 관련 템플릿 가져오기
from langchain_core.output_parsers import StrOutputParser #문자열을 출력하는 파서 가져오기

model = ChatNVIDIA(model="mistral_7b")# NVIDIA NIM의 Mistral 7B 모델을 불러옴
  • ChatPromptTemplate: 특정 텍스트 형식을 정의하여, 모델에게 어떤 질문을 할지 설정합니다.
  • StrOutputParser: 모델의 출력을 문자열로 파싱하는 역할을 합니다.
  • Mistral 7B 모델은 대규모 언어 모델로, 다양한 텍스트 생성 작업을 수행할 수 있습니다.

 

 

# 가상의 답변을 생성하는 템플릿을 정의
hyde_template = """Even if you do not know the full answer, generate a one-paragraph hypothetical answer to the below question:

{question}"""
hyde_prompt = ChatPromptTemplate.from_template(hyde_template)# 위 템플릿을 사용해 ChatPromptTemplate 인스턴스를 생성
hyde_query_transformer = hyde_prompt | model | StrOutputParser()# 템플릿, 모델, 출력 파서를 결합하여 쿼리 변환기(hyde_query_transformer)를 생성

답변을 작성하기 위한 템플릿입니다. 템플릿, 모델, 출력 파서를 결합하여 쿼리 변환기(hyde_query_transformer)를 생성합니다.

hyde_query_transformer# 쿼리 변환기를 반환

"쿼리 변환기를 반환"한다는 의미는 hyde_query_transformer가 질문에 대한 응답을 생성하는 전체 프로세스를 담당하는 객체라는 뜻입니다. 이를 통해 사용자는 질문을 입력으로 제공하고, hyde_query_transformer를 통해 템플릿에 따라 모델의 응답을 생성하고, 그 응답을 문자열 형태로 받을 수 있습니다. 이 객체는 질문을 받아 처리하는 일련의 과정을 포함하고, 그 결과를 반환하는 기능을 수행합니다.

from langchain_core.runnables import chain# LangChain의 체인 데코레이터를 가져옴

@chain#질문에 대한 데코레이터 함수 작성
def hyde_retriever(question):
    hypothetical_document = hyde_query_transformer.invoke({"question": question})
    return retriever.invoke(hypothetical_document) # 생성된 가상의 답변을 retriever에 전달하여 관련 문서를 검색
  • 이 함수는 질문을 받아서 가상의 답변을 생성하고, 이를 사용해 문서를 검색합니다.

 

# 최종 답변을 생성하기 위한 템플릿을 정의
template = """Answer the question based only on the following context:
{context}

Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template) # 위 템플릿을 사용해 ChatPromptTemplate 인스턴스를 생성
answer_chain = prompt | model | StrOutputParser() # 템플릿, 모델, 출력 파서를 결합하여 답변 체인(answer_chain)을 생성

최종 답변을 생성하기 위한 템플릿을 정의해줍니다.

 

@chain
def final_chain(question):
    documents = hyde_retriever.invoke(question) # hyde_retriever를 사용해 질문에 대한 관련 문서를 검색
    for s in answer_chain.stream({"question": question, "context": documents}): # answer_chain을 사용해 문서를 기반으로 최종 답변을 스트리밍 방식으로 생성
        yield s

위 함수는 질문을 받아 관련 문서를 검색하고, 그 문서를 기반으로 최종 답변을 생성합니다.

"스트리밍 방식으로 생성"한다는 것은 최종 결과를 한 번에 제공하지 않고, 처리가 완료되는 대로 결과를 점진적으로 제공하는 방식을 의미합니다. 실시간 응답, 메모리 효율성, 응답 속도에 대해 장점이 있습니다.


3. NIM 사용해보기

이제 필요한 모든 작업이 끝났습니다! 제가 입력한 블로그의 내용 대한 질문을 해봅시다,

위와 같이 What is LLM Memory requirement? 라고 물었을 때,
Model Weights와 KV cache로 이루어져있다고 뱉어내는 것을 볼 수 있습니다.

블로그 원문과 비교해볼까요?

캬~ 아주 질문에 대한 답변을 잘 하는 것을 볼 수 있습니다.

 

한국인이라면 이제 엉뚱한 질문을 해봐야겠죠?

흠..엔비디아 오늘 주가를 물어봅시다.

기대했던 대로 엔비디아의 주가를 제공할 수 없답니다. 😊

 

제가 준비한 것은 여기까지입니다.

일하랴, 블로그쓰랴, 현생살랴 요즘 너무 정신이 없게 하루를 보내고 있습니다.

그래도 이렇게 블로그를 완료하고 나니 조금 뿌듯하네요.

 

읽어주셔서 감사합니다.

진또배기 올림

 

 

'Computer Science > NVIDIA' 카테고리의 다른 글

vGPU 실습2  (0) 2024.02.23
vGPU 실습1  (0) 2024.02.21
3-1. Fundamentals of Accelerated Computing with CUDA Python  (0) 2024.01.21
GPU Architecture  (0) 2023.12.21
GPU란 무엇인가  (0) 2023.12.17