/// <summary> /// Execute Backpropagation through time /// </summary> /// <returns></returns> public (float loss, Array <FloatArray2D> dwy, Array <FloatArray> dby, Array <Array <FloatArray2D> > dwh, Array <FloatArray> dbh, Array <FloatArray> hs) BPTT(int[] inputs, int[] targets, Array <FloatArray> hprev) { float loss = 0f; //Feedforward var xs = new Array <FloatArray>(inputs.Length); // Inputs var hs = new Array <Array <FloatArray> >(inputs.Length); // Hidden Result var ps = new Array <Array <FloatArray> >(inputs.Length); // Softmax probabilit var tg = new Array <FloatArray>(inputs.Length); // Targets hs[-1] = hprev; //Backward var dwy = new Array <FloatArray2D>(1); var dby = new Array <FloatArray>(1); var dwh = new Array <Array <FloatArray2D> >(recurrentUnits); var dbh = new Array <FloatArray>(recurrentUnits); var dhnext = new Array <FloatArray>(recurrentUnits); for (int t = 0; t < inputs.Length; t++) { xs[t] = new FloatArray(input_size); xs[t][inputs[t]] = 1; tg[t] = new FloatArray(output_size); tg[t][targets[t]] = 1; (hs[t], ps[t]) = FeedForward(xs[t], hs[t - 1]); } for (int t = inputs.Length - 1; t >= 0; t--) { // Sequencial (var l, var dy) = decoder.ComputeErrorNBackward(tg[t], ps[t]); (dhnext, _) = encoder.Backward(dy, dhnext, hs[t]); // Parallel (var wy, var by) = decoder.ComputeGradient(hs[t][-1]); (var wh, var bh) = encoder.ComputeGradient(xs[t], hs[t - 1]); // Parallel dwy = dwy.Sum(wy); dby = dby.Sum(by); dwh = dwh.Sum(wh); dbh = dbh.Sum(bh); loss += l; } // Parallel dwy = NumMath.Normalize(-5, 5, dwy); dby = NumMath.Normalize(-5, 5, dby); dwh = NumMath.Normalize(-5, 5, dwh); dbh = NumMath.Normalize(-5, 5, dbh); return(loss, dwy, dby, dwh, dbh, hs[-1]);