Android端部署DeepSeek的詳細(xì)教程
DeepSeek最近幾個(gè)月很火熱,很多產(chǎn)品以及企業(yè)都在接入DeepSeek,比如微信搜索接入,可以搜索公眾號(hào)信息并總結(jié),這個(gè)對(duì)于查一些資料還挺好用,因?yàn)楝F(xiàn)在很多都會(huì)在公眾號(hào)上寫一些東西,進(jìn)行宣傳,畢竟手機(jī)才是用戶用的最多的。
既然談到了手機(jī),那么DeepSeek能否部署于手機(jī)之上呢,在不聯(lián)網(wǎng)的情況下就能使用?基于這個(gè)問題,查詢了相關(guān)資料,發(fā)現(xiàn)android端部署DeepSeek兩種方法:
第一種是使用Termux。Termux 是一款終端模擬器應(yīng)用程序,專為 Android 系統(tǒng)設(shè)計(jì),提供完整的 Linux 環(huán)境,允許用戶在 Android 設(shè)備上運(yùn)行 Linux 命令和工具,無需 root 權(quán)限。然后使用ollama相關(guān)命令下載部署模型即可。目前網(wǎng)上基本上都是這種方式,這種方式其實(shí)跟在服務(wù)端部署差不多,所以為啥不直接用服務(wù)端部署的模型呢。
第二種就是直接將模型文件下載到手機(jī)中,應(yīng)用內(nèi)直接加載模型文件并運(yùn)行,這種方式好處在于,可結(jié)合自身業(yè)務(wù)做一些基于大模型的離線本地私有化應(yīng)用,耗費(fèi)基本為0。
本文主要采用第二種方法,基于阿里MNN庫進(jìn)行部署。
1 準(zhǔn)備環(huán)境
1.1 MNN轉(zhuǎn)換工具
cd MNN mkdir build && cd build cmake .. -DMNN_BUILD_CONVERTER=ON make -j8
這個(gè)主要是得到MNNConvert轉(zhuǎn)換工具,可用來轉(zhuǎn)換onnx格式為mnn格式
1.2 大模型轉(zhuǎn)換工具
安裝大模型轉(zhuǎn)換工具需要的一些依賴,可用conda來進(jìn)行環(huán)境管理
cd path/MNN/transformers/llm/export pip install -r requirements.txt
如果只是想試試大模型android端部署,把這些依賴下載下來,然后使用如下方式一轉(zhuǎn)換模型就行了
1.3 模型下載
git lfs install git clone https://www.modelscope.cn/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B.
1.4 模型轉(zhuǎn)換
方式一:直接使用llmexport.py直接轉(zhuǎn)換得到mnn格式的模型文件
python llmexport.py --path path/model/DeepSeek-R1-Distill-Qwen-1.5B --export mnn
方式二:可先轉(zhuǎn)換為onnx,然后再使用MNNConvert轉(zhuǎn)換為mnn格式模型
python llmexport.py --path path/model/DeepSeek-R1-Distill-Qwen-1.5B --export onnx ./MNNConvert -f ONNX --modelFile llm.onnx --MNNModel llm.mnn --bizCode biz
兩種方式都嘗試過,轉(zhuǎn)換出來的模型都沒啥問題,方式二主要可以進(jìn)行其他bits數(shù)的量化
成功:
產(chǎn)物解釋:
1.5 編譯android依賴庫
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_OPENCL=true -DMNN_USE_LOGCAT=true" mkdir build_32 && cd build_32 ../build_32.sh "-DMNN_LOW_MEMORY=true -DMNN_CPU_WEIGHT_DEQUANT_GEMM=true -DMNN_BUILD_LLM=true -DMNN_SUPPORT_TRANSFORMER_FUSE=true -DMNN_ARM82=true -DMNN_OPENCL=true -DMNN_USE_LOGCAT=true"
這個(gè)主要是用于編譯android需要用的mnn庫,編譯完成后將*.so文件將其放在android工程中
提示:如果需要調(diào)試mnn庫,需要將build_64/32.sh文件中的如下參數(shù)設(shè)置為true
2 android工程
主要介紹一下其中一些關(guān)鍵的點(diǎn):CMakeList文件的編寫、JNI文件的編寫,以及簡要說一下android native的實(shí)現(xiàn)
2.1 頭文件導(dǎo)入
將MNN庫中的頭文件(要包含llm.hpp頭文件),以及1.5編譯的android依賴庫放入android工程中,目錄如下:
2.2 CMakeList
cmake_minimum_required(VERSION 3.10.2) project("my_deep_seek") aux_source_directory(./ SRC_LIST) add_library(my_deep_seek SHARED ${SRC_LIST}) find_library(log-lib log) find_library(android-lib android) include_directories(${CMAKE_SOURCE_DIR}/mnn/include) include_directories(${CMAKE_SOURCE_DIR}/mnn/include/expr/) add_library(libMNN STATIC IMPORTED) add_library(libMNN_CL STATIC IMPORTED) add_library(libMNN_Express STATIC IMPORTED) add_library(libllm STATIC IMPORTED) set_target_properties( libMNN PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/mnn/${CMAKE_ANDROID_ARCH_ABI}/libMNN.so ) set_target_properties( libMNN_CL PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/mnn/${CMAKE_ANDROID_ARCH_ABI}/libMNN_CL.so ) set_target_properties( libMNN_Express PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/mnn/${CMAKE_ANDROID_ARCH_ABI}/libMNN_Express.so ) set_target_properties( libllm PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/mnn/${CMAKE_ANDROID_ARCH_ABI}/libllm.so ) message("===>>>> abi is : ${CMAKE_ANDROID_ARCH_ABI} <<<<===") target_link_libraries( my_deep_seek ${log-lib} ${android-lib} libMNN libMNN_CL libMNN_Express libllm )
2.3 JNI
class Chat : Serializable { companion object { init { System.loadLibrary("my_deep_seek") } } external fun Init(modelDir: String): Boolean // 加載模型 external fun Submit(input: String): String // 輸入請(qǐng)求 external fun Respose(): ByteArray // 模型輸出 external fun Done() external fun Reset() }
#include <android/asset_manager_jni.h> #include <android/bitmap.h> #include <android/log.h> #include <jni.h> #include <string> #include <vector> #include <sstream> #include <thread> #include "MNN/llm.hpp" #ifndef LOG_TAG #define LOG_TAG "MyDeepSeek" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__) // 定義LOGD類型 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG ,__VA_ARGS__) // 定義LOGI類型 #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG ,__VA_ARGS__) // 定義LOGW類型 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG ,__VA_ARGS__) // 定義LOGE類型 #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG ,__VA_ARGS__) // 定義LOGF類型 #endif static std::unique_ptr<MNN::Transformer::Llm> llm(nullptr); static std::stringstream response_buffer; extern "C" { // 模型加載 JNIEXPORT jboolean JNICALL Java_com_example_mydeepseek_Chat_Init(JNIEnv *env, jobject thiz, jstring modelDir) { const char* model_dir = env->GetStringUTFChars(modelDir, 0); if (!llm.get()) { llm.reset(MNN::Transformer::Llm::createLLM(model_dir)); try { llm->load(); } catch (const std::exception& e) { LOGI("=== 異常:%s ====", e.what()); return JNI_FALSE; } } return JNI_TRUE; } // 將問題輸入模型 JNIEXPORT jstring JNICALL Java_com_example_mydeepseek_Chat_Submit(JNIEnv *env, jobject thiz, jstring inputStr) { if (!llm.get()) { return env->NewStringUTF("Failed, Chat is not ready!"); } const char* input_str = env->GetStringUTFChars(inputStr, 0); auto chat = [&](std::string str) { llm->response(str, &response_buffer, "<eop>"); }; std::thread chat_thread(chat, input_str); //子線程運(yùn)行 chat_thread.detach(); jstring result = env->NewStringUTF("Submit success!"); return result; } // 取出模型輸出 JNIEXPORT jbyteArray JNICALL Java_com_example_mydeepseek_Chat_Respose(JNIEnv *env, jobject thiz) { auto len = response_buffer.str().size(); jbyteArray res = env->NewByteArray(len); env->SetByteArrayRegion(res, 0, len, (const jbyte*)response_buffer.str().c_str()); return res; } JNIEXPORT void JNICALL Java_com_example_mydeepseek_Chat_Done(JNIEnv *env, jobject thiz) { response_buffer.str(""); } JNIEXPORT void JNICALL Java_com_example_mydeepseek_Chat_Reset(JNIEnv *env, jobject thiz) { llm->reset(); } } // extern "C"
2.4 android native
app實(shí)現(xiàn)方面比較簡單,使用recycleview來顯示與模型的對(duì)話,其他就調(diào)用jni接口即可
(1)加載模型
將1.4節(jié)模型轉(zhuǎn)換得到的那些文件將其放到手機(jī)的/data/local/tmp/DeepSeek-R1-Distill-Qwen-1.5B目錄下,然后mModelDir就為/data/local/tmp/DeepSeek-R1-Distill-Qwen-1.5B/llm.mnn
Thread { mChat = Chat() if (mChat?.Init(mModelDir) == true) { runOnUiThread { mIntent?.putExtra("chat", mChat) startActivityForResult(mIntent, 100) } } else { Toast.makeText(this,"加載模型失敗", Toast.LENGTH_SHORT).show() } }.start()
(2)向模型輸入
mChat?.Submit(input)
(3)得到模型輸出
Thread { mChat?.Submit(input) // 輸入 var lastResponse = "" while (!lastResponse.contains("<eop>")) { // 模型輸出結(jié)束標(biāo)志"<eop>" try { Thread.sleep(50) // 等模型輸出一點(diǎn)信息 val response: String = String(mChat?.Respose() ?: ByteArray(0)) if (response != lastResponse) { lastResponse = response lifecycleScope.launch { updateBotResponse( response.replaceFirst( "<eop>".toRegex(), "" ) ) } } } catch (e: InterruptedException) { Thread.currentThread().interrupt() } } mChat?.Done() }
3 總結(jié)
1.5B模型,運(yùn)行內(nèi)存最高1.5G,推理時(shí)1G,占用內(nèi)存還挺多,且模型性能相比云端模型還是差很多。但需向前看,最近阿里的QwQ-32B模型不是達(dá)到了DeepSeek 671B模型的性能了嗎,甚至某些方面還超越DeepSeek,發(fā)展還是很快的。說不定后面不到1B參數(shù)的模型,性能可比肩671B模型,狠狠期待一下。
以上就是Android端部署DeepSeek的詳細(xì)教程的詳細(xì)內(nèi)容,更多關(guān)于Android端部署DeepSeek的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android Manifest中meta-data擴(kuò)展元素?cái)?shù)據(jù)的配置與獲取方式
這篇文章主要介紹了Android Manifest中meta-data擴(kuò)展元素?cái)?shù)據(jù)的配置與獲取方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android獲取WiFi網(wǎng)絡(luò)列表的流程步驟
在Android開發(fā)中,我們經(jīng)常需要獲取設(shè)備附近可用的Wi-Fi網(wǎng)絡(luò)列表,這對(duì)于開發(fā)需要基于Wi-Fi網(wǎng)絡(luò)進(jìn)行功能或者與其他設(shè)備進(jìn)行通信的應(yīng)用程序非常重要,本文將介紹如何在Android應(yīng)用程序中獲取Wi-Fi網(wǎng)絡(luò)列表,需要的朋友可以參考下2024-11-11關(guān)于Android Studio安裝完后activity_main.xml前幾行報(bào)錯(cuò)的解決建議
這篇文章主要介紹了關(guān)于Android Studio安裝完后activity_main.xml前幾行報(bào)錯(cuò)的解決建議,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android仿QQ微信實(shí)時(shí)監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài)
這篇文章主要為大家詳細(xì)介紹了Android仿QQ微信實(shí)時(shí)監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android利用屬性動(dòng)畫實(shí)現(xiàn)優(yōu)酷菜單
這篇文章主要為大家詳細(xì)介紹了Android利用屬性動(dòng)畫實(shí)現(xiàn)優(yōu)酷菜單,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Android實(shí)現(xiàn)快遞物流跟蹤布局效果
本篇文章主要介紹了Android實(shí)現(xiàn)快遞跟蹤布局效果,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05Android 浮動(dòng)編輯框的具體實(shí)現(xiàn)代碼
本篇文章主要介紹了Android 浮動(dòng)編輯框的具體實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10Android?hid發(fā)送apdu格式數(shù)據(jù)示例詳解
這篇文章主要介紹了Android?hid發(fā)送apdu格式數(shù)據(jù),在?Android?中,如果你想通過?HID(Human?Interface?Device)發(fā)送?APDU?格式的數(shù)據(jù),通常會(huì)涉及?USB?HID?設(shè)備或藍(lán)牙?HID?設(shè)備,本文給大家講解的非常詳細(xì),需要的朋友可以參考下2023-08-08