TensorFlow系列:第五讲:移动端部署模型
项目地址:https://github.com/LionJackson/imageClassification
Flutter项目地址:https://github.com/LionJackson/flutter_image
一. 模型转换
编写tflite模型工具类:
import osimport PIL
import tensorflow as tf
import keras
import numpy as np
from PIL.Image import Image
from matplotlib import pyplot as pltfrom utils.dataset_loader import DatasetLoader
from utils.utils import Utils"""
tflite模型工具类
"""class TFLiteUtil:def __init__(self, saved_model_dir, path_url):self.save_model_dir = saved_model_dirself.path_url = path_url# 训练的模型生成标签列表def get_folder_names(self):folder_names = []for root, dirs, files in os.walk(self.path_url + '/train'):for dir_name in dirs:folder_names.append(dir_name)with open(self.save_model_dir + '.label', 'w') as file:for name in folder_names:file.write(name + '\n')return folder_names# 模型转成tflite格式def convert_tflite(self):self.get_folder_names()converter = tf.lite.TFLiteConverter.from_saved_model(self.save_model_dir)tflite_model = converter.convert()# 将转换后的 TFLite 模型保存为文件with open(self.save_model_dir + '.tflite', 'wb') as f:f.write(tflite_model)print("转换成功,已保存为 tflite")# 加载keras并转成tflitedef convert_model_tflite(self):self.get_folder_names()model = keras.models.load_model(self.save_model_dir + ".keras")converter = tf.lite.TFLiteConverter.from_keras_model(model)converter.optimizations = [tf.lite.Optimize.DEFAULT]converter.target_spec.supported_types = [tf.float16]tflite_model = converter.convert()# 将转换后的 TFLite 模型保存为文件with open(self.save_model_dir + '.tflite', 'wb') as f:f.write(tflite_model)print("转换成功(model),已保存为 tflite")# 批量识别 进行可视化显示def batch_evaluation(self, class_mode='categorical', image_size=(224, 224), num_images=25):dataset_loader = DatasetLoader(self.path_url, image_size=image_size, class_mode=class_mode)train_ds, val_ds, test_ds, class_names = dataset_loader.load_data()interpreter = tf.lite.Interpreter(self.save_model_dir + '.tflite')interpreter.allocate_tensors()# 获取输入和输出张量的信息input_details = interpreter.get_input_details()output_details = interpreter.get_output_details()plt.figure(figsize=(10, 10))for images, labels in test_ds.take(1):outputs = []for img in images:img_expanded = np.expand_dims(img, axis=0)interpreter.set_tensor(input_details[0]['index'], img_expanded)interpreter.invoke()output = interpreter.get_tensor(output_details[0]['index'])outputs.append(output)for i in range(num_images):plt.subplot(5, 5, i + 1)image = np.array(images[i]).astype("uint8")plt.imshow(image)index = int(np.argmax(outputs[i]))prediction = outputs[i][0][index]percentage_str = "{:.2f}%".format(prediction * 100)plt.title(f"{class_names[index]}: {percentage_str}")plt.axis("off")plt.subplots_adjust(hspace=0.5, wspace=0.5)plt.show()# 查看tflite模型信息def tflite_analyzer(self):# 加载 TFLite 模型interpreter = tf.lite.Interpreter(model_path=self.save_model_dir + '.tflite')interpreter.allocate_tensors()# 获取输入和输出的详细信息input_details = interpreter.get_input_details()output_details = interpreter.get_output_details()# 打印输入和输出的详细信息print("Input Details:")for detail in input_details:print(detail)print("\nOutput Details:")for detail in output_details:print(detail)# 列出所有使用的算子tensor_details = interpreter.get_tensor_details()print("\nTensor Details:")for tensor_detail in tensor_details:print("Index:", tensor_detail['index'])print("Name:", tensor_detail['name'])print("Shape:", tensor_detail['shape'])print("Shape Signature:", tensor_detail['shape_signature'])print("dtype:", tensor_detail['dtype'])print("Quantization:", tensor_detail['quantization'])print("Quantization Parameters:", tensor_detail['quantization_parameters'])print("Sparsity Parameters:", tensor_detail['sparsity_parameters'])print()
引用工具类:
if __name__ == '__main__':# train()# model_util = ModelUtil(SAVED_MODEL_DIR, PATH_URL)# model_util.batch_evaluation()tflite_util = TFLiteUtil(SAVED_MODEL_DIR, PATH_URL)tflite_util.convert_tflite()tflite_util.tflite_analyzer()tflite_util.batch_evaluation()
此时会生成tflite模型文件:

二. 使用模型
创建flutter项目,引入以下库:
image: ^4.0.17path: ^1.8.3path_provider: ^2.0.15image_picker: ^0.8.8tflite_flutter: ^0.10.4camera: ^0.10.5+2
把模型文件拷贝到项目中:

核心代码:
import 'dart:developer';
import 'dart:io';
import 'dart:isolate';import 'package:camera/camera.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart';
import 'package:tflite_flutter/tflite_flutter.dart';import 'isolate_inference.dart';class ImageClassificationHelper {static const modelPath = 'assets/models/fruits.tflite';static const labelsPath = 'assets/models/fruits.label';late final Interpreter interpreter;late final List<String> labels;late final IsolateInference isolateInference;late Tensor inputTensor;late Tensor outputTensor;// Load modelFuture<void> _loadModel() async {final options = InterpreterOptions();// Use XNNPACK Delegateif (Platform.isAndroid) {options.addDelegate(XNNPackDelegate());}// Use GPU Delegate// doesn't work on emulator// if (Platform.isAndroid) {// options.addDelegate(GpuDelegateV2());// }// Use Metal Delegateif (Platform.isIOS) {options.addDelegate(GpuDelegate());}// Load model from assetsinterpreter = await Interpreter.fromAsset(modelPath, options: options);// Get tensor input shape [1, 224, 224, 3]inputTensor = interpreter.getInputTensors().first;// Get tensor output shape [1, 1001]outputTensor = interpreter.getOutputTensors().first;log('Interpreter loaded successfully');}// Load labels from assetsFuture<void> _loadLabels() async {final labelTxt = await rootBundle.loadString(labelsPath);labels = labelTxt.split('\n');}Future<void> initHelper() async {_loadLabels();_loadModel();isolateInference = IsolateInference();await isolateInference.start();}Future<Map<String, double>> _inference(InferenceModel inferenceModel) async {ReceivePort responsePort = ReceivePort();isolateInference.sendPort.send(inferenceModel..responsePort = responsePort.sendPort);// get inference result.var results = await responsePort.first;return results;}// inference camera frameFuture<Map<String, double>> inferenceCameraFrame(CameraImage cameraImage) async {var isolateModel = InferenceModel(cameraImage, null, interpreter.address,labels, inputTensor.shape, outputTensor.shape);return _inference(isolateModel);}// inference still imageFuture<Map<String, double>> inferenceImage(Image image) async {var isolateModel = InferenceModel(null, image, interpreter.address, labels,inputTensor.shape, outputTensor.shape);return _inference(isolateModel);}Future<void> close() async {isolateInference.close();}
}
页面部分:

相关文章:
TensorFlow系列:第五讲:移动端部署模型
项目地址:https://github.com/LionJackson/imageClassification Flutter项目地址:https://github.com/LionJackson/flutter_image 一. 模型转换 编写tflite模型工具类: import osimport PIL import tensorflow as tf import keras import …...
深度学习DeepLearning二元分类 学习笔记
文章目录 类别区分变量与概念逻辑回归Sigmoid函数公式决策边逻辑损失函数和代价函数逻辑回归的梯度下降泛化过拟合的解决方案正则化 类别区分 变量与概念 决策边置信度阈值threshold过拟合欠拟合正则化高偏差lambda(λ) 线性回归受个别极端值影响&…...
Eureka 介绍与使用
Eureka 是一个开源的服务发现框架,它主要用于在分布式系统中管理和发现服务实例。它由 Netflix 开发并开源,是 Netflix OSS 中的一部分。 使用 Eureka 可以方便地将新的服务实例注册到 Eureka 服务器,并且让其他服务通过 Eureka 服务器来发现…...
Java异常体系、UncaughtExceptionHandler、Spring MVC统一异常处理、Spring Boot统一异常处理
概述 所有异常都是继承自java.lang.Throwable类,Throwable有两个直接子类,Error和Exception。 Error用来表示程序底层或硬件有关的错误,这种错误和程序本身无关,如常见的NoClassDefFoundError。这种异常和程序本身无关࿰…...
bash终端快捷键
快捷键作用ShiftCtrlC复制ShiftCtrlV粘贴CtrlAltT新建终端ShiftPgUp/PgDn终端上下翻页滚动CtrlC终止命令CtrlD关闭终端CtrlA光标移动到最开始为止CtrlE光标移动到最末尾CtrlK删除此处到末尾的所有内容CtrlU删除此处至开始的所有内容CtrlD删除当前字符CtrlH删除当前字符的前一个…...
【Visual Studio】Visual Studio报错合集及解决办法
目录 Visual Studio报错:error LNK2001 Visual Studio报错:error C2061 Visual Studio报错:error C1075 Visual Studio报错:error C4430 Visual Studio报错error C3867 概述 持续更细Visual Studio报错及解决方法 Visual Studio报错:error LNK2001 问题 : error LNK2001…...
【微信小程序知识点】转发功能的实现
转发功能,主要帮助用户更流畅地与好友分享内容与服务。 想实现转发功能,有两种方式: 1.页面js文件必须声明onShareAppMessage事件监听函数,并自定义转发内容。只有定义了此事件处理函数,右上角菜单才会显示“转发”按…...
用python识别二维码(python实例二十三)
目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.识别二维码 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&…...
电脑文件夹怎么设置密码?让你的文件更安全!
在日常使用电脑的过程中,我们常常会有一些需要保护的个人文件或资料。为了防止这些文件被他人未经授权访问,对重要文件夹设置密码是一种有效的保护措施,可是电脑文件夹怎么设置密码呢?本文将介绍2种简单有效的方法帮助您为电脑文件…...
paddla模型转gguf
在使用ollama配置本地模型时,只支持gguf格式的模型,所以我们首先需要把自己的模型转化为bin格式,本文为paddle,onnx,pytorch格式的模型提供说明,safetensors格式比较简单请参考官方文档,或其它教…...
Memcached vs Redis——Java项目缓存选择
在Java项目开发中,缓存系统作为提升性能、优化资源利用的关键技术之一,扮演着至关重要的角色。Memcached和Redis作为两种流行的缓存解决方案,各有其独特的优势和应用场景。本文旨在通过分析项目大小、用户访问量、业务复杂度以及服务器部署情…...
大模型最新黑书:基于GPT-3、ChatGPT、GPT-4等Transformer架构的自然语言处理 PDF
今天给大家推荐一本丹尼斯罗斯曼(Denis Rothman)编写的关于大语言模型(LLM)权威教程<<大模型应用解决方案> 基于GPT-3、ChatGPT、GPT-4等Transformer架构的自然语言处理>!Google工程总监Antonio Gulli作序,这含金量不…...
【电子数据取证】电子数据司法鉴定
文章关键词:电子数据取证、司法鉴定服务、司法鉴定流程 一、定义 什么是司法鉴定? 在诉讼活动中鉴定人运用科学技术或者专业知识对诉讼涉及的专门性问题进行鉴别和判断并提供鉴定意见的活动。 电子数据司法鉴定 那么电子数据司法鉴定,就…...
使用 OpenCV 的 inRange 函数进行颜色分割
使用 OpenCV 的 inRange 函数进行颜色分割 在图像处理领域,颜色分割是一个常见的任务,常用于识别和提取图像中的特定颜色区域。OpenCV 提供了一个非常方便的函数 inRange 来实现这一功能。在这篇博客中,我们将详细介绍 inRange 函数的用法&a…...
OpenAI终止对中国提供API服务,对国内AI市场产生重大冲击?
6月25日,OpenAI突然宣布终止向包括中国在内的国家地区提供API服务,本月9日这一政策已经正式生效了! 有人说,这个事件给中国AI行业带来很大冲击!是这样吗?在展开讨论前,我们先来看看什么是API服务…...
JavaDS —— 栈 Stack 和 队列 Queue
栈的概念 栈是一种先进后出的线性表,只允许在固定的一端进行插入和删除操作。 进行插入和删除操作的一端被称为栈顶,另一端被称为栈底 栈的插入操作叫做进栈/压栈/入栈 栈的删除操作叫做出栈 现实生活中栈的例子: 栈的模拟实现 下面是Jav…...
C++进阶:继承和多态
文章目录 ❤️继承🩷继承与友元🧡继承和静态成员💛菱形继承及菱形虚拟继承💚继承和组合 ❤️多态🩷什么是多态?🧡多态的定义以及实现💛虚函数💚虚函数的重写💙…...
【八大排序】java版(上)(冒泡、快排、堆排、选择排序)
文章目录 一、冒泡排序(重点)思路代码 二、快排(面试重点)思路代码 三、堆排序(面试重点)思路代码 四、选择排序思路代码 一、冒泡排序(重点) 思路 前后两两数据进行比较,小的数据往前走,大的数据往后走,每一轮结束之后,最大的数…...
.Net Core 微服务之Consul(二)-集群搭建
引言: 集合上一期.Net Core 微服务之Consul(一)(.Net Core 微服务之Consul(一)-CSDN博客) 。 目录 一、 Consul集群搭建 1. 高可用 1.1 高可用性概念 1.2 高可用集群的基本原理 1.3 高可用集群的架构设计 1.3.1 主从复制架构 1.3.2 共享存储架构 1.3.3 负载均衡…...
C++ --> 类和对象(二)
前言 在前面简单的介绍了OOP,什么是类,在类中的this指针。接下来就深入理解类和对象。 默认成员函数 默认构造函数:用于在创建对象时初始化对象的成员变量。默认拷贝构造函数:用于使用已存在的对象来初始化新创建的对象。默认析构…...
2026年Java面试最常被问的1000道题目及参考答案
Java学到什么程度可以面试工作? 要达到能够面试Java开发工作的水平,需要掌握以下几个方面的知识和技能: 1. 基础扎实:熟悉Java语法、面向对象编程概念、异常处理、I/O流等基础知识。这是所有Java开发者必备的基础,也…...
用STM32的定时器输入捕获功能,精准解码433MHz遥控器信号(附完整代码)
STM32定时器输入捕获技术解析:433MHz遥控信号精准解码实战 在智能家居DIY和工业控制领域,433MHz无线通信凭借其穿透性强、成本低廉的优势成为常见选择。但如何稳定可靠地解码这些无线信号,一直是开发者面临的挑战。本文将深入探讨基于STM32硬…...
3大技术突破重新定义魔兽地图编辑工作流
3大技术突破重新定义魔兽地图编辑工作流 【免费下载链接】HiveWE A Warcraft III world editor. 项目地址: https://gitcode.com/gh_mirrors/hi/HiveWE 对于《魔兽争霸III》地图制作者而言,最令人沮丧的体验莫过于:精心设计的地形布局在实际测试中…...
从原理图到实测:手把手打造Ti电量计通讯盒EV2400
1. 为什么需要自制EV2400通讯盒 搞锂电池开发的朋友应该都熟悉Ti的电量计芯片,比如bq系列。这些芯片需要通过I2C/SMBus或者HDQ接口与电脑通信,这时候就需要一个通讯盒作为桥梁。官方EV2400虽然好用,但价格实在不亲民,而且功能上可…...
手把手教你部署OpenClaw(小龙虾),打造专属AI数字员工
2026年,开源AI智能体OpenClaw(国内昵称“小龙虾”)凭借独特的“数字员工”定位迅速崛起,GitHub星标一路攀升至28万,成为当下最受开发者和办公人群青睐的开源AI项目。 一、OpenClaw核心优势解析 OpenClaw能在众多开源…...
大数据在电力行业应用案例解析 -【电力技术】(25)RPA 在电力业扩报装中的自动化应用与实现
目录 一、引言:业扩报装的效率瓶颈 二、RPA 技术特点与电力适用性 三、RPA 在业扩报装中的四大核心应用场景 3.1 预受理自动审核 3.2 批量用户信息自动导入 3.3 勘查工单自动派工 3.4 流程自动流转与归档 四、RPA 实施流程(标准化) 五、典型应用成效 六、完整可运行…...
MultiAgentBench:一套真正评测多智能体协作与博弈能力的基准
摘要:大语言模型已经展现出作为自主智能体的显著能力,但现有基准要么只关注单智能体任务,要么局限于狭窄领域,无法刻画多智能体协作与竞争的动态过程。本文提出 MultiAgentBench,这是一个面向 LLM 多智能体系统的综合性…...
深入解析RK3576 Android14中camera3_profiles_rkxxxx.xml的自定义数据格式支持
1. RK3576 Android14相机配置文件的秘密 最近在调试RK3576平台的相机模块时,遇到了一个棘手的问题:需要为定制摄像头添加特殊数据格式。当我打开camera3_profiles_rkxxxx.xml文件时,发现它只支持BLOB、YCbCr_420_888和IMPLEMENTATION_DEFINED…...
Qwen3.5-4B-Claude-Opus-GGUF部署教程:llama-server API对接与Web前端联调
Qwen3.5-4B-Claude-Opus-GGUF部署教程:llama-server API对接与Web前端联调 1. 模型概述 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF是基于Qwen3.5-4B的推理蒸馏模型,特别强化了结构化分析、分步骤回答、代码与逻辑类问题的处理能力。该版本…...
OpenModScan:免费开源的Modbus调试工具完整指南
OpenModScan:免费开源的Modbus调试工具完整指南 【免费下载链接】OpenModScan Open ModScan is a Free Modbus Master (Client) Utility 项目地址: https://gitcode.com/gh_mirrors/op/OpenModScan 在工业自动化领域,Modbus通讯协议的调试和测试是…...
