MediaPipe Tasks 在 Android 中的生成式 AI 实践:基于 Gemma 3n 的移动端

目录

  1. 引言
  2. MediaPipe 简介
  3. Android 环境搭建与使用
  4. Gemma 3n 功能特性
  5. 多模态支持与高级功能
  6. 移动端 AI 的优势与前景
  7. 总结与展望
  8. 参考资源

引言

随着人工智能技术的快速发展,移动端 AI 应用需求日益增长。Google 的 MediaPipe 作为一个开源的机器学习框架,为开发者提供了强大的工具集来构建跨平台的 AI 应用。本文将深入探讨 MediaPipe Tasks 在 Android 平台上的应用,特别是基于最新的 Gemma 3n 模型实现生成式 AI 任务。

Gemma 3n 是 Google 最新发布的生成式 AI 模型,专门为手机、笔记本电脑和平板电脑等移动设备优化。该模型采用了参数高效处理创新技术,包括:

  • 每层嵌入 (PLE) 参数缓存:通过分层参数复用降低内存占用
  • MatFormer 模型架构:针对移动设备优化的轻量级 Transformer 结构

这些技术能够灵活地降低计算和内存要求,在移动端生成内容的速度和 AI 能力上都表现很优秀。

MediaPipe 简介

MediaPipe 是一套工具和库,它可以让我们在移动端快速部署人工智能 (AI) 和机器学习 (ML)模型。

核心组件

MediaPipe 包含以下核心组件:

  1. MediaPipe Tasks:提供跨平台 API 和库,用于部署各种 AI 解决方案
  2. MediaPipe 模型:预训练的即用型模型,支持多种 AI 任务
  3. MediaPipe Model Maker:自定义模型训练工具
  4. MediaPipe Studio:可视化评估和对比解决方案的浏览器工具

MediaPipe Model Maker

MediaPipe Model Maker 是一款用于自定义机器学习模型的工具,它通过新数据对已有模型进行重新训练来实现定制。
这款工具适用范围较广,能用于多种传统 AI 任务的模型定制,比如对象检测、手势识别,以及图片、文本、音频数据的分类器等。
需要注意的是,它与后面会介绍的 LoRA 模型定制有所不同:LoRA 主要面向生成式 AI 领域,尤其专注于大语言模型(LLM)的定制化。

MediaPipe Studio

MediaPipe Studio 是一款网页版工具,专门用来调试和定制能在设备端运行的机器学习模型及流程。
用它的时候,你可以直接在浏览器里上传自己的数据、用自己定制的机器学习模型,快速测试 MediaPipe 的各种解决方案(比如手势识别、图像分类等)。
简单说,它就像一个在线工作台,不用复杂配置,打开就能直观地评估模型效果,或者根据自己的需求调整模型和运行流程,很适合快速验证想法。

支持的任务类型

MediaPipe Tasks 支持的功能和平台如下表格所示:

解决方案 Android 网页 Python iOS 自定义模型
LLM Inference API ✓ ✓ ✓ ✓
对象检测 ✓ ✓ ✓ ✓ ✓
图片分类 ✓ ✓ ✓ ✓ ✓
图片分割 ✓ ✓ ✓
交互式细分 ✓ ✓ ✓
手部地标检测 ✓ ✓ ✓ ✓
手势识别 ✓ ✓ ✓ ✓ ✓
图片嵌入 ✓ ✓ ✓
人脸检测 ✓ ✓ ✓ ✓
人脸特征点检测 ✓ ✓ ✓
人脸风格化 ✓ ✓ ✓ ✓
姿势特征点检测 ✓ ✓ ✓
图片生成 ✓ ✓
文本分类 ✓ ✓ ✓ ✓ ✓
文本嵌入 ✓ ✓ ✓
语言检测器 ✓ ✓ ✓
音频分类 ✓ ✓ ✓

第三方模型生态

LiteRT Community 平台是一个专为移动端优化的模型分发平台,提供预转换的.task 格式模型,这种格式可以使用 MediaPipe LLM Inference API 直接加载使用,避免开发者手动转换。模型库中主要包含以下热门的生成式 AI 模型:

  • Gemma 系列:Gemma-3 1B、Gemma-3 2B、Gemma 3n 等
  • Deepseek 系列:针对代码生成和推理优化的模型
  • Qwen 系列:阿里巴巴的多语言大模型,如 Qwen2.5-1.5B-Instruct
  • SmolVLM:轻量级多模态视觉语言模型
  • MedGemma:医疗领域专用模型

图片生成模型

MediaPipe 虽然支持文本到图像生成功能,但第三方的模型并不完善,需要转换。兼容的模型主要有以下几个,这些模型只能实现生成固定的风格,比如 hakurei/waifu-diffusion-v1-4 可以生成动漫风格图片。这些模型需要转换成 .task 格式才能在 MediaPipe 中使用。

推荐的兼容模型:

  • runwayml/stable-diffusion-v1-5:主推荐模型,稳定性和质量最佳
  • justinpinkney/miniSD:轻量级版本,适合移动端
  • hakurei/waifu-diffusion-v1-4:动漫风格图片生成
  • Fictiverse/Stable_Diffusion_PaperCut_Model:纸切艺术风格

设备端转换流程:

  1. 从 Hugging Face 下载基础模型后,使用 image_generator_converter 将模型转换为适用于图片生成器的设备端格式

  2. 安装必要的依赖项:

$ pip install torch typing_extensions numpy Pillow requests pytorch_lightning absl-py
  1. 运行转换脚本:
$ python3 convert.py --ckpt_path <ckpt_path> --output_path <output_path>

转换完成后,就可以在 MediaPipe 应用中使用图片生成功能,通过文本提示创建各种风格的图像。


Android 环境搭建与使用

项目依赖配置

首先,在 Android 项目中添加 MediaPipe Tasks 依赖:

// app/build.gradle
dependencies {
    // LLM 推理专用依赖
    implementation 'com.google.mediapipe:tasks-genai:0.10.24'

    // 其他 MediaPipe 任务依赖
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
    implementation 'com.google.mediapipe:tasks-text:latest.release'
    implementation 'com.google.mediapipe:tasks-audio:latest.release'
}

各包功能说明:

  • tasks-genai:专门用于生成式 AI 任务(LLM 推理、多模态推理等)
  • tasks-vision:用于视觉任务(对象检测、图像分类、人脸识别等)
  • tasks-text:用于传统文本任务(文本分类、文本嵌入、语言检测等)
  • tasks-audio:用于音频任务(音频分类等)

模型下载与部署

从 Hugging Face 下载.task 格式的Gemma 3n 模型或从 LiteRT Community 选择其他适合的模型。

模型文件说明:

  • 典型的 LLM 模型大小在 3GB-5GB 左右
  • 由于文件过大,不建议直接打包到 APK 中

可以直接使用 ADB 推送模型到手机本地目录,或者部署到服务端供用户下载到手机本地目录。


Gemma 3n 功能特性

核心功能

基于 Gemma 3n 的 LLM Inference API 主要功能包括:

  • 完全设备端运行:无需网络连接,保护用户隐私
  • 智能文本生成:根据输入提示生成各类高质量文本内容
  • 多模态输入支持:同时支持文本和图像输入,实现图像理解与文本生成
  • 广泛语言支持:支持超过 140 种语言,可以翻译各种语言
  • 大上下文处理:32K token 上下文,处理复杂长文档

配置参数详解

LLM Inference API 提供了丰富的配置选项来优化模型性能:

选项名称 说明 值范围 默认值 建议用法
modelPath 模型在项目目录中的存储路径 路径字符串 无 绝对路径
maxTokens 模型处理的词元数量上限(输入+输出) 整数 512 根据设备性能调整,一般 256-1024
topK 每个步骤考虑的高概率词元数量 整数 40 较小值提高一致性,较大值增加多样性
temperature 生成过程中的随机性程度 0.0-2.0 0.8 0.7-0.9 适合大多数应用
maxNumImages 最大可以识别的图片数量 整数 1 一次识别一张
randomSeed 文本生成的随机种子 整数 0 固定种子可确保结果可重现

代码实现

LLM 管理器

class LLMManager(private val context: Context) {
    private var llmInference: LlmInference? = null

    suspend fun initializeModel(modelPath: String) {
        val options = LlmInference.LlmInferenceOptions.builder()
            .setModelPath(modelPath)        // 指定模型文件路径
            .setMaxTokens(1024)             // 设置最大处理token数(输入+输出)
            .setTopK(40)                    // 限制候选词数量,提高输出质量
            .setTemperature(0.8f)           // 控制输出随机性,0.8适合对话任务
            .setRandomSeed(101)             // 设置随机种子,确保结果可重现
            .build()

        llmInference = LlmInference.createFromOptions(context, options)
    }

    suspend fun generateText(prompt: String): String {
        return try {
            val response = llmInference?.generateResponse(prompt)
            response?.text() ?: "生成失败"
        } catch (e: Exception) {
            Log.e("LLMManager", "推理失败: ${e.message}")
            "推理出错: ${e.message}"
        }
    }

    suspend fun generateStreamingText(
        prompt: String,
        callback: (String) -> Unit
    ) {
        try {
            llmInference?.generateResponseAsync(prompt) { result ->
                result.text()?.let { callback(it) }
            }
        } catch (e: Exception) {
            Log.e("LLMManager", "流式推理失败: ${e.message}")
        }
    }

    fun release() {
        llmInference?.close()
        llmInference = null
    }
}

多模态支持与高级功能

图像预处理

图片需要转换为 MPImage 对象才能识别,下面是转换方法:

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

class ImageProcessor {

    fun convertBitmapToMPImage(bitmap: Bitmap): MPImage {
        return BitmapImageBuilder(bitmap).build()
    }

    fun loadImageFromAssets(context: Context, fileName: String): MPImage {
        val inputStream = context.assets.open(fileName)
        val bitmap = BitmapFactory.decodeStream(inputStream)
        return BitmapImageBuilder(bitmap).build()
    }

    fun loadImageFromUri(context: Context, uri: Uri): MPImage? {
        return try {
            val inputStream = context.contentResolver.openInputStream(uri)
            val bitmap = BitmapFactory.decodeStream(inputStream)
            BitmapImageBuilder(bitmap).build()
        } catch (e: Exception) {
            Log.e("ImageProcessor", "加载图像失败: ${e.message}")
            null
        }
    }
}

视觉功能配置

使用之前要为 LLM Inference API 启用视觉功能,下面是配置的方法:

import android.content.Context
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.google.mediapipe.tasks.genai.llminference.*
import com.google.mediapipe.framework.image.MPImage

class MultimodalLLMManager(private val context: Context) {
    private var llmInference: LlmInference? = null

    fun createMultimodalSession(llmInference: LlmInference): LlmInferenceSession {
        val sessionOptions = LlmInferenceSession.LlmInferenceSessionOptions.builder()
            .setTopK(10)
            .setTemperature(0.4f)
            .setGraphOptions(
                GraphOptions.builder()
                    .setEnableVisionModality(true)  // 启用视觉模态支持,允许模型接收图像输入
                    .build()
            )
            .build()

        return LlmInferenceSession.createFromOptions(llmInference, sessionOptions)
    }

    fun createMultimodalLLMOptions(modelPath: String): LlmInferenceOptions {
        return LlmInferenceOptions.builder()
            .setModelPath(modelPath)
            .setMaxNumImages(1)  // Gemma 3n 每次会话最多接受一张图片
            .setMaxTokens(2048)  // Gemma 3n 支持更大的上下文窗口(32K tokens)
            .setTopK(40)         // 控制输出多样性的参数
            .setTemperature(0.7f) // 控制生成随机性,0.7适合多模态任务
            .build()
    }
    suspend fun initializeModel(modelPath: String) = withContext(Dispatchers.IO) {
        try {
            val options = createMultimodalLLMOptions(modelPath)
            llmInference = LlmInference.createFromOptions(context, options)
        } catch (e: Exception) {
            throw e
        }
    }

    suspend fun analyzeImageWithText(
        image: MPImage,
        question: String
    ): String {
        return try {
            llmInference?.let { llm ->
                val session = createMultimodalSession(llm)
                session.use { s ->
                    s.addQueryChunk(question)
                    s.addImage(image)
                    s.generateResponse()
                }
            } ?: "模型未初始化"
        } catch (e: Exception) {
            Log.e("MultimodalLLM", "多模态推理失败: ${e.message}")
            "推理失败: ${e.message}"
        }
    }
}

使用方法

创建MultimodalLLMManager并调用initializeModel初始化模型,然后就可以调用MultimodalLLMManager的analyzeImageWithText识别图片了。


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

class MultimodalDemoActivity : AppCompatActivity() {

    private lateinit var multimodalManager: MultimodalLLMManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        multimodalManager = MultimodalLLMManager(this)
        initializeModels()
    }

    private fun initializeModels() {
        lifecycleScope.launch {
            try {
                val modelPath = "${filesDir.absolutePath}/gemma_3n_model.task"
                multimodalManager.initializeModel(modelPath)
            } catch (e: Exception) {
                Log.e("MultimodalDemo", "模型初始化失败: ${e.message}")
            }
        }
    }

}

实际应用示例

下面是实际使用的几个例子,直接传入LlmInference和MPImage就可以解决不同的图片问题

class VisionQAHelper(private val multimodalManager: MultimodalLLMManager) {

    // 图像描述
    suspend fun describeImage(image: MPImage): String {
        return multimodalManager.analyzeImageWithText(
            image,
            "请详细描述这张图片中的内容。"
        )
    }

    // 对象识别
    suspend fun identifyObjects(image: MPImage): String {
        return multimodalManager.analyzeImageWithText(
            image,
            "识别图片中的所有对象,并列出它们的位置。"
        )
    }

    // 实用场景:菜单识别
    suspend fun analyzeMenu(menuImage: MPImage): String {
        return multimodalManager.analyzeImageWithText(
            menuImage,
            "分析这份菜单,提取菜品名称和价格,并推荐几道受欢迎的菜。"
        )
    }

    // 问题解答
    suspend fun answerImageQuestion(
        image: MPImage,
        question: String
    ): String {
        return multimodalManager.analyzeImageWithText(
            image,
            "根据图片回答问题:$question"
        )
    }
}

LoRA 模型定制

LoRA(Low-Rank Adaptation,低秩自适应)是一种参数高效的微调技术,让开发者能够使用相对较少的标注数据定制专用模型。

核心原理

LoRA 的核心价值就是"花小钱办大事"。传统的全量微调需要重新训练模型所有参数(数十亿个),而 LoRA 微调只训练模型中注意力层的少量参数(约万分之一),像给模型加个"插件",既保留原模型能力,又能学会新任务。

技术优势:

  • 内存效率:只需要存储少量额外参数(通常 < 10MB)
  • 训练速度:比全量微调快 3-5 倍
  • 移动端友好:可以在手机 GPU 上运行
  • 可组合性:可以为不同任务训练多个 LoRA 适配器

在 MediaPipe 中使用 LoRA

// 加载带有 LoRA 适配器的模型
class LoRAEnabledLLM(private val context: Context) {

    fun createLoRAModel(baseModelPath: String, loraAdapterPath: String): LlmInference {
        val options = LlmInference.LlmInferenceOptions.builder()
            .setModelPath(baseModelPath)
            .setLoraPath(loraAdapterPath)  // 指定 LoRA 适配器路径
            .setMaxTokens(1024)
            .setTemperature(0.7f)
            .build()

        return LlmInference.createFromOptions(context, options)
    }

}

实际应用场景

医疗助手:基础 Gemma 3n + 医疗知识 LoRA

val medicalLLM = createLoRAModel(
    "gemma_3n_base.task",
    "medical_knowledge_lora.task"
)

代码助手:基础 Gemma 3n + 编程 LoRA

val codingLLM = createLoRAModel(
    "gemma_3n_base.task",
    "coding_assistant_lora.task"
)

感兴趣的同学可以参考 LoRA 官方文档 了解更多技术细节。


移动端 AI 的优势与前景

核心优势

移动端大模型的优势有三个方面:

数据不用上传,更安全
适合医疗图像分析等隐私敏感场景。

小内存也能高效运行
在手机上既能快速响应,又能保证准确性。

本地就能定制模型
可以定制模型,满足特定场景需求。

应用场景

离线刚需场景:地铁、偏远地区的语音导航和翻译;自然灾害中的图像处理和应急方案生成;出差途中的文档处理和设备故障诊断。

隐私保护场景:医疗影像分析、金融风险评估、法律合同审查、政府机密文件处理等,确保敏感数据不出设备。

实时交互场景:毫秒级语音助手响应、实时翻译、游戏剧情生成、短视频智能配音等,提供流畅的用户体验。


总结与展望

本文详细阐述了基于 MediaPipe Tasks 与最新 Gemma 3n 模型在 Android 平台实现生成式 AI 应用的完整方案,涵盖环境搭建、基础推理到多模态支持的全流程。
Gemma 3n 依托 PLE 缓存、MatFormer 架构等创新技术,为移动设备赋予了强大的 AI 能力,尤其在隐私保护、实时响应、云端与移动端协同处理等场景中具有显著应用价值。
希望本文能为相关开发者提供实用参考。


参考资源

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容