Exemple #1
0
        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;
            }));
        }
Exemple #2
0
        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;
            }));
        }
Exemple #3
0
        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;
            }));
        }
Exemple #4
0
        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;
            }));
        }
Exemple #5
0
        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;
            }));
        }
Exemple #6
0
        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;
            }));
        }
Exemple #7
0
        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;
            }));
        }