public override void Execute() { // Let only one node init the shared thing if ((Owner.VectorMode == VectorGenerationMode.AverageBaseVectors && !_firstBase) || !_first) { return; } var random = new Random(Owner.Seed); var dotKernel = MyReductionFactory.Kernel(Owner.GPU, MyReductionFactory.Mode.f_DotProduct_f); var multKernel = MyKernelFactory.Instance.Kernel(Owner.GPU, @"common\CombineVectorsKernel", "CombineTwoVectorsKernelVarSize"); var transposeKernel = MyKernelFactory.Instance.Kernel(Owner.GPU, @"VSA\RandomMapper", "Transpose"); int xDim, yDim; AxisToNormalizeEnum axisToNormalize = AxisToNormalize; if (!Owner.DoDecoding) { xDim = Owner.InputSize; yDim = Owner.OutputSize; } else { xDim = Owner.OutputSize; yDim = Owner.InputSize; axisToNormalize = axisToNormalize == AxisToNormalizeEnum.xDim ? AxisToNormalizeEnum.yDim : AxisToNormalizeEnum.xDim; } GenerateTransformMatrix( Owner.UnmanagedVectors, Owner.UnmanagedBaseVectors, Owner.Temp, random, xDim, yDim, dotKernel, multKernel, transposeKernel, Owner.GPU, Owner.VectorMode, axisToNormalize); MyMemoryManager.Instance.ClearGlobalVariable(Owner.GlobalVariableBasesName, Owner.GPU); MyMemoryManager.Instance.RemoveBlock(Owner, Owner.UnmanagedBaseVectors); }
/// <summary> /// Generates a matrix with <paramref name="xDim"/> being the leading dimension in column-major storage. /// </summary> /// <param name="unmanagedVectors">A memory block to store the generated matrix. /// Must be as large as <paramref name="xDim"/> x <paramref name="yDim"/>.</param> /// <param name="unmanagedBaseVectors">A temporary block to store all the base vectors. /// Must be as large as Max(<paramref name="xDim"/>, <paramref name="yDim"/>)^2. /// Only neccessary when <paramref name="mode"/> is set to <see cref="VectorGenerationMode.AverageBaseVectors"/>.</param> /// <param name="temp">The temporary storage. It should be as long as the longer of the dimensions.</param> /// <param name="random">The random object for number generation.</param> /// <param name="xDim">The size of the other dimension.</param> /// <param name="yDim">The size of the leading dimension.</param> /// <param name="mode">If true, the vectors along the longer dimension will be orthonormalized.</param> /// <param name="axisToNormalize">The axis along which to normalize vectors after orthonormalization.</param> public static void GenerateTransformMatrix( MyMemoryBlock<float> unmanagedVectors, MyMemoryBlock<float> unmanagedBaseVectors, MyMemoryBlock<float> temp, Random random, int xDim, int yDim, MyProductKernel<float> dotKernel, MyCudaKernel multKernel, MyCudaKernel transposeKernel, int GPU, VectorGenerationMode mode = VectorGenerationMode.Normal, AxisToNormalizeEnum axisToNormalize = AxisToNormalizeEnum.yDim) { Debug.Assert(random != null, "Missing random object"); Debug.Assert(unmanagedVectors != null && (mode != VectorGenerationMode.AverageBaseVectors || unmanagedBaseVectors != null) && temp != null, "Missing data!"); Debug.Assert(dotKernel != null && multKernel != null && transposeKernel != null, "Missing a kernel!"); // Mapping to rows --- Column-major storage --- rows will the leading dimension // The larger dimension vectors will be orthogonal; the cols dimension vectors will be normalized switch (mode) { case VectorGenerationMode.Normal: if (axisToNormalize == AxisToNormalizeEnum.xDim) { // Generate normalized vectors with xDim as the leading dim GenerateRandomNormalVectors(unmanagedVectors.Host, random, xDim, yDim); unmanagedVectors.SafeCopyToDevice(); // Transpose to the correct position transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { GenerateRandomNormalVectors(unmanagedVectors.Host, random, yDim, xDim); unmanagedVectors.SafeCopyToDevice(); } break; case VectorGenerationMode.Orthonormalize: int largerDim = Math.Max(xDim, yDim); int smallerDim = Math.Min(xDim, yDim); // Generate vectors with larger leading dimension GenerateRandomNormalVectors(unmanagedVectors.Host, random, largerDim, smallerDim, normalize: false); unmanagedVectors.SafeCopyToDevice(); // Orthonormalize along the larger dimension OrthonormalizeVectors(unmanagedVectors, temp, largerDim, smallerDim, dotKernel, multKernel, GPU); if (xDim > yDim) { // xDim is leading and is normalized // We need to transpose to get the correct dims transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); if (axisToNormalize == AxisToNormalizeEnum.yDim) NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } else { // yDim is leading and is normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.xDim) { // TODO: generate the matrix with transposed dims? // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; case VectorGenerationMode.AverageBaseVectors: int longerDim = Math.Max(xDim, yDim); int shorterDim = Math.Min(xDim, yDim); GenerateTransformMatrix( unmanagedBaseVectors, null, temp, random, longerDim, longerDim, dotKernel, multKernel, transposeKernel, GPU, VectorGenerationMode.Orthonormalize); if (shorterDim == longerDim) break; float it = 0f; float step = longerDim / (float)shorterDim; int beg, end = 0; for (int i = 0; i < shorterDim; i++) { beg = end; it += step; end = (int)it; var vect = unmanagedVectors.GetDevicePtr(GPU, i * longerDim); for (int j = beg; j < end; j++) { var baseVect = unmanagedBaseVectors.GetDevicePtr(GPU, j * longerDim); multKernel.Run(baseVect, vect, vect, (int)MyJoin.MyJoinOperation.Addition, longerDim, longerDim); } } if (xDim > yDim) { // xDim is leading and is not normalized // We need to transpose to get the correct dims if (axisToNormalize == AxisToNormalizeEnum.xDim) { NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } } else { // yDim is leading and is not normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.yDim) NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); else { // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; } }
/// <summary> /// Generates a matrix with <paramref name="yDim"/> being the leading dimension in column-major storage. /// </summary> /// <param name="random">The random object for number generation.</param> /// <param name="xDim">The size of the leading dimension.</param> /// <param name="yDim">The size of the other dimension.</param> /// <param name="orthonormalize">If true, the vectors along the longer dimension will be orthonormalized.</param> /// <param name="axisToNormalize">The axis along which to normalize vectors after orthonormalization.</param> /// <returns>The generated matrix.</returns> public static float[] GenerateTransformMatrix(Random random, int xDim, int yDim, bool orthonormalize = false, AxisToNormalizeEnum axisToNormalize = AxisToNormalizeEnum.yDim) { Debug.Assert(random != null, "Missing random object"); var buffer = new float[xDim * yDim]; // Mapping to rows --- Column-major storage --- rows will the leading dimension // The larger dimension vectors will be orthogonal; the cols dimension vectors will be normalized if (!orthonormalize) { // Generate normalized vectors along the cols dim if (axisToNormalize == AxisToNormalizeEnum.xDim) { GenerateRandomNormalVectors(buffer, random, xDim, yDim); // Transpose to the correct position Transpose(ref buffer, xDim, yDim); } else { GenerateRandomNormalVectors(buffer, random, yDim, xDim); } } else { int largerDim = Math.Max(xDim, yDim); int smallerDim = Math.Min(xDim, yDim); // Generate vectors with larger leading dimension GenerateRandomNormalVectors(buffer, random, largerDim, smallerDim, normalize: false); // Orthonormalize along the larger dimension OrthonormalizeVectors(buffer, largerDim, smallerDim); if (xDim > yDim) { // cols is leading and is normalized // We need to transpose to get the correct dims Transpose(ref buffer, largerDim, smallerDim); if (axisToNormalize == AxisToNormalizeEnum.xDim) NormalizeLeadingDim(buffer, yDim, xDim); } else { // rows is leading and is normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.yDim) { // TODO: SMELLY VERSION: Transpose(ref buffer, yDim, xDim); NormalizeLeadingDim(buffer, xDim, yDim); Transpose(ref buffer, xDim, yDim); } } } return buffer; }
/// <summary> /// Generates a matrix with <paramref name="xDim"/> being the leading dimension in column-major storage. /// </summary> /// <param name="unmanagedVectors">A memory block to store the generated matrix. /// Must be as large as <paramref name="xDim"/> x <paramref name="yDim"/>.</param> /// <param name="unmanagedBaseVectors">A temporary block to store all the base vectors. /// Must be as large as Max(<paramref name="xDim"/>, <paramref name="yDim"/>)^2. /// Only neccessary when <paramref name="mode"/> is set to <see cref="VectorGenerationMode.AverageBaseVectors"/>.</param> /// <param name="temp">The temporary storage. It should be as long as the longer of the dimensions.</param> /// <param name="random">The random object for number generation.</param> /// <param name="xDim">The size of the other dimension.</param> /// <param name="yDim">The size of the leading dimension.</param> /// <param name="mode">If true, the vectors along the longer dimension will be orthonormalized.</param> /// <param name="axisToNormalize">The axis along which to normalize vectors after orthonormalization.</param> public static void GenerateTransformMatrix( MyMemoryBlock <float> unmanagedVectors, MyMemoryBlock <float> unmanagedBaseVectors, MyMemoryBlock <float> temp, Random random, int xDim, int yDim, MyCudaKernel dotKernel, MyCudaKernel multKernel, MyCudaKernel transposeKernel, int GPU, VectorGenerationMode mode = VectorGenerationMode.Normal, AxisToNormalizeEnum axisToNormalize = AxisToNormalizeEnum.yDim) { Debug.Assert(random != null, "Missing random object"); Debug.Assert(unmanagedVectors != null && (mode != VectorGenerationMode.AverageBaseVectors || unmanagedBaseVectors != null) && temp != null, "Missing data!"); Debug.Assert(dotKernel != null && multKernel != null && transposeKernel != null, "Missing a kernel!"); // Mapping to rows --- Column-major storage --- rows will the leading dimension // The larger dimension vectors will be orthogonal; the cols dimension vectors will be normalized switch (mode) { case VectorGenerationMode.Normal: if (axisToNormalize == AxisToNormalizeEnum.xDim) { // Generate normalized vectors with xDim as the leading dim GenerateRandomNormalVectors(unmanagedVectors.Host, random, xDim, yDim); unmanagedVectors.SafeCopyToDevice(); // Transpose to the correct position transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { GenerateRandomNormalVectors(unmanagedVectors.Host, random, yDim, xDim); unmanagedVectors.SafeCopyToDevice(); } break; case VectorGenerationMode.Orthonormalize: int largerDim = Math.Max(xDim, yDim); int smallerDim = Math.Min(xDim, yDim); // Generate vectors with larger leading dimension GenerateRandomNormalVectors(unmanagedVectors.Host, random, largerDim, smallerDim, normalize: false); unmanagedVectors.SafeCopyToDevice(); // Orthonormalize along the larger dimension OrthonormalizeVectors(unmanagedVectors, temp, largerDim, smallerDim, dotKernel, multKernel, GPU); if (xDim > yDim) { // xDim is leading and is normalized // We need to transpose to get the correct dims transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); if (axisToNormalize == AxisToNormalizeEnum.yDim) { NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } } else { // yDim is leading and is normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.xDim) { // TODO: generate the matrix with transposed dims? // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; case VectorGenerationMode.AverageBaseVectors: int longerDim = Math.Max(xDim, yDim); int shorterDim = Math.Min(xDim, yDim); GenerateTransformMatrix( unmanagedBaseVectors, null, temp, random, longerDim, longerDim, dotKernel, multKernel, transposeKernel, GPU, VectorGenerationMode.Orthonormalize); if (shorterDim == longerDim) { break; } float it = 0f; float step = longerDim / (float)shorterDim; int beg, end = 0; for (int i = 0; i < shorterDim; i++) { beg = end; it += step; end = (int)it; var vect = unmanagedVectors.GetDevicePtr(GPU, i * longerDim); for (int j = beg; j < end; j++) { var baseVect = unmanagedBaseVectors.GetDevicePtr(GPU, j * longerDim); multKernel.Run(baseVect, vect, vect, (int)MyJoin.MyJoinOperation.Addition, longerDim, longerDim); } } if (xDim > yDim) { // xDim is leading and is not normalized // We need to transpose to get the correct dims if (axisToNormalize == AxisToNormalizeEnum.xDim) { NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } } else { // yDim is leading and is not normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.yDim) { NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } else { // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; } }
/// <summary> /// Generates a matrix with <paramref name="yDim"/> being the leading dimension in column-major storage. /// </summary> /// <param name="random">The random object for number generation.</param> /// <param name="xDim">The size of the leading dimension.</param> /// <param name="yDim">The size of the other dimension.</param> /// <param name="orthonormalize">If true, the vectors along the longer dimension will be orthonormalized.</param> /// <param name="axisToNormalize">The axis along which to normalize vectors after orthonormalization.</param> /// <returns>The generated matrix.</returns> public static float[] GenerateTransformMatrix(Random random, int xDim, int yDim, bool orthonormalize = false, AxisToNormalizeEnum axisToNormalize = AxisToNormalizeEnum.yDim) { Debug.Assert(random != null, "Missing random object"); var buffer = new float[xDim * yDim]; // Mapping to rows --- Column-major storage --- rows will the leading dimension // The larger dimension vectors will be orthogonal; the cols dimension vectors will be normalized if (!orthonormalize) { // Generate normalized vectors along the cols dim if (axisToNormalize == AxisToNormalizeEnum.xDim) { GenerateRandomNormalVectors(buffer, random, xDim, yDim); // Transpose to the correct position Transpose(ref buffer, xDim, yDim); } else { GenerateRandomNormalVectors(buffer, random, yDim, xDim); } } else { int largerDim = Math.Max(xDim, yDim); int smallerDim = Math.Min(xDim, yDim); // Generate vectors with larger leading dimension GenerateRandomNormalVectors(buffer, random, largerDim, smallerDim, normalize: false); // Orthonormalize along the larger dimension OrthonormalizeVectors(buffer, largerDim, smallerDim); if (xDim > yDim) { // cols is leading and is normalized // We need to transpose to get the correct dims Transpose(ref buffer, largerDim, smallerDim); if (axisToNormalize == AxisToNormalizeEnum.xDim) { NormalizeLeadingDim(buffer, yDim, xDim); } } else { // rows is leading and is normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.yDim) { // TODO: SMELLY VERSION: Transpose(ref buffer, yDim, xDim); NormalizeLeadingDim(buffer, xDim, yDim); Transpose(ref buffer, xDim, yDim); } } } return(buffer); }