Beispiel #1
0
        /// <inheritdoc />
        public float Loss(Tensor y, int[] expected, bool calculateGradient)
        {
            if (y == null)
            {
                throw new ArgumentNullException(nameof(y));
            }

            if (expected == null)
            {
                throw new ArgumentNullException(nameof(expected));
            }

#pragma warning disable SA1312       // Variable names must begin with lower-case letter
            int L = expected.Length; // Number of labels
            int T = y.Axes[0];       // Number of mini-batches (time)
            int A = y.Strides[0];    // Number of classes (alphabet size)
#pragma warning restore SA1312       // Variable names must begin with lower-case letter

            int[] labels = CTCLoss.InsertBlanks(expected, A, this.BlankLabelIndex, out int repeats);
            if (L + repeats > T)
            {
                if (calculateGradient)
                {
                    Vectors.Copy(y.Length, y.Weights, 0, y.Gradient, 0);
                }

                // not enough elements to compute
                return(float.PositiveInfinity);
            }

#pragma warning disable SA1312     // Variable names must begin with lower-case letter
            int S = labels.Length; // Number of labels with blanks
#pragma warning restore SA1312     // Variable names must begin with lower-case letter

            // convert predicted probabilities into log space
            float[] ylog = new float[y.Length];
            Vectors.Log(y.Length, y.Weights, 0, ylog, 0);

            // compute alphas
            float[] alphas = new float[T * S];
            ////CTCLoss.CTCComputeAlphas(T, A, S, ylog, labels, alphas);
            NativeMethods.CTCComputeAlphas(T, A, S, ylog, labels, alphas);

            float logLossA = Mathematics.LogSumExp(alphas[alphas.Length - 1], alphas[alphas.Length - 2]);
            if (float.IsNegativeInfinity(logLossA))
            {
                if (calculateGradient)
                {
                    Vectors.Copy(y.Length, y.Weights, 0, y.Gradient, 0);
                }

                return(float.PositiveInfinity);
            }

            if (calculateGradient)
            {
                // compute betas
                float[] betas = new float[T * S];
                NativeMethods.CTCComputeBetas(T, A, S, ylog, labels, betas);
                ////float logLossB = MKL.LogSumExp(betas.Weights[0], betas.Weights[1]);

                // compute unnormalized gradient
                Mathematics.Add(alphas.Length, betas, 0, alphas, 0);
                NativeMethods.CTCReduceAlphasBetas(T, A, S, alphas, labels, y.Gradient);
                Mathematics.Sub(y.Length, ylog, 0, y.Gradient, 0);
                Mathematics.SubC(y.Length, logLossA, y.Gradient, 0);
                Vectors.Exp(y.Length, y.Gradient, 0);

                // remove NaN
                // NaN may come from various sources (for instance log(y) where y = 0)
                Arrays.Replace(y.Length, y.Gradient, 0, float.NaN, 0.0f, y.Gradient, 0);

                Debug.Assert(!float.IsNaN(y.Gradient[0]), "Tensor contains invalid weight.");
            }

            Debug.Assert(!float.IsNaN(logLossA), "Calculated loss is invalid.");
            return(-logLossA);
        }