@@ -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,15 @@ 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 (" [vivante] Convert output to fp32!" );
554+ _convert_output_fp32 = TRUE ;
555+ } else {
556+ g_warning (" Ignore unsupported output type (%s)" , option[1 ]);
557+ }
545558 } else {
546559 g_warning (" Unknown option (%s)." , options[op]);
547560 }
@@ -600,6 +613,12 @@ ml_vivante_configure_instance (void *backend_private, const void *prop_)
600613 GstTensorInfo *info = gst_tensors_info_get_nth_info (&vivante->outputInfo , i);
601614
602615 info->type = convert_to_tensor_type (o_tensor->attr .dtype .vx_type );
616+
617+ /* Output tensors should be converted into fp32 */
618+ if (_convert_output_fp32 && info->type != _NNS_FLOAT32) {
619+ info->type = _NNS_FLOAT32;
620+ vivante->convert_output_fp32 = TRUE ;
621+ }
603622 info->name = g_strdup_printf (" %i" , vivante->graph ->output .tensors [i]);
604623 for (unsigned int j = 0 ; j < o_tensor->attr .dim_num ; ++j) {
605624 info->dimension [j] = o_tensor->attr .size [j];
@@ -641,8 +660,22 @@ ml_vivante_invoke (void *backend_private, const void *input_, void *output_)
641660 for (unsigned int i = 0 ; i < vivante->graph ->output .num ; i++) {
642661 vsi_nn_tensor_t *out_tensor
643662 = 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 );
663+
664+ /* Convert to fp32 */
665+ if (vivante->convert_output_fp32 ) {
666+ float *fp32_data = vsi_nn_ConvertTensorToFloat32Data (vivante->graph , out_tensor);
667+ if (fp32_data == NULL ) {
668+ g_critical (" [vivante] Failed to convert output tensor to FP32." );
669+ return HAL_ML_ERROR_RUNTIME_ERROR ;
670+ }
671+
672+ vsi_size_t num_elements = vsi_nn_GetElementNum (out_tensor);
673+ memcpy (output[i].data , fp32_data, num_elements * sizeof (float ));
674+ vsi_nn_Free (fp32_data);
675+ } else {
676+ /* Do not check return value of vsi_nnCopyTensorToBuffer. It returns error in normal case */
677+ vsi_nn_CopyTensorToBuffer (vivante->graph , out_tensor, output[i].data );
678+ }
646679 }
647680
648681 return HAL_ML_ERROR_NONE ;
0 commit comments