无法在 FLOAT32 类型的 TensorFlowLite 张量和 Java 对象之间转换
Posted
技术标签:
【中文标题】无法在 FLOAT32 类型的 TensorFlowLite 张量和 Java 对象之间转换【英文标题】:Cannot convert between a TensorFlowLite tensor with type FLOAT32 and a Java object 【发布时间】:2022-01-02 20:31:06 【问题描述】:我正在尝试在 android 上使用 TFlite 构建推荐系统。我已经成功地创建了模型,并且还对其进行了推理,运行得非常好。但问题在于尝试将应用程序与模型集成。我正在尝试将模型集成到 tensorflow 团队提供的官方应用程序中。我已经完成了他们要求的所有步骤,但我面临的问题是关于模型的输入/输出。我遇到了错误说:
无法在 FLOAT32 类型的 TensorFlowLite 张量和 [I 类型的 Java 对象(与 TensorFlowLite 兼容) 输入 INT32)。
我无法理解此错误的含义,也没有任何相关文档。 官方代码中用于输入和输出的代码如下: 这是定义输入和输出的主要代码:
/** Given a list of selected items, and returns the recommendation results. */
@WorkerThread
public synchronized List<Result> recommend(List<MovieItem> selectedMovies)
Object[] inputs = preprocess(selectedMovies);
// Run inference.
float[] outputIds = new float[config.outputLength];
float[] confidences = new float[config.outputLength];
Map<Integer, Object> outputs = new HashMap<>();
outputs.put(config.outputIdsIndex, outputIds);
outputs.put(config.outputScoresIndex, confidences);
tflite.runForMultipleInputsOutputs(inputs, outputs);
return postprocess(outputIds, confidences, selectedMovies);
这定义了预处理部分:
int[] preprocessIds(List<MovieItem> selectedMovies, int length)
int[] inputIds = new int[length];
Arrays.fill(inputIds, config.pad); // Fill inputIds with the default.
int i = 0;
for (MovieItem item : selectedMovies)
if (i >= inputIds.length)
break;
inputIds[i] = item.id;
++i;
return inputIds;
int[] preprocessGenres(List<MovieItem> selectedMovies, int length)
// Fill inputGenres.
int[] inputGenres = new int[length];
Arrays.fill(inputGenres, config.unknownGenre); // Fill inputGenres with the default.
int i = 0;
for (MovieItem item : selectedMovies)
if (i >= inputGenres.length)
break;
for (String genre : item.genres)
if (i >= inputGenres.length)
break;
inputGenres[i] = genres.containsKey(genre) ? genres.get(genre) : config.unknownGenre;
++i;
return inputGenres;
/** Given a list of selected items, preprocess to get tflite input. */
@WorkerThread
synchronized Object[] preprocess(List<MovieItem> selectedMovies)
List<Object> inputs = new ArrayList<>();
// Sort features.
List<Feature> sortedFeatures = new ArrayList<>(config.inputs);
Collections.sort(sortedFeatures, (Feature a, Feature b) -> Integer.compare(a.index, b.index));
for (Feature feature : sortedFeatures)
if (Config.FEATURE_MOVIE.equals(feature.name))
inputs.add(preprocessIds(selectedMovies, feature.inputLength));
else if (Config.FEATURE_GENRE.equals(feature.name))
inputs.add(preprocessGenres(selectedMovies, feature.inputLength));
else
Log.e(TAG, String.format("Invalid feature: %s", feature.name));
return inputs.toArray();
要使建议生效,需要进行哪些更改?
编辑: 我能够解决上述问题。我发现流派所需的输入是 float 类型,因此将流派的 float 数组作为输入传递,问题就解决了。 但是,出现了一个新错误:
java.lang.IllegalStateException:内部错误:意外失败 在准备张量分配时: tensorflow/lite/kernels/reshape.cc:66 num_input_elements != num_output_elements (10 != 32) 节点号 0 (RESHAPE) 准备失败。
问题与输入和输出元素不匹配有关。我无法找出相同的解决方案。
model.tflite 的链接可以在这里找到:
https://drive.google.com/file/d/1CZxlJRqLZmwrsmgcA8lBz6XCh2KG3lWa/view?usp=sharing
【问题讨论】:
我认为问题在于输入。您正在为模型提供整数数组的 Object 数组。那么您的模型对输入的期望究竟是什么?整数?浮动?您是否使用 netron.app 将模型可视化? 嘿@Farmaker,感谢您与我们联系。你是对的,问题在于输入。但是正在解决同样的问题,又弹出了一个新的错误。如果您指导相同的内容将会很有帮助。 是的,这更复杂。您可以将 .tflite 文件上传到某处并分享链接吗?似乎某些数组内部没有足够的元素。 我已根据需要添加了 .tflite 文件。我觉得很复杂,会尝试做正确的尝试。 感谢@Farmaker 的帮助 【参考方案1】:这个问题是完全混淆和被 colab 文件误导的结果。 tensorflow/examples/recommendation 中的 colab 文件指导创建一个 tensorflow lite 模型,该模型具有三个输入,即流派、评级和电影 ID,但是存在于同一存储库中的 android 应用程序实现代码以仅考虑两个输入,即电影id 和流派。可以在以下位置找到 colab:
https://colab.research.google.com/github/tensorflow/examples/blob/master/lite/examples/recommendation/ml/ondevice_recommendation.ipynb#scrollTo=og0qkYavz3Nt
根据@Farmaker 提供的指导,我可视化了我的模型以及 tensorflow-recommendation 存储库中存在的 android 应用程序中的模型。如下所示:
我的模型:
谷歌的模型:
我没有考虑用于解释 android 内部 .tflite 模型的代码,盲目地遵循 Google colab 文件,其中只提到了 .tflite 与 android 的协作,而无需任何额外的编码。
解决方案: 第一个错误:
无法在 FLOAT32 类型的 TensorFlowLite 张量和 [I 类型的 Java 对象(与 TensorFlowLite 兼容) 输入 INT32)。
由于输入对象需要采用模型所需的特定格式,因此第二个输入应该是浮点类型,但我将它作为参数传递给 int。这会导致特定错误,在以特定顺序传递参数后解决,这是 .tflite 模型所需的格式。
第二个错误:
java.lang.IllegalStateException:内部错误:意外失败 在准备张量分配时: tensorflow/lite/kernels/reshape.cc:66 num_input_elements != num_output_elements (10 != 32) 节点号 0 (RESHAPE) 未能 准备。
这个错误是由于流派参数要求浮点数组的大小为 32,但我只为模型提供了一个大小为 10 的浮点数组,在观察错误时可以很容易地这么说。我通过传递大小为 32 的类型浮点数组解决了这个问题。
我对推荐系统的android存储库进行了一些必要的更改,并且代码运行良好。
【讨论】:
以上解释不是很详细,如果有人希望对任何问题进行详细解释,请发表评论以上是关于无法在 FLOAT32 类型的 TensorFlowLite 张量和 Java 对象之间转换的主要内容,如果未能解决你的问题,请参考以下文章
TypeError:“Mul”Op 的输入“y”的类型为 float32,与参数“x”的类型 int32 不匹配
typedef float _Float32 的声明说明符中有两个或多个数据类型;
TypeError:“numpy.float32”类型的对象没有 len()
TypeError:“float32”类型的对象不是 JSON 可序列化的 [重复]