public static void CheckLayer(ILayer layer, int fanInWidth, int fanInHeight, int fanInDepth,
                                      int batchSize, float epsilon, Random random)
        {
            var accuracyCondition = 1e-2;

            layer.Initialize(fanInWidth, fanInHeight, fanInDepth, batchSize,
                             Initialization.GlorotUniform, random);

            var fanIn  = fanInWidth * fanInHeight * fanInDepth;
            var fanOut = layer.Width * layer.Height * layer.Depth;

            // Forward pass - set input activation in layer
            var input = Matrix <float> .Build.Random(batchSize, fanIn, random.Next());

            layer.Forward(input);

            // Set delta to 1
            var delta = Matrix <float> .Build.Dense(batchSize, fanOut, 1.0f);

            // Backward pass to calculate gradients
            layer.Backward(delta);

            // get weights and gradients
            var parametersAndGradients = new List <ParametersAndGradients>();

            layer.AddParameresAndGradients(parametersAndGradients);

            foreach (var parameterAndGradient in parametersAndGradients)
            {
                var gradients  = parameterAndGradient.Gradients;
                var parameters = parameterAndGradient.Parameters;

                var output1 = Matrix <float> .Build.Dense(batchSize, fanOut);

                var output2 = Matrix <float> .Build.Dense(batchSize, fanOut);

                for (int i = 0; i < parameters.Length; i++)
                {
                    output1.Clear();
                    output2.Clear();

                    var oldValue = parameters[i];

                    parameters[i] = oldValue + epsilon;
                    layer.Forward(input).CopyTo(output1);
                    parameters[i] = oldValue - epsilon;
                    layer.Forward(input).CopyTo(output2);

                    parameters[i] = oldValue;

                    output1.Subtract(output2, output1); // output1 = output1 - output2

                    var grad     = output1.ToRowMajorArray().Select(f => f / (2.0f * epsilon));
                    var gradient = grad.Sum(); // approximated gradient
                    var actual   = gradients[i];

                    Assert.AreEqual(gradient, actual, accuracyCondition);
                }
            }
        }