MindSpore开发之路:MindSpore Lite实战:在端侧部署AI应用

1. 前言

在上一篇文章中,我们成功地将一个PyTorch模型转换为了MindSpore Lite专用的.ms格式。现在,我们终于来到了最激动人心的环节——将这个模型部署到真实的移动设备上,赋予App以AI的能力。

本文将以Android平台为例,通过一个图像分类的Demo,手把手带你走完端侧推理的“最后一公里”。我们将详细讲解如何在Android项目中集成MindSpore Lite、加载模型、处理数据、执行推理并最终展示结果。虽然我们不会涉及完整的App UI构建,但会提供核心的、可直接复用的Java/Kotlin代码逻辑。

2. 端侧推理的通用流程

无论是在Android还是iOS上,使用MindSpore Lite进行推理都遵循一个标准流程:

  1. 集成SDK:将MindSpore Lite的推理库(AAR for Android, Framework for iOS)集成到你的移动应用项目中。
  2. 加载模型:从App的资源或文件系统中读取.ms模型文件,构建一个Model实例。
  3. 准备输入:获取模型的输入Tensor信息(如数据类型、形状),并将你的原始输入数据(如Bitmap图片)预处理成符合模型要求的Tensor格式。
  4. 执行推理:调用model.predict()方法,传入预处理好的输入Tensor。
  5. 获取输出:从模型中获取输出Tensor。
  6. 后处理与展示:对输出Tensor进行解析(如执行Softmax、查找最大值索引),并将结果(如分类标签和置信度)显示在UI上。

3. Android实战:手写数字识别App核心逻辑

让我们以之前训练和转换的LeNet手写数字识别模型(lenet.ms)为例,看看如何在Android App中实现它。

3.1. 步骤一:集成MindSpore Lite AAR

首先,你需要从MindSpore官网下载适用于Android的MindSpore Lite发布包。解压后,你会找到一个名为mindspore-lite-*.aar的文件。

在Android Studio中,将这个.aar文件放入你的App模块的libs目录下。然后,在build.gradle文件中添加对它的依赖:

// app/build.gradle dependencies { // ... 其他依赖 implementation files('libs/mindspore-lite-2.2.11.aar') // 替换为你的AAR文件名 }

同时,将你的.ms模型文件(例如lenet.ms)放入app/src/main/assets目录下,这样App在运行时就可以访问它了。

3.2. 步骤二:封装一个推理帮助类

为了代码的整洁和复用,我们通常会创建一个帮助类(Helper Class)来封装所有与MindSpore Lite推理相关的操作。下面是一个使用Java编写的MindSporeDigitRecognition类的骨架。

import android.content.Context; import android.graphics.Bitmap; import com.mindspore.lite.Model; import com.mindspore.lite.MSTensor; import com.mindspore.lite.LiteSession; import com.mindspore.lite.config.MSConfig; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; public class MindSporeDigitRecognition { private LiteSession session; private final int inputWidth = 32; private final int inputHeight = 32; // 构造函数:加载模型 public MindSporeDigitRecognition(Context context, String modelName) { // 1. 创建和配置 LiteSession MSConfig config = new MSConfig(); config.setDeviceType(DeviceType.DT_CPU); // 使用CPU推理 config.setThreadNum(2); // 使用2个线程 // 2. 从assets加载模型文件并构建Session session = LiteSession.createSession(modelName, context, config); if (session == null) { throw new IllegalStateException("Failed to create MindSpore Lite session."); } } // 预处理:将Bitmap转换为ByteBuffer private ByteBuffer preprocess(Bitmap bitmap) { // ... 实现见下文 } // 推理方法 public float[] predict(Bitmap bitmap) { // ... 实现见下文 } // 释放资源 public void release() { if (session != null) { session.release(); } } }

3.3. 步骤三:实现数据预处理

我们的LeNet模型需要一个[1, 1, 32, 32]尺寸、经过归一化的float32输入。因此,我们需要将用户提供的手写数字图片(Bitmap)进行相应的转换。

// 在 MindSporeDigitRecognition 类中 private ByteBuffer preprocess(Bitmap bitmap) { // 1. 将Bitmap缩放到32x32 Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, inputWidth, inputHeight, true); // 2. 分配一个ByteBuffer来存放模型输入数据 // 1 * 32 * 32 * 1 * 4 bytes (Batch, Height, Width, Channels, Float32) ByteBuffer inputBuffer = ByteBuffer.allocateDirect(1 * inputWidth * inputHeight * 1 * 4); inputBuffer.order(ByteOrder.nativeOrder()); inputBuffer.rewind(); int[] pixels = new int[inputWidth * inputHeight]; resizedBitmap.getPixels(pixels, 0, inputWidth, 0, 0, inputWidth, inputHeight); // 3. 遍历像素,进行灰度化和归一化 for (int pixelValue : pixels) { // 从ARGB中提取灰度值 (R, G, B分量是相同的) int gray = (pixelValue >> 16) & 0xFF; // 归一化到[0, 1]范围 float normalizedGray = gray / 255.0f; inputBuffer.putFloat(normalizedGray); } return inputBuffer; }

这段代码完成了缩放、灰度化和归一化三个关键步骤,并将最终的浮点数据写入了ByteBuffer,这正是MindSpore Lite可以直接使用的数据格式。

3.4. 步骤四:实现推理和后处理

这是最核心的部分。我们调用predict方法,然后解析其输出。

// 在 MindSporeDigitRecognition 类中 public float[] predict(Bitmap bitmap) { // 1. 预处理图片 ByteBuffer inputBuffer = preprocess(bitmap); // 2. 获取输入Tensor并填充数据 // 假设模型只有一个输入 MSTensor inputTensor = session.getInputs().get(0); inputTensor.setData(inputBuffer); // 3. 执行推理 if (!session.runGraph()) { System.err.println("MindSpore Lite runGraph failed."); return null; } // 4. 获取输出Tensor // 假设模型只有一个输出 MSTensor outputTensor = session.getOutputs().get(0); // 5. 获取输出数据并返回 // LeNet的输出是一个包含10个float值的数组,代表每个数字的logit return outputTensor.getFloatData(); }

在你的Activity或ViewModel中,你可以这样使用它:

// 在你的Activity中 private MindSporeDigitRecognition recognizer; // onCreate时初始化 recognizer = new MindSporeDigitRecognition(this, "lenet.ms"); // 当获取到用户绘制的Bitmap时 Bitmap userBitmap = getUserDrawingBitmap(); float[] logits = recognizer.predict(userBitmap); // 对logits进行后处理,找到最大值的索引 if (logits != null) { int maxIndex = -1; float maxProb = -Float.MAX_VALUE; for (int i = 0; i < logits.length; i++) { if (logits[i] > maxProb) { maxProb = logits[i]; maxIndex = i; } } // maxIndex 就是识别出的数字 (0-9) // 你可以在这里更新UI,显示结果 textViewResult.setText("识别结果: " + maxIndex); } // onDestroy时释放资源 @Override protected void onDestroy() { super.onDestroy(); if (recognizer != null) { recognizer.release(); } }

至此,一个完整的手写数字识别功能的核心逻辑就完成了!

4. 总结

将AI模型部署到端侧设备,是技术落地、创造价值的关键一步。通过本文的实战演练,我们完整地体验了使用MindSpore Lite在Android平台上部署一个AI模型的过程。

我们学习了:

  • 集成:如何将MindSpore Lite的AAR库集成到Android项目中。
  • 加载:如何通过LiteSession加载.ms模型文件。
  • 预处理:如何将原始数据(Bitmap)处理成符合模型输入要求的ByteBuffer
  • 推理:如何调用runGraph执行模型推理。
  • 后处理:如何解析模型的输出Tensor,并将其转换为有意义的应用结果。

虽然这只是一个简单的Demo,但它包含了端侧AI应用开发的所有核心要素。掌握了这个流程,你就已经具备了将更复杂、更强大的MindSpore模型部署到移动端的能力,为创造出更多富有想象力的AI应用打下了坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1169075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

收藏必备!LLM与LMM大模型全解析:从零到精通的学习指南

LLM vs. LMM: What’s all the Buzz About? 文章摘要 本文深入比较了大型语言模型&#xff08;LLM&#xff09;与大型营销模型&#xff08;LMM&#xff09;在AI赋能营销中的角色差异&#xff0c;并介绍了Open Intelligence新架构如何通过智能化、安全隐私和实时响应重塑品牌与…

Cesium中的 Entity、Terrain、DataSource开发场景示例

&#x1f3af; 一、Entity模块&#xff1a;SampledPositionProperty 深度解析与动态航线实现 1. SampledPositionProperty 核心定义与用途 &#x1f50d; 定义 SampledPositionProperty 是 Cesium 中用于描述随时间变化的三维位置属性的核心类&#xff0c;支持通过采样点插值…

Chroma向量数据库:超越`client = chromadb.Client()`的深度探索与生产实践

好的&#xff0c;没问题。根据您提供的随机种子&#xff08;1768525200065&#xff09;&#xff0c;我将深入探讨一个关于向量数据库Chroma的技术主题&#xff0c;重点放在其新的本地API设计、核心原理解析以及在实际生产环境中常常被忽视的高级特性和性能考量上。这篇文章将避…

灵敏度随电池电量下降就会变得不灵敏, 有的时候电机或舵机不工作

我先按你这张原理图里电源拓扑把问题“对上号”&#xff0c;再给你一套最可能的根因 立刻可做的验证 改法。1) 这两个现象&#xff0c;90%像“电源掉压/纹波 地弹”引起的从图上看&#xff1a;电池(VCC) → MT3608B 升压 → 得到 5V(VOUT)5V 再进两个 TLV75733 做 D3V3 / A3…

Cyber Triage 3.16 发布 - 通过 Cyber Triage Enterprise 更快开展调查

Cyber Triage 3.16 发布 - 通过 Cyber Triage Enterprise 更快开展调查 Digital Forensics Specialized For Incident Response 请访问原文链接&#xff1a;https://sysin.org/blog/cybertriage-3/ 查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;s…

导师严选2026 TOP8 AI论文写作软件:本科生毕业论文全攻略

导师严选2026 TOP8 AI论文写作软件&#xff1a;本科生毕业论文全攻略 2026年AI论文写作软件测评&#xff1a;从功能到体验的全面解析 随着人工智能技术在学术领域的深入应用&#xff0c;AI论文写作工具已成为本科生撰写毕业论文的重要辅助。然而&#xff0c;面对市场上琳琅满目…

Vue3 + Element Plus 表格复选框踩坑记录

在开发能耗对比功能时,遇到了几个 Element Plus 表格复选框的典型问题。本文记录了问题现象、排查思路和解决方案,希望能帮助到遇到类似问题的开发者。 &#x1f4cb; 问题背景 在使用 Element Plus 的 el-table 组件实现多选功能时,遇到了以下几个问题: ❌ 点击单个复选框后…

【收藏级干货】RAG技术深度解析:让大语言模型告别“闭卷考试“

引言 人工智能的范式转移 近年来&#xff0c;大语言模型&#xff08;LLM&#xff09;的发展标志着人工智能领域的一次重大飞跃。然而&#xff0c;这些模型在很大程度上是“闭卷”系统&#xff0c;其能力完全依赖于其庞大参数中存储的知识 (1)。这种架构带来了固有的挑战&#x…

前后端分离靓车汽车销售网站系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

摘要 随着互联网技术的快速发展&#xff0c;传统汽车销售模式逐渐向线上转移&#xff0c;消费者对购车体验的需求也日益多样化。传统的汽车销售网站通常采用前后端耦合的架构&#xff0c;导致系统维护困难、扩展性差&#xff0c;难以满足现代用户对高响应速度和交互体验的要求。…

基于Simulink平台实现无人驾驶运动控制中的非线性模型预测控制算法

基于simulink平台的非线性模型预测控制算法实现代码&#xff0c;无人驾驶运动控制在无人驾驶领域&#xff0c;运动控制是确保车辆安全、高效行驶的核心环节。非线性模型预测控制&#xff08;NMPC&#xff09;算法因其能够处理复杂的非线性系统和约束条件&#xff0c;在无人驾驶…

信号不太好,有什么要优化的地方

ESP32-C2 “信号不太好”&#xff0c;绝大多数情况不是协议栈问题&#xff0c;而是 天线/射频走线/地/电源噪声 这几件事没做到位。给你一份从“最常见、最有效”到“细节项”的优化清单&#xff0c;你可以按优先级逐条排查&#xff08;不改软件也能明显改善的那种&#xff09;…

Elasticsearch Enterprise 8.19.10 发布 - 分布式搜索和分析引擎

Elasticsearch Enterprise 8.19.10 (macOS, Linux, Windows) - 分布式搜索和分析引擎 The Official Distributed Search & Analytics Engine 请访问原文链接&#xff1a;https://sysin.org/blog/elastic-8/ 查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&…

中国GEO优化专家孟庆涛获牛津大学与联合国教科文组织权威认证

中国生成式引擎优化&#xff08;GEO&#xff09;领域的开拓者、系统性构建者&#xff0c;辽宁粤穗网络科技有限公司总经理孟庆涛&#xff0c;近日完成由牛津大学赛德商学院与联合国教科文组织&#xff08;UNESCO&#xff09;联合开发的《政府中的AI与数字化转型》权威课程&…

掌握f-string高级用法:日期、数字与嵌套表达式的实战指南

免费编程软件「pythonpycharm」 链接&#xff1a;https://pan.quark.cn/s/48a86be2fdc0在Python开发中&#xff0c;字符串格式化是高频操作。传统方法如%格式化或str.format()存在可读性差、性能不足等问题。Python 3.6引入的f-string&#xff08;格式化字符串字面量&#xff0…

二分+滑窗|hash

lc2982二分定窗class Solution { public:int maximumLength(string s) {auto check [&](int mid)->bool {unordered_map<char, int> fre_map;for (int i 0; i < s.length();) {int l i;char c s[i];int fre 0;while (s[i] c) {i;}if (i - l > mid) {f…

【必藏】从零开始掌握大模型:Dify知识库优化秘籍,让AI助手回答更精准

摘要&#xff1a;目前很多人在使用dify进行AI agent的开发&#xff0c;而在开发智能体的时候&#xff0c;经常会遇到AI助手回答的问题不完整&#xff0c;或者回答的问题不全对&#xff0c;似是而非&#xff0c;那么是构建的知识库有问题导致的&#xff0c;一个高效、准确的知识…

Flowable 7.x 超详细技术(2026 最新版)

基于 Flowable 7.0/7.1 正式 release 代码与官方 changelog 整理&#xff0c;覆盖「架构 → 启动 → 高阶 → 性能 → 云原生」全链路&#xff0c;复制即可落地。一、版本动态&#xff1a;2025 年 Flowable 7.x 带来了什么维度7.x 变化一句话总结基线Spring Boot 3.3 Spring 6…

当AI成为标准配置,知识服务者如何构建新竞争力?

智谱AI的上市不仅是一家企业的里程碑&#xff0c;更是整个AI产业从技术探索走向商业成熟的分水岭。对于知识付费与在线教育行业而言&#xff0c;这意味着AI技术已从“可选配件”转变为“标准配置”。在这样的背景下&#xff0c;教育从业者应当如何重新思考自身的核心竞争力&…

大厂Java面试八股文精选(蚂蚁金服/滴滴/美团/腾讯)

作为一名优秀的程序员&#xff0c;技术面试都是不可避免的一个环节&#xff0c;一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识。如果你参加过一些大厂面试&#xff0c;肯定会遇到一些这样的问题&#xff1a;1、看你项目都用的框架&#xff0c;熟悉 Sp…

2022VS及以上版本的scanf函数的使用,引发的错误导致编译器运行不了

注&#xff1a;首先我先说一下由于VS版本的更新,Visual Studio软件上对scanf函数的使用&#xff0c;是不同于其他版本,Visual Studio 2022及以上的版本用的是scanf_s函数进行输入读取,因为S 认为 scanf 存在缓冲区溢出风险&#xff0c;默认禁用了这类 “不安全” 函数&#xff…