一、 Lite 是针对移动和嵌入式设备的轻量级解决方案。Lite 支持、iOS 甚至 Pi。二、格式
生成的模型不能直接在移动端使用,需要离线转换为.file格式。
存储格式为。
是一个开源的免费软件库,用于实现序列化格式。它类似于 , , Avro。
因此,如果要在移动端使用,必须将训练好的模型文件转换成格式。官方提供toco实现模型格式的转换。
三、API
Lite 提供两种类型的 API,C++ 和 Java。任一 API 都需要加载和运行模型。
另一方面,Lite 的 Java API 使用类(解释器)来执行加载和运行模型的任务。后面的例子会看到如何使用它。
四、 Lite 实现手写数字识别 mnist。模型文件已包含在下面的演示中。(如果没有,需要自己训练,保存为pb文件,再转成格式)
对于一个识别类,首先需要初始化Lite解释器,以及输入输出。
// The tensorflow lite file private lateinit var tflite: Interpreter // Input byte buffer private lateinit var inputBuffer: ByteBuffer // Output array [batch_size, 10] private lateinit var mnistOutput: Array init { try { tflite = Interpreter(loadModelFile(activity)) inputBuffer = ByteBuffer.allocateDirect( BYTE_SIZE_OF_FLOAT * DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE) inputBuffer.order(ByteOrder.nativeOrder()) mnistOutput = Array(DIM_BATCH_SIZE) { FloatArray(NUMBER_LENGTH) } Log.d(TAG, "Created a Tensorflow Lite MNIST Classifier.") } catch (e: IOException) { Log.e(TAG, "IOException loading the tflite file failed.") } }
从文件中加载 mnist.model:
/** * Load the model file from the assets folder */ @Throws(IOException::class) private fun loadModelFile(activity: Activity): MappedByteBuffer { val fileDescriptor = activity.assets.openFd(MODEL_PATH) val inputStream = FileInputStream(fileDescriptor.fileDescriptor) val fileChannel = inputStream.channel val startOffset = fileDescriptor.startOffset val declaredLength = fileDescriptor.declaredLength return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength) }
手写数字的真正识别在()方法中:
val digit = mnistClassifier.classify(Bitmap.createScaledBitmap(paintView.bitmap, PIXEL_WIDTH, PIXEL_WIDTH, false))
() 方法包含初始化、运行 mnist 模型和识别数字的预处理。
/** * Classifies the number with the mnist model. * * @param bitmap * @return the identified number */ fun classify(bitmap: Bitmap): Int { if (tflite == null) { Log.e(TAG, "Image classifier has not been initialized; Skipped.") } preProcess(bitmap) runModel() return postProcess() } /** * Converts it into the Byte Buffer to feed into the model * * @param bitmap */ private fun preProcess(bitmap: Bitmap?) { if (bitmap == null || inputBuffer == null) { return } // Reset the image data inputBuffer.rewind() val width = bitmap.width val height = bitmap.height // The bitmap shape should be 28 x 28 val pixels = IntArray(width * height) bitmap.getPixels(pixels, 0, width, 0, 0, width, height) for (i in pixels.indices) { // Set 0 for white and 255 for black pixels val pixel = pixels[i] // The color of the input is black so the blue channel will be 0xFF. val channel = pixel and 0xff inputBuffer.putFloat((0xff - channel).toFloat()) } } /** * Run the TFLite model */ private fun runModel() = tflite.run(inputBuffer, mnistOutput) /** * Go through the output and find the number that was identified. * * @return the number that was identified (returns -1 if one wasn't found) */ private fun postProcess(): Int { for (i in 0 until mnistOutput[0].size) { val value = mnistOutput[0][i] if (value == 1f) { return i } } return -1 }
有一个地方需要注意,build 中必须添加以下语句。应用程序模块,否则无法加载模型。
影响:
五、总结
本次demo地址:
当然也可以运行官方的例子:
虽然不是很准确。. .
更有趣的 Lite 示例:
参考链接:
© 版权声明
本站下载的源码均来自公开网络收集转发二次开发而来,
若侵犯了您的合法权益,请来信通知我们1413333033@qq.com,
我们会及时删除,给您带来的不便,我们深表歉意。
下载用户仅供学习交流,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担,访问及下载者下载默认同意本站声明的免责申明,请合理使用切勿商用。
THE END
暂无评论内容