오늘은 브라우저에서 직접 언어 모델 추론을 가능하게 하는 고성능 인퍼런스 엔진인 WebLLM에 대해 다뤄 보고자 합니다.
WebLLM은 하드웨어 가속을 통해 서버 지원 없이 모든 작업을 브라우저 내에서 실행하며, WebGPU로 가속됩니다. 이러한 기능을 통해 누구나 AI 비서를 구축하면서도 개인정보를 보호할 수 있는 다양한 기회를 얻을 수 있습니다.
이번 포스트는 한국어 오픈소스 모델인 EEVE 모델을 Web GPU로 서빙하는 것을 실습하는 위주로 작성할 예정입니다.
MLC LLM
MLC LLM은 대규모 언어 모델을 위한 머신 러닝 컴파일러 및 고성능 배포 엔진입니다. 이 프로젝트의 미션은 모든 사용자가 AI 모델을 개발, 최적화 및 배포할 수 있도록 지원하는 것입니다. MLC LLM을 실행하는 것에는 세 가지 주요 단계가 있습니다.
1단계: 사전 양자화된 가중치 다운로드. 이 단계에서는 Hugging Face에서 사전 양자화된 모델을 자동으로 다운로드하고, 이를 로컬 캐시 디렉터리에 저장합니다.
2단계: 모델 컴파일. 이 단계에서는 Apache TVM 컴파일러의 머신 러닝 컴파일 기술을 사용하여 모델을 최적화하고, GPU에서 모델 추론을 가속화합니다. 이 과정에서 로컬 GPU에서 실행할 수 있는 바이너리 모델 라이브러리가 생성됩니다.
3단계: 채팅 런타임. 이 단계에서는 2단계에서 생성된 모델 라이브러리와 1단계에서 다운로드된 모델 가중치를 사용하여, 플랫폼 네이티브 채팅 런타임을 시작하고 모델의 실행을 구동합니다.
사전 양자화된 모델 가중치와 컴파일된 모델 라이브러리는 로컬에 캐시됩니다. 따라서, 1단계와 2단계는 여러 번 실행할 때 한 번만 실행됩니다.
WebLLM은 MLC LLM를 베이스로 구동됩니다.
WebLLM의 주요 기능
In-Browser Inference 브라우저 내 추론: WebLLM은 고성능 브라우저 내 언어 모델 추론 엔진으로, WebGPU를 활용하여 하드웨어 가속을 제공합니다. 이를 통해 서버 측 처리 없이 웹 브라우저 내에서 강력한 LLM 작업을 수행할 수 있습니다.
Full OpenAI API Compatibility OpenAI API와의 완벽한 호환성: WebLLM은 OpenAI API를 사용하여 앱과 원활하게 통합할 수 있습니다. JSON 모드, 함수 호출, 스트리밍 등의 기능을 제공합니다.
Extensive Model Support 광범위한 모델 지원: WebLLM은 Llama 3, Phi 3, Gemma, Mistral, Qwen(通义千问) 등 다양한 모델을 네이티브로 지원하여 여러 AI 작업에 유연하게 사용할 수 있습니다. 지원되는 전체 모델 목록은 MLC Models에서 확인할 수 있습니다.
Custom Model Integration 맞춤형 모델 통합: MLC 형식의 맞춤형 모델을 쉽게 통합하고 배포할 수 있어, 특정 요구 사항과 시나리오에 맞춰 WebLLM을 적응시킬 수 있습니다. 이는 모델 배포의 유연성을 향상시킵니다.
Plug-and-Play Integration 플러그 앤 플레이 통합: NPM과 Yarn 같은 패키지 관리자를 사용하거나 CDN을 통해 WebLLM을 프로젝트에 쉽게 통합할 수 있습니다. 포괄적인 예제와 모듈식 디자인을 통해 UI 컴포넌트와의 연결도 용이합니다
Streaming & Real-Time Interactions 스트리밍 및 실시간 상호작용: 스트리밍 채팅 완성을 지원하여 실시간 출력 생성이 가능하며, 이는 챗봇 및 가상 비서와 같은 인터랙티브 애플리케이션을 향상시킵니다.
Web Worker & Service Worker Support 웹 워커 및 서비스 워커 지원: 별도의 워커 스레드나 서비스 워커로 계산 작업을 분리하여 UI 성능을 최적화하고 모델의 수명 주기를 효율적으로 관리할 수 있습니다.
Chrome Extension Support Chrome 확장 기능 지원: WebLLM을 사용하여 맞춤형 Chrome 확장 기능을 통해 웹 브라우저의 기능을 확장할 수 있습니다. 기본 및 고급 확장 기능을 구축하기 위한 예제가 제공됩니다.
WebLLM 데모
WebLLM으로 구성된 채팅 데모 사이트는 아래에서 확인해볼 수 있습니다.
EEVE 모델을 Web GPU로 서빙하기
오늘 WebLLM을 사용해서 Web GPU로 서빙하고자 하는 모델은 야놀자에서 공개한 오픈 소스 한국어 모델인 EEVE 모델입니다. 공개한지는 꽤 되었지만, 최근까지도 좋은 성능으로 여러 프로젝트에서 많이 사용되고 있는 모델입니다.
위의 EEVE 모델은 10.8B 크기의 커다란 언어 모델입니다. 이러한 모델은 Web GPU에 올리기에는 다소 무리가 있으므로 양자화하여 사이즈를 줄여야 합니다. 모델에 대한 양자화는 MLC LLM에서 지원하며, 이렇게 사전 양자화된 모델을 WebLLM에서 사용합니다.
먼저, MLC LLM 및 디펜던시들을 설치합니다. 이 포스트에서는 소스에서 직접 빌드하는 방식을 위주로 설명합니다.
Apache TVM 설치
시작하기에 앞서 conda 환경을 생성합니다.
# make sure to start with a fresh environment
conda env remove -n tvm-build-venv
# create the conda environment with build dependency
conda create -n tvm-build-venv -c conda-forge \
"llvmdev>=15" \
"cmake>=3.24" \
git \
python=3.10
# enter the build environment
conda activate tvm-build-venv
conda 환경이 설치되었으면, tvm을 설치하기 위해 소스를 클론하고 빌드 config를 생성합니다.
# clone from GitHub
git clone --recursive https://github.com/mlc-ai/relax.git tvm-unity && cd tvm-unity
# create the build directory
rm -rf build && mkdir build && cd build
# specify build requirements in `config.cmake`
cp ../cmake/config.cmake .
저는 M1 Mac에서 진행했기 때문에, 아래와 같이 cmake config에 내용을 추가해주었습니다.
# controls default compilation flags
echo "set(CMAKE_BUILD_TYPE RelWithDebInfo)" >> config.cmake
# LLVM is a must dependency
echo "set(USE_LLVM \"llvm-config --ignore-libllvm --link-static\")" >> config.cmake
echo "set(HIDE_PRIVATE_SYMBOLS ON)" >> config.cmake
# GPU SDKs, turn on if needed
echo "set(USE_CUDA OFF)" >> config.cmake
echo "set(USE_METAL ON)" >> config.cmake
echo "set(USE_VULKAN OFF)" >> config.cmake
echo "set(USE_OPENCL OFF)" >> config.cmake
# FlashInfer related, requires CUDA w/ compute capability 80;86;89;90
echo "set(USE_FLASHINFER OFF)" >> config.cmake
echo "set(FLASHINFER_CUDA_ARCHITECTURES 89)" >> config.cmake
echo "set(CMAKE_CUDA_ARCHITECTURES 89)" >> config.cmake
CUDA를 사용하시거나 VULKAN, 또는 OPENCL, FLASHINFER를 사용하시는 분들은 각자 환경에 맞춰서 ON/OFF 등을 설정해주시면 되겠습니다.
설정이 완료되었다면 아래 명령어를 실행하여 빌드를 진행합니다.
cmake .. && cmake --build . --parallel $(nproc)
빌드가 완료되면 파이썬에서 모듈을 접근할 수 있도록 환경변수에 추가합니다.
export TVM_SOURCE_DIR=/path-to-tvm-unity
export PYTHONPATH=$TVM_SOURCE_DIR/python:$PYTHONPATH
MLC LLM 설치
마찬가지로 시작하기에 앞서 conda 환경을 생성합니다.
# make sure to start with a fresh environment
conda env remove -n mlc-chat-venv
# create the conda environment with build dependency
conda create -n mlc-chat-venv -c conda-forge \
"cmake>=3.24" \
rust \
git \
python=3.10
# enter the build environment
conda activate mlc-chat-venv
conda 환경이 설치되었으면, tvm을 설치하기 위해 소스를 클론하고 빌드 config를 생성합니다. gen_make_config.py를 실행하면 아래와 같은 프롬프트가 떠서 추가적인 설정을 진행합니다. 저는 M1 Mac에서 진행했기 때문에, 아래와 같이 프롬프트에 답변하였습니다.
# clone from GitHub
git clone --recursive https://github.com/mlc-ai/mlc-llm.git && cd mlc-llm/
# create build directory
mkdir -p build && cd build
# generate build configuration
python ../cmake/gen_cmake_config.py
Enter TVM_SOURCE_DIR in absolute path. If not specified, 3rdparty/tvm will be used by default: /path-to-tvm-unity/tvm-unity
Use CUDA? (y/n): n
Use CUTLASS? (y/n): n
Use CUBLAS? (y/n): n
Use ROCm? (y/n): n
Use Vulkan? (y/n): n
Use Metal (Apple M1/M2 GPU) ? (y/n): y
Use OpenCL? (y/n) n
Use OpenCLHostPtr? (y/n): n
Use FlashInfer? (need CUDA w/ compute capability 80;86;89;90) (y/n): n
Writing the following configuration to config.cmake...
set(TVM_SOURCE_DIR 3rdparty/tvm)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
set(USE_CUDA OFF)
set(USE_CUTLASS OFF)
set(USE_CUBLAS OFF)
set(USE_ROCM OFF)
set(USE_VULKAN OFF)
set(USE_METAL ON)
set(USE_OPENCL OFF)
set(USE_OPENCL_ENABLE_HOST_PTR OFF)
set(USE_FLASHINFER OFF)
설정이 완료되었다면 아래 명령어를 실행하여 빌드를 진행합니다.
cmake .. && cmake --build . --parallel $(nproc)
빌드가 완료되면 파이썬에서 모듈을 접근할 수 있도록 환경변수에 추가합니다. 이후 mlc_llm을 간편하게 사용하기 위해 alias로 지정합니다.
export MLC_LLM_SOURCE_DIR=/path-to-mlc-llm
export PYTHONPATH=$MLC_LLM_SOURCE_DIR/python:$PYTHONPATH
alias mlc_llm="python -m mlc_llm"
Wasm 빌드 환경 세팅
다음은 Web에서 수행할 수 있는 라이브러리은 wasm 포맷으로 빌드하기 위한 환경을 세팅합니다. 먼저 emsdk를 설치합니다. emsdk 레포를 클론하여 최신 버전을 pull합니다.
# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git
# Enter that directory
cd emsdk
# Fetch the latest version of the emsdk (not needed the first time you clone)
git pull
위에서 클론한 디렉토리에서 아래 명령어를 실행하여 emsdk를 설치합니다.
# Download and install the latest SDK tools.
./emsdk install latest
# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./emsdk activate latest
# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
설치가 완료되면 emcc --version 명령어를 실행하여 설치가 정상적으로 되었는지 확인합니다.
emcc --version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.61 (67fa4c16496b157a7fc3377afd69ee0445e8a6e3)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
정상적으로 설치가 되었다면, TVM_SOURCE_DIR과 MLC_LLM_SOURCE_DIR 환경변수를 세팅합니다. 위의 과정을 전부 잘 진행하셨다면 이미 환경변수가 잘 세팅되어 있을 겁니다. 그렇지 않으면 아래를 실행하여 환경변수를 추가합니다.
export TVM_SOURCE_DIR=/path-to-tvm
export MLC_LLM_SOURCE_DIR=/path-to-mlc-llm
Wasm 런타임을 준비하기 위해 아래와 같은 명령어를 수행합니다.
cd $MLC_LLM_SOURCE_DIR
# prepare wasm runtime using the script in mlc-llm repo
./web/prep_emcc_deps.sh
이 후 아래 명령어를 실행하여 정상적으로 설치되었는지 확인합니다. 아래의 세개의 bc 파일이 있으면 정상적으로 준비가 되었습니다.
ls -l ${TVM_SOURCE_DIR}/web/dist/wasm/*.bc
tvmjs_support.bc
wasm_runtime.bc
webgpu_runtime.bc
EEVE 모델 준비하기
위의 환경 설정이 다 끝났으면 본격적으로 EEVE 모델을 변환하고 서빙 준비를 할 차례입니다. 먼저 EEVE 모델을 다운받습니다.
mkdir -p models/hf && cd models/hf
git clone https://huggingface.co/yanolja/EEVE-Korean-Instruct-10.8B-v1.0
EEVE 모델 변환하기
다운받은 EEVE-Korean-Instruct-10.8B-v1.0 모델을 4비트 양자화를 진행합니다. 이전 블로그 글에서 양자화에 대한 기본적인 개념과 다양한 기법을 다루었으니, 자세한 내용을 알고 싶다면 해당 글을 참고하시기 바랍니다.
mlc_llm convert_weight ./models/hf/EEVE-Korean-Instruct-10.8B-v1.0/ \
--quantization q4f16_1 \
-o ./models/mlc/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC
다음으로는 해당 모델에 대한 gen_config를 생성해야 합니다. 이 과정에서 conv_template이라고 하는 사전 정의된 conversation template에 대한 작성이 필요합니다. 관련된 PR을 참고하여 MLC LLM 프로젝트에 아래 내용을 추가합니다.
# Eeve
ConvTemplateRegistry.register_conv_template(
Conversation(
name="eeve",
system_template=f"<s>{MessagePlaceholders.SYSTEM.value}</s>\n",
system_message="A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.",
roles={
"user": "<s>Human:",
"assistant": "<s>Assistant:",
},
seps=["</s>\n"],
role_content_sep="\n",
role_empty_sep="\n",
stop_str=["</s>", "<|im_end|>"],
stop_token_ids=[2, 32000], # "</s>", "<|im_end|>"
system_prefix_token_ids=[1],
add_role_after_system_message=True,
)
)
위와 같이 내용을 추가하였다면, 위의 MLC LLM 설치 파트를 다시 진행하여 소스 변경 사항을 반영합니다. 이 후 gen_config cli를 실행하여 mlc-chat-config.json을 생성합니다.
mlc_llm gen_config \
./models/hf/EEVE-Korean-Instruct-10.8B-v1.0/ \
--quantization q4f16_1 --conv-template eeve \
-o ./models/mlc/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC/
mlc-chat-config.json을 생성했다면, 다음은 webgpu에서 작동할 수 있도록 wasm 파일로 변환해야 합니다. 변환은 아래 cli를 수행하여 진행할 수 있습니다.
mlc_llm compile \
./models/mlc/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC/mlc-chat-config.json \
--device webgpu \
-o ./models/mlc_lib/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-webgpu.wasm
EEVE 모델 서빙하기
앞서 서빙하기 위한 모델 바이너리들을 만들었다면, 이제는 해당 바이너리들을 서빙할 차례입니다. wasm을 제외한 바이너리들은 huggingface 모델 레포로 등록하여 업로드합니다.
# First, please create a repository on Hugging Face.
# With the repository created, run
git lfs install
git clone https://huggingface.co/my-huggingface-account/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC
cd EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC
cp models/mlc/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC/* .
git add . && git commit -m "Add model"
git push origin main
wasm 파일은 github에 업로드합니다.
업로드가 모두 완료되었다면, 이제 WebLLM을 사용하여 웹 페이지를 작성해야 합니다.
아래는 제가 사전에 미리 만들어 놓은 레포이며, 참고하시면 좋을 것 같습니다.
app-config.js에 작성된 것 처럼, 다음과 같이 설정하면 위에서 업로드한 모델들을 WebLLM에서 동적으로 가져와 사용할 수 있습니다.
import { prebuiltAppConfig } from "@mlc-ai/web-llm";
const modelLibURLPrefix =
"https://raw.githubusercontent.com/pfldy2850/web-llm-eeve/main/models/";
export default {
useIndexedDBCache: false,
model_list: [
{
model:
"https://huggingface.co/pfldy2850/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-MLC",
model_id: "EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1",
model_lib:
modelLibURLPrefix +
"/EEVE-Korean-Instruct-10.8B-v1.0/EEVE-Korean-Instruct-10.8B-v1.0-q4f16_1-webgpu.wasm",
vram_required_MB: 6108.76,
overrides: {
context_window_size: 1024,
},
low_resource_required: true,
},
],
use_web_worker: true,
};
아래 명령어를 실행하시면, EEVE 모델을 서빙하는 웹 페이지를 실행할 수 있습니다.
git clone https://github.com/pfldy2850/web-llm-eeve.git
cd web-llm-eeve
npm install
npm start
정상적으로 실행된다면, http://localhost:8883에서 아래와 같은 웹 페이지를 확인할 수 있습니다.
'AI > 모델 인퍼런스' 카테고리의 다른 글
Llama.cpp, GGUF 포맷, 그리고 양자화(Quantization) (2) | 2024.05.28 |
---|---|
주요 LLM API 비용 정리 (ChatGPT, Gemini, Claude, HyperClova + LLaMA3) (0) | 2024.05.11 |
LLM 인퍼런스 훑어보기 (6) - quantization (0) | 2023.11.17 |
LLM 인퍼런스 훑어보기 (5) - continuous batching (0) | 2023.11.10 |
LLM 인퍼런스 훑어보기 (4) - kernel fusion (0) | 2023.10.14 |