[FFmpeg-devel] [PATCH 4/8] libavfilter/dnn: determine dnn output during execute_model instead of set_input_output

Steven Liu lq at chinaffmpeg.org
Tue Apr 16 15:04:21 EEST 2019



> 在 2019年4月2日,22:29,Guo, Yejun <yejun.guo at intel.com> 写道:
> 
> Currently, within interface set_input_output, the dims/memory of the tensorflow
> dnn model output is determined by executing the model with zero input,
> actually, the output dims might vary with different input data for networks
> such as object detection models faster-rcnn, ssd and yolo.
> 
> This patch moves the logic from set_input_output to execute_model which
> is suitable for all the cases. Since interface changed, and so dnn_backend_native
> also changes.
> 
> In vf_sr.c, it knows it's srcnn or espcn by executing the model with zero input,
> so execute_model has to be called in function config_props
> 
> Signed-off-by: Guo, Yejun <yejun.guo at intel.com>
> ---
> libavfilter/dnn_backend_native.c | 14 +++++-----
> libavfilter/dnn_backend_native.h |  2 +-
> libavfilter/dnn_backend_tf.c     | 55 ++++++++++++++++------------------------
> libavfilter/dnn_backend_tf.h     |  2 +-
> libavfilter/dnn_interface.h      |  6 ++---
> libavfilter/vf_sr.c              | 20 ++++++++++++---
> 6 files changed, 51 insertions(+), 48 deletions(-)
> 
> diff --git a/libavfilter/dnn_backend_native.c b/libavfilter/dnn_backend_native.c
> index fe43116..18735c0 100644
> --- a/libavfilter/dnn_backend_native.c
> +++ b/libavfilter/dnn_backend_native.c
> @@ -25,7 +25,7 @@
> 
> #include "dnn_backend_native.h"
> 
> -static DNNReturnType set_input_output_native(void *model, DNNData *input, const char *input_name, DNNData *output, const char *output_name)
> +static DNNReturnType set_input_output_native(void *model, DNNData *input, const char *input_name, const char *output_name)
> {
>     ConvolutionalNetwork *network = (ConvolutionalNetwork *)model;
>     InputParams *input_params;
> @@ -81,11 +81,6 @@ static DNNReturnType set_input_output_native(void *model, DNNData *input, const
>         }
>     }
> 
> -    output->data = network->layers[network->layers_num - 1].output;
> -    output->height = cur_height;
> -    output->width = cur_width;
> -    output->channels = cur_channels;
> -
>     return DNN_SUCCESS;
> }
> 
> @@ -280,7 +275,7 @@ static void depth_to_space(const float *input, float *output, int block_size, in
>     }
> }
> 
> -DNNReturnType ff_dnn_execute_model_native(const DNNModel *model)
> +DNNReturnType ff_dnn_execute_model_native(const DNNModel *model, DNNData *output)
> {
>     ConvolutionalNetwork *network = (ConvolutionalNetwork *)model->model;
>     int cur_width, cur_height, cur_channels;
> @@ -322,6 +317,11 @@ DNNReturnType ff_dnn_execute_model_native(const DNNModel *model)
>         }
>     }
> 
> +    output->data = network->layers[network->layers_num - 1].output;
> +    output->height = cur_height;
> +    output->width = cur_width;
> +    output->channels = cur_channels;
> +
>     return DNN_SUCCESS;
> }
> 
> diff --git a/libavfilter/dnn_backend_native.h b/libavfilter/dnn_backend_native.h
> index 51d4cac..adaf4a7 100644
> --- a/libavfilter/dnn_backend_native.h
> +++ b/libavfilter/dnn_backend_native.h
> @@ -63,7 +63,7 @@ typedef struct ConvolutionalNetwork{
> 
> DNNModel *ff_dnn_load_model_native(const char *model_filename);
> 
> -DNNReturnType ff_dnn_execute_model_native(const DNNModel *model);
> +DNNReturnType ff_dnn_execute_model_native(const DNNModel *model, DNNData *output);
> 
> void ff_dnn_free_model_native(DNNModel **model);
> 
> diff --git a/libavfilter/dnn_backend_tf.c b/libavfilter/dnn_backend_tf.c
> index a838907..7966688 100644
> --- a/libavfilter/dnn_backend_tf.c
> +++ b/libavfilter/dnn_backend_tf.c
> @@ -35,7 +35,6 @@ typedef struct TFModel{
>     TF_Status *status;
>     TF_Output input, output;
>     TF_Tensor *input_tensor;
> -    DNNData *output_data;
> } TFModel;
> 
> static void free_buffer(void *data, size_t length)
> @@ -76,13 +75,12 @@ static TF_Buffer *read_graph(const char *model_filename)
>     return graph_buf;
> }
> 
> -static DNNReturnType set_input_output_tf(void *model, DNNData *input, const char *input_name, DNNData *output, const char *output_name)
> +static DNNReturnType set_input_output_tf(void *model, DNNData *input, const char *input_name, const char *output_name)
> {
>     TFModel *tf_model = (TFModel *)model;
>     int64_t input_dims[] = {1, input->height, input->width, input->channels};
>     TF_SessionOptions *sess_opts;
>     const TF_Operation *init_op = TF_GraphOperationByName(tf_model->graph, "init");
> -    TF_Tensor *output_tensor;
> 
>     // Input operation
>     tf_model->input.oper = TF_GraphOperationByName(tf_model->graph, input_name);
> @@ -132,26 +130,6 @@ static DNNReturnType set_input_output_tf(void *model, DNNData *input, const char
>         }
>     }
> 
> -    // Execute network to get output height, width and number of channels
> -    TF_SessionRun(tf_model->session, NULL,
> -                  &tf_model->input, &tf_model->input_tensor, 1,
> -                  &tf_model->output, &output_tensor, 1,
> -                  NULL, 0, NULL, tf_model->status);
> -    if (TF_GetCode(tf_model->status) != TF_OK){
> -        return DNN_ERROR;
> -    }
> -    else{
> -        output->height = TF_Dim(output_tensor, 1);
> -        output->width = TF_Dim(output_tensor, 2);
> -        output->channels = TF_Dim(output_tensor, 3);
> -        output->data = av_malloc(output->height * output->width * output->channels * sizeof(float));
> -        if (!output->data){
> -            return DNN_ERROR;
> -        }
> -        tf_model->output_data = output;
> -        TF_DeleteTensor(output_tensor);
> -    }
> -
>     return DNN_SUCCESS;
> }
> 
> @@ -508,10 +486,12 @@ DNNModel *ff_dnn_load_model_tf(const char *model_filename)
> 
> 
> 
> -DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model)
> +DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model, DNNData *output)
> {
>     TFModel *tf_model = (TFModel *)model->model;
>     TF_Tensor *output_tensor;
> +    uint32_t count;
> +    uint32_t old_count = output->height * output->width * output->channels * sizeof(float);
Is this will overflow?

> 
>     TF_SessionRun(tf_model->session, NULL,
>                   &tf_model->input, &tf_model->input_tensor, 1,
> @@ -521,14 +501,26 @@ DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model)
>     if (TF_GetCode(tf_model->status) != TF_OK){
>         return DNN_ERROR;
>     }
> -    else{
> -        memcpy(tf_model->output_data->data, TF_TensorData(output_tensor),
> -               tf_model->output_data->height * tf_model->output_data->width *
> -               tf_model->output_data->channels * sizeof(float));
> -        TF_DeleteTensor(output_tensor);
> 
> -        return DNN_SUCCESS;
> +    output->height = TF_Dim(output_tensor, 1);
> +    output->width = TF_Dim(output_tensor, 2);
> +    output->channels = TF_Dim(output_tensor, 3);
> +    count = output->height * output->width * output->channels * sizeof(float);
> +    if (output->data) {
> +        if (count > old_count) {
> +            av_freep(&output->data);
> +        }
> +    }
> +    if (!output->data) {
> +        output->data = av_malloc(count);
> +        if (!output->data){
> +            return DNN_ERROR;
> +        }
>     }
> +    memcpy(output->data, TF_TensorData(output_tensor), count);
> +    TF_DeleteTensor(output_tensor);
> +
> +    return DNN_SUCCESS;
> }
> 
> void ff_dnn_free_model_tf(DNNModel **model)
> @@ -550,9 +542,6 @@ void ff_dnn_free_model_tf(DNNModel **model)
>         if (tf_model->input_tensor){
>             TF_DeleteTensor(tf_model->input_tensor);
>         }
> -        if (tf_model->output_data){
> -            av_freep(&tf_model->output_data->data);
> -        }
>         av_freep(&tf_model);
>         av_freep(model);
>     }
> diff --git a/libavfilter/dnn_backend_tf.h b/libavfilter/dnn_backend_tf.h
> index 7ba84f4..47a24ec 100644
> --- a/libavfilter/dnn_backend_tf.h
> +++ b/libavfilter/dnn_backend_tf.h
> @@ -31,7 +31,7 @@
> 
> DNNModel *ff_dnn_load_model_tf(const char *model_filename);
> 
> -DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model);
> +DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model, DNNData *output);
> 
> void ff_dnn_free_model_tf(DNNModel **model);
> 
> diff --git a/libavfilter/dnn_interface.h b/libavfilter/dnn_interface.h
> index 0390e39..822f6e5 100644
> --- a/libavfilter/dnn_interface.h
> +++ b/libavfilter/dnn_interface.h
> @@ -38,9 +38,9 @@ typedef struct DNNData{
> typedef struct DNNModel{
>     // Stores model that can be different for different backends.
>     void *model;
> -    // Sets model input and output, while allocating additional memory for intermediate calculations.
> +    // Sets model input and output.
>     // Should be called at least once before model execution.
> -    DNNReturnType (*set_input_output)(void *model, DNNData *input, const char *input_name, DNNData *output, const char *output_name);
> +    DNNReturnType (*set_input_output)(void *model, DNNData *input, const char *input_name, const char *output_name);
> } DNNModel;
> 
> // Stores pointers to functions for loading, executing, freeing DNN models for one of the backends.
> @@ -48,7 +48,7 @@ typedef struct DNNModule{
>     // Loads model and parameters from given file. Returns NULL if it is not possible.
>     DNNModel *(*load_model)(const char *model_filename);
>     // Executes model with specified input and output. Returns DNN_ERROR otherwise.
> -    DNNReturnType (*execute_model)(const DNNModel *model);
> +    DNNReturnType (*execute_model)(const DNNModel *model, DNNData *output);
>     // Frees memory allocated for model.
>     void (*free_model)(DNNModel **model);
> } DNNModule;
> diff --git a/libavfilter/vf_sr.c b/libavfilter/vf_sr.c
> index 085ac19..7c92730 100644
> --- a/libavfilter/vf_sr.c
> +++ b/libavfilter/vf_sr.c
> @@ -122,20 +122,31 @@ static int config_props(AVFilterLink *inlink)
>     sr_context->input.height = inlink->h * sr_context->scale_factor;
>     sr_context->input.channels = 1;
> 
> -    result = (sr_context->model->set_input_output)(sr_context->model->model, &sr_context->input, "x", &sr_context->output, "y");
> +    result = (sr_context->model->set_input_output)(sr_context->model->model, &sr_context->input, "x", "y");
>     if (result != DNN_SUCCESS){
>         av_log(context, AV_LOG_ERROR, "could not set input and output for the model\n");
>         return AVERROR(EIO);
>     }
> 
> +    result = (sr_context->dnn_module->execute_model)(sr_context->model, &sr_context->output);
> +    if (result != DNN_SUCCESS){
> +        av_log(context, AV_LOG_ERROR, "failed to execute loaded model\n");
> +        return AVERROR(EIO);
> +    }
> +
>     if (sr_context->input.height != sr_context->output.height || sr_context->input.width != sr_context->output.width){
>         sr_context->input.width = inlink->w;
>         sr_context->input.height = inlink->h;
> -        result = (sr_context->model->set_input_output)(sr_context->model->model, &sr_context->input, "x", &sr_context->output, "y");
> +        result = (sr_context->model->set_input_output)(sr_context->model->model, &sr_context->input, "x", "y");
>         if (result != DNN_SUCCESS){
>             av_log(context, AV_LOG_ERROR, "could not set input and output for the model\n");
>             return AVERROR(EIO);
>         }
> +        result = (sr_context->dnn_module->execute_model)(sr_context->model, &sr_context->output);
> +        if (result != DNN_SUCCESS){
> +            av_log(context, AV_LOG_ERROR, "failed to execute loaded model\n");
> +            return AVERROR(EIO);
> +        }
>         sr_context->scale_factor = 0;
>     }
>     outlink->h = sr_context->output.height;
> @@ -248,7 +259,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
>     }
>     av_frame_free(&in);
> 
> -    dnn_result = (sr_context->dnn_module->execute_model)(sr_context->model);
> +    dnn_result = (sr_context->dnn_module->execute_model)(sr_context->model, &sr_context->output);
>     if (dnn_result != DNN_SUCCESS){
>         av_log(context, AV_LOG_ERROR, "failed to execute loaded model\n");
>         return AVERROR(EIO);
> @@ -266,6 +277,9 @@ static av_cold void uninit(AVFilterContext *context)
>     int i;
>     SRContext *sr_context = context->priv;
> 
> +    if (sr_context->backend_type == DNN_TF)
> +        av_freep(&sr_context->output.data);
> +
>     if (sr_context->dnn_module){
>         (sr_context->dnn_module->free_model)(&sr_context->model);
>         av_freep(&sr_context->dnn_module);
> -- 
> 2.7.4
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".

Thanks
Steven







More information about the ffmpeg-devel mailing list