如果您希望能有一种简单、高效且灵活的方式把 tensorflow 模型集成到 flutter 应用里,那请您一定不要错过我们今天介绍的这个全新插件tflite_flutter。这个插件的开发者是 google summer of code (gsoc) 的一名实习生 amish garg。
tflite_flutter插件的核心特性:
插件提供了与 tflite java 和 swift api 相似的 dart api,所以其灵活性和在这些平台上的效果是完全一样的;
插件通过 dart:ffi 直接与 tensorflow lite c api 相绑定,所以它比其它平台集成方式更加高效;
无需编写特定平台的代码;
通过 nnapi 提供加速支持,在 android 上使用 gpu delegate,在 ios 上使用 metal delegate。
本文中,我们将使用 tflite_flutter 构建一个文字分类 flutter 应用,带您体验 tflite_flutter 插件。首先从新建一个 flutter 项目text_classification_app开始。
初始化配置
linux 和 mac用户
将 install.sh 拷贝到您应用的根目录,然后在根目录执行 sh install.sh,本例中就是目录 text_classification_app/。
windows 用户
将 install.bat 文件拷贝到应用根目录,并在根目录运行批处理文件 install.bat,本例中就是目录 text_classification_app/。
它会自动从github 仓库的 releases 里下载最新的二进制资源,然后把它放到指定的目录下。
请点击到 readme 文件里查看更多关于初始配置的信息。
tflite_flutter 的 github 仓库
https://github.com/am15h/tflite_flutter_plugin
获取插件
在pubspec.yaml添加tflite_flutter: ^
最新版本情况参考插件的发布地址
https://pub.flutter-io.cn/packages/tflite_flutter
下载模型
要在移动端上运行 tensorflow 训练模型,我们需要使用 .tflite 格式。如果需要了解如何将 tensorflow 训练的模型转换为 .tflite 格式,请参阅官方指南。
这里我们准备使用 tensorflow 官方站点上预训练的文字分类模型。
该预训练的模型可以预测当前段落的情感是积极还是消极。它是基于来自 mass 等人的 large movie review dataset v1.0数据集进行训练的。数据集由基于 imdb 电影评论所标记的积极或消极标签组成,查看更多信息。
将 text_classification.tflite 和 text_classification_vocab.txt 文件拷贝到 text_classification_app/assets/ 目录下。
在 pubspec.yaml 文件中添加 assets/。
assets: - assets/
现在万事俱备,我们可以开始写代码了。
模型转换器(converter)的 python api 指南
https://tensorflow.google.cn/lite/convert/python_api
预训练的文字分类模型(text_classification.tflite)
https://files.flutter-io.cn/posts/flutter-cn/2020/tensorflow-lite-plugin/text_classification.tflite
数据集(text_classification_vocab.txt)
https://files.flutter-io.cn/posts/flutter-cn/2020/tensorflow-lite-plugin/text_classification_vocab.txt
实现分类器
预处理
正如文字分类模型页面里所提到的。可以按照下面的步骤使用模型对段落进行分类:
对段落文本进行分词,然后使用预定义的词汇集将它转换为一组词汇 id;
将生成的这组词汇 id 输入 tensorflow lite 模型里;
从模型的输出里获取当前段落是积极或者是消极的概率值。
我们首先写一个方法对原始字符串进行分词,其中使用 text_classification_vocab.txt作为词汇集。
在 lib/文件夹下创建一个新文件 classifier.dart。
这里先写代码加载 text_classification_vocab.txt 到字典里。
import 'package:flutter/services.dart'; class classifier { final _vocabfile = 'text_classification_vocab.txt'; map _dict; classifier() { _loaddictionary(); } void _loaddictionary() async { final vocab = await rootbundle.loadstring('assets/$_vocabfile'); var dict = {}; final vocablist = vocab.split(' '); for (var i = 0; i < vocablist.length; i++) { var entry = vocablist[i].trim().split(' '); dict[entry[0]] = int.parse(entry[1]); } _dict = dict; print('dictionary loaded successfully'); } }
△加载字典
现在我们来编写一个函数对原始字符串进行分词。
import 'package:flutter/services.dart'; class classifier { final _vocabfile = 'text_classification_vocab.txt'; // 单句的最大长度 final int _sentencelen = 256; final string start = ''; final string pad = ''; final string unk = ''; map _dict; list tokenizeinputtext(string text) { // 使用空格进行分词 final toks = text.split(' '); // 创建一个列表,它的长度等于 _sentencelen,并且使用 的对应的字典值来填充 var vec = list.filled(_sentencelen, _dict[pad].todouble()); var index = 0; if (_dict.containskey(start)) { vec[index++] = _dict[start].todouble(); } // 对于句子里的每个单词,在映射里找到相应的索引值 for (var tok in toks) { if (index > _sentencelen) { break; } vec[index++] = _dict.containskey(tok) ? _dict[tok].todouble() : _dict[unk].todouble(); } // 按照我们的解释器输入 tensor 所需的格式 [1, 256] 返回 list return [vec]; } }
△分词代码
使用 tflite_flutter 进行分析
这是本文的主体部分,这里我们会讨论 tflite_flutter 插件的用途。
此处的分析指的是在设备上基于输入的数据,使用 tensorflow lite 模型的处理过程。要使用 tensorflow lite 模型进行分析,需要通过解释器来运行它,了解更多。
创建解释器,加载模型
tflite_flutter 提供了一个方法直接通过资源创建解释器。
static future fromasset(string assetname, {interpreteroptions options})
由于我们的模型在 assets/文件夹下,需要使用上面的方法来创建解析器。对于 interpreteroptions 的相关说明,请参考这里。
import 'package:flutter/services.dart'; // 引入 tflite_flutter import 'package:tflite_flutter/tflite_flutter.dart'; class classifier { // 模型文件的名称 final _modelfile = 'text_classification.tflite'; // tensorflow lite 解释器对象 interpreter _interpreter; classifier() { // 当分类器初始化以后加载模型 _loadmodel(); } void _loadmodel() async { // 使用 interpreter.fromasset 创建解释器 _interpreter = await interpreter.fromasset(_modelfile); print('interpreter loaded successfully'); } }
△创建解释器的代码
如果您不希望将模型放在assets/目录下,tflite_flutter 还提供了工厂构造函数创建解释器,更多信息。
我们开始进行分析!
现在用下面方法启动分析:
void run(object input, object output);
注意这里的方法和 java api 中的是一样的。
object input 和 object output 必须是与 input tensor 和 output tensor 维度相同的列表。
要查看 input tensor 和 output tensor 的维度,可以使用如下代码:
_interpreter.allocatetensors(); // 打印 input tensor 列表 print(_interpreter.getinputtensors()); // 打印 output tensor 列表 print(_interpreter.getoutputtensors());
在本例中 text_classification 模型的输出如下:
inputtensorlist: [tensor{_tensor: pointer: address=0xbffcf280, name: embedding_input, type: tflitetype.float32, shape: [1, 256], data: 1024] outputtensorlist: [tensor{_tensor: pointer: address=0xbffcf140, name: dense_1/softmax, type: tflitetype.float32, shape: [1, 2], data: 8]
现在,我们实现分类方法,该方法返回值为 1 表示积极,返回值为 0 表示消极。
int classify(string rawtext) { // tokenizeinputtext 返回形状为 [1, 256] 的 list list input = tokenizeinputtext(rawtext); // [1,2] 形状的输出 var output = list(2).reshape([1, 2]); // run 方法会运行分析并且存储输出的值 _interpreter.run(input, output); var result = 0; // 如果输出中第一个元素的值比第二个大,那么句子就是消极的 if ((output[0][0] as double) > (output[0][1] as double)) { result = 0; } else { result = 1; } return result; }
△用于分析的代码
在 tflite_flutter 的 extension listshape on list 下面定义了一些使用的扩展:
// 将提供的列表进行矩阵变形,输入参数为元素总数并保持相等 // 用法:list(400).reshape([2,10,20]) // 返回 list list reshape(list shape) // 返回列表的形状 list get shape // 返回列表任意形状的元素数量 int get computenumelements
最终的 classifier.dart 应该是这样的:
import 'package:flutter/services.dart'; // 引入 tflite_flutter import 'package:tflite_flutter/tflite_flutter.dart'; class classifier { // 模型文件的名称 final _modelfile = 'text_classification.tflite'; final _vocabfile = 'text_classification_vocab.txt'; // 语句的最大长度 final int _sentencelen = 256; final string start = ''; final string pad = ''; final string unk = ''; map _dict; // tensorflow lite 解释器对象 interpreter _interpreter; classifier() { // 当分类器初始化的时候加载模型 _loadmodel(); _loaddictionary(); } void _loadmodel() async { // 使用 intepreter.fromasset 创建解析器 _interpreter = await interpreter.fromasset(_modelfile); print('interpreter loaded successfully'); } void _loaddictionary() async { final vocab = await rootbundle.loadstring('assets/$_vocabfile'); var dict = {}; final vocablist = vocab.split(' '); for (var i = 0; i < vocablist.length; i++) { var entry = vocablist[i].trim().split(' '); dict[entry[0]] = int.parse(entry[1]); } _dict = dict; print('dictionary loaded successfully'); } int classify(string rawtext) { // tokenizeinputtext 返回形状为 [1, 256] 的 list list input = tokenizeinputtext(rawtext); //输出形状为 [1, 2] 的矩阵 var output = list(2).reshape([1, 2]); // run 方法会运行分析并且将结果存储在 output 中。 _interpreter.run(input, output); var result = 0; // 如果第一个元素的输出比第二个大,那么当前语句是消极的 if ((output[0][0] as double) > (output[0][1] as double)) { result = 0; } else { result = 1; } return result; } list tokenizeinputtext(string text) { // 用空格分词 final toks = text.split(' '); // 创建一个列表,它的长度等于 _sentencelen,并且使用 对应的字典值来填充 var vec = list.filled(_sentencelen, _dict[pad].todouble()); var index = 0; if (_dict.containskey(start)) { vec[index++] = _dict[start].todouble(); } // 对于句子中的每个单词,在 dict 中找到相应的 index 值 for (var tok in toks) { if (index > _sentencelen) { break; } vec[index++] = _dict.containskey(tok) ? _dict[tok].todouble() : _dict[unk].todouble(); } // 按照我们的解释器输入 tensor 所需的形状 [1,256] 返回 list return [vec]; } }
现在,可以根据您的喜好实现 ui 的代码,分类器的用法比较简单。
// 创建 classifier 对象 classifer _classifier = classifier(); // 将目标语句作为参数,调用 classify 方法 _classifier.classify(i liked the movie); // 返回 1 (积极的) _classifier.classify(i didn't liked the movie); // 返回 0 (消极的)
△ 文字分类示例应用
了解更多关于 tflite_flutter 插件的信息,请访问 github repo:am15h/tflite_flutter_plugin。
你问我答
问:tflite_flutter 和 tflite v1.0.5 有哪些区别?
tflite v1.0.5 侧重于为特定用途的应用场景提供高级特性,比如图片分类、物体检测等等。而新的 tflite_flutter 则提供了与 java api 相同的特性和灵活性,而且可以用于任何 tflite 模型中,它还支持 delegate。
由于使用 dart:ffi (dart (ffi) c),tflite_flutter 非常快 (拥有低延时)。而 tflite 使用平台集成 (dart platform-channel (java/swift) jni c)。
问:如何使用 tflite_flutter 创建图片分类应用?有没有类似 tensorflow lite android support library 的依赖包?
tensorflow lite flutter helper library为处理和控制输入及输出的 tflite 模型提供了易用的架构。它的 api 设计和文档与 tensorflow lite android support library 是一样的。更多信息请参考 tflite flutter helper 的 github 。
tflite flutter helper 开发库 github 仓库地址
https://github.com/am15h/tflite_flutter_helper
以上是本文的全部内容,欢迎大家对 tflite_flutter 插件进行反馈,请在 github报 bug 或提出功能需求。谢谢关注,感谢 flutter 团队的 michael thomsen。
向 tflite_flutter 插件提出建议和反馈
https://github.com/am15h/tflite_flutter_plugin/issues
绝对值编码器:断电零点丢失怎么办?
连接器应该具备什么要素
TDK-EPC推出体积最小尺寸的EPCOS B4300 GPS滤波器
贸泽开售STMicroelectronics BlueNRG-2N和BlueNRG-LP器件
海康威视推出交通事故分析研判系统
全新插件tflite_flutter
Imagination携手Xilinx推出MIPSfpga计划
热敏晶振OZ26030001在电路板中的作用
行业 | 当Faster RCNN遇到FPGA,自动驾驶开始起飞!
真正的Facebook手机叫Buffy
服务器为什么配大带宽会更好
一位IT工程师的感慨
焊接二极管时需要注意什么
富士通拟设计2纳米芯片 委托台积电代工
算力时代DPU让不可能成为可能
如何拆解Zen V播放器
差分输出、电流模式DAC的参数和测量方法
我们在使用Go语言编程之前有什么呢?为什么选择Go语言编程?
在ARM工控机上实现SQLite3的优势
可不使用微控制器配置Dallas Semiconductor