如何从内部存储加载张量流模型?



我想知道是否可以从Android设备的内部存储而不是资产文件夹中存储和读取经过训练的.tflite模型?

下面是从 assets 文件夹加载模型的原始代码(有效)。

private MappedByteBuffer loadLocalModelFile() throws IOException {
AssetFileDescriptor fileDescriptor = getAssets().openFd(MODEL_PATH);
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
long startOffset = fileDescriptor.getStartOffset();
long declaredLength = fileDescriptor.getDeclaredLength();
FileChannel fileChannel = inputStream.getChannel();
return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}

有没有办法从内部存储器加载模型,并且仍然获得 fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength) 的 startOffset 和 declaredLength?如果没有,有没有办法计算新模型的 startOffset 及其从内部存储读取原始二进制文件时的声明长度?

我尝试使用AssetManager中的openNonAssetFd()函数来获取位于内部存储中的文件的AssetFileDescriptor。

private MappedByteBuffer loadOnlineModelFile() throws IOException {
FileInputStream inputStream = openFileInput(MODEL);
AssetManager manager = getAssets();
AssetFileDescriptor afd = manager.openNonAssetFd(getFilesDir() + "/graph.lite");
long startOffset = afd.getStartOffset();
long declaredLength = afd.getDeclaredLength();
FileChannel fileChannel = inputStream.getChannel();
return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}

但是,这将导致"java.lang.IllegalArgumentException:Model ByteBuffer应该是模型文件的MappedByteBuffer,或者是使用ByteOrder.nativeOrder()的直接ByteBuffer,其中包含模型内容的字节数"和"java.io.FileNotFoundException"。

好吧,我一直在到处寻找,终于想通了。这很简单。
出于某种原因,我认为AssetFileDescriptorgetStartOffset与实际tflite model有关,但事实并非如此。我认为getStartOffset给出了应用程序资产中文件的start点。对于tflite model,应该0startOffset,因为这是文件开始的地方,因为它只是一个文件。 所以,代码应该是

File file = new File('path_to_model');
FileInputStream is = new FileInputStream(file);
return is.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
Combining all the answer over stackoverflow i found a solution 
which is working in my android application.
InputStream inputStream = null;
try {
inputStream = context.getAssets().open("model.tflite");
} catch (IOException e) {
e.printStackTrace();
}
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
byte file[] = output.toByteArray();
ByteBuffer bb = ByteBuffer.allocateDirect(file.length);
bb.order(ByteOrder.nativeOrder());
bb.put(file);
imageClassifier = ImageClassifier.createFromBuffer(bb );

您可以直接从内部存储访问该文件。 这是一个演示代码,用于从位于内部存储中的示例文件夹中读取名为 model.tflite 的 tflite 模型。

@NonNull
public MappedByteBuffer loadMappedFile(@NonNull Context context, @NonNull String filePath) throws IOException {
SupportPreconditions.checkNotNull(context, "Context should not be null.");
SupportPreconditions.checkNotNull(filePath, "File path cannot be null.");
File file = new File(Environment.getExternalStorageDirectory() + "/sample/" + filePath);
MappedByteBuffer var9;
try {
FileInputStream inputStream = new FileInputStream(file);
try {
FileChannel fileChannel = inputStream.getChannel();
var9 = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
} catch (Throwable var12) {
try {
inputStream.close();
} catch (Throwable var11) {
var12.addSuppressed(var11);
}
throw var12;
}
inputStream.close();
} catch (Throwable var13) {
throw var13;
}
return var9;
}

文件路径将是模型的名称。 这里是 model.tflite。 我们可以像这样调用该方法,

loadMappedFile(Classifier.this, "model.tflite");

最新更新