/// <summary> /// Given (symbolic) log-domain potentials, construct the graph for forward inference in a chain CRF. /// </summary> /// <param name="obs_potentials">(n_steps, n_classes) Axes correspond to time and the value of the discrete label variable /// This is the energy assigned to a configuration (so higher energy = lower probability).</param> /// <param name="chain_potentials">(n_classes, n_classes, n_classes) Axes correspond to left label state, right label state, and the global label. /// Corresponds to the energy of a given pair of labels adjacent to one another (higher energy = lower probability).</param> /// <param name="viterbi">Perform MAP inference with the Viterbi algorithm rather than marginalizing the step-specific /// label variables, Instead, use the single most likely configuration.</param> /// <returns>(1-dimensional) The energy assigned for a given global label. /// This can be turned into a log probability by subtracting logsumexp(energy).</returns> public static Tensor <float> Forward(Tensor <float> obs_potentials, Tensor <float> chain_potentials, bool viterbi = false) { Func <Tensor <float>, Tensor <float>, Tensor <float> > inner_function = (obs, prior_result /*, chain_potentials*/) => { prior_result = prior_result.DimShuffle(0, 'x', 1); obs = obs.DimShuffle('x', 0, 'x'); if (viterbi) { return(T.Max((-prior_result - obs - chain_potentials), axis: 0)); } else { return(LogSumExp(-prior_result - obs - chain_potentials, axis: 0)); } }; Debug.Assert(obs_potentials.NDim == 2); Debug.Assert(chain_potentials.NDim == 3); var initial = (obs_potentials[0].DimShuffle(0, 'x') * T.OnesLike(chain_potentials[0])); var scanned = T.Scan( fn: inner_function, outputsInfo: initial, sequences: new[] { obs_potentials[XSlicer.From(1)] } //non_sequences: chain_potentials ); if (viterbi) { return(-(T.Max(scanned[-1], axis: 0))); } else { return(-LogSumExp(scanned[-1], axis: 0)); } }
public void TestShapeOfSlice() { var v = T.Shared(0.2f * NN.Random.Uniform(-1.0f, 1.0f, 13).As <float>(), "v"); AssertArray.WriteTheSame(new[] { 3 }, v[XSlicer.Range(5, 8)].Shape); AssertArray.WriteTheSame(new[] { 3 }, v[XSlicer.Range(8, 5, -1)].Shape); AssertArray.WriteTheSame(new[] { 4 }, v[XSlicer.Range(3, 11, 2)].Shape); var M = T.Shared(0.2f * NN.Random.Uniform(-1.0f, 1.0f, 8, 22).As <float>(), "M"); AssertArray.WriteTheSame(new[] { 5, 17 }, M[XSlicer.Range(6, 1, -1), XSlicer.From(5)].Shape); }
public void TestRecursive() { // http://deeplearning.net/software/theano/tutorial/loop.html // define tensor variables var X = T.Vector <float>("X"); var W = T.Matrix <float>("W"); var b_sym = T.Matrix <float>("b_sym"); var U = T.Matrix <float>("U"); var Y = T.Matrix <float>("Y"); var V = T.Matrix <float>("V"); var P = T.Matrix <float>("P"); var results = T.Scan((yy, pp, xx_tm1) => T.Tanh(T.Dot(xx_tm1, W) + T.Dot(yy, U) + T.Dot(pp, V)), sequences: new[] { Y, P[XSlicer.Step(-1)] }, outputsInfo: X); var compute_seq = T.Function(inputs: new[] { X, W, Y, U, P, V }, output: results); // test values var x = NN.Zeros <float>(2); x.Item[1] = 1; var w = NN.Ones <float>(2, 2); var y = NN.Ones <float>(5, 2); y.Item[0] = -3; var u = NN.Ones <float>(2, 2); var p = NN.Ones <float>(5, 2); p.Item[0] = 3; var v = NN.Ones <float>(2, 2); var result = compute_seq(new[] { x, w, y, u, p, v }); // Array<float>[5] => theano returns Array<float>[5][1] // comparison with numpy var x_res = NN.Zeros <float>(5, 2); x_res[0] = NN.Tanh(x.Dot(w) + y[0].Dot(u) + p[4].Dot(v)); for (int i = 1; i < 5; i++) { x_res[i] = NN.Tanh(x_res[i - 1].Dot(w) + y[i].Dot(u) + p[4 - i].Dot(v)); } AssertArray.AreAlmostEqual(x_res, result); }