summaryrefslogtreecommitdiff
path: root/libavfilter
diff options
context:
space:
mode:
Diffstat (limited to 'libavfilter')
-rw-r--r--libavfilter/Makefile3
-rw-r--r--libavfilter/tests/.gitignore8
-rw-r--r--libavfilter/tests/dnn-layer-avgpool.c197
-rw-r--r--libavfilter/tests/dnn-layer-conv2d.c248
-rw-r--r--libavfilter/tests/dnn-layer-dense.c131
-rw-r--r--libavfilter/tests/dnn-layer-depth2space.c102
-rw-r--r--libavfilter/tests/dnn-layer-mathbinary.c214
-rw-r--r--libavfilter/tests/dnn-layer-mathunary.c148
-rw-r--r--libavfilter/tests/dnn-layer-maximum.c71
-rw-r--r--libavfilter/tests/dnn-layer-pad.c239
10 files changed, 1361 insertions, 0 deletions
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 9a061ba3c8..cb328c2bf8 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -590,6 +590,9 @@ SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_filter.h
TOOLS = graph2dot
TESTPROGS = drawutils filtfmts formats integral
+TESTPROGS-$(CONFIG_DNN) += dnn-layer-avgpool dnn-layer-conv2d dnn-layer-dense \
+ dnn-layer-depth2space dnn-layer-mathbinary \
+ dnn-layer-mathunary dnn-layer-maximum dnn-layer-pad \
TOOLS-$(CONFIG_LIBZMQ) += zmqsend
diff --git a/libavfilter/tests/.gitignore b/libavfilter/tests/.gitignore
index 65ef86f2e5..db482cd49b 100644
--- a/libavfilter/tests/.gitignore
+++ b/libavfilter/tests/.gitignore
@@ -1,3 +1,11 @@
+/dnn-layer-conv2d
+/dnn-layer-depth2space
+/dnn-layer-maximum
+/dnn-layer-pad
+/dnn-layer-mathbinary
+/dnn-layer-mathunary
+/dnn-layer-avgpool
+/dnn-layer-dense
/drawutils
/filtfmts
/formats
diff --git a/libavfilter/tests/dnn-layer-avgpool.c b/libavfilter/tests/dnn-layer-avgpool.c
new file mode 100644
index 0000000000..4a925ea22a
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-avgpool.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_avgpool.h"
+
+#define EPSON 0.00001
+
+static int test_with_same(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ import tensorflow as tf
+ import numpy as np
+
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.layers.average_pooling2d(x, pool_size=[2,2], strides=[1,1], padding='VALID')
+ data = np.random.rand(1, 5, 6, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+
+ output = sess.run(y, feed_dict={x: data})
+
+ print("input:")
+ print(data.shape)
+ print(list(data.flatten()))
+
+ print("output:")
+ print(output.shape)
+ print(list(output.flatten()))
+ */
+
+ AvgPoolParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*5*6*3] = {
+ 0.7461309859908424, 0.7567538372797069, 0.07662743569678687, 0.8882112610336333, 0.9720443314026668, 0.3337200343220823, 0.4421032129780248,
+ 0.14940809044964876, 0.6773177061961277, 0.9778844630669781, 0.6522650522626998, 0.0317651530878591, 0.31259897552911364, 0.6235936821891896,
+ 0.40016094349542775, 0.4599222930032276, 0.7893807222960093, 0.8475986363538283, 0.5058802717647394, 0.7827005363222633, 0.3032188123727916,
+ 0.8983728631302361, 0.20622408444965523, 0.22966072303869878, 0.09535751273161308, 0.8760709100995375, 0.9982324154558745, 0.7904595468621013,
+ 0.13883671508879347, 0.9332751439533138, 0.0010861680752152214, 0.3607210449251048, 0.6600652759586171, 0.7629572058138805, 0.29441975810476106,
+ 0.2683471432889405, 0.22574580829831536, 0.8893251976212904, 0.3907737043801005, 0.6421829842863968, 0.6670373870457297, 0.9383850793160277,
+ 0.4120458907436003, 0.3589847212711481, 0.48047736550128983, 0.6428192648418949, 0.0313661686292348, 0.429357100401472, 0.5123413386514056,
+ 0.8492446404097114, 0.9045286128486804, 0.8123708563814285, 0.3943245008451698, 0.9576713003177785, 0.5985610965938726, 0.9350833279543561,
+ 0.8010079897491659, 0.45882114217642866, 0.35275037908941487, 0.4555844661432271, 0.12352455940255314, 0.37801756635035544, 0.2824056214573083,
+ 0.6229462823245029, 0.7235305681391472, 0.5408259266122064, 0.12142224381781208, 0.34431198802873686, 0.7112823816321276, 0.6307144385115417,
+ 0.8136734589018082, 0.842095618140585, 0.8602767724004784, 0.6649236853766185, 0.5184782829419623, 0.9119607270982825, 0.3084111974561645,
+ 0.39460705638161364, 0.17710447526170836, 0.1715485945814199, 0.17277563576521882, 0.40188232428735704, 0.22847985411491878, 0.4135361701550696,
+ 0.24621846601980057, 0.6576588108454774, 0.6063336087333997, 0.6452342242996931, 0.7071689702737508, 0.1973416063225648
+ };
+ float expected_output[] = {
+ 0.75964886, 0.6794307, 0.23580676, 0.5810112, 0.5509369, 0.55973274, 0.5764512, 0.45414522, 0.6601476, 0.52050734, 0.44385415,
+ 0.50631666, 0.38414115, 0.5170288, 0.544043, 0.61143976, 0.5419003, 0.5579729, 0.5680455, 0.6363218, 0.4655096, 0.51198983,
+ 0.5270792, 0.66168886, 0.48517057, 0.3513146, 0.7103355, 0.48667657, 0.34504217, 0.7318065, 0.5221889, 0.4746775, 0.69765306,
+ 0.78766406, 0.34437215, 0.6130092, 0.48132777, 0.7110491, 0.6464378, 0.40914366, 0.4391975, 0.5392131, 0.45033398, 0.37297475,
+ 0.43326652, 0.4748823, 0.48711336, 0.64649844, 0.51921225, 0.60038865, 0.8538945, 0.7215426, 0.60399896, 0.89988345, 0.707405,
+ 0.5652921, 0.54241943, 0.41785273, 0.30268195, 0.3263432, 0.3313644, 0.37539417, 0.35238582, 0.34811732, 0.48849532, 0.56799453,
+ 0.41089734, 0.63070333, 0.5892633, 0.6379743, 0.7604212, 0.5197186, 0.88611877, 0.48666745, 0.45654267, 0.5445326, 0.2399799,
+ 0.28369135, 0.28949338, 0.20001422, 0.2931559, 0.3240504, 0.44306934, 0.5099349, 0.44572634, 0.68241394, 0.40183762, 0.6452342,
+ 0.707169, 0.1973416
+ };
+ float *output;
+
+ params.strides = 1;
+ params.kernel_size = 2;
+ params.padding_method = SAME;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 5;
+ operands[0].dims[2] = 6;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_avg_pool(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); ++i) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+static int test_with_valid(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ import tensorflow as tf
+ import numpy as np
+
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.layers.average_pooling2d(x, pool_size=[2,2], strides=[1,1], padding='VALID')
+ data = np.random.rand(1, 5, 6, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+
+ output = sess.run(y, feed_dict={x: data})
+
+ print("input:")
+ print(data.shape)
+ print(list(data.flatten()))
+
+ print("output:")
+ print(output.shape)
+ print(list(output.flatten()))
+ */
+
+ AvgPoolParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*5*6*3] = {
+ 0.5046741692941682, 0.9273653202485155, 0.8193878359859937, 0.1904059431360905, 0.8664919633253656, 0.7484625128286059, 0.984534184632278,
+ 0.31900804890072254, 0.3259426099940872, 0.05388974903570376, 0.7356610151331133, 0.46710858713311965, 0.718553768817036, 0.062478421853278676,
+ 0.7813224786584609, 0.4826837517658389, 0.9748095400220147, 0.8078547703898341, 0.11976750668368585, 0.8713586777195065, 0.41447321551284355,
+ 0.9818788239089807, 0.4335715767584073, 0.4059793452147419, 0.3677205907204525, 0.47919995923571, 0.8341395256258882, 0.7059726374074609,
+ 0.5478504551919791, 0.8622900484790175, 0.8343709722511167, 0.05089827275068537, 0.6465283980840416, 0.544539116066677, 0.39812057257884337,
+ 0.9578115576866337, 0.25012888117580145, 0.579333516024662, 0.5556732133051457, 0.6119862111181243, 0.0018736758772316398, 0.9795490254040474,
+ 0.4488085008883018, 0.28947489777011737, 0.4834108668633247, 0.9280490084385024, 0.9895821458049648, 0.31777618554697606, 0.42679693258977847,
+ 0.74447844466923, 0.9752225305081498, 0.17564130841849335, 0.22382692067314292, 0.009602884447469373, 0.5144884415025782, 0.031622570708844555,
+ 0.8277532752502512, 0.4111593210409763, 0.5272084646575664, 0.28856508082905297, 0.11317726946036655, 0.7203328275540273, 0.8310055019972384,
+ 0.8535951508685228, 0.40230347305233227, 0.2819703265132867, 0.6243143957791139, 0.7512463693822311, 0.7523056340495644, 0.8838077258040928,
+ 0.5472240664033092, 0.2550538284454935, 0.5560317774456567, 0.8966847087518931, 0.6728358284165321, 0.30361297147530875, 0.464343925441822,
+ 0.34507695659461224, 0.6333175615390685, 0.26661369038523497, 0.9926748632253231, 0.9994267301382666, 0.8684917986974414, 0.3598754806113009,
+ 0.49550268625464666, 0.03652458679973214, 0.13469081713137177, 0.4579424049273835, 0.48641107969110353, 0.9670250266945365
+ };
+ float expected_output[1*4*5*3] = {
+ 0.44918162, 0.7746969, 0.5970757, 0.63113487, 0.5245679, 0.578631, 0.52802926, 0.52042985, 0.6223702, 0.57819676, 0.34922206,
+ 0.6893124, 0.64503694, 0.37157673, 0.7983793, 0.49094033, 0.47153437, 0.5889187, 0.6025985, 0.30103004, 0.6757697, 0.6126377,
+ 0.5765268, 0.62440413, 0.7237974, 0.5832023, 0.7004543, 0.49533707, 0.35433105, 0.6472913, 0.44694072, 0.28500956, 0.6628852,
+ 0.39628282, 0.38472247, 0.6456326, 0.58590746, 0.60042334, 0.47854072, 0.7081889, 0.7219026, 0.5818187, 0.5276401, 0.56669396,
+ 0.49804622, 0.4463231, 0.4799649, 0.5335578, 0.36531678, 0.4946247, 0.6143306, 0.6498792, 0.5644355, 0.6163815, 0.7432098,
+ 0.5146416, 0.38221055, 0.6153918, 0.45535153, 0.5272688
+ };
+ float *output;
+
+ params.strides = 1;
+ params.kernel_size = 2;
+ params.padding_method = VALID;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 5;
+ operands[0].dims[2] = 6;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_avg_pool(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); ++i) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ if (test_with_same())
+ return 1;
+ if (test_with_valid())
+ return 1;
+
+ return 0;
+}
diff --git a/libavfilter/tests/dnn-layer-conv2d.c b/libavfilter/tests/dnn-layer-conv2d.c
new file mode 100644
index 0000000000..5ee60eeaf0
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-conv2d.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2019 Guo Yejun
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_conv2d.h"
+
+#define EPSON 0.00001
+
+static int test_with_same_dilate(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.layers.conv2d(x, 2, 3, activation=tf.nn.tanh, padding='same', dilation_rate=(2, 2), bias_initializer=tf.keras.initializers.he_normal())
+ data = np.random.rand(1, 5, 6, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+
+ weights = dict([(var.name, sess.run(var)) for var in tf.trainable_variables()])
+ kernel = weights['conv2d/kernel:0']
+ kernel = np.transpose(kernel, [3, 0, 1, 2])
+ print("kernel:")
+ print(kernel.shape)
+ print(list(kernel.flatten()))
+
+ bias = weights['conv2d/bias:0']
+ print("bias:")
+ print(bias.shape)
+ print(list(bias.flatten()))
+
+ output = sess.run(y, feed_dict={x: data})
+
+ print("input:")
+ print(data.shape)
+ print(list(data.flatten()))
+
+ print("output:")
+ print(output.shape)
+ print(list(output.flatten()))
+ */
+
+ ConvolutionalParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*5*6*3] = {
+ 0.7012556460308194, 0.4233847954643357, 0.19515900664313612, 0.16343083004926495, 0.5758261611052848, 0.9510767434014871, 0.11014085055947687,
+ 0.906327053637727, 0.8136794715542507, 0.45371764543639526, 0.5768443343523952, 0.19543668786046986, 0.15648326047898609, 0.2099500241141279,
+ 0.17658777090552413, 0.059335724777169196, 0.1729991838469117, 0.8150514704819208, 0.4435535466703049, 0.3752188477566878, 0.749936650421431,
+ 0.6823494635284907, 0.10776389679424747, 0.34247481674596836, 0.5147867256244629, 0.9063709728129032, 0.12423605800856818, 0.6064872945412728,
+ 0.5891681538551459, 0.9865836236466314, 0.9002163879294677, 0.003968273184274618, 0.8628374809643967, 0.1327176268279583, 0.8449799925703798,
+ 0.1937671869354366, 0.41524410152707425, 0.02038786604756837, 0.49792466069597496, 0.8881874553848784, 0.9683921035597336, 0.4122972568010813,
+ 0.843553550993252, 0.9588482762501964, 0.5190350762645546, 0.4283584264145317, 0.09781496073714646, 0.9501058833776156, 0.8665541760152776,
+ 0.31669272550095806, 0.07133074675453632, 0.606438007334886, 0.7007157020538224, 0.4827996264130444, 0.5167615606392761, 0.6385043039312651,
+ 0.23069664707810555, 0.058233497329354456, 0.06323892961591071, 0.24816458893245974, 0.8646369065257812, 0.24742185893094837, 0.09991225948167437,
+ 0.625700606979606, 0.7678541502111257, 0.6215834594679912, 0.5623003956582483, 0.07389123942681242, 0.7659100715711249, 0.486061471642225,
+ 0.9947455699829012, 0.9094911797643259, 0.7644355876253265, 0.05384315321492239, 0.13565394382783613, 0.9810628204953316, 0.007386389078887889,
+ 0.226182754156241, 0.2609021390764772, 0.24182802076928933, 0.13264782451941648, 0.2035816485767682, 0.005504188177612557, 0.7014619934040155,
+ 0.956215988391991, 0.5670398541013633, 0.9809764721750784, 0.6886338100487461, 0.5758152317218274, 0.7137823176776179
+ };
+ float expected_output[1*5*6*2] = {
+ -0.9480655, -0.7169147, -0.9404794, -0.5567385, -0.8991124, -0.8306558, -0.94487447, -0.8932543, -0.88238764, -0.7301602,
+ -0.8974813, -0.7026703, -0.8858988, -0.53203243, -0.92881465, -0.5648504, -0.8871471, -0.7000097, -0.91754407, -0.79684794,
+ -0.760465, -0.117928326, -0.88302773, -0.8975289, -0.70615053, 0.19231977, -0.8318776, -0.386184, -0.80698484, -0.8556624,
+ -0.7336671, -0.6168619, -0.7658234, -0.63449603, -0.73314047, -0.87502456, -0.58158904, -0.4184259, -0.52618927, -0.13613208,
+ -0.5093187, -0.21027721, -0.39455596, -0.44507834, -0.22269244, -0.73400885, -0.77655095, -0.74408925, -0.57313335, -0.15333457,
+ -0.74620694, -0.34858236, -0.42586932, -0.5240488, 0.1634339, -0.2447881, -0.57927346, -0.62732303, -0.82287043, -0.8474058
+ };
+ float *output;
+ float kernel[2*3*3*3] = {
+ 0.26025516, 0.16536498, -0.24351254, 0.33892477, -0.34005195, 0.35202783, 0.34056443, 0.01422739, 0.13799345, 0.29489166,
+ 0.2781723, 0.178585, 0.22122234, 0.044115514, 0.13134438, 0.31705368, 0.22527462, -0.021323413, 0.115134746, -0.18216397,
+ -0.21197563, -0.027848959, -0.01704529, -0.12401503, -0.23415318, -0.12661739, -0.35338148, 0.20049328, -0.076153606,
+ -0.23642601, -0.3125769, -0.025851756, -0.30006272, 0.050762743, 0.32003498, 0.3052225, -0.0017385483, 0.25337684, -0.25664508,
+ 0.27846587, -0.3112659, 0.2066065, 0.31499845, 0.113178134, 0.09449363, -0.11828774, -0.12671001, -0.36259216, 0.2710235,
+ -0.19676702, 0.023612618, -0.2596915, -0.34949252, -0.108270735
+ };
+ float bias[2] = { -1.6574852, -0.72915393 };
+
+ NativeContext ctx;
+ ctx.class = NULL;
+ ctx.options.conv2d_threads = 1;
+
+ params.activation = TANH;
+ params.has_bias = 1;
+ params.biases = bias;
+ params.dilation = 2;
+ params.input_num = 3;
+ params.kernel = kernel;
+ params.kernel_size = 3;
+ params.output_num = 2;
+ params.padding_method = SAME;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 5;
+ operands[0].dims[2] = 6;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_conv2d(operands, input_indexes, 1, &params, &ctx);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+static int test_with_valid(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.layers.conv2d(x, 2, 3, activation=tf.nn.tanh, padding='valid', bias_initializer=tf.keras.initializers.he_normal())
+ data = np.random.rand(1, 5, 6, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+
+ weights = dict([(var.name, sess.run(var)) for var in tf.trainable_variables()])
+ kernel = weights['conv2d/kernel:0']
+ kernel = np.transpose(kernel, [3, 0, 1, 2])
+ print("kernel:")
+ print(kernel.shape)
+ print(list(kernel.flatten()))
+
+ bias = weights['conv2d/bias:0']
+ print("bias:")
+ print(bias.shape)
+ print(list(bias.flatten()))
+
+ output = sess.run(y, feed_dict={x: data})
+
+ print("input:")
+ print(data.shape)
+ print(list(data.flatten()))
+
+ print("output:")
+ print(output.shape)
+ print(list(output.flatten()))
+ */
+
+ ConvolutionalParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*5*6*3] = {
+ 0.26126657468269665, 0.42762216215337556, 0.7466274030131497, 0.802550266787863, 0.3709323443076644, 0.5919817068197668, 0.49274512279324967,
+ 0.7170132295090351, 0.0911793215410649, 0.5134213878288361, 0.670132600785118, 0.49417034512633484, 0.03887389460089885, 0.436785102836845,
+ 0.1490231658611978, 0.6413606121498127, 0.8595987991375995, 0.9132593077586231, 0.7075959004873255, 0.17754995944845464, 0.5212507214937141,
+ 0.35379732738215475, 0.25205107358505296, 0.3928792840544273, 0.09485294189485782, 0.8685115437448666, 0.6489046799288605, 0.509253797582924,
+ 0.8993255536791972, 0.18740056466602373, 0.34237617336313986, 0.3871438962989183, 0.1488532571774911, 0.5187002331293636, 0.8137098818752955,
+ 0.521761863717401, 0.4622312310118274, 0.29038411334638825, 0.16194915718170566, 0.5175999923925211, 0.8852230040101133, 0.0218263385047206,
+ 0.08482355352852367, 0.3463638568376264, 0.28627127120619733, 0.9553293378948409, 0.4803391055970835, 0.841635695030805, 0.3556828280031952,
+ 0.06778527221541808, 0.28193560357091596, 0.8399957619031576, 0.03305536359456385, 0.6625039162109645, 0.9300552020023897, 0.8551529138204146,
+ 0.6133216915522418, 0.222427800857393, 0.1315422686800336, 0.6189144989185527, 0.5346184916866876, 0.8348888624532548, 0.6544834567840291,
+ 0.2844062293389934, 0.28780026600883324, 0.5372272015684924, 0.6250226011503823, 0.28119106062279453, 0.49655812908420094, 0.6451488959145951,
+ 0.7362580606834843, 0.44815578616664087, 0.6454760235835586, 0.6794062414265861, 0.045378883014935756, 0.9008388543865096, 0.7949752851269782,
+ 0.4179928876222264, 0.28733419007048644, 0.996902319501908, 0.5690851338677467, 0.9511814013279738, 0.025323788678181636, 0.5594359732604794,
+ 0.1213732595086251, 0.7172624313368294, 0.6759328959074691, 0.07252138454885071, 0.17557735158403442, 0.5988895455048769
+ };
+ float expected_output[1*3*4*2] = {
+ -0.556947, -0.42143887, -0.092070885, 0.27404794, -0.41886684, 0.0862887, -0.25001016, -0.342721, 0.020730592, 0.04016919, -0.69839877,
+ -0.06136704, 0.14186388, -0.11655602, -0.23489095, -0.3845829, -0.19017771, 0.1595885, -0.18308741, -0.3071209, -0.5848686, -0.22509028,
+ -0.6023201, -0.14448485
+ };
+ float *output;
+ float kernel[2*3*3*3] = {
+ -0.25291282, 0.22402048, 0.028642118, -0.14615723, -0.27362752, -0.34801802, -0.2759148, 0.19594926, -0.25029412, 0.34606284, 0.10376671,
+ -0.1015394, 0.23616093, 0.2134214, 0.35285157, 0.05893758, 0.0024731457, -0.17143056, 0.35758412, 0.2186206, -0.28384736, -0.21206513,
+ -0.20871592, 0.27070445, 0.25878823, 0.11136332, -0.33737376, 0.08353335, -0.34290665, 0.041805506, -0.09738535, 0.3284936, -0.16838405,
+ -0.032494456, -0.29193437, 0.033259362, -0.09272635, -0.2802651, -0.28648436, 0.3542878, 0.2432127, -0.24551713, 0.27813476, 0.21024024,
+ -0.013690501, -0.1350077, -0.07826337, -0.34563828, 0.3220685, -0.07571727, 0.19420576, 0.20783454, 0.18738335, 0.16672492
+ };
+ float bias[2] = { -0.4773722, -0.19620377 };
+
+ NativeContext ctx;
+ ctx.class = NULL;
+ ctx.options.conv2d_threads = 1;
+
+ params.activation = TANH;
+ params.has_bias = 1;
+ params.biases = bias;
+ params.dilation = 1;
+ params.input_num = 3;
+ params.kernel = kernel;
+ params.kernel_size = 3;
+ params.output_num = 2;
+ params.padding_method = VALID;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 5;
+ operands[0].dims[2] = 6;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_conv2d(operands, input_indexes, 1, &params, &ctx);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ if (test_with_valid())
+ return 1;
+ if (test_with_same_dilate())
+ return 1;
+
+ return 0;
+}
diff --git a/libavfilter/tests/dnn-layer-dense.c b/libavfilter/tests/dnn-layer-dense.c
new file mode 100644
index 0000000000..696f7505e5
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-dense.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_dense.h"
+
+#define EPSON 0.00001
+
+static int test(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.layers.dense(input_x, 3, activation=tf.nn.sigmoid, bias_initializer=tf.keras.initializers.he_normal())
+ data = np.random.rand(1, 5, 6, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+
+ weights = dict([(var.name, sess.run(var)) for var in tf.trainable_variables()])
+ kernel = weights['dense/kernel:0']
+ kernel = np.transpose(kernel, [1, 0])
+ print("kernel:")
+ print(kernel.shape)
+ print(list(kernel.flatten()))
+
+ bias = weights['dense/bias:0']
+ print("bias:")
+ print(bias.shape)
+ print(list(bias.flatten()))
+
+ output = sess.run(y, feed_dict={x: data})
+
+ print("input:")
+ print(data.shape)
+ print(list(data.flatten()))
+
+ print("output:")
+ print(output.shape)
+ print(list(output.flatten()))
+ */
+
+ DenseParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*5*6*3] = {
+ 0.5552418686576308, 0.20653189262022464, 0.31115120939398877, 0.5897014433221428, 0.37340078861060655, 0.6470921693941893, 0.8039950367872679, 0.8762700891949274,
+ 0.6556655583829558, 0.5911096107039339, 0.18640250865290997, 0.2803248779238966, 0.31586613136402053, 0.9447300740056483, 0.9443980824873418, 0.8158851991115941,
+ 0.5631010340387631, 0.9407402251929046, 0.6485434876551682, 0.5631376966470001, 0.17581924875609634, 0.7033802439103178, 0.04802402495561675, 0.9183681450194972,
+ 0.46059317944364, 0.07964160481596883, 0.871787076270302, 0.973743142324361, 0.15923146943258415, 0.8212946080584571, 0.5415954459227064, 0.9552813822803975,
+ 0.4908552668172057, 0.33723691635292274, 0.46588057864910026, 0.8994239961321776, 0.09845220457674186, 0.1713400292123486, 0.39570294912818826, 0.08018956486392803,
+ 0.5290478278169032, 0.7141906125920976, 0.0320878067840098, 0.6412406575332606, 0.0075712007102423096, 0.7150828462386156, 0.1311989216968138, 0.4706847944253756,
+ 0.5447610794883336, 0.3430923933318001, 0.536082357943209, 0.4371629342483694, 0.40227962985019927, 0.3553806249465469, 0.031806622424259245, 0.7053916426174,
+ 0.3261570237309813, 0.419500213292063, 0.3155691223480851, 0.05664028113178088, 0.3636491555914486, 0.8502419746667123, 0.9836596530684955, 0.1628681802975801,
+ 0.09410832912479894, 0.28407218939480294, 0.7983417928813697, 0.24132158596506748, 0.8154729498062224, 0.29173768373895637, 0.13407102008052096, 0.18705786678800385,
+ 0.7167943621295573, 0.09222004247174376, 0.2319220738766018, 0.17708964382285064, 0.1391440370249517, 0.3254088083499256, 0.4013916894718289, 0.4819742663322323,
+ 0.15080103744648077, 0.9302407847555013, 0.9397597961319524, 0.5719200825550793, 0.9538938024682824, 0.9583882089203861, 0.5168861091262276, 0.1926396841842669,
+ 0.6781176744337578, 0.719366447288566
+ };
+ float expected_output[1*5*6*3] = {
+ -0.3921688, -0.9243112, -0.29659146, -0.64000785, -0.9466343, -0.62125254, -0.71759033, -0.9171336, -0.735589, -0.34365994,
+ -0.92100817, -0.23903961, -0.8962277, -0.9521279, -0.90962386, -0.7488303, -0.9563761, -0.7701762, -0.40800542, -0.87684774,
+ -0.3339763, -0.6354543, -0.97068924, -0.6246325, -0.6992075, -0.9706726, -0.6818918, -0.51864433, -0.9592881, -0.51187396,
+ -0.7423632, -0.89911884, -0.7457824, -0.82009757, -0.96402895, -0.8235518, -0.61980766, -0.94494647, -0.5410502, -0.8281218,
+ -0.95508635, -0.8201453, -0.5937325, -0.8679507, -0.500767, -0.39430764, -0.93967676, -0.32183182, -0.58913624, -0.939717,
+ -0.55179894, -0.55004454, -0.9214453, -0.4889004, -0.75294703, -0.9118363, -0.7200309, -0.3248641, -0.8878874, -0.18977344,
+ -0.8873837, -0.9571257, -0.90145934, -0.50521654, -0.93739635, -0.39051685, -0.61143184, -0.9591179, -0.605999, -0.40008977,
+ -0.92219675, -0.26732883, -0.19607787, -0.9172511, -0.07068595, -0.5409857, -0.9387041, -0.44181606, -0.4705004, -0.8899935,
+ -0.37997037, -0.66105115, -0.89754754, -0.68141997, -0.6324047, -0.886776, -0.65066385, -0.8334821, -0.94801456, -0.83297
+ };
+ float *output;
+ float kernel[3*3] = {
+ 0.56611896, -0.5144603, -0.82600045, 0.19219112, 0.3835776, -0.7475352, 0.5209291, -0.6301091, -0.99442935};
+ float bias[3] = {-0.3654299, -1.5711838, -0.15546428};
+
+ params.activation = TANH;
+ params.has_bias = 1;
+ params.biases = bias;
+ params.input_num = 3;
+ params.kernel = kernel;
+ params.output_num = 3;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 5;
+ operands[0].dims[2] = 6;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_dense(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ if (test())
+ return 1;
+
+ return 0;
+}
diff --git a/libavfilter/tests/dnn-layer-depth2space.c b/libavfilter/tests/dnn-layer-depth2space.c
new file mode 100644
index 0000000000..958247e675
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-depth2space.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 Guo Yejun
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native.h"
+#include "libavfilter/dnn/dnn_backend_native_layer_depth2space.h"
+
+#define EPSON 0.00001
+
+static int test(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 4])
+ y = tf.depth_to_space(x, 2)
+ data = np.random.rand(1, 5, 3, 4);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+
+ output = sess.run(y, feed_dict={x: data})
+
+ print("input:")
+ print(data.shape)
+ print(list(data.flatten()))
+
+ print("output:")
+ print(output.shape)
+ print(list(output.flatten()))
+ */
+
+ DepthToSpaceParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*5*3*4] = {
+ 0.09771065121566602, 0.6336807372403175, 0.5142416549709786, 0.8027206567330333, 0.2154276025069397, 0.12112878462616772, 0.913936596765778,
+ 0.38881443647542646, 0.5850447615898835, 0.9311499327398275, 0.3613660929428246, 0.5420722002125493, 0.6002131190230359, 0.44800665702299525,
+ 0.7271322557896777, 0.3869293511885826, 0.5144404769364138, 0.6910844856987723, 0.6142102742269762, 0.6249991371621018, 0.45663376215836626,
+ 0.19523477129943423, 0.2483895888532045, 0.64326768256278, 0.5485877602998981, 0.45442067849873546, 0.529374943304256, 0.30439850391811885,
+ 0.11961343361340993, 0.2909643484561082, 0.9810970344127848, 0.8886928489786549, 0.6112237084436409, 0.8852482695156674, 0.9110868043114374,
+ 0.21242780027585217, 0.7101536973207572, 0.9709717457443375, 0.2702666770969332, 0.7718295953780221, 0.3957005164588574, 0.24383544252475453,
+ 0.040143453532367035, 0.26358051835323115, 0.013130251443791319, 0.3016550481482074, 0.03582340459943956, 0.718025513612361, 0.09844204177633753,
+ 0.04433767496953056, 0.6221895044119757, 0.6190414032940228, 0.8963550834625371, 0.5642449700064629, 0.2482982014723497, 0.17824909294583013,
+ 0.024401882408643272, 0.21742800875253465, 0.6794724473181843, 0.4814830479242237
+ };
+ float expected_output[1*10*6*1] = {
+ 0.097710654, 0.63368076, 0.2154276, 0.12112878, 0.58504474, 0.93114996, 0.51424164, 0.80272067, 0.9139366, 0.38881445,
+ 0.3613661, 0.5420722, 0.6002131, 0.44800666, 0.5144405, 0.6910845, 0.45663378, 0.19523478, 0.72713226, 0.38692936,
+ 0.61421025, 0.62499917, 0.24838959, 0.6432677, 0.54858774, 0.4544207, 0.11961343, 0.29096434, 0.6112237, 0.88524824,
+ 0.52937496, 0.3043985, 0.98109704, 0.88869286, 0.9110868, 0.2124278, 0.7101537, 0.97097176, 0.3957005, 0.24383545,
+ 0.013130251, 0.30165505, 0.27026668, 0.7718296, 0.040143453, 0.26358053, 0.035823405, 0.7180255, 0.09844204,
+ 0.044337675, 0.8963551, 0.564245, 0.024401883, 0.21742801, 0.6221895, 0.6190414, 0.2482982, 0.17824909, 0.67947245, 0.48148304
+ };
+ float *output;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 5;
+ operands[0].dims[2] = 3;
+ operands[0].dims[3] = 4;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ params.block_size = 2;
+ ff_dnn_execute_layer_depth2space(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ return test();
+}
diff --git a/libavfilter/tests/dnn-layer-mathbinary.c b/libavfilter/tests/dnn-layer-mathbinary.c
new file mode 100644
index 0000000000..2e41dc1ae7
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-mathbinary.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2020
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_mathbinary.h"
+#include "libavutil/avassert.h"
+
+#define EPSON 0.00005
+
+static float get_expected(float f1, float f2, DNNMathBinaryOperation op)
+{
+ switch (op)
+ {
+ case DMBO_SUB:
+ return f1 - f2;
+ case DMBO_ADD:
+ return f1 + f2;
+ case DMBO_MUL:
+ return f1 * f2;
+ case DMBO_REALDIV:
+ return f1 / f2;
+ case DMBO_MINIMUM:
+ return (f1 < f2) ? f1 : f2;
+ case DMBO_FLOORMOD:
+ return (float)((int)(f1) % (int)(f2));
+ default:
+ av_assert0(!"not supported yet");
+ return 0.f;
+ }
+}
+
+static int test_broadcast_input0(DNNMathBinaryOperation op)
+{
+ DnnLayerMathBinaryParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*1*2*3] = {
+ -3, 2.5, 2, -2.1, 7.8, 100
+ };
+ float *output;
+
+ params.bin_op = op;
+ params.input0_broadcast = 1;
+ params.input1_broadcast = 0;
+ params.v = 7.28;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 1;
+ operands[0].dims[2] = 2;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_math_binary(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(input) / sizeof(float); i++) {
+ float expected_output = get_expected(params.v, input[i], op);
+ if (fabs(output[i] - expected_output) > EPSON) {
+ printf("op %d, at index %d, output: %f, expected_output: %f (%s:%d)\n",
+ op, i, output[i], expected_output, __FILE__, __LINE__);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+static int test_broadcast_input1(DNNMathBinaryOperation op)
+{
+ DnnLayerMathBinaryParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*1*2*3] = {
+ -3, 2.5, 2, -2.1, 7.8, 100
+ };
+ float *output;
+
+ params.bin_op = op;
+ params.input0_broadcast = 0;
+ params.input1_broadcast = 1;
+ params.v = 7.28;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 1;
+ operands[0].dims[2] = 2;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_math_binary(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(input) / sizeof(float); i++) {
+ float expected_output = get_expected(input[i], params.v, op);
+ if (fabs(output[i] - expected_output) > EPSON) {
+ printf("op %d, at index %d, output: %f, expected_output: %f (%s:%d)\n",
+ op, i, output[i], expected_output, __FILE__, __LINE__);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+static int test_no_broadcast(DNNMathBinaryOperation op)
+{
+ DnnLayerMathBinaryParams params;
+ DnnOperand operands[3];
+ int32_t input_indexes[2];
+ float input0[1*1*2*3] = {
+ -3, 2.5, 2, -2.1, 7.8, 100
+ };
+ float input1[1*1*2*3] = {
+ -1, 2, 3, -21, 8, 10.0
+ };
+ float *output;
+
+ params.bin_op = op;
+ params.input0_broadcast = 0;
+ params.input1_broadcast = 0;
+
+ operands[0].data = input0;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 1;
+ operands[0].dims[2] = 2;
+ operands[0].dims[3] = 3;
+ operands[1].data = input1;
+ operands[1].dims[0] = 1;
+ operands[1].dims[1] = 1;
+ operands[1].dims[2] = 2;
+ operands[1].dims[3] = 3;
+ operands[2].data = NULL;
+
+ input_indexes[0] = 0;
+ input_indexes[1] = 1;
+ ff_dnn_execute_layer_math_binary(operands, input_indexes, 2, &params, NULL);
+
+ output = operands[2].data;
+ for (int i = 0; i < sizeof(input0) / sizeof(float); i++) {
+ float expected_output = get_expected(input0[i], input1[i], op);
+ if (fabs(output[i] - expected_output) > EPSON) {
+ printf("op %d, at index %d, output: %f, expected_output: %f (%s:%d)\n",
+ op, i, output[i], expected_output, __FILE__, __LINE__);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+static int test(DNNMathBinaryOperation op)
+{
+ if (test_broadcast_input0(op))
+ return 1;
+
+ if (test_broadcast_input1(op))
+ return 1;
+
+ if (test_no_broadcast(op))
+ return 1;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ if (test(DMBO_SUB))
+ return 1;
+
+ if (test(DMBO_ADD))
+ return 1;
+
+ if (test(DMBO_MUL))
+ return 1;
+
+ if (test(DMBO_REALDIV))
+ return 1;
+
+ if (test(DMBO_MINIMUM))
+ return 1;
+
+ if (test(DMBO_FLOORMOD))
+ return 1;
+
+ return 0;
+}
diff --git a/libavfilter/tests/dnn-layer-mathunary.c b/libavfilter/tests/dnn-layer-mathunary.c
new file mode 100644
index 0000000000..0f84c12960
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-mathunary.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_mathunary.h"
+#include "libavutil/avassert.h"
+
+#define EPS 0.00001
+
+static float get_expected(float f, DNNMathUnaryOperation op)
+{
+ switch (op)
+ {
+ case DMUO_ABS:
+ return (f >= 0) ? f : -f;
+ case DMUO_SIN:
+ return sin(f);
+ case DMUO_COS:
+ return cos(f);
+ case DMUO_TAN:
+ return tan(f);
+ case DMUO_ASIN:
+ return asin(f);
+ case DMUO_ACOS:
+ return acos(f);
+ case DMUO_ATAN:
+ return atan(f);
+ case DMUO_SINH:
+ return sinh(f);
+ case DMUO_COSH:
+ return cosh(f);
+ case DMUO_TANH:
+ return tanh(f);
+ case DMUO_ASINH:
+ return asinh(f);
+ case DMUO_ACOSH:
+ return acosh(f);
+ case DMUO_ATANH:
+ return atanh(f);
+ case DMUO_CEIL:
+ return ceil(f);
+ case DMUO_FLOOR:
+ return floor(f);
+ case DMUO_ROUND:
+ return round(f);
+ case DMUO_EXP:
+ return exp(f);
+ default:
+ av_assert0(!"not supported yet");
+ return 0.f;
+ }
+}
+
+static int test(DNNMathUnaryOperation op)
+{
+ DnnLayerMathUnaryParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*1*3*3] = {
+ 0.1, 0.5, 0.75, -3, 2.5, 2, -2.1, 7.8, 100};
+ float *output;
+
+ params.un_op = op;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 1;
+ operands[0].dims[2] = 3;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_math_unary(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(input) / sizeof(float); ++i) {
+ float expected_output = get_expected(input[i], op);
+ int output_nan = isnan(output[i]);
+ int expected_nan = isnan(expected_output);
+ if ((!output_nan && !expected_nan && fabs(output[i] - expected_output) > EPS) ||
+ (output_nan && !expected_nan) || (!output_nan && expected_nan)) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+}
+
+int main(int agrc, char **argv)
+{
+ if (test(DMUO_ABS))
+ return 1;
+ if (test(DMUO_SIN))
+ return 1;
+ if (test(DMUO_COS))
+ return 1;
+ if (test(DMUO_TAN))
+ return 1;
+ if (test(DMUO_ASIN))
+ return 1;
+ if (test(DMUO_ACOS))
+ return 1;
+ if (test(DMUO_ATAN))
+ return 1;
+ if (test(DMUO_SINH))
+ return 1;
+ if (test(DMUO_COSH))
+ return 1;
+ if (test(DMUO_TANH))
+ return 1;
+ if (test(DMUO_ASINH))
+ return 1;
+ if (test(DMUO_ACOSH))
+ return 1;
+ if (test(DMUO_ATANH))
+ return 1;
+ if (test(DMUO_CEIL))
+ return 1;
+ if (test(DMUO_FLOOR))
+ return 1;
+ if (test(DMUO_ROUND))
+ return 1;
+ if (test(DMUO_EXP))
+ return 1;
+ return 0;
+}
diff --git a/libavfilter/tests/dnn-layer-maximum.c b/libavfilter/tests/dnn-layer-maximum.c
new file mode 100644
index 0000000000..bf22f3719f
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-maximum.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Guo Yejun
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_maximum.h"
+
+#define EPSON 0.00001
+
+static int test(void)
+{
+ DnnLayerMaximumParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*1*2*3] = {
+ -3, 2.5, 2, -2.1, 7.8, 100
+ };
+ float *output;
+
+ params.val.y = 2.3;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 1;
+ operands[0].dims[2] = 2;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_maximum(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(input) / sizeof(float); i++) {
+ float expected_output = input[i] > params.val.y ? input[i] : params.val.y;
+ if (fabs(output[i] - expected_output) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+
+}
+
+int main(int argc, char **argv)
+{
+ if (test())
+ return 1;
+
+ return 0;
+}
diff --git a/libavfilter/tests/dnn-layer-pad.c b/libavfilter/tests/dnn-layer-pad.c
new file mode 100644
index 0000000000..a8443ce3be
--- /dev/null
+++ b/libavfilter/tests/dnn-layer-pad.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2019 Guo Yejun
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "libavfilter/dnn/dnn_backend_native_layer_pad.h"
+
+#define EPSON 0.00001
+
+static int test_with_mode_symmetric(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.pad(x, [[0, 0], [2, 3], [3, 2], [0, 0]], 'SYMMETRIC')
+ data = np.arange(48).reshape(1, 4, 4, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+ output = sess.run(y, feed_dict={x: data})
+
+ print(list(data.flatten()))
+ print(list(output.flatten()))
+ print(data.shape)
+ print(output.shape)
+ */
+
+ LayerPadParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*4*4*3] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
+ };
+ float expected_output[1*9*9*3] = {
+ 18.0, 19.0, 20.0, 15.0, 16.0, 17.0, 12.0, 13.0, 14.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 21.0, 22.0, 23.0, 18.0, 19.0, 20.0, 6.0, 7.0, 8.0, 3.0,
+ 4.0, 5.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 9.0, 10.0, 11.0, 6.0, 7.0, 8.0, 6.0, 7.0, 8.0, 3.0, 4.0, 5.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 3.0,
+ 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 9.0, 10.0, 11.0, 6.0, 7.0, 8.0, 18.0, 19.0, 20.0, 15.0, 16.0, 17.0, 12.0, 13.0, 14.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0,
+ 21.0, 22.0, 23.0, 21.0, 22.0, 23.0, 18.0, 19.0, 20.0, 30.0, 31.0, 32.0, 27.0, 28.0, 29.0, 24.0, 25.0, 26.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 33.0,
+ 34.0, 35.0, 30.0, 31.0, 32.0, 42.0, 43.0, 44.0, 39.0, 40.0, 41.0, 36.0, 37.0, 38.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 45.0, 46.0, 47.0, 42.0, 43.0,
+ 44.0, 42.0, 43.0, 44.0, 39.0, 40.0, 41.0, 36.0, 37.0, 38.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 45.0, 46.0, 47.0, 42.0, 43.0, 44.0, 30.0, 31.0, 32.0,
+ 27.0, 28.0, 29.0, 24.0, 25.0, 26.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 33.0, 34.0, 35.0, 30.0, 31.0, 32.0, 18.0, 19.0, 20.0, 15.0, 16.0, 17.0, 12.0,
+ 13.0, 14.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 21.0, 22.0, 23.0, 18.0, 19.0, 20.0
+ };
+ float *output;
+
+ params.mode = LPMP_SYMMETRIC;
+ params.paddings[0][0] = 0;
+ params.paddings[0][1] = 0;
+ params.paddings[1][0] = 2;
+ params.paddings[1][1] = 3;
+ params.paddings[2][0] = 3;
+ params.paddings[2][1] = 2;
+ params.paddings[3][0] = 0;
+ params.paddings[3][1] = 0;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 4;
+ operands[0].dims[2] = 4;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_pad(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+
+}
+
+static int test_with_mode_reflect(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[3, None, None, 3])
+ y = tf.pad(x, [[1, 2], [0, 0], [0, 0], [0, 0]], 'REFLECT')
+ data = np.arange(36).reshape(3, 2, 2, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+ output = sess.run(y, feed_dict={x: data})
+
+ print(list(data.flatten()))
+ print(list(output.flatten()))
+ print(data.shape)
+ print(output.shape)
+ */
+
+ LayerPadParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[3*2*2*3] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
+ };
+ float expected_output[6*2*2*3] = {
+ 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
+ 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0,
+ 35.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0
+ };
+ float *output;
+
+ params.mode = LPMP_REFLECT;
+ params.paddings[0][0] = 1;
+ params.paddings[0][1] = 2;
+ params.paddings[1][0] = 0;
+ params.paddings[1][1] = 0;
+ params.paddings[2][0] = 0;
+ params.paddings[2][1] = 0;
+ params.paddings[3][0] = 0;
+ params.paddings[3][1] = 0;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 3;
+ operands[0].dims[1] = 2;
+ operands[0].dims[2] = 2;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_pad(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+
+}
+
+static int test_with_mode_constant(void)
+{
+ // the input data and expected data are generated with below python code.
+ /*
+ x = tf.placeholder(tf.float32, shape=[1, None, None, 3])
+ y = tf.pad(x, [[0, 0], [1, 0], [0, 0], [1, 2]], 'CONSTANT', constant_values=728)
+ data = np.arange(12).reshape(1, 2, 2, 3);
+
+ sess=tf.Session()
+ sess.run(tf.global_variables_initializer())
+ output = sess.run(y, feed_dict={x: data})
+
+ print(list(data.flatten()))
+ print(list(output.flatten()))
+ print(data.shape)
+ print(output.shape)
+ */
+
+ LayerPadParams params;
+ DnnOperand operands[2];
+ int32_t input_indexes[1];
+ float input[1*2*2*3] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+ };
+ float expected_output[1*3*2*6] = {
+ 728.0, 728.0, 728.0, 728.0, 728.0, 728.0, 728.0, 728.0, 728.0, 728.0, 728.0,
+ 728.0, 728.0, 0.0, 1.0, 2.0, 728.0, 728.0, 728.0, 3.0, 4.0, 5.0, 728.0, 728.0,
+ 728.0, 6.0, 7.0, 8.0, 728.0, 728.0, 728.0, 9.0, 10.0, 11.0, 728.0, 728.0
+ };
+ float *output;
+
+ params.mode = LPMP_CONSTANT;
+ params.constant_values = 728;
+ params.paddings[0][0] = 0;
+ params.paddings[0][1] = 0;
+ params.paddings[1][0] = 1;
+ params.paddings[1][1] = 0;
+ params.paddings[2][0] = 0;
+ params.paddings[2][1] = 0;
+ params.paddings[3][0] = 1;
+ params.paddings[3][1] = 2;
+
+ operands[0].data = input;
+ operands[0].dims[0] = 1;
+ operands[0].dims[1] = 2;
+ operands[0].dims[2] = 2;
+ operands[0].dims[3] = 3;
+ operands[1].data = NULL;
+
+ input_indexes[0] = 0;
+ ff_dnn_execute_layer_pad(operands, input_indexes, 1, &params, NULL);
+
+ output = operands[1].data;
+ for (int i = 0; i < sizeof(expected_output) / sizeof(float); i++) {
+ if (fabs(output[i] - expected_output[i]) > EPSON) {
+ printf("at index %d, output: %f, expected_output: %f\n", i, output[i], expected_output[i]);
+ av_freep(&output);
+ return 1;
+ }
+ }
+
+ av_freep(&output);
+ return 0;
+
+}
+
+int main(int argc, char **argv)
+{
+ if (test_with_mode_symmetric())
+ return 1;
+
+ if (test_with_mode_reflect())
+ return 1;
+
+ if (test_with_mode_constant())
+ return 1;
+}