将介绍一个基于Cycle-Consistent Adversarial Networks(CycleGAN)的移动图像到图像翻译系统。将构建一个CycleGAN,它能够执行非成对的图像到图像的翻译,并展示一些既有趣又具有学术深度的例子。还将讨论如何将使用TensorFlow和Keras训练的网络转换为TensorFlow Lite,并在移动设备上作为应用程序使用。
假设熟悉深度学习的概念,以及Jupyter Notebooks和TensorFlow。欢迎下载项目代码。
在之前的文章中,保存并加载了TensorFlow Lite(.tflite)模型。在本文中,将在Android Studio中加载它,并选择正确的TensorFlow Lite Android支持库来运行推理。
构建Android应用程序的第一步是下载Android Studio。下载完成后,开始所谓的“机器学习(ML)和模块依赖绑定”,通过将.tflite模型导入Android Studio文件。
要将模型导入Android Studio,请右键单击希望使用TFLite模型的模块,或选择File > New > Other > TensorFlow Lite Model。然后,选择TFLite文件的位置。请注意,该工具将自动为配置模块的依赖关系,ML模型绑定和所有依赖项将自动插入到Android模块的build.gradle文件中。
完成后点击Finish。
为了解释模型输出,必须将TensorFlow Lite Android支持库集成到应用程序中。这将提供高级API,帮助将原始输入数据转换和预处理,以适应模型期望的大小和格式。
此解释器库支持常见的输入和输出数据格式,包括图像和数组。此外,此库还包括一些预处理功能,如图像缩放和裁剪。
要导入Gradle依赖项,首先将.tflite模型文件复制到模型将运行的Android模块的assets目录中。指定文件不应被压缩,并在模块的build.gradle文件中添加TensorFlow Lite库:
dependencies {
// Other dependencies
// Import tflite dependencies
implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT'
// The GPU delegate library is optional. If needed, select the second checkbox
// for importing TensorFlow GPU if you want to use GPU acceleration.
implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly-SNAPSHOT'
implementation 'org.tensorflow:tensorflow-lite-support:0.0.0-nightly-SNAPSHOT'
}
此时有一个存储在文件tflite_model.tflite中的神经网络。如果想使用它,需要创建一个新项目(例如命名为CycleGAN_App),并将模型文件放置在CycleGAN_App/app/src/main/assets文件夹中。由于Android Studio默认会为性能原因压缩资源文件,还需要明确告诉它不要压缩神经网络,方法是在gradle文件中添加以下行:
aaptOptions {
noCompress "tflite"
}
其次,需要添加所需的依赖项:更新gradle文件,添加以下行:
implementation 'org.tensorflow:tensorflow-lite:1.13.1'
为了演示移动图像到图像的翻译,创建了一个简单的Android应用程序,它有一个按钮来上传图像,通过TensorFlow Lite模型运行它,并显示翻译后的图像。
可以下载项目代码以查看其实际效果!尽管本文不讨论应用程序代码的完整讨论,但将探讨其最重要的部分。
在能够将图像输入模型之前,必须将其转换为模型可以处理的大小和格式。
为了使用TensorFlow Lite的图像操作和转换方法,必须创建一个ImagePreprocessor并添加所需的操作。要将图像转换为TensorFlow Lite解释器所需的张量格式,请创建一个TensorImage作为输入:
import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.image.ops.ResizeOp;
// Initialization code
// Create an ImageProcessor with all ops required. For more ops,
// refer to the ImageProcessor Architecture section in this README.
ImageProcessor imageProcessor =
new ImageProcessor.Builder()
.add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR))
.build();
// Create a TensorImage object. This creates the tensor of the corresponding
// tensor type (uint8 in this case) that the TensorFlow Lite interpreter needs.
TensorImage tImage = new TensorImage(DataType.UINT8);
// Analysis code
for every frame
// Preprocess the image
tImage.load(bitmap);
tImage = imageProcessor.process(tImage);
要运行模型,需要创建将用于存储结果的容器对象(TensorBuffer):
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
// Create a container for the result and specify that this is
// a quantized model. Hence, the 'DataType' is defined as UINT8
// (8-bit unsigned integer)
TensorBuffer probabilityBuffer =
TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);
要加载模型并运行推理:
import org.tensorflow.lite.support.model.Model;
// Initialise the model
try {
MappedByteBuffer tfliteModel =
FileUtil.loadMappedFile(activity, "mobilenet_v1_1.0_224_quant.tflite");
Interpreter tflite = new Interpreter(tfliteModel);
} catch (IOException e){
Log.e("tfliteSupport", "Error reading model", e);
}
// Run inference
if (null != tflite) {
tflite.run(tImage.getBuffer(), probabilityBuffer.getBuffer());
}
如上所述,ImageProcessor支持一些基本的图像操作方法;即裁剪、缩放和旋转:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = height > width ? width : height;
ImageProcessor imageProcessor =
new ImageProcessor.Builder()
// Center crop the image to the largest square possible
.add(new ResizeWithCropOrPadOp(size, size))
// Resize using Bilinear or Nearest neighbour
.add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR));
// Rotate counter-clockwise in 90 degree increments
.add(new Rot90Op(rotateDegrees / 90))
.add(new NormalizeOp(127.5, 127.5))
.add(new QuantizeOp(128.0, 1/128.0))
.build();
在初始化输入和输出对象,如TensorImage或TensorBuffer时,需要指定对象类型为DataType.UINT8或DataType.FLOAT32:
TensorImage tImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);
TensorProcessor is used to quantize input tensors or dequantize output tensors:
import org.tensorflow.lite.support.common.TensorProcessor;
// Post-processor that dequantizes the result
TensorProcessor probabilityProcessor =
new TensorProcessor.Builder().add(new DequantizeOp(0, 1/255.0)).build();
TensorBuffer dequantizedBuffer = probabilityProcessor.process(probabilityBuffer);