aboutsummaryrefslogtreecommitdiffstats
path: root/libavfilter/dnn_backend_tf.c
diff options
context:
space:
mode:
authorSergey Lavrushkin <dualfal@gmail.com>2018-07-27 19:31:55 +0300
committerPedro Arthur <bygrandao@gmail.com>2018-08-07 11:58:03 -0300
commit4eb63efbdaea6d36ad94f1bb0dd129b7f7aaa899 (patch)
treec33879607c8c16eacd64a1313c1b3a4a0946150d /libavfilter/dnn_backend_tf.c
parent243ecadad5e5e83afdd518c067030e12ac457120 (diff)
downloadffmpeg-4eb63efbdaea6d36ad94f1bb0dd129b7f7aaa899.tar.gz
libavfilter: Adds on the fly generation of default DNN models for tensorflow backend instead of storing binary model.
Signed-off-by: Pedro Arthur <bygrandao@gmail.com>
Diffstat (limited to 'libavfilter/dnn_backend_tf.c')
-rw-r--r--libavfilter/dnn_backend_tf.c271
1 files changed, 231 insertions, 40 deletions
diff --git a/libavfilter/dnn_backend_tf.c b/libavfilter/dnn_backend_tf.c
index 302ff9e4e1..51608c73d9 100644
--- a/libavfilter/dnn_backend_tf.c
+++ b/libavfilter/dnn_backend_tf.c
@@ -203,52 +203,191 @@ DNNModel* ff_dnn_load_model_tf(const char* model_filename)
return model;
}
-DNNModel* ff_dnn_load_default_model_tf(DNNDefaultModel model_type)
+static TF_Operation* add_pad_op(TFModel* tf_model, TF_Operation* input_op, int32_t pad)
{
- DNNModel* model = NULL;
- TFModel* tf_model = NULL;
- TF_Buffer* graph_def;
- unsigned char* graph_data = NULL;
- TF_ImportGraphDefOptions* graph_opts;
+ TF_OperationDescription* op_desc;
+ TF_Operation* op;
+ TF_Tensor* tensor;
+ TF_Output input;
+ int32_t* pads;
+ int64_t pads_shape[] = {4, 2};
+
+ op_desc = TF_NewOperation(tf_model->graph, "Const", "pads");
+ TF_SetAttrType(op_desc, "dtype", TF_INT32);
+ tensor = TF_AllocateTensor(TF_INT32, pads_shape, 2, 4 * 2 * sizeof(int32_t));
+ pads = (int32_t*)TF_TensorData(tensor);
+ pads[0] = 0; pads[1] = 0;
+ pads[2] = pad; pads[3] = pad;
+ pads[4] = pad; pads[5] = pad;
+ pads[6] = 0; pads[7] = 0;
+ TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+ op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
- graph_def = TF_NewBuffer();
- switch (model_type){
- case DNN_SRCNN:
- graph_data = av_malloc(srcnn_tf_size);
- if (!graph_data){
- TF_DeleteBuffer(graph_def);
+ op_desc = TF_NewOperation(tf_model->graph, "MirrorPad", "mirror_pad");
+ input.oper = input_op;
+ input.index = 0;
+ TF_AddInput(op_desc, input);
+ input.oper = op;
+ TF_AddInput(op_desc, input);
+ TF_SetAttrType(op_desc, "T", TF_FLOAT);
+ TF_SetAttrType(op_desc, "Tpaddings", TF_INT32);
+ TF_SetAttrString(op_desc, "mode", "SYMMETRIC", 9);
+ op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+
+ return op;
+}
+
+static TF_Operation* add_const_op(TFModel* tf_model, const float* values, const int64_t* dims, int dims_len, const char* name)
+{
+ int dim;
+ TF_OperationDescription* op_desc;
+ TF_Tensor* tensor;
+ size_t len;
+
+ op_desc = TF_NewOperation(tf_model->graph, "Const", name);
+ TF_SetAttrType(op_desc, "dtype", TF_FLOAT);
+ len = sizeof(float);
+ for (dim = 0; dim < dims_len; ++dim){
+ len *= dims[dim];
+ }
+ tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len, len);
+ memcpy(TF_TensorData(tensor), values, len);
+ TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+
+ return TF_FinishOperation(op_desc, tf_model->status);
+}
+
+static TF_Operation* add_conv_layers(TFModel* tf_model, const float** consts, const int64_t** consts_dims,
+ const int* consts_dims_len, const char** activations,
+ TF_Operation* input_op, int layers_num)
+{
+ int i;
+ TF_OperationDescription* op_desc;
+ TF_Operation* op;
+ TF_Operation* transpose_op;
+ TF_Output input;
+ int64_t strides[] = {1, 1, 1, 1};
+ int32_t* transpose_perm;
+ TF_Tensor* tensor;
+ int64_t transpose_perm_shape[] = {4};
+ #define NAME_BUFF_SIZE 256
+ char name_buffer[NAME_BUFF_SIZE];
+
+ op_desc = TF_NewOperation(tf_model->graph, "Const", "transpose_perm");
+ TF_SetAttrType(op_desc, "dtype", TF_INT32);
+ tensor = TF_AllocateTensor(TF_INT32, transpose_perm_shape, 1, 4 * sizeof(int32_t));
+ transpose_perm = (int32_t*)TF_TensorData(tensor);
+ transpose_perm[0] = 1;
+ transpose_perm[1] = 2;
+ transpose_perm[2] = 3;
+ transpose_perm[3] = 0;
+ TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+ transpose_op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+
+ input.index = 0;
+ for (i = 0; i < layers_num; ++i){
+ snprintf(name_buffer, NAME_BUFF_SIZE, "conv_kernel%d", i);
+ op = add_const_op(tf_model, consts[i << 1], consts_dims[i << 1], consts_dims_len[i << 1], name_buffer);
+ if (TF_GetCode(tf_model->status) != TF_OK || op == NULL){
return NULL;
}
- memcpy(graph_data, srcnn_tf_model, srcnn_tf_size);
- graph_def->data = (void*)graph_data;
- graph_def->length = srcnn_tf_size;
- graph_def->data_deallocator = free_buffer;
- break;
- case DNN_ESPCN:
- graph_data = av_malloc(espcn_tf_size);
- if (!graph_data){
- TF_DeleteBuffer(graph_def);
+
+ snprintf(name_buffer, NAME_BUFF_SIZE, "transpose%d", i);
+ op_desc = TF_NewOperation(tf_model->graph, "Transpose", name_buffer);
+ input.oper = op;
+ TF_AddInput(op_desc, input);
+ input.oper = transpose_op;
+ TF_AddInput(op_desc, input);
+ TF_SetAttrType(op_desc, "T", TF_FLOAT);
+ TF_SetAttrType(op_desc, "Tperm", TF_INT32);
+ op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+
+ snprintf(name_buffer, NAME_BUFF_SIZE, "conv2d%d", i);
+ op_desc = TF_NewOperation(tf_model->graph, "Conv2D", name_buffer);
+ input.oper = input_op;
+ TF_AddInput(op_desc, input);
+ input.oper = op;
+ TF_AddInput(op_desc, input);
+ TF_SetAttrType(op_desc, "T", TF_FLOAT);
+ TF_SetAttrIntList(op_desc, "strides", strides, 4);
+ TF_SetAttrString(op_desc, "padding", "VALID", 5);
+ input_op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+
+ snprintf(name_buffer, NAME_BUFF_SIZE, "conv_biases%d", i);
+ op = add_const_op(tf_model, consts[(i << 1) + 1], consts_dims[(i << 1) + 1], consts_dims_len[(i << 1) + 1], name_buffer);
+ if (TF_GetCode(tf_model->status) != TF_OK || op == NULL){
+ return NULL;
+ }
+
+ snprintf(name_buffer, NAME_BUFF_SIZE, "bias_add%d", i);
+ op_desc = TF_NewOperation(tf_model->graph, "BiasAdd", name_buffer);
+ input.oper = input_op;
+ TF_AddInput(op_desc, input);
+ input.oper = op;
+ TF_AddInput(op_desc, input);
+ TF_SetAttrType(op_desc, "T", TF_FLOAT);
+ input_op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ return NULL;
+ }
+
+ snprintf(name_buffer, NAME_BUFF_SIZE, "activation%d", i);
+ op_desc = TF_NewOperation(tf_model->graph, activations[i], name_buffer);
+ input.oper = input_op;
+ TF_AddInput(op_desc, input);
+ TF_SetAttrType(op_desc, "T", TF_FLOAT);
+ input_op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
return NULL;
}
- memcpy(graph_data, espcn_tf_model, espcn_tf_size);
- graph_def->data = (void*)graph_data;
- graph_def->length = espcn_tf_size;
- graph_def->data_deallocator = free_buffer;
- break;
- default:
- TF_DeleteBuffer(graph_def);
- return NULL;
}
+ return input_op;
+}
+
+DNNModel* ff_dnn_load_default_model_tf(DNNDefaultModel model_type)
+{
+ DNNModel* model = NULL;
+ TFModel* tf_model = NULL;
+ TF_OperationDescription* op_desc;
+ TF_Operation* op;
+ TF_Operation* const_ops_buffer[6];
+ TF_Output input;
+ int64_t input_shape[] = {1, -1, -1, 1};
+
+ input.index = 0;
+
model = av_malloc(sizeof(DNNModel));
if (!model){
- TF_DeleteBuffer(graph_def);
return NULL;
}
tf_model = av_malloc(sizeof(TFModel));
if (!tf_model){
- TF_DeleteBuffer(graph_def);
av_freep(&model);
return NULL;
}
@@ -258,16 +397,68 @@ DNNModel* ff_dnn_load_default_model_tf(DNNDefaultModel model_type)
tf_model->graph = TF_NewGraph();
tf_model->status = TF_NewStatus();
- graph_opts = TF_NewImportGraphDefOptions();
- TF_GraphImportGraphDef(tf_model->graph, graph_def, graph_opts, tf_model->status);
- TF_DeleteImportGraphDefOptions(graph_opts);
- TF_DeleteBuffer(graph_def);
+
+ #define CLEANUP_ON_ERROR(tf_model, model) { \
+ TF_DeleteGraph(tf_model->graph); \
+ TF_DeleteStatus(tf_model->status); \
+ av_freep(&tf_model); \
+ av_freep(&model); \
+ return NULL; \
+ }
+
+ op_desc = TF_NewOperation(tf_model->graph, "Placeholder", "x");
+ TF_SetAttrType(op_desc, "dtype", TF_FLOAT);
+ TF_SetAttrShape(op_desc, "shape", input_shape, 4);
+ op = TF_FinishOperation(op_desc, tf_model->status);
if (TF_GetCode(tf_model->status) != TF_OK){
- TF_DeleteGraph(tf_model->graph);
- TF_DeleteStatus(tf_model->status);
- av_freep(&tf_model);
- av_freep(&model);
- return NULL;
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+
+ switch (model_type){
+ case DNN_SRCNN:
+ op = add_pad_op(tf_model, op, 6);
+ if (!op){
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+ op = add_conv_layers(tf_model, srcnn_consts,
+ srcnn_consts_dims, srcnn_consts_dims_len,
+ srcnn_activations, op, 3);
+ if (!op){
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+ break;
+ case DNN_ESPCN:
+ op = add_pad_op(tf_model, op, 4);
+ if (!op){
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+ op = add_conv_layers(tf_model, espcn_consts,
+ espcn_consts_dims, espcn_consts_dims_len,
+ espcn_activations, op, 3);
+ if (!op){
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+
+ op_desc = TF_NewOperation(tf_model->graph, "DepthToSpace", "depth_to_space");
+ input.oper = op;
+ TF_AddInput(op_desc, input);
+ TF_SetAttrType(op_desc, "T", TF_FLOAT);
+ TF_SetAttrInt(op_desc, "block_size", 2);
+ op = TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+ break;
+ default:
+ CLEANUP_ON_ERROR(tf_model, model);
+ }
+
+ op_desc = TF_NewOperation(tf_model->graph, "Identity", "y");
+ input.oper = op;
+ TF_AddInput(op_desc, input);
+ TF_FinishOperation(op_desc, tf_model->status);
+ if (TF_GetCode(tf_model->status) != TF_OK){
+ CLEANUP_ON_ERROR(tf_model, model);
}
model->model = (void*)tf_model;