데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      MLC LLM을 이용한 안드로이드 On-device AI 맛보기

      이너 25.05.02
      7,904 5 1
      DEVOTEE 요약
      AI 기술 발전으로 대형 언어 모델(LLM)을 스마트폰에서도 실행할 수 있게 되어 네트워크 연결 없이도 AI를 활용하며 개인정보를 보호할 수 있습니다. MLC LLM은 오픈소스 프로젝트로 안드로이드 환경에서 LLM을 실행하고 앱을 개발할 수 있는 방법을 제공합니다. Python 환경 설정, Android 개발 도구 설치, MLC LLM 패키지 설치 및 모델 변환을 통해 스마트폰에서도 효율적인 AI 애플리케이션을 구현할 수 있습니다.
      DEVOTEE 추천 블로그

      들어가며

      AI 기술이 급속도로 발전하면서 이제는 클라우드뿐만 아니라 모바일 기기에서도 인공지능 모델을 직접 구동할 수 있는 시대가 되었습니다.

      특히, 대형 언어 모델(LLM)을 경량화하여 스마트폰에서 직접 실행할 수 있다면 네트워크 연결 없이도 AI 기능을 활용할 수 있고, 개인정보 보호 측면에서도 큰 장점이 있습니다.

      이 글은 AI 분야에 깊은 지식이 없더라도, 안드로이드 디바이스에서 LLM을 직접 구동해보며 AI를 경험해보고 싶은 소프트웨어 개발자들을 위해 작성되었습니다.

      제목에 소개된 MLC LLM은 다양한 플랫폼에서 LLM을 효율적으로 실행할 수 있게 해주는 오픈소스 프로젝트로,

      이를 활용하면 복잡한 AI 지식 없이도 모바일 환경에서 대화형 AI 애플리케이션을 구현할 수 있습니다.


      MLC LLM 환경 구축하기

      MLC LLM을 사용하기 위해서는 Python 환경이 필요합니다. 그리고 추가로 안드로이드 라이브러리화하는 과정에서 Python뿐만 아니라 여러 가지 도구들이 함께 사용됩니다.

      이 글에 설명된 설치 가이드는 x86_64 기반의 Ubuntu 22.04 (jammy) 환경에서 테스트되었습니다.

      필수 도구 설치하기

      Python 3.11 버전과 Rust를 설치합니다. Python 패키지를 독립된 환경에서 사용하기 위해 virtualenv도 같이 설치합니다.

      # Python 3.11 설치 및 기타 도구들 설치
      sudo apt install python3.11 python3-virtualenv curl wget unzip
      
      # Rust 설치 및 환경변수(PATH)를 현재 쉘에 업데이트
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
      . "$HOME/.cargo/env"

      virtualenv를 사용하여 MLC LLM 작업을 위한 독립된 Python 환경을 생성합니다.

      virtualenv -p /usr/bin/python3.11 ~/venv/mlc

      다음으로, Android 개발 환경을 설치합니다. Android Studio 자체는 MLC LLM을 빌드하는 데 필요는 없지만, 차후 IDE를 이용한 앱 개발을 진행한다고 가정하고 같이 설치해 줍니다.

      (Android Studio 설치 없이 진행하려면 openjdk를 설치하고 ANDROID_HOME과 JAVA_HOME 환경변수를 다르게 설정해야 합니다. 자세한 내용은 글 하단에 있는 Dockerfile을 참고 바랍니다.)

      # Android Studio 다운로드 및 설치
      wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.2.13/android-studio-2024.1.2.13-linux.tar.gz
      tar xvf android-studio-2024.1.2.13-linux.tar.gz
      mv android-studio ~/
      
      # 커맨드라인 도구 설치
      wget https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip
      unzip commandlinetools-linux-13114758_latest.zip
      mkdir -p ~/android-studio/cmdline-tools/latest
      mv cmdline-tools/* ~/android-studio/cmdline-tools/latest

      sdkmanager를 사용하기 위해 환경 변수를 설정합니다.

      export ANDROID_HOME=~/android-studio
      export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
      export JAVA_HOME=$ANDROID_HOME/jbr

      이제 sdkmanager를 사용하여 추가로 필요한 패키지를 설치합니다.

      yes | sdkmanager --licenses
      sdkmanager --update
      sdkmanager "platform-tools" "platforms;android-35" "build-tools;35.0.0"
      sdkmanager "ndk;27.2.12479018" "cmake;3.22.1"

      환경변수에 cmake와 ndk 정보를 추가합니다.

      export PATH=$PATH:$ANDROID_HOME/cmake/3.22.1/bin:$ANDROID_HOME/platform-tools
      export ANDROID_NDK=$ANDROID_HOME/ndk/27.2.12479018

      이렇게 해서 기본적인 준비 과정을 완료했습니다.

      MLC LLM 설치

      MLC LLM은 친절하게 미리 빌드된 패키지(Prebuilt package)를 제공하고 있어 pip 명령으로 쉽게 설치할 수 있습니다.

      물론, 필요할 경우 소스를 통한 빌드도 함께 제공합니다. 자세한 내용은 공식 문서를 참고 바랍니다.

      # mlc virtualenv 환경 활성화 (이후 쉘 프롬프트에 mlc가 표시됨)
      $ source ~/venv/mlc/bin/activate
      
      # TVM Unity Compiler 설치
      (mlc) $ pip install --pre -U -f https://mlc.ai/wheels mlc-ai-nightly-cpu
      
      # 설치 확인 - 설정 정보들이 출력됨
      (mlc) $ python -c "import tvm; print('\n'.join(f'{k}: {v}' for k, v in tvm.support.libinfo().items()))"
      
      # MLC LLM 설치
      (mlc) $ pip install --pre -U -f https://mlc.ai/wheels mlc-llm-nightly-cpu
      
      # 설치 확인 - mlc_llm 모듈 정보가 출력됨
      (mlc) $ python -c "import mlc_llm; print(mlc_llm)"

      설치가 정상적으로 완료되면 아래와 같이 mlc_llm 명령을 터미널에서 사용할 수 있습니다.

      (mlc) $ mlc_llm
      ------------------------- Usage -------------------------
      usage: MLC LLM Command Line Interface. [-h] {compile,convert_weight,gen_config,chat,serve,package,calibrate,router}
      
      positional arguments:
      {compile,convert_weight,gen_config,chat,serve,package,calibrate,router}
                              Subcommand to to run. (choices: compile, convert_weight, gen_config, chat, serve, package, calibrate, router)
      
      options:
      -h, --help            show this help message and exit
      ------------------------- Error -------------------------
      the following arguments are required: subcommand

      virtualenv에서 제공하는 deactivate 명령으로 독립된 mlc python 환경을 종료합니다.

      (mlc) $ deactivate

      이제 모든 준비 과정이 끝났습니다. 다음 단계에서 MLC LLM을 Android 라이브러리로 빌드하는 과정을 알아보겠습니다.


      안드로이드 샘플 앱 빌드하기

      MLC LLM은 두 가지 안드로이드 샘플 앱을 제공합니다. MLCChat과 MLCEngineExample 각각의 빌드 방법을 알아보겠습니다.

      먼저 코드를 다운로드 받습니다.

      # git, git-lfs 설치 (git-lfs는 모델 다운로드 과정에서 사용됨)
      sudo apt install git git-lfs
      
      # 코드 다운로드
      git clone https://github.com/mlc-ai/mlc-llm.git

      샘플 코드는 mlc-llm/android 디렉토리에서 찾을 수 있습니다.

      앱 빌드를 위한 사전 단계로 mlc_llm package라는 명령을 사용하게 되는데, 이 때 추가로 필요로 하는 모듈들이 있어 아래와 같이 git submodule 명령으로 의존성 모듈들을 같이 준비합니다.

      cd mlc-llm
      git submodule update --init --recursive

      또한, 추가로 설정이 필요한 환경변수가 있어 마지막으로 아래와 같이 설정합니다.

      export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang
      export MLC_LLM_SOURCE_DIR=~/mlc-llm

      참고로 지금까지 추가된 환경변수들을 정리하면 아래와 같습니다. 쉘 설정 파일($HOME/.bashrc)에 추가하면 좀 더 편리하게 사용할 수 있습니다.

      export ANDROID_HOME=~/android-studio
      export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
      export JAVA_HOME=$ANDROID_HOME/jbr
      
      export PATH=$PATH:$ANDROID_HOME/cmake/3.22.1/bin:$ANDROID_HOME/platform-tools
      export ANDROID_NDK=$ANDROID_HOME/ndk/27.2.12479018
      
      export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang
      export MLC_LLM_SOURCE_DIR=~/mlc-llm

      빌드 환경 설정이 모두 완료되었습니다. 이제 예제 애플리케이션을 빌드하여 테스트해 보겠습니다. 전체적인 진행 과정은 아래 그림과 같습니다.

      MLC LLM Flow diagram

      두 애플리케이션 모두 기본적인 설정 및 빌드 과정은 유사하지만, MLCEngineExample의 경우 최소화된 기능만 제공하므로 몇 가지 작업을 수동으로 추가해야 합니다.

      그리고 Hugging Face의 mlc-ai 저장소에서 제공하는 모델을 사용할 경우 큰 수정 없이 진행할 수 있으나, 다른 모델을 사용하려면 별도의 변환 과정이 필요합니다.

      다음 단계에서 이 과정을 더 자세히 살펴보겠습니다.

      MLCChat 앱 빌드

      MLCChat (경로: mlc-llm/android/MLCChat)은 모델 다운로드 기능이 포함된 채팅 형태의 애플리케이션입니다.

      사용하고 있는 모델 목록은 mlc-package-config.json 파일에 아래와 같이 정의되어 있습니다.

      {
          "device": "android",
          "model_list": [
              {
                  "model": "HF://mlc-ai/Phi-3.5-mini-instruct-q4f16_0-MLC",
                  "estimated_vram_bytes": 4250586449,
                  "model_id": "Phi-3.5-mini-instruct-q4f16_0-MLC",
                  "overrides": {
                      "prefill_chunk_size": 128
                  }
              },
              {
                  "model": "HF://mlc-ai/Qwen2.5-1.5B-Instruct-q4f16_1-MLC",
                  "estimated_vram_bytes": 3980990464,
                  "model_id": "Qwen2.5-1.5B-Instruct-q4f16_1-MLC"
              },
              {
                  "model": "HF://mlc-ai/gemma-2-2b-it-q4f16_1-MLC",
                  "model_id": "gemma-2-2b-it-q4f16_1-MLC",
                  "estimated_vram_bytes": 3000000000
              },
              {
                  "model": "HF://mlc-ai/Llama-3.2-3B-Instruct-q4f16_0-MLC",
                  "estimated_vram_bytes": 4679979417,
                  "model_id": "Llama-3.2-3B-Instruct-q4f16_0-MLC"
              },
              {
                  "model": "HF://mlc-ai/Mistral-7B-Instruct-v0.3-q4f16_1-MLC",
                  "estimated_vram_bytes": 4115131883,
                  "model_id": "Mistral-7B-Instruct-v0.3-q4f16_1-MLC",
                  "overrides": {
                      "sliding_window_size": 768,
                      "prefill_chunk_size": 256
                  }
              }
          ]
      }

      mlc_llm package 명령을 수행하면, 위 파일의 model_list에 정의된 각 모델을 다운로드 후 이를 기반으로 안드로이드 앱 빌드를 위한 라이브러리를 생성합니다.

      따라서, 앱에서 사용할 모델 정보 변경이 필요할 경우 위 json 파일을 수정하고 다시 mlc_llm package 명령을 실행해야 합니다.

      $ source ~/venv/mlc/bin/activate
      (mlc) $ cd mlc-llm/android/MLCChat
      (mlc) $ mlc_llm package

      모델 다운로드와 TVM Unity 컴파일 과정이 시작되며, 이 과정은 다소 시간이 걸릴 수 있습니다. 작업 진행중 다음과 같은 로그가 출력됩니다.

      ...
      INFO download_cache.py:56: [Git] Cloning https://huggingface.co/mlc-ai/Phi-3.5-mini-instruct-q4f16_0-MLC to /tmp/tmpjp7kggh4/tmp
      INFO download_cache.py:92: [Git LFS] Downloading 1 files with Git LFS: ['tokenizer.model']
      ...
      INFO compile.py:158: Exporting the model to TVM Unity compiler
      ...
      INFO model_metadata.py:94: Total memory usage without KV cache:: 2060.82 MB (Parameters: 2050.06 MB. Temporary buffer: 10.76 MB)
      INFO model_metadata.py:102: To reduce memory usage, tweak `prefill_chunk_size`, `context_window_size` and `sliding_window_size`
      INFO compile.py:208: Generated: /tmp/tmp4j2o862c/lib.tar
      INFO jit.py:126: Using compiled model lib: /home/work/.cache/mlc_llm/model_lib/35a0c13d99e88b056340407deeef9863.tar
      ...

      모델에 대한 작업이 끝나면 아래와 같이 로그가 출력됩니다.

      ...
      INFO package.py:154: Dump the app config below to "dist/bundle/mlc-app-config.json":
      {
        "model_list": [
          {
            "model_id": "Phi-3.5-mini-instruct-q4f16_0-MLC",
            "model_lib": "phi3_q4f16_0_5fe42298399a05eb2a1878fdc1c8c115",
            "model_url": "https://huggingface.co/mlc-ai/Phi-3.5-mini-instruct-q4f16_0-MLC",
            "estimated_vram_bytes": 4250586449
          },
          {
            "model_id": "Qwen2.5-1.5B-Instruct-q4f16_1-MLC",
            "model_lib": "qwen2_q4f16_1_2e221f430380225c03990ad24c3d030e",
            "model_url": "https://huggingface.co/mlc-ai/Qwen2.5-1.5B-Instruct-q4f16_1-MLC",
            "estimated_vram_bytes": 3980990464
          },
          {
            "model_id": "gemma-2-2b-it-q4f16_1-MLC",
            "model_lib": "gemma2_q4f16_1_5cc7dbd3ae3d1040984d9720b2d7b7d4",
            "model_url": "https://huggingface.co/mlc-ai/gemma-2-2b-it-q4f16_1-MLC",
            "estimated_vram_bytes": 3000000000
          },
          {
            "model_id": "Llama-3.2-3B-Instruct-q4f16_0-MLC",
            "model_lib": "llama_q4f16_0_4f9f463aaf4b0ede5dc8c431d8a8fb3b",
            "model_url": "https://huggingface.co/mlc-ai/Llama-3.2-3B-Instruct-q4f16_0-MLC",
            "estimated_vram_bytes": 4679979417
          },
          {
            "model_id": "Mistral-7B-Instruct-v0.3-q4f16_1-MLC",
            "model_lib": "mistral_q4f16_1_c2cba77a6def4dd52f7e20b5d8576ab5",
            "model_url": "https://huggingface.co/mlc-ai/Mistral-7B-Instruct-v0.3-q4f16_1-MLC",
            "estimated_vram_bytes": 4115131883
          }
        ]
      }
      ...

      이후 cmake와 Android NDK를 이용한 mlc4j 빌드가 진행됩니다.

      ...
      Install the project...
      -- Install configuration: "Release"
      -- Installing: /home/work/mlc-llm/android/MLCChat/build/output/tvm4j_core.jar
      -- Installing: /home/work/mlc-llm/android/MLCChat/build/output/arm64-v8a/libtvm4j_runtime_packed.so
      INFO package.py:279: Clean up all directories under "dist/lib/mlc4j"
      INFO package.py:286: Copying "/home/work/mlc-llm/android/mlc4j/src" to "dist/lib/mlc4j/src"
      INFO package.py:291: Copying "/home/work/mlc-llm/android/mlc4j/build.gradle" to "dist/lib/mlc4j/build.gradle"
      INFO package.py:296: Copying "build/output" to "dist/lib/mlc4j/output"
      INFO package.py:302: Moving "dist/bundle/mlc-app-config.json" to "dist/lib/mlc4j/src/main/assets/mlc-app-config.json"
      INFO package.py:367: All finished.

      MLC LLM 준비가 모두 끝났습니다. 이제 gradle을 이용해 안드로이드 애플리케이션을 빌드합니다.

      # Android application 빌드
      (mlc) $ ./gradlew assembleDebug
      
      # apk 설치
      (mlc) $ adb install app/build/outputs/apk/debug/app-debug.apk

      설치 후 실행하면 아래와 같이 모델 목록 화면이 나타나는데, 테스트를 원하는 모델을 찾아 다운로드 버튼을 선택하면 모델 다운로드가 진행됩니다.

      일부 대형 모델의 경우 스마트폰 메모리 부족으로 다운로드 후 채팅을 시작할 때 앱이 강제 종료될 수 있으니 유의해야 합니다.

      참고로, Gemma2-2B 모델의 경우 Galaxy S23 기기에서 정상적으로 동작했습니다.

      MLCChat-download-screen

      Gemma2-2B 모델의 다운로드가 완료된 후 채팅 아이콘을 선택하면 모델 로딩이 시작됩니다.

      MLCChat-model-init

      모델에 따라 로딩 시간이 오래 걸릴 수 있습니다. 로딩이 완료되면, 아래와 같이 'Ready to chat' 메시지가 표시됩니다.

      MLCChat-model-ready

      이제 챗봇 사용자 인터페이스를 이용해서 질문을 입력하고 AI 응답을 받을 수 있습니다.

      "What is the capital of France?" 라고 입력하니 "The capital of France is Paris." 라고 잘 답변하는 것을 확인할 수 있습니다.

      MLCChat-model-chat

      MLCEngineExample 앱 빌드

      MLCEngineExample은 MLCChat과 달리 UI 중심의 앱이 아니라 MLCEngine API를 보여주는 코드 중심의 예제 애플리케이션입니다.

      앱을 실행하면 미리 정의된 프롬프트에 대한 응답을 생성합니다. 빌드 과정은 MLCChat과 동일한데, 모델 사용 방식이 조금 다릅니다.

      코드에서 모델을 직접 명시한 후, 앱을 빌드하고 apk를 설치한 뒤 adb push 명령으로 모델 파일을 안드로이드 디바이스에 수동으로 복사해야 합니다.

      먼저 mlc_llm package 명령을 수행합니다.

      $ source ~/venv/mlc/bin/activate
      (mlc) $ cd mlc-llm/android/MLCEngineExample
      (mlc) $ mlc_llm package
      ...
      INFO package.py:154: Dump the app config below to "dist/bundle/mlc-app-config.json":
      {
        "model_list": [
          {
            "model_id": "phi-2-q4f16_1-MLC",
            "model_lib": "phi_msft_q4f16_1_959e51eb59401996c38a702577525ca9",
            "model_url": "https://huggingface.co/mlc-ai/phi-2-q4f16_1-MLC",
            "estimated_vram_bytes": 2036816936
          }
        ]
      }
      ...

      mlc_llm package 명령이 정상적으로 완료되면, MLCChat과 다르게 소스코드 수정 과정이 추가로 필요합니다.

      위 로그 정보에서 얻은 model_lib 값을 MainActivity.kt 파일에 반영합니다.

      class MainActivity : ComponentActivity() {
          // ...
          override fun onCreate(savedInstanceState: Bundle?) {
              // ...
              // need to be changed to the custom system lib prefix used while compiling the model
              val modelLib = "phi_msft_q4f16_1_959e51eb59401996c38a702577525ca9"

      이후 안드로이드 앱 빌드 과정은 동일합니다.

      # Android application 빌드
      ./gradlew assembleDebug
      
      # apk 설치
      adb install app/build/outputs/apk/debug/app-debug.apk

      MLCEngineExample은 MLCChat과 달리 모델을 자동으로 다운로드하지 않으므로, 모델 파일을 직접 안드로이드 기기에 복사해야 합니다.

      # 모델 다운로드
      git clone https://huggingface.co/mlc-ai/phi-2-q4f16_1-MLC
      
      # 디렉토리 생성
      adb shell mkdir -p /storage/emulated/0/Android/data/ai.mlc.mlcengineexample/files/phi-2-q4f16_1-MLC
      
      # 모델 복사
      adb push phi-2-q4f16_1-MLC/* /storage/emulated/0/Android/data/ai.mlc.mlcengineexample/files/phi-2-q4f16_1-MLC/

      앱을 실행하면 지정된 모델을 메모리에 로드하고 코드에 사전에 정의된 대화("What is the meaning of life?")를 수행합니다.

      모델 로딩에는 시간이 걸릴 수 있으며, 처리가 완료되면 화면에 결과가 표시됩니다.

      MLCEngineExample


      다른 모델들 사용해보기

      MLC LLM에서 사용할 수 있도록 미리 준비된 모델은 https://huggingface.co/mlc-ai 웹페이지에서 찾아볼 수 있습니다.

      MLCChat 샘플앱 mlc-package-config.json에 기본 정의된 모델들은 사양이 낮은 스마트폰에서 실행이 어려울 수 있습니다.

      따라서 아래와 같이 좀 더 작은 사이즈의 모델들을 사용하는 것이 좋습니다.

      모델 양자화와 컨버팅

      MLC LLM에서는 모델을 더 효율적으로 실행하기 위해 양자화(Quantization)를 적용합니다.

      양자화는 모델의 가중치 정밀도를 낮추어 크기를 줄이고 실행 속도를 향상시키는 기법입니다.

      예를 들어, q4f16_1은 4비트 양자화를 의미합니다.

      직접 파인튜닝한 모델이 있을 경우, MLC LLM에서 제공하는 다음 명령을 이용해 모델을 컨버팅하고 테스트해볼 수 있습니다.

      # 모델 변환
      mlc_llm convert_weight
      
      # 모델 설정 파일 생성
      mlc_llm gen_config
      
      # 모델 테스트 (cli 인터페이스 제공)
      mlc_llm chat

      컨버팅 과정은 시간이 많이 소요되기 때문에 CPU 보다는 GPU 기반의 환경에서 수행하는 것을 추천합니다.

      GPU 기반의 MLC LLM 설치는 아래 명령을 통해 가능합니다

      # CUDA 12.2 기준 TVM Unity Compiler 및 MLC LLM 설치
      pip install --pre -U -f https://mlc.ai/wheels mlc-ai-nightly-cu122
      pip install --pre -U -f https://mlc.ai/wheels mlc-llm-nightly-cu122

      컨버팅 예시 - Qwen2.5-0.5B

      Qwen2.5-0.5B 기반으로 fine tuning된 모델을 MLC LLM에서 사용 가능한 형태로 변환하는 예시입니다.

      # 컨버팅 대상 모델 설정 (qwen_merged 디렉토리 아래에 safetensor 등 모델 관련 파일들이 위치)
      (mlc) $ export MLC_SOURCE_PATH=./qwen_merged
      
      # 저장될 위치 설정
      (mlc) $ export MLC_MODEL_PATH=./dist/Qwen2.5-0.5B-Instruct-custom-q4f16_1-MLC
      
      # convert_weight 명령으로 모델 가중치를 MLC LLM 형식으로 변환 (q4f16_1: 4비트 양자화)
      (mlc) $ mlc_llm convert_weight $MLC_SOURCE_PATH -o $MLC_MODEL_PATH --quantization q4f16_1
      
      # 설정 생성 (prefill-chunk-size 기본값 8192, 스마트폰에서 용량 부족으로 crash 발생시 단계를 낮추기)
      (mlc) $ mlc_llm gen_config $MLC_SOURCE_PATH -o $MLC_MODEL_PATH \
          --quantization q4f16_1 --conv-template qwen2 \
          --prefill-chunk-size 1024
      
      # chat 모드를 이용해 테스트
      (mlc) $ mlc_llm chat $MLC_MODEL_PATH

      여기서 prefill-chunk-size는 모델이 한 번에 처리하는 토큰의 개수를 제한하는 값으로, 메모리 사용량과 관련이 있습니다.

      값이 클수록 처리 속도는 향상될 수 있지만 메모리 사용량이 증가합니다.

      저사양 기기에서는 이 값을 줄여서 메모리 부족 문제를 해결할 수 있습니다.

      컨버팅 예시 - SmolLM2-360M

      SmolLM2-360M 기반으로 fine tuning된 모델의 변환 과정은 다음과 같습니다.

      # 컨버팅 대상 모델 설정 (smollm2-merged 디렉토리 아래에 safetensor 등 모델 관련 파일들이 위치)
      (mlc) $ export MLC_SOURCE_PATH=./smollm2-merged
      
      # 저장될 위치 설정
      (mlc) $ export MLC_MODEL_PATH=./dist/SmolLM2-360M-Instruct-custom-q4f16_1-MLC
      
      # convert_weight 명령으로 모델 가중치를 MLC LLM 형식으로 변환 (q4f16_1: 4비트 양자화)
      (mlc) $ mlc_llm convert_weight $MLC_SOURCE_PATH -o $MLC_MODEL_PATH --quantization q4f16_1
      
      # 설정 생성
      (mlc) $ mlc_llm gen_config $MLC_SOURCE_PATH -o $MLC_MODEL_PATH \
          --quantization q4f16_1 --conv-template chatml
      
      # chat 모드를 이용해 테스트
      (mlc) $ mlc_llm chat $MLC_MODEL_PATH

      --conv-template 옵션은 모델의 대화 형식을 지정합니다. 각 모델마다 학습된 대화 형식이 다를 수 있으므로, 적절한 템플릿을 선택하는 것이 중요합니다.

      Qwen2.5 시리즈는 qwen2 템플릿을, SmolLM2는 chatml 템플릿을 사용합니다.


      컨버팅이 성공적으로 완료되고 제공된 chat 모드를 이용해 정상 동작이 확인되면,

      변환된 모델을 Hugging Face 등에 업로드한 후 MLCChat 샘플의 mlc-package-config.json 파일을 수정하여 앱에서 사용할 수 있습니다.


      설치 과정 요약

      지금까지 위에서 설명드린 설치 과정들을 하나로 요약하면 아래의 Dockerfile과 같은 형태가 됩니다.

      단, 도커 이미지 용량이 너무 커지는 이슈가 있어서 몇가지 수정 사항을 반영했습니다.

      • Debian 12 (bookworm) 기반의 Python 3.11 이미지 사용

      • Android Studio에서 제공하는 jbr java 대신 openjdk 사용

      • 직접 모델 컨버팅은 수행하지 않기 때문에 일부 불필요한 pip 모듈 제거

      FROM python:3.11-bookworm
       
      ENV ANDROID_HOME=/opt/android-sdk \
          JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/ \
          MLC_LLM_SOURCE_DIR=/opt/mlc-llm
       
      ENV PATH=$PATH:/root/.cargo/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmake/3.22.1/bin \
          ANDROID_NDK=$ANDROID_HOME/ndk/27.2.12479018
       
      ENV TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android34-clang \
          TVM_SOURCE_DIR=$MLC_LLM_SOURCE_DIR/3rdparty/tvm
       
      # Rust, openjdk-17, git-lfs, cmdline-tools, sdkmanager
      RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
          && rm -rf /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/doc/ \
          && apt update && apt install -y openjdk-17-jdk git-lfs && rm -rf /var/lib/apt/lists/* \
          && mkdir -p $ANDROID_HOME/cmdline-tools/latest \
          && wget https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip \
          && unzip commandlinetools-linux-13114758_latest.zip \
          && rm commandlinetools-linux-13114758_latest.zip \
          && mv cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest \
          && rmdir cmdline-tools \
          && yes | sdkmanager --licenses \
          && sdkmanager --update \
          && sdkmanager "platform-tools" "platforms;android-35"  "build-tools;35.0.0" "ndk;27.2.12479018" "cmake;3.22.1" \
          && sdkmanager --list_installed
       
      # MLC LLM repository
      RUN cd /opt \
          && git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/mlc-ai/mlc-llm.git \
          && rm -rf mlc-llm/.git
      
      # disable a pip version check to reduce run-time & log-spam
      # cache is useless in docker image, so disable to reduce image size
      ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
          PIP_NO_CACHE_DIR=1
       
      # TVM Unity Compiler & MLC LLM package
      RUN pip install --upgrade pip \
          && pip install --pre -U -f https://mlc.ai/wheels mlc-ai-nightly-cpu \
          && pip install --pre -U -f https://mlc.ai/wheels mlc-llm-nightly-cpu \
          && pip uninstall -y nvidia-nvtx-cu12 nvidia-nvjitlink-cu12 nvidia-nccl-cu12 nvidia-cusparselt-cu12 \
          && pip uninstall -y nvidia-cusparse-cu12 nvidia-cublas-cu12 nvidia-cusolver-cu12 nvidia-curand-cu12 \
          && pip uninstall -y nvidia-cufft-cu12 nvidia-cudnn-cu12 nvidia-cuda-runtime-cu12 nvidia-cuda-nvrtc-cu12 \
          && pip uninstall -y nvidia-cuda-cupti-cu12

      위 이미지를 사용하면 mlc_llm package 또는 ./gradlew assembleDebug 같은 명령을 바로 실행할 수 있고, MLC LLM 기반의 안드로이드 앱을 쉽게 빌드하실 수 있습니다.


      마치며

      이 글에서는 MLC LLM을 사용하여 안드로이드 기기에서 경량화된 LLM을 실행하는 방법을 알아보았습니다.

      MLC LLM은 다양한 모델을 지원하며, 언어 모델을 모바일 기기에서 구동할 수 있게 해주는 강력한 도구입니다.

      On-device AI는 개인정보 보호, 네트워크 연결 없는 사용, 그리고 응답 지연시간 감소 등 여러 장점을 제공합니다.

      또한, 모델 양자화를 통해 메모리 사용량을 줄이고 실행 속도를 향상시킬 수 있어 자원이 제한된 모바일 환경에서도 효율적으로 AI를 활용할 수 있습니다.

      이 글이 안드로이드 개발자들이 자신의 앱에 AI 기능을 추가하는 데 도움이 되길 바랍니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      이너 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기