无法在 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 可序列化的 [重复]

如何将数据类型更改为 float64 以便 sklearn 可以处理数据大于 np.float32 的数据帧

如何使用霓虹内在函数准确地将 uchar 转换为 float32 ,反之亦然