public static Tensor Tile(this Session session, Tensor x, int axis, int count) { const string ActionName = "tile"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } if (count == 1) { return(ArrayOperations.Copy(session, x)); } return(session.RunOperation( ActionName, () => { bool calculateGradient = session.CalculateGradients && x.CalculateGradient; // allocate destination Tensor y = session.AllocateTensor(ActionName, x.Shape.Reshape(axis, x.Axes[axis] * count), calculateGradient); ArrayOperations.Tile(x, axis, count, y, false); #if !NOLEARNING if (calculateGradient) { session.Push(ActionName, () => ArrayOperations.Untile(y, axis, count, x, true)); } #endif return y; })); }
public static Tensor[] Unstack(this Session session, Tensor x, int axis) { const string ActionName = "unstack"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } return(session.RunOperation( ActionName, () => { bool calculateGradient = session.CalculateGradients && x.CalculateGradient; // allocate destination Tensor[] ys = session.AllocateTensors(ActionName, x.Axes[axis], x.Shape.RemoveAxis(axis), calculateGradient); ArrayOperations.Unstack(x, axis, ys, false); #if !NOLEARNING if (calculateGradient) { session.Push(ActionName, () => ArrayOperations.Stack(ys, axis, x, true)); // return copy of the array; calling method can replace its content; our closure keeps the array, not its items return ys.ToArray(); } #endif return ys; })); }
public static Tensor Concat(this Session session, IList <Tensor> xs, int axis) { const string ActionName = "concat"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } return(session.RunOperation( ActionName, () => { bool calculateGradient = session.CalculateGradients && xs.Any(x => x.CalculateGradient); Tensor y = session.AllocateTensor(ActionName, Shape.Concat(xs.Select(x => x.Shape).ToArray(), axis), calculateGradient); ArrayOperations.Concat(xs, axis, y, false); #if !NOLEARNING if (calculateGradient) { session.Push(ActionName, () => ArrayOperations.Split(y, axis, xs, true)); } #endif return y; })); }
public static Tensor[] Split(this Session session, Tensor x, int axis, int[] sizes) { const string ActionName = "split"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } return(session.RunOperation( ActionName, () => { bool calculateGradient = session.CalculateGradients && x.CalculateGradient; // check sizes int ydim = sizes.Length; int sum = 0; for (int i = 0; i < ydim; i++) { sum += sizes[i]; } if (sum != x.Shape.Axes[axis]) { throw new ArgumentException("The sub tensors sizes must be provided."); } // allocate destination Tensor[] ys = new Tensor[ydim]; for (int i = 0; i < ydim; i++) { ys[i] = session.AllocateTensor(ActionName, x.Shape.Reshape(axis, sizes[i]), calculateGradient); } ArrayOperations.Split(x, axis, ys, false); #if !NOLEARNING if (calculateGradient) { session.Push(ActionName, () => ArrayOperations.Concat(ys, axis, x, true)); // return copy of the array; calling method can replace its content; our closure keeps the array, not its items return ys.ToArray(); } #endif return ys; })); }
public static Tensor Stack(this Session session, IList <Tensor> xs, int axis) { const string ActionName = "stack"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } return(session.RunOperation( ActionName, () => { bool calculateGradient = session.CalculateGradients && xs.Any(x => x.CalculateGradient); // check source int xdim = xs.Count; if (xdim == 0) { throw new ArgumentException("There should be at least one source tensor."); } if (!Shape.AreSame(xs)) { throw new ArgumentException("All source tensors must have the same rank and shape."); } Tensor y = session.AllocateTensor(ActionName, xs[0].Shape.InsertAxis(axis, xdim), calculateGradient); ArrayOperations.Stack(xs, axis, y, false); #if !NOLEARNING if (calculateGradient) { session.Push(ActionName, () => ArrayOperations.Unstack(y, axis, xs, true)); } #endif y.Validate(); return y; })); }
public static Tensor[] Split(this Session session, Tensor x, int axis, int numberOfSplits) { const string ActionName = "split"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } // check number of splits if ((x.Axes[axis] % numberOfSplits) != 0) { throw new ArgumentException("The number of tensors to split into must evenly divide the tensor split dimension.", nameof(numberOfSplits)); } return(session.RunOperation( ActionName, () => { bool calculateGradient = session.CalculateGradients && x.CalculateGradient; // allocate destination Tensor[] ys = session.AllocateTensors( ActionName, numberOfSplits, x.Shape.Reshape(axis, x.Axes[axis] / numberOfSplits), calculateGradient); ArrayOperations.Split(x, axis, ys, false); #if !NOLEARNING if (calculateGradient) { session.Push(ActionName, () => ArrayOperations.Concat(ys, axis, x, true)); // return copy of the array; calling method can replace its content; our closure keeps the array, not its items return ys.ToArray(); } #endif return ys; })); }
public static Tensor MaxReduce(this Session session, Tensor x, int axis, int count) { const string ActionName = "max reduce"; if (axis < 0) { throw new ArgumentException(Properties.Resources.E_NegativeAxisIndex, nameof(axis)); } if (count == 1) { return(ArrayOperations.Copy(session, x)); } return(session.RunOperation( ActionName, () => { int xaxis = x.Axes[axis]; int xstride = x.Strides[axis]; if ((xaxis % count) != 0) { throw new ArgumentException("The axis dimension must be a count multiple."); } bool calculateGradient = session.CalculateGradients && x.CalculateGradient; // allocate destination Tensor y = session.AllocateTensor(ActionName, x.Shape.Reshape(axis, xaxis / count), calculateGradient); float[] xw = x.Weights; float[] yw = y.Weights; if (xstride == 1) { int length = x.Length / count; Arrays.Pack(length, xw, 0, count, yw, 0); float[] wsp = new float[length]; for (int i = 1; i < count; i++) { Arrays.Pack(length, xw, i, count, wsp, 0); Vectors.Max(length, wsp, 0, yw, 0); } } else { for (int offx = 0, offy = 0, ylen = y.Length; offy < ylen; offy += xstride) { Vectors.Copy(xstride, xw, offx, yw, offy); offx += xstride; for (int i = 1; i < count; i++, offx += xstride) { Vectors.Max(xstride, xw, offx, yw, offy); } } } #if !NOLEARNING if (calculateGradient) { session.Push( ActionName, () => { float[] dxw = x.Gradient; float[] dyw = y.Gradient; if (xstride == 1) { for (int xpos = 0, ypos = 0, len = y.Length; ypos < len; ypos++) { for (int i = 0; i < count; i++, xpos++) { if (xw[xpos] == yw[ypos]) { dxw[xpos] += dyw[ypos]; } } } } else { for (int xpos = 0, ypos = 0, len = y.Length; ypos < len; ypos += xstride) { for (int i = 0; i < count; i++, xpos += xstride) { Mathematics.MatchAndAdd(xstride, dyw, yw, ypos, dxw, xw, xpos); } } } }); } #endif return y; })); }