Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FFmpeg/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2021-12-15 15:51:16 +0300
committerAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2021-12-19 02:46:29 +0300
commitc26730ed8fb7ca94ef448f53dd69da472aa4e75b (patch)
treed1b289a838a3a5a816e5cb96f3ce7ac6e60bc161 /libavfilter/tests
parent69a45b8a4998e61efd40b054e70abc722f7e155f (diff)
tests/dnn: Make DNN tests regular libavfilter tests
They test libavfilter internal API, so they should be libavfilter test programs (which implies: linked statically to libavfilter to access internal APIs and linked normally (statically or dynamically depending upon the build configuration) against all the other libs). Right now, they are always linked statically against all libs, which is a significant size waste compared to shared libs as all of libavcodec has been pulled in despite not being really used. This also leads to linking failures on systems for which av_export_avutil is intended: libavcodec does not expect to be linked statically against the library providing avpriv_(cga|vga16)_font in this case. This is fixed by this commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Diffstat (limited to 'libavfilter/tests')
-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
9 files changed, 1358 insertions, 0 deletions
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;
+}