Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 290 additions & 1 deletion docs/EasterEgg/Android/readme.md
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,291 @@
# InternLM 1.8B 安卓端部署实践
![image](https://github.com/user-attachments/assets/5ede99d5-e82b-4ff8-acd8-407f9277967a)

本文将带大家手把手使用[mlc-llm](https://llm.mlc.ai/docs/deploy/android.html#android-sdk)将 InternLM2 部署到安卓手机上

首先我们来看一下最终的效果~
<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>

## 1 环境准备
### 1.1 安装rust
参考 [https://forge.rust-lang.org/infra/other-installation-methods.html#which](https://forge.rust-lang.org/infra/other-installation-methods.html#which)

使用了国内的镜像,出现选项直接Enter

```
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh
```

### 1.2 安装Android Studio
参考 [https://developer.android.com/studio](https://developer.android.com/studio)

```
mkdir -p /root/android && cd /root/android
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2024.1.1.12/android-studio-2024.1.1.12-linux.tar.gz
tar -xvzf android-studio-2024.1.1.12-linux.tar.gz
cd android-studio
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=zh-cn
unzip commandlinetools-linux-11076708_latest.zip\?hl\=zh-cn
export JAVA_HOME=/root/Downloads/android-studio/jbr
cmdline-tools/bin/sdkmanager "ndk;27.0.12077973" "cmake;3.22.1" "platforms;android-34" "build-tools;33.0.1" --sdk_root='sdk'
```


### 1.3 设置环境变量
```
. "$HOME/.cargo/env"
export ANDROID_NDK=/root/android/android-studio/sdk/ndk/27.0.12077973
export TVM_NDK_CC=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang
export JAVA_HOME=/root/android//android-studio/jbr
export ANDROID_HOME=/root/android/android-studio/sdk
export PATH=/usr/local/cuda-12/bin:$PATH
export PATH=/root/android/android-studio/sdk/cmake/3.22.1/bin:$PATH
```
## 2 转换模型
### 2.1 安装mlc-llm
参考[https://llm.mlc.ai/docs/install/mlc_llm.html](https://llm.mlc.ai/docs/install/mlc_llm.html)
(如果下载很慢可以取消重新运行一下,或者本地下载了拷过去)
```
conda create --name mlc-prebuilt python=3.11
conda activate mlc-prebuilt
conda install -c conda-forge git-lfs
pip install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 transformers sentencepiece protobuf
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
wget https://github.com/mlc-ai/package/releases/download/v0.9.dev0/mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_ai_nightly_cu122-0.15.dev404-cp311-cp311-manylinux_2_28_x86_64.whl
pip install mlc_llm_nightly_cu122-0.1.dev1445-cp311-cp311-manylinux_2_28_x86_64.whl
```
测试如下输出说明安装正确

```
python -c "import mlc_llm; print(mlc_llm)"
```
![image](https://github.com/user-attachments/assets/f497f704-de19-4043-b901-af26856a62c9)

克隆项目
```
git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
```

### 2.2 转换参数
You can be under the mlc-llm repo, or your own working directory. Note that all platforms can share the same compiled/quantized weights. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `convert_weight`.

```
cd android/MLCChat
export TVM_SOURCE_DIR=/root/android/mlc-llm/3rdparty/tvm
export MLC_LLM_SOURCE_DIR=/root/android/mlc-llm
mlc_llm convert_weight /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC
```
### 2.3 生成配置
Use mlc_llm gen_config to generate mlc-chat-config.json and process tokenizers. See [Compile Command Specification](https://llm.mlc.ai/docs/compilation/compile_models.html#compile-command-specification) for specification of `gen_config`.

```

mlc_llm gen_config /root/models/internlm2-chat-1_8b-sft/ \
--quantization q4f16_1 --conv-template chatml \
-o dist/internlm2-chat-1_8b-sft-q4f16_1-MLC

```
### 2.4 上传到huggingface
上传这一步需要能访问huggingface,可能需要部署代理
如果没有代理可以直接在接下来的配置中使用如下链接的模型(和文档中的转换方法一样)
[https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC](https://huggingface.co/timws/internlm2-chat-1_8b-sft-q4f16_1-MLC)
### 2.5 (可选) 测试转换的模型
在打包之前可以测试模型效果,需要编译成二进制文件
在个人电脑上运行测试代码正常,**InternStudio**上**暂未成功**
```

mlc_llm compile ./dist/internlm2-chat-1_8b-sft-q4f16_1-MLC/mlc-chat-config.json \
--device cuda -o dist/libs/internlm2-chat-1_8b-sft-q4f16_1-MLC-cuda.so
```
测试编译的模型是否符合预期,手机端运行的效果和测试效果接近
```python3
from mlc_llm import MLCEngine

# Create engine
engine = MLCEngine(model="./dist/internlm2-1_8b-q4f16_1-MLC", model_lib="./dist/libs/internlm2-1_8b-q4f16_1-MLC-cuda.so")

# Run chat completion in OpenAI API.
print(engine)
for response in engine.chat.completions.create(
messages=[{"role": "user", "content": "你是谁?"}],
stream=True
):
for choice in response.choices:
print(choice.delta.content, end="", flush=True)
print("\n")
engine.terminate()
```

## 3 打包运行
### 3.1 修改配置文件
修改`mlc-package-config.json`
参考如下
```
{
"device": "android",
"model_list": [
{
"model": "HF://timws/internlm2-chat-1_8b-sft-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464,
"model_id": "internlm2-chat-1_8b-sft-q4f16_1-MLC"

},
{
"model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
"model_id": "gemma-2b-q4f16_1-MLC",
"estimated_vram_bytes": 3980990464
}
]
}

```

### 3.2 运行打包命令

```
mlc_llm package
```
![image](https://github.com/user-attachments/assets/0e1db9c5-6252-4c6f-81b2-a739fa4fac44)


### 3.3 创建签名
```
cd /root/android/mlc-llm/android/MLCChat
/root/android/android-studio/jbr/bin/keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Any
What is the name of your organizational unit?
[Unknown]: Any
What is the name of your organization?
[Unknown]: Any
What is the name of your City or Locality?
[Unknown]: Any
What is the name of your State or Province?
[Unknown]: Any
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN correct?
[no]: yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Any, OU=Any, O=Any, L=Any, ST=Any, C=CN
[Storing my-release-key.jks]
```
### 3.4 修改gradle配置
如果是本地可以WIFI或USB调试不用签名,在服务器构建需要签名
修改`app/build.gradle`为如下内容,主要是增加了签名部分,注意确认签名文件的位置
```
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'ai.mlc.mlcchat'
compileSdk 34

defaultConfig {
applicationId "ai.mlc.mlcchat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.4.3'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

signingConfigs {
release {
storeFile file("/root/android/mlc-llm/android/MLCChat/my-release-key.jks")
storePassword "123456"
keyAlias "mykey"
keyPassword "123456"
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

dependencies {
implementation project(":mlc4j")
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3:1.1.0'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.navigation:navigation-compose:2.5.3'
implementation 'com.google.code.gson:gson:2.10.1'
implementation fileTree(dir: 'src/main/libs', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

}
```

### 3.5 命令行编译
运行编译命令,完成后在`app/build/outputs/apk/release`生成`app-release.apk`安装包,下载到手机上运行
运行App需要能访问huggingface下载模型(参考文档中的bundle方法需要ADB刷入模型数据)
```
./gradlew assembleRelease
```
![image](https://github.com/user-attachments/assets/df7673f7-7128-4079-b77d-37093fff6660)



### 3.6 运行体验
运行App需要能访问huggingface下载模型

<div align="center">
<img src="https://github.com/user-attachments/assets/cd9fe502-490e-40c6-8649-30671a4fe504" width="50%" height="50%">
</div>