1 /*
2 * Copyright (c) 2018 Sergey Lavrushkin
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * DNN tensorflow backend implementation.
24 */
25
35 #include "../internal.h"
41 #include <tensorflow/c/c_api.h>
42
48
53
64
65 /**
66 * Stores execution parameters for single
67 * call to the TensorFlow C API
68 */
75
82
83 #define OFFSET(x) offsetof(TFContext, x)
84 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
89 };
90
92
96
98 {
100 }
101
102 /**
103 * Free the contents of TensorFlow inference request.
104 * It does not free the TFInferRequest instance.
105 *
106 * @param request pointer to TFInferRequest instance.
107 * NULL pointer is allowed.
108 */
110 {
111 if (!request)
112 return;
116 }
121 for (uint32_t
i = 0;
i < nb_output; ++
i) {
125 }
126 }
128 }
129 }
130
131 /**
132 * Create a TensorFlow inference request. All properties
133 * are initially unallocated and set as NULL.
134 *
135 * @return pointer to the allocated TFInferRequest instance.
136 */
138 {
140 if (!infer_request) {
142 }
147 return infer_request;
148 }
149
150 /**
151 * Start synchronous inference for the TensorFlow model.
152 *
153 * @param request pointer to the TFRequestItem for inference
154 * @retval DNN_SUCCESS if execution is successful
155 * @retval DNN_ERROR if execution fails
156 */
158 {
164
165 if (!request) {
168 }
169
175 if (TF_GetCode(request->
status) != TF_OK) {
180 }
182 }
184 }
185
186 /**
187 * Free the TFRequestItem completely.
188 *
189 * @param arg Address of the TFInferRequest instance.
190 */
194 return;
195 }
200 TF_DeleteStatus(request->
status);
203 }
204
206 {
210 if (!lltask) {
213 }
221 }
223 }
224
226 {
227 TF_Buffer *graph_buf;
228 unsigned char *graph_data =
NULL;
230 long size, bytes_read;
231
234 }
235
237
239 if (!graph_data){
242 }
243 bytes_read =
avio_read(model_file_context, graph_data,
size);
245 if (bytes_read !=
size){
248 }
249
250 graph_buf = TF_NewBuffer();
251 graph_buf->data = graph_data;
252 graph_buf->length =
size;
254
255 return graph_buf;
256 }
257
259 {
260 TF_DataType dt;
262 int64_t input_dims[] = {1,
input->height,
input->width,
input->channels};
265 dt = TF_FLOAT;
266 size =
sizeof(float);
267 break;
269 dt = TF_UINT8;
271 break;
272 default:
274 }
275
276 return TF_AllocateTensor(dt, input_dims, 4,
277 input_dims[1] * input_dims[2] * input_dims[3] *
size);
278 }
279
281 {
285 int64_t dims[4];
286
287 TF_Output tf_output;
288 tf_output.oper = TF_GraphOperationByName(tf_model->
graph, input_name);
289 if (!tf_output.oper) {
292 }
293
294 tf_output.index = 0;
295 input->dt = TF_OperationOutputType(tf_output);
297
299 TF_GraphGetTensorShape(tf_model->
graph, tf_output, dims, 4,
status);
300 if (TF_GetCode(
status) != TF_OK){
304 }
306
307 // currently only NHWC is supported
309 input->height = dims[1];
310 input->width = dims[2];
311 input->channels = dims[3];
312
314 }
315
317 const char *output_name, int *output_width, int *output_height)
318 {
326 .output_names = &output_name,
327 .nb_output = 1,
330 };
331
333 goto err;
334 }
335
339 goto err;
340 }
341
343 if (!request) {
346 goto err;
347 }
348
352
353 err:
357 }
358
359 #define SPACE_CHARS " \t\r\n"
361 {
363
365 v = 1;
366 for (;;) {
368 if (*p == '0円')
369 break;
371 if (
c >=
'0' &&
c <=
'9')
373 else if (
c >=
'A' &&
c <=
'F')
375 else
376 break;
378 if (v & 0x100) {
381 }
383 v = 1;
384 }
385 }
387 }
388
390 {
392 TF_Buffer *graph_def;
393 TF_ImportGraphDefOptions *graph_opts;
394 TF_SessionOptions *sess_opts;
395 const TF_Operation *init_op;
396 uint8_t *sess_config =
NULL;
397 int sess_config_length = 0;
398
399 // prepare the sess config data
402 /*
403 tf_model->ctx.options.sess_config is hex to present the serialized proto
404 required by TF_SetConfig below, so we need to first generate the serialized
405 proto in a python script, tools/python/tf_sess_config.py is a script example
406 to generate the configs of sess_config.
407 */
411 }
414
416 if (!sess_config) {
419 }
423 }
424 }
425
427 if (!graph_def){
431 }
432 tf_model->
graph = TF_NewGraph();
433 tf_model->
status = TF_NewStatus();
434 graph_opts = TF_NewImportGraphDefOptions();
435 TF_GraphImportGraphDef(tf_model->
graph, graph_def, graph_opts, tf_model->
status);
436 TF_DeleteImportGraphDefOptions(graph_opts);
437 TF_DeleteBuffer(graph_def);
438 if (TF_GetCode(tf_model->
status) != TF_OK){
439 TF_DeleteGraph(tf_model->
graph);
440 TF_DeleteStatus(tf_model->
status);
444 }
445
446 init_op = TF_GraphOperationByName(tf_model->
graph,
"init");
447 sess_opts = TF_NewSessionOptions();
448
449 if (sess_config) {
450 TF_SetConfig(sess_opts, sess_config, sess_config_length,tf_model->
status);
452 if (TF_GetCode(tf_model->
status) != TF_OK) {
453 TF_DeleteGraph(tf_model->
graph);
454 TF_DeleteStatus(tf_model->
status);
455 TF_DeleteSessionOptions(sess_opts);
459 }
460 }
461
463 TF_DeleteSessionOptions(sess_opts);
464 if (TF_GetCode(tf_model->
status) != TF_OK)
465 {
466 TF_DeleteGraph(tf_model->
graph);
467 TF_DeleteStatus(tf_model->
status);
470 }
471
472 // Run initialization operation with name "init" if it is present in graph
473 if (init_op){
478 if (TF_GetCode(tf_model->
status) != TF_OK)
479 {
481 TF_DeleteGraph(tf_model->
graph);
482 TF_DeleteStatus(tf_model->
status);
485 }
486 }
487
489 }
490
491 #define NAME_BUFFER_SIZE 256
492
495 {
498 TF_OperationDescription *op_desc;
500 int64_t strides[] = {1, 1, 1, 1};
501 TF_Tensor *kernel_tensor =
NULL, *biases_tensor =
NULL;
502 int64_t dims[4];
503 int dims_len;
506
509
511 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
512 TF_SetAttrType(op_desc, "dtype", TF_FLOAT);
517 dims_len = 4;
518 kernel_tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len,
size *
sizeof(
float));
519 memcpy(TF_TensorData(kernel_tensor), params->
kernel,
size *
sizeof(
float));
520 TF_SetAttrTensor(op_desc,
"value", kernel_tensor, tf_model->
status);
521 if (TF_GetCode(tf_model->
status) != TF_OK){
522 goto err;
523 }
524 op = TF_FinishOperation(op_desc, tf_model->
status);
525 if (TF_GetCode(tf_model->
status) != TF_OK){
526 goto err;
527 }
528
530 op_desc = TF_NewOperation(tf_model->
graph,
"Transpose", name_buffer);
532 TF_AddInput(op_desc,
input);
533 input.oper = transpose_op;
534 TF_AddInput(op_desc,
input);
535 TF_SetAttrType(op_desc, "T", TF_FLOAT);
536 TF_SetAttrType(op_desc, "Tperm", TF_INT32);
537 op = TF_FinishOperation(op_desc, tf_model->
status);
538 if (TF_GetCode(tf_model->
status) != TF_OK){
539 goto err;
540 }
541
543 op_desc = TF_NewOperation(tf_model->
graph,
"Conv2D", name_buffer);
544 input.oper = *cur_op;
545 TF_AddInput(op_desc,
input);
547 TF_AddInput(op_desc,
input);
548 TF_SetAttrType(op_desc, "T", TF_FLOAT);
549 TF_SetAttrIntList(op_desc, "strides", strides, 4);
550 TF_SetAttrString(op_desc, "padding", "VALID", 5);
551 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
552 if (TF_GetCode(tf_model->
status) != TF_OK){
553 goto err;
554 }
555
557 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
558 TF_SetAttrType(op_desc, "dtype", TF_FLOAT);
560 dims_len = 1;
561 biases_tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len, params->
output_num *
sizeof(
float));
562 memcpy(TF_TensorData(biases_tensor), params->
biases, params->
output_num *
sizeof(
float));
563 TF_SetAttrTensor(op_desc,
"value", biases_tensor, tf_model->
status);
564 if (TF_GetCode(tf_model->
status) != TF_OK){
565 goto err;
566 }
567 op = TF_FinishOperation(op_desc, tf_model->
status);
568 if (TF_GetCode(tf_model->
status) != TF_OK){
569 goto err;
570 }
571
573 op_desc = TF_NewOperation(tf_model->
graph,
"BiasAdd", name_buffer);
574 input.oper = *cur_op;
575 TF_AddInput(op_desc,
input);
577 TF_AddInput(op_desc,
input);
578 TF_SetAttrType(op_desc, "T", TF_FLOAT);
579 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
580 if (TF_GetCode(tf_model->
status) != TF_OK){
581 goto err;
582 }
583
587 op_desc = TF_NewOperation(tf_model->
graph,
"Relu", name_buffer);
588 break;
590 op_desc = TF_NewOperation(tf_model->
graph,
"Tanh", name_buffer);
591 break;
593 op_desc = TF_NewOperation(tf_model->
graph,
"Sigmoid", name_buffer);
594 break;
595 default:
598 }
599 input.oper = *cur_op;
600 TF_AddInput(op_desc,
input);
601 TF_SetAttrType(op_desc, "T", TF_FLOAT);
602 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
603 if (TF_GetCode(tf_model->
status) != TF_OK){
604 goto err;
605 }
606
608 err:
609 TF_DeleteTensor(kernel_tensor);
610 TF_DeleteTensor(biases_tensor);
613 }
614
617 {
619 TF_OperationDescription *op_desc;
622
624 op_desc = TF_NewOperation(tf_model->
graph,
"DepthToSpace", name_buffer);
625 input.oper = *cur_op;
627 TF_AddInput(op_desc,
input);
628 TF_SetAttrType(op_desc, "T", TF_FLOAT);
629 TF_SetAttrInt(op_desc,
"block_size", params->
block_size);
630 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
631 if (TF_GetCode(tf_model->
status) != TF_OK){
634 }
635
637 }
638
641 {
644 TF_Tensor *tensor;
645 TF_OperationDescription *op_desc;
648 int64_t pads_shape[] = {4, 2};
649
652
653 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
654 TF_SetAttrType(op_desc, "dtype", TF_INT32);
655 tensor = TF_AllocateTensor(TF_INT32, pads_shape, 2, 4 * 2 *
sizeof(
int32_t));
656 pads = (
int32_t *)TF_TensorData(tensor);
665 TF_SetAttrTensor(op_desc,
"value", tensor, tf_model->
status);
666 if (TF_GetCode(tf_model->
status) != TF_OK){
667 TF_DeleteTensor(tensor);
670 }
671 op = TF_FinishOperation(op_desc, tf_model->
status);
672 if (TF_GetCode(tf_model->
status) != TF_OK){
673 TF_DeleteTensor(tensor);
676 }
677
678 op_desc = TF_NewOperation(tf_model->
graph,
"MirrorPad",
"mirror_pad");
679 input.oper = *cur_op;
681 TF_AddInput(op_desc,
input);
683 TF_AddInput(op_desc,
input);
684 TF_SetAttrType(op_desc, "T", TF_FLOAT);
685 TF_SetAttrType(op_desc, "Tpaddings", TF_INT32);
686 TF_SetAttrString(op_desc, "mode", "SYMMETRIC", 9);
687 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
688 if (TF_GetCode(tf_model->
status) != TF_OK){
689 TF_DeleteTensor(tensor);
692 }
693
695 }
696
699 {
702 TF_Tensor *tensor;
703 TF_OperationDescription *op_desc;
705 float *y;
706
709
710 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
711 TF_SetAttrType(op_desc, "dtype", TF_FLOAT);
712 tensor = TF_AllocateTensor(TF_FLOAT,
NULL, 0, TF_DataTypeSize(TF_FLOAT));
713 y = (float *)TF_TensorData(tensor);
715 TF_SetAttrTensor(op_desc,
"value", tensor, tf_model->
status);
716 if (TF_GetCode(tf_model->
status) != TF_OK){
717 TF_DeleteTensor(tensor);
720 }
721 op = TF_FinishOperation(op_desc, tf_model->
status);
722 if (TF_GetCode(tf_model->
status) != TF_OK){
723 TF_DeleteTensor(tensor);
726 }
727
729 op_desc = TF_NewOperation(tf_model->
graph,
"Maximum", name_buffer);
730 input.oper = *cur_op;
732 TF_AddInput(op_desc,
input);
734 TF_AddInput(op_desc,
input);
735 TF_SetAttrType(op_desc, "T", TF_FLOAT);
736 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
737 if (TF_GetCode(tf_model->
status) != TF_OK){
738 TF_DeleteTensor(tensor);
741 }
742
744 }
745
747 {
750 TF_OperationDescription *op_desc;
752 TF_Operation *transpose_op;
753 TF_Tensor *tensor =
NULL;
756 int64_t transpose_perm_shape[] = {4};
757 int64_t input_shape[] = {1, -1, -1, -1};
761
763 if (!model){
766 }
767
768 native_model = model->
model;
769 tf_model->
graph = TF_NewGraph();
770 tf_model->
status = TF_NewStatus();
771
772 #define CLEANUP_ON_ERROR(tf_model) \
773 { \
774 TF_DeleteTensor(tensor); \
775 TF_DeleteGraph(tf_model->graph); \
776 TF_DeleteStatus(tf_model->status); \
777 av_log(ctx, AV_LOG_ERROR, "Failed to set value or add operator to layer\n"); \
778 return DNN_ERROR; \
779 }
780
781 op_desc = TF_NewOperation(tf_model->
graph,
"Placeholder",
"x");
782 TF_SetAttrType(op_desc, "dtype", TF_FLOAT);
783 TF_SetAttrShape(op_desc, "shape", input_shape, 4);
784 op = TF_FinishOperation(op_desc, tf_model->
status);
785 if (TF_GetCode(tf_model->
status) != TF_OK){
787 }
788
789 op_desc = TF_NewOperation(tf_model->
graph,
"Const",
"transpose_perm");
790 TF_SetAttrType(op_desc, "dtype", TF_INT32);
791 tensor = TF_AllocateTensor(TF_INT32, transpose_perm_shape, 1, 4 *
sizeof(
int32_t));
797 TF_SetAttrTensor(op_desc,
"value", tensor, tf_model->
status);
798 if (TF_GetCode(tf_model->
status) != TF_OK){
800 }
801 transpose_op = TF_FinishOperation(op_desc, tf_model->
status);
802 if (TF_GetCode(tf_model->
status) != TF_OK){
804 }
805
806 for (layer = 0; layer < native_model->
layers_num; ++layer){
810 break;
814 break;
818 break;
822 break;
826 break;
827 default:
829 }
830
833 }
834 }
835
836 op_desc = TF_NewOperation(tf_model->
graph,
"Identity",
"y");
839 TF_AddInput(op_desc,
input);
840 TF_FinishOperation(op_desc, tf_model->
status);
841 if (TF_GetCode(tf_model->
status) != TF_OK){
843 }
844
846
848 }
849
851 {
855
857 if (!model){
859 }
860
862 if (!tf_model){
865 }
866 tf_model->
model = model;
868 ctx->class = &dnn_tensorflow_class;
869
870 //parse options
874 goto err;
875 }
876
879 goto err;
880 }
881 }
882
883 if (
ctx->options.nireq <= 0) {
885 }
886
887 #if !HAVE_PTHREAD_CANCEL
888 if (
ctx->options.async) {
889 ctx->options.async = 0;
891 }
892 #endif
893
896 goto err;
897 }
898
899 for (
int i = 0;
i <
ctx->options.nireq;
i++) {
901 if (!item) {
902 goto err;
903 }
909 goto err;
910 }
911 item->
status = TF_NewStatus();
915
918 goto err;
919 }
920 }
921
924 goto err;
925 }
926
929 goto err;
930 }
931
932 model->
model = tf_model;
938
939 return model;
940 err:
943 }
944
951
956
958 goto err;
959 }
960
964
968 goto err;
969 }
970
972 if (!infer_request->
tf_input->oper){
974 goto err;
975 }
977
981 goto err;
982 }
984
990 } else {
992 }
993 }
994 break;
997 break;
998 default:
1000 break;
1001 }
1002
1006 goto err;
1007 }
1008
1012 goto err;
1013 }
1014
1020 goto err;
1021 }
1023 }
1024
1026 err:
1029 }
1030
1039
1043 goto err;
1044 }
1045
1052 }
1055 //it only support 1 output if it's frame in & frame out
1059 } else {
1061 }
1062 } else {
1065 }
1066 break;
1070 return;
1071 }
1073 break;
1074 default:
1076 goto err;
1077 }
1079 err:
1082
1086 }
1087 }
1088
1090 {
1095
1099 }
1100
1102 task = lltask->
task;
1103 tf_model = task->
model;
1105
1107 goto err;
1108 }
1109
1112 goto err;
1113 }
1115 } else {
1117 goto err;
1118 }
1121 }
1122 err:
1126 }
1128 }
1129
1131 {
1136
1139 }
1140
1142 if (!task) {
1145 }
1146
1150 }
1151
1156 }
1157
1161 }
1162
1164 if (!request) {
1167 }
1169 }
1170
1172 {
1175 }
1176
1178 {
1183
1185 // no pending task need to flush
1187 }
1188
1190 if (!request) {
1193 }
1194
1200 }
1202 }
1203
1205 }
1206
1208 {
1210
1211 if (*model){
1212 tf_model = (*model)->
model;
1216 }
1218
1222 }
1224
1230 }
1232
1233 if (tf_model->
graph){
1234 TF_DeleteGraph(tf_model->
graph);
1235 }
1239 }
1241 TF_DeleteStatus(tf_model->
status);
1242 }
1245 }
1246 }