mirror of https://github.com/alibaba/MNN.git
Compare commits
8 Commits
b6a99e001c
...
d4eb5b7e74
Author | SHA1 | Date |
---|---|---|
|
d4eb5b7e74 | |
|
6ed0ea9bf3 | |
|
fad7396a0a | |
|
bf63541e58 | |
|
737c766fd4 | |
|
bd59e631c2 | |
|
7b9854b4af | |
|
8d39cdf685 |
|
@ -35,28 +35,38 @@ This is our full multimodal language model (LLM) Android app
|
|||
|
||||
|
||||
# Development
|
||||
+ Prepare
|
||||
+ Android Studio
|
||||
+ NDK(21 recommended)
|
||||
+ `export ANDROID_NDK=${YOUR_NDK_ROOT}`
|
||||
## Windows
|
||||
Using `Android Studio` IDE for building:
|
||||
+ Clone the repository:
|
||||
```shell
|
||||
git clone https://github.com/alibaba/MNN.git
|
||||
```
|
||||
+ In `Android Studio`, go to the top-left corner and click File → Open, then select the project. After that, click Build and choose either Make Project or Build Bundle(s) / APK(s) to generate the APK.
|
||||
+ If you need to integrate a prebuilt `libMNN.so` library, please place the prebuilt `libMNN.so` in `project\android\build_64\lib`, and modify the `gradle.properties` file in the `MnnLlmChat` project to configure `MNN_BUILD_LLM_FROM_PREBUILT=ON`.
|
||||
## Linux
|
||||
+ Clone the repository:
|
||||
```shell
|
||||
git clone https://github.com/alibaba/MNN.git
|
||||
git clone https://github.com/alibaba/MNN.git
|
||||
```
|
||||
+ Build library:
|
||||
```shell
|
||||
+ Configure Android SDK NDK
|
||||
```
|
||||
#here we use sdkmanager to install SDK/NDK tools
|
||||
sudo sdkmanager "platforms;android-35"
|
||||
sudo sdkmanager "build-tools;33.0.1"
|
||||
```
|
||||
+ Compile&Build
|
||||
```
|
||||
#build debug version with preebuilt libMNN
|
||||
cd project/android
|
||||
mkdir build_64
|
||||
cd build_64
|
||||
../build_64.sh "-DMNN_LOW_MEMORY=true -DMNN_CPU_WEIGHT_DEQUANT_GEMM=true -DMNN_BUILD_LLM=true -DMNN_SUPPORT_TRANSFORMER_FUSE=true -DMNN_ARM82=true -DMNN_USE_LOGCAT=true -DMNN_OPENCL=true -DLLM_SUPPORT_VISION=true -DMNN_BUILD_OPENCV=true -DMNN_IMGCODECS=true -DLLM_SUPPORT_AUDIO=true -DMNN_BUILD_AUDIO=true -DMNN_BUILD_DIFFUSION=ON -DMNN_SEP_BUILD=OFF -DCMAKE_SHARED_LINKER_FLAGS='-Wl,-z,max-page-size=16384' -DCMAKE_INSTALL_PREFIX=."
|
||||
make install
|
||||
```
|
||||
|
||||
+ build android app project and install
|
||||
```shell
|
||||
cd ../../../apps/Android/MnnLlmChat
|
||||
./gradlew installDebug
|
||||
```
|
||||
./gradlew assembleDebug -PMNN_BUILD_LLM_FROM_PREBUILT=ON
|
||||
#build debug verion from current MNN source
|
||||
./gradlew assembleDebug
|
||||
```
|
||||
|
||||
# Releases
|
||||
## Version 0.5.1.2
|
||||
|
|
|
@ -34,23 +34,40 @@
|
|||
!!!warning!!! 此版本目前仅在 OnePlus 13 和 小米 14 Ultra 上进行了测试。由于大型语言模型(LLM)对设备性能要求较高,许多低配置设备可能会遇到以下问题:推理速度缓慢、应用不稳定甚至无法运行。对于其他设备的稳定性无法保证。如果您在使用过程中遇到问题,请随时提交问题以获取帮助。
|
||||
|
||||
|
||||
# 开发
|
||||
# 开发
|
||||
## Windows
|
||||
基于`AndroidStuido` IDE进行构建:
|
||||
+ 克隆代码库:
|
||||
```shell
|
||||
git clone https://github.com/alibaba/MNN.git
|
||||
git clone https://github.com/alibaba/MNN.git
|
||||
```
|
||||
+ 构建库:
|
||||
+ `AndroidStuido`左上角File->Open,选择该工程,点击`Build`,选择`Make Project`或者`Build App Bundle(s)/APK(s)`,即可生成APK
|
||||
+ 如果需要以预编译`libMNN.so`库的形式集成,请将预编译好的`libMNN.so`放置于`project\android\build_64\lib`,并修改`MnnLlmChat`工程内的`gradle.properties`文件,配置`MNN_BUILD_LLM_FROM_PREBUILT=ON`
|
||||
## Linux
|
||||
+ 克隆代码库:
|
||||
```shell
|
||||
git clone https://github.com/alibaba/MNN.git
|
||||
```
|
||||
+ 配置Android SDK与NDK
|
||||
```shell
|
||||
#here we use sdkmanager to install SDK/NDK tools
|
||||
sudo sdkmanager "platforms;android-35"
|
||||
sudo sdkmanager "build-tools;33.0.1"
|
||||
```
|
||||
+ 编译构建
|
||||
|
||||
```shell
|
||||
#集成预编译好的libMNN.so,打包debug版本的APK
|
||||
cd project/android
|
||||
mkdir build_64
|
||||
cd build_64
|
||||
../build_64.sh "-DMNN_LOW_MEMORY=true -DMNN_CPU_WEIGHT_DEQUANT_GEMM=true -DMNN_BUILD_LLM=true -DMNN_SUPPORT_TRANSFORMER_FUSE=true -DMNN_ARM82=true -DMNN_USE_LOGCAT=true -DMNN_OPENCL=true -DLLM_SUPPORT_VISION=true -DMNN_BUILD_OPENCV=true -DMNN_IMGCODECS=true -DLLM_SUPPORT_AUDIO=true -DMNN_BUILD_AUDIO=true -DMNN_BUILD_DIFFUSION=ON -DMNN_SEP_BUILD=OFF -DCMAKE_INSTALL_PREFIX=."
|
||||
make install
|
||||
```
|
||||
+ 构建 Android 应用项目并安装:
|
||||
```shell
|
||||
cd ../../../apps/Android/MnnLlmChat
|
||||
./gradlew installDebug
|
||||
```
|
||||
./gradlew assembleDebug -PMNN_BUILD_LLM_FROM_PREBUILT=ON
|
||||
#以当前仓库内的源码进行编译生成libMNN.so,打包debug版本的APK
|
||||
./gradlew assembleDebug
|
||||
```
|
||||
|
||||
# Releases
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ plugins {
|
|||
|
||||
}
|
||||
|
||||
// if BUILT_FROM_PREBUILT passed, use its value,or will use default value "OFF"
|
||||
def builtFromPrebuilt = project.hasProperty('MNN_BUILD_LLM_FROM_PREBUILT') ? project.MNN_BUILD_LLM_FROM_PREBUILT : "OFF"
|
||||
|
||||
android {
|
||||
namespace 'com.alibaba.mnnllm.android'
|
||||
compileSdk 35
|
||||
|
@ -23,8 +26,34 @@ android {
|
|||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags '-std=c++17'
|
||||
|
||||
// Enable 16KB page size support for NDK r27
|
||||
arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||
if (builtFromPrebuilt == "OFF") {
|
||||
arguments "-DMNN_USE_SSE=OFF",
|
||||
"-DMNN_BUILD_TEST=ON",
|
||||
"-DANDROID_STL=c++_static",
|
||||
"-DMNN_BUILD_BENCHMARK=ON",
|
||||
"-DANDROID_NATIVE_API_LEVEL=android-21",
|
||||
"-DMNN_BUILD_FOR_ANDROID_COMMAND=true",
|
||||
"-DMNN_LOW_MEMORY=true",
|
||||
"-DMNN_CPU_WEIGHT_DEQUANT_GEMM=true",
|
||||
"-DMNN_BUILD_LLM=true",
|
||||
"-DMNN_SUPPORT_TRANSFORMER_FUSE=true",
|
||||
"-DMNN_ARM82=true",
|
||||
"-DMNN_USE_LOGCAT=true",
|
||||
"-DMNN_OPENCL=true",
|
||||
"-DLLM_SUPPORT_VISION=true",
|
||||
"-DMNN_BUILD_OPENCV=true",
|
||||
"-DMNN_IMGCODECS=true",
|
||||
"-DLLM_SUPPORT_AUDIO=true",
|
||||
"-DMNN_BUILD_AUDIO=true",
|
||||
"-DMNN_BUILD_DIFFUSION=ON",
|
||||
"-DMNN_SEP_BUILD=OFF",
|
||||
"-DMNN_BUILD_LLM_FROM_PREBUILT=OFF"
|
||||
} else {
|
||||
arguments "-DMNN_BUILD_LLM_FROM_PREBUILT=ON"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +220,8 @@ dependencies {
|
|||
|
||||
// 日志相关依赖
|
||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||
// implementation(name: 'android_device_names', ext: 'aar')
|
||||
|
||||
//implementation(name: 'android_device_names', ext: 'aar')
|
||||
implementation 'com.github.Juude:AndroidDeviceNames:0.0.1'
|
||||
testImplementation 'androidx.test:core:1.5.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
|
|
@ -11,6 +11,11 @@ cmake_minimum_required(VERSION 3.22.1)
|
|||
# build script scope).
|
||||
project("mnnllmapp")
|
||||
|
||||
# 设置是否使用预编译MNN库
|
||||
option(MNN_BUILD_LLM_FROM_PREBUILT "use prebuilt MNN library" OFF)
|
||||
|
||||
message(INFO "MNN_BUILD_LLM_FROM_PREBUILT: ${MNN_BUILD_LLM_FROM_PREBUILT}")
|
||||
|
||||
add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||
# List C/C++ source files with relative paths to this CMakeLists.txt.
|
||||
llm_mnn_jni.cpp
|
||||
|
@ -20,21 +25,18 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
|
|||
crash_util.cpp
|
||||
)
|
||||
|
||||
|
||||
# Add 16KB page size support (required for Android 15+ devices)
|
||||
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE "-Wl,-z,max-page-size=16384")
|
||||
|
||||
#mnn
|
||||
set (MNN_SOURCE_ROOT "${CMAKE_SOURCE_DIR}/../../../../../../../")
|
||||
set(MNN_SOURCE_ROOT "${CMAKE_SOURCE_DIR}/../../../../../../../")
|
||||
#set (MNN_SOURCE_ROOT "/Users/songjinde/git/DAI/AliNNPrivate")
|
||||
set (MNN_INSTALL_ROOT "${MNN_SOURCE_ROOT}/project/android/build_64")
|
||||
# set (MNN_INSTALL_ROOT "/Users/songjinde/MNN/project/android/build_64")
|
||||
|
||||
#set (MNN_ROOT "${CMAKE_SOURCE_DIR}/../../../../../../../")
|
||||
message(INFO "MNN_SOURCE_ROOT: ${MNN_SOURCE_ROOT}")
|
||||
message(INFO "MNN_INSTALL_ROOT: ${MNN_INSTALL_ROOT}")
|
||||
|
||||
include_directories("${MNN_SOURCE_ROOT}/include/")
|
||||
|
||||
#diffusion
|
||||
include_directories("${MNN_SOURCE_ROOT}/transformers/diffusion/engine/include/")
|
||||
|
||||
|
@ -45,31 +47,37 @@ include_directories("${MNN_SOURCE_ROOT}/transformers/llm/engine/include")
|
|||
#audio
|
||||
include_directories("${MNN_SOURCE_ROOT}/tools/audio/include")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/third_party")
|
||||
# Add library paths
|
||||
set(LIB_PATH "${MNN_INSTALL_ROOT}/lib")
|
||||
|
||||
# Link the shared library
|
||||
if (MNN_BUILD_LLM_FROM_PREBUILT)
|
||||
#use prebuilt mnn library,use build_64.sh to build
|
||||
set(MNN_INSTALL_ROOT "${MNN_SOURCE_ROOT}/project/android/build_64")
|
||||
# Add library paths
|
||||
set(LIB_PATH "${MNN_INSTALL_ROOT}/lib")
|
||||
# Link the shared library
|
||||
add_library(MNN SHARED IMPORTED)
|
||||
set_target_properties(MNN PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN.so")
|
||||
|
||||
add_library(MNN SHARED IMPORTED)
|
||||
set_target_properties(MNN PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN.so")
|
||||
#add_library(llm SHARED IMPORTED)
|
||||
#set_target_properties(llm PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libllm.so")
|
||||
|
||||
#add_library(llm SHARED IMPORTED)
|
||||
#set_target_properties(llm PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libllm.so")
|
||||
#
|
||||
#add_library(diffusion SHARED IMPORTED)
|
||||
#set_target_properties(diffusion PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libdiffusion.so")
|
||||
#
|
||||
#add_library(mnn_cl SHARED IMPORTED)
|
||||
#set_target_properties(mnn_cl PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN_CL.so")
|
||||
#
|
||||
#add_library(mnn_audio SHARED IMPORTED)
|
||||
#set_target_properties(mnn_audio PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNNAudio.so")
|
||||
#
|
||||
#add_library(mnn_cv SHARED IMPORTED)
|
||||
#set_target_properties(mnn_cv PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNNOpenCV.so")
|
||||
#
|
||||
#add_library(mnn_Express SHARED IMPORTED)
|
||||
#set_target_properties(mnn_Express PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN_Express.so")
|
||||
#add_library(diffusion SHARED IMPORTED)
|
||||
#set_target_properties(diffusion PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libdiffusion.so")
|
||||
|
||||
#add_library(mnn_cl SHARED IMPORTED)
|
||||
#set_target_properties(mnn_cl PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN_CL.so")
|
||||
|
||||
#add_library(mnn_audio SHARED IMPORTED)
|
||||
#set_target_properties(mnn_audio PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNNAudio.so")
|
||||
|
||||
#add_library(mnn_cv SHARED IMPORTED)
|
||||
#set_target_properties(mnn_cv PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNNOpenCV.so")
|
||||
|
||||
#add_library(mnn_Express SHARED IMPORTED)
|
||||
#set_target_properties(mnn_Express PROPERTIES IMPORTED_LOCATION "${LIB_PATH}/libMNN_Express.so")
|
||||
else ()
|
||||
#load local mnn,output dir will changed to .cxx
|
||||
add_subdirectory(../../../../../../../ build-mnn)
|
||||
endif ()
|
||||
|
||||
|
||||
# Link your native library with the `.so` file
|
||||
|
@ -82,4 +90,4 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
|
|||
android
|
||||
log
|
||||
MNN
|
||||
)
|
||||
)
|
||||
|
|
|
@ -19,4 +19,6 @@ android.useAndroidX=true
|
|||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.suppressUnsupportedCompileSdk=35
|
||||
android.suppressUnsupportedCompileSdk=35
|
||||
#control whether use prebuilt library
|
||||
MNN_BUILD_LLM_FROM_PREBUILT=OFF
|
|
@ -824,15 +824,37 @@ static PyObject* PyMNNInterpreter_setSessionMode(PyMNNInterpreter *self, PyObjec
|
|||
}
|
||||
static PyObject* PyMNNInterpreter_setSessionHint(PyMNNInterpreter *self, PyObject *args) {
|
||||
int type_val = 0;
|
||||
int num_val = 0;
|
||||
if (!PyArg_ParseTuple(args, "ii", &type_val, &num_val)) {
|
||||
PyObject* num_val = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "iO", &type_val, &num_val)) {
|
||||
PyErr_SetString(PyExc_Exception,
|
||||
"PyMNNInterpreter_setSessionHint: Not interger input and interger input");
|
||||
return NULL;
|
||||
"PyMNNInterpreter_setSessionHint: Not interger input and interger/list/tuple input");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto type = (MNN::Interpreter::HintMode)type_val;
|
||||
self->interpreter->setSessionHint(type, num_val);
|
||||
if (PyList_Check(num_val)) {
|
||||
size_t size = PyList_Size(num_val);
|
||||
int* list = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
list[i] = static_cast<int>(PyLong_AsLong(PyList_GetItem(num_val, i)));
|
||||
}
|
||||
self->interpreter->setSessionHint(type, list, size);
|
||||
delete[] list;
|
||||
} else if (PyTuple_Check(num_val)) {
|
||||
size_t size = PyTuple_Size(num_val);
|
||||
int* list = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
list[i] = static_cast<int>(PyLong_AsLong(PyTuple_GetItem(num_val, i)));
|
||||
}
|
||||
self->interpreter->setSessionHint(type, list, size);
|
||||
delete[] list;
|
||||
} else if (PyLong_Check(num_val)) {
|
||||
self->interpreter->setSessionHint(type, static_cast<int>(PyLong_AsLong(num_val)));
|
||||
} else {
|
||||
PyErr_SetString(PyExc_Exception,
|
||||
"PyMNNInterpreter_setSessionHint: num_val must be a list, tuple or int");
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
static PyObject* PyMNNInterpreter_runSession(PyMNNInterpreter *self, PyObject *args) {
|
||||
|
|
|
@ -345,15 +345,37 @@ static PyObject* PyMNNRuntimeManager_set_mode(PyMNNRuntimeManager *self, PyObjec
|
|||
}
|
||||
static PyObject* PyMNNRuntimeManager_set_hint(PyMNNRuntimeManager *self, PyObject *args) {
|
||||
int type_val = 0;
|
||||
int num_val = 0;
|
||||
if (!PyArg_ParseTuple(args, "ii", &type_val, &num_val)) {
|
||||
PyObject* num_val = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "iO", &type_val, &num_val)) {
|
||||
PyErr_SetString(PyExc_Exception,
|
||||
"PyMNNRuntimeManager_set_hint: Not interger input and interger input");
|
||||
return NULL;
|
||||
"PyMNNRuntimeManager_set_hint: Not interger input and interger/list/tuple input");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto type = (MNN::Interpreter::HintMode)type_val;
|
||||
(*(self->ptr))->setHint(type, num_val);
|
||||
if (PyList_Check(num_val)) {
|
||||
size_t size = PyList_Size(num_val);
|
||||
int* list = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
list[i] = static_cast<int>(PyLong_AsLong(PyList_GetItem(num_val, i)));
|
||||
}
|
||||
(*(self->ptr))->setHint(type, list, size);
|
||||
delete[] list;
|
||||
} else if (PyTuple_Check(num_val)) {
|
||||
size_t size = PyTuple_Size(num_val);
|
||||
int* list = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
list[i] = static_cast<int>(PyLong_AsLong(PyTuple_GetItem(num_val, i)));
|
||||
}
|
||||
(*(self->ptr))->setHint(type, list, size);
|
||||
delete[] list;
|
||||
} else if (PyLong_Check(num_val)) {
|
||||
(*(self->ptr))->setHint(type, static_cast<int>(PyLong_AsLong(num_val)));
|
||||
} else {
|
||||
PyErr_SetString(PyExc_Exception,
|
||||
"PyMNNRuntimeManager_set_hint: num_val must be a list, tuple or int");
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue