public unsafe void SoftmaxBackwardOutput()
        {
            float[,]
            x = WeightsProvider.NewFullyConnectedWeights(TensorInfo.Linear(400), 250, WeightsInitializationMode.GlorotNormal).AsSpan().AsMatrix(400, 250),
            y = new float[400, 127];
            for (int i = 0; i < 400; i++)
            {
                y[i, ThreadSafeRandom.NextInt(max: 127)] = 1;
            }
            OutputLayerBase
                cpu = new SoftmaxLayer(TensorInfo.Linear(250), 127, WeightsInitializationMode.GlorotNormal, BiasInitializationMode.Gaussian),
                gpu = new CuDnnSoftmaxLayer(cpu.InputInfo, cpu.OutputInfo.Size, cpu.Weights, cpu.Biases);

            fixed(float *px = x, py = y)
            {
                Tensor.Reshape(px, x.GetLength(0), x.GetLength(1), out Tensor xt);
                cpu.Forward(xt, out Tensor z, out Tensor a);
                a.Duplicate(out Tensor a2);
                Tensor.Reshape(py, y.GetLength(0), y.GetLength(1), out Tensor yt);
                cpu.Backpropagate(a, yt, z);
                gpu.Backpropagate(a2, yt, z);
                Assert.IsTrue(a.ContentEquals(a2));
                a.Free();
                a2.Free();
                z.Free();
            }
        }
        public void SoftmaxForward()
        {
            OutputLayerBase
                cpu = new SoftmaxLayer(TensorInfo.Linear(250), 127, WeightsInitializationMode.GlorotNormal, BiasInitializationMode.Gaussian),
                gpu = new CuDnnSoftmaxLayer(cpu.InputInfo, cpu.OutputInfo.Size, cpu.Weights, cpu.Biases);

            TestForward(cpu, gpu, 400);
        }
        public void SoftmaxForward()
        {
            float[,] x = WeightsProvider.NewFullyConnectedWeights(TensorInfo.Linear(400), 250, WeightsInitializationMode.GlorotNormal).AsSpan().AsMatrix(400, 250);
            OutputLayerBase
                cpu = new SoftmaxLayer(TensorInfo.Linear(250), 127, WeightsInitializationMode.GlorotNormal, BiasInitializationMode.Gaussian),
                gpu = new CuDnnSoftmaxLayer(cpu.InputInfo, cpu.OutputInfo.Size, cpu.Weights, cpu.Biases);

            TestForward(cpu, gpu, x);
        }
        public void SoftmaxBackwardOutput()
        {
            float[,] y = new float[400, 127];
            for (int i = 0; i < 400; i++)
            {
                y[i, ThreadSafeRandom.NextInt(max: 127)] = 1;
            }
            OutputLayerBase
                cpu = new SoftmaxLayer(TensorInfo.Linear(250), 127, WeightsInitializationMode.GlorotNormal, BiasInitializationMode.Gaussian),
                gpu = new CuDnnSoftmaxLayer(cpu.InputInfo, cpu.OutputInfo.Size, cpu.Weights, cpu.Biases);

            TestBackward(cpu, gpu, y);
        }
        internal static INetworkLayer CuDnnLayerDeserialize([NotNull] Stream stream, LayerType type)
        {
            switch (type)
            {
            case LayerType.FullyConnected: return(CuDnnFullyConnectedLayer.Deserialize(stream));

            case LayerType.Convolutional: return(CuDnnConvolutionalLayer.Deserialize(stream));

            case LayerType.Pooling: return(CuDnnPoolingLayer.Deserialize(stream));

            case LayerType.Softmax: return(CuDnnSoftmaxLayer.Deserialize(stream));

            case LayerType.Inception: return(CuDnnInceptionLayer.Deserialize(stream));

            default: return(null);
            }
        }