关于flutter:在-Flutter-中使用-TensorFlow-Lite-插件实现文字分类

39次阅读

共计 7573 个字符,预计需要花费 19 分钟才能阅读完成。

如果您心愿能有一种简略、高效且灵便的形式把 TensorFlow 模型集成到 Flutter 利用里,那请您肯定不要错过咱们明天介绍的这个全新插件 tflite_flutter。这个插件的开发者是 Google Summer of Code(GSoC) 的一名实习生 Amish Garg,本文来自他在 Medium 上的一篇文章《在 Flutter 中应用 TensorFlow Lite 插件实现文字分类》。

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/

它会主动从 release assets 下载最新的二进制资源,而后把它放到指定的目录下。

请点击到 README 文件里查看更多 对于初始配置的信息。

获取插件

pubspec.yaml 增加 tflite_flutter: ^<latest_version>(详情)。

下载模型

要在挪动端上运行 TensorFlow 训练模型,咱们须要应用 .tflite 格局。如果须要理解如何将 TensorFlow 训练的模型转换为 .tflite 格局,请参阅官网指南。

这里咱们筹备应用 TensorFlow 官方站点上预训练的文字分类模型,可从这里下载。

该预训练的模型能够预测以后段落的情感是踊跃还是消极。它是基于来自 Mass 等人的  Large Movie Review Dataset v1.0 数据集进行训练的。数据集由基于 IMDB 电影评论所标记的踊跃或消极标签组成,点击查看更多信息。

text_classification.tflitetext_classification_vocab.txt 文件拷贝到 text_classification_app/assets/ 目录下。

pubspec.yaml 文件中增加 assets/

assets:    
  - assets/

当初万事俱备,咱们能够开始写代码了。????

实现分类器

预处理

正如 文字分类模型页面 里所提到的。能够依照上面的步骤应用模型对段落进行分类:

  1. 对段落文本进行分词,而后应用预约义的词会集将它转换为一组词汇 ID;
  2. 将生成的这组词汇 ID 输出 TensorFlow Lite 模型里;
  3. 从模型的输入里获取以后段落是踊跃或者是消极的概率值。

咱们首先写一个办法对原始字符串进行分词,其中应用 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<String, int> _dict;

  Classifier() {_loadDictionary();
  }

  void _loadDictionary() async {final vocab = await rootBundle.loadString('assets/$_vocabFile');
    var dict = <String, int>{};
    final vocabList = vocab.split('\n');
    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 = '<START>';
  final String pad = '<PAD>';
  final String unk = '<UNKNOWN>';

  Map<String, int> _dict;
  
  List<List<double>> tokenizeInputText(String text) {
    
    // 应用空格进行分词
    final toks = text.split(' ');
    
    // 创立一个列表,它的长度等于 _sentenceLen,并且应用 <pad> 的对应的字典值来填充
    var vec = List<double>.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<List<double>>
    return [vec];
  }
}

应用 tflite_flutter 进行剖析

这是本文的主体局部,这里咱们会探讨 tflite_flutter 插件的用处。

这里的剖析是指基于输出数据在设施上应用 TensorFlow Lite 模型的处理过程。要应用 TensorFlow Lite 模型进行剖析,须要通过 解释器 来运行它,理解更多。

创立解释器,加载模型

tflite_flutter 提供了一个办法间接通过资源创立解释器。

static Future<Interpreter> 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 inputObject output 必须是和 Input Tensor 与 Output Tensor 维度雷同的列表。

要查看  input tensors 和 output tensors 的维度,能够应用如下代码:

_interpreter.allocateTensors();
// 打印 input tensor 列表
print(_interpreter.getInputTensors());
// 打印 output tensor 列表
print(_interpreter.getOutputTensors());

在本例中 text_classification 模型的输入如下:

InputTensorList:
[Tensor{_tensor: Pointer<TfLiteTensor>: address=0xbffcf280, name: embedding_input, type: TfLiteType.float32, shape: [1, 256], data:  1024]
OutputTensorList:
[Tensor{_tensor: Pointer<TfLiteTensor>: 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<double>>
    List<List<double>> input = tokenizeInputText(rawText);
   
    // [1,2] 形态的输入
    var output = List<double>(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<dynamic>

List reshape(List<int> shape)
// 返回列表的形态
List<int> 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 = '<START>';
  final String pad = '<PAD>';
  final String unk = '<UNKNOWN>';

  Map<String, int> _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 = <String, int>{};
    final vocabList = vocab.split('\n');
    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<double>>
    List<List<double>> input = tokenizeInputText(rawText);

    // 输入形态为 [1, 2] 的矩阵
    var output = List<double>(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<List<double>> tokenizeInputText(String text) {
    // 用空格分词
    final toks = text.split(' ');

    // 创立一个列表,它的长度等于 _sentenceLen,并且应用 <pad> 对应的字典值来填充
    var vec = List<double>.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<List<double>>
    return [vec];
  }
}

当初,能够依据您的爱好实现 UI 的代码,分类器的用法比较简单。

// 创立 Classifier 对象
Classifer _classifier = Classifier();
// 将指标语句作为参数,调用 classify 办法
_classifier.classify("I liked the movie");
// 返回 1(踊跃的)_classifier.classify("I didn't liked the movie");
// 返回 0(消极的)

请在这里查阅残缺代码:Text Classification Example app with UI。

文字分类示例利用

理解更多对于 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 的依赖包?

更新(07/01/2020): TFLite Flutter Helper 开发库已公布。

TensorFlow Lite Flutter Helper Library 为解决和管制输出及输入的 TFLite 模型提供了易用的架构。它的 API 设计和文档与 TensorFlow Lite Android Support Library 是一样的。更多信息请 参考这里。

以上是本文的全部内容,欢送大家对 tflite_flutter 插件进行反馈,请在这里 上报 bug 或提出性能需要。

谢谢关注。

感激 Michael Thomsen。

致谢

  • 译者:Yuan,谷创字幕组
  • 审校:Xinlei、Lynn Wang、Alex,CFUG 社区。

本文联结公布在 TensorFlow 线上讨论区、101.dev 和 Flutter 中文文档,以及 Flutter 社区线上渠道。

正文完
 0