/// <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); }