@@ -22,6 +22,8 @@ typedef struct _vivante_handle_s {
2222 gboolean use_json_for_graph;
2323 gboolean has_post_process; /* * @deprecated Do not use it. */
2424
25+ gboolean convert_output_fp32; /* Convert all output tensor into fp32 */
26+
2527 GstTensorsInfo inputInfo;
2628 GstTensorsInfo outputInfo;
2729
@@ -447,6 +449,7 @@ _init_vivante_handle (vivante_handle_s *vivante)
447449
448450 vivante->use_json_for_graph = TRUE ;
449451 vivante->has_post_process = FALSE ;
452+ vivante->convert_output_fp32 = FALSE ;
450453}
451454
452455/* * @brief Close model and clear internal data in handle. */
@@ -510,6 +513,7 @@ ml_vivante_configure_instance (void *backend_private, const void *prop_)
510513{
511514 const GstTensorFilterProperties *prop = (const GstTensorFilterProperties *) prop_;
512515 vivante_handle_s *vivante = (vivante_handle_s *) backend_private;
516+ gboolean _convert_output_fp32 = FALSE ;
513517
514518 if (!vivante || !prop) {
515519 g_critical (" [vivante] invalid backend_private" );
@@ -542,6 +546,16 @@ ml_vivante_configure_instance (void *backend_private, const void *prop_)
542546 vivante->use_json_for_graph = TRUE ;
543547 vivante->json_path = g_strdup (option[1 ]);
544548 g_info (" [vivante] Using JSON for graph setup: %s" , vivante->json_path );
549+ } else if (g_ascii_strcasecmp (option[0 ], " OutputType" ) == 0 ) {
550+ /* @todo let each output tensor has different outputtype */
551+ gchar *type = option[1 ];
552+ if (g_ascii_strcasecmp (type, " FLOAT32" ) == 0 || g_ascii_strcasecmp (type, " FP32" ) == 0 ) {
553+ g_info (" convert to fp32!" );
554+ _convert_output_fp32 = TRUE ;
555+ } else {
556+ g_warning (" Ignore unsupported output type (%s)" , option[1 ]);
557+ }
558+
545559 } else {
546560 g_warning (" Unknown option (%s)." , options[op]);
547561 }
@@ -600,6 +614,12 @@ ml_vivante_configure_instance (void *backend_private, const void *prop_)
600614 GstTensorInfo *info = gst_tensors_info_get_nth_info (&vivante->outputInfo , i);
601615
602616 info->type = convert_to_tensor_type (o_tensor->attr .dtype .vx_type );
617+
618+ /* Output tensors should be converted into fp32 */
619+ if (_convert_output_fp32 && info->type != _NNS_FLOAT32) {
620+ info->type = _NNS_FLOAT32;
621+ vivante->convert_output_fp32 = TRUE ;
622+ }
603623 info->name = g_strdup_printf (" %i" , vivante->graph ->output .tensors [i]);
604624 for (unsigned int j = 0 ; j < o_tensor->attr .dim_num ; ++j) {
605625 info->dimension [j] = o_tensor->attr .size [j];
@@ -641,8 +661,22 @@ ml_vivante_invoke (void *backend_private, const void *input_, void *output_)
641661 for (unsigned int i = 0 ; i < vivante->graph ->output .num ; i++) {
642662 vsi_nn_tensor_t *out_tensor
643663 = vsi_nn_GetTensor (vivante->graph , vivante->graph ->output .tensors [i]);
644- /* Do not check return value of vsi_nnCopyTensorToBuffer. It returns error in normal case */
645- vsi_nn_CopyTensorToBuffer (vivante->graph , out_tensor, output[i].data );
664+
665+ /* Convert to fp32 */
666+ if (vivante->convert_output_fp32 ) {
667+ float *fp32_data = vsi_nn_ConvertTensorToFloat32Data (vivante->graph , out_tensor);
668+ if (fp32_data == NULL ) {
669+ g_critical (" [vivante] Failed to convert output tensor to FP32." );
670+ return HAL_ML_ERROR_RUNTIME_ERROR ;
671+ }
672+
673+ vsi_size_t num_elements = vsi_nn_GetElementNum (out_tensor);
674+ memcpy (output[i].data , fp32_data, num_elements * sizeof (float ));
675+ vsi_nn_Free (fp32_data);
676+ } else {
677+ /* Do not check return value of vsi_nnCopyTensorToBuffer. It returns error in normal case */
678+ vsi_nn_CopyTensorToBuffer (vivante->graph , out_tensor, output[i].data );
679+ }
646680 }
647681
648682 return HAL_ML_ERROR_NONE ;
0 commit comments