public static Array <Real> Min(this Array <Real> a, int axis, bool keepDims = false, Array <Real> result = null) { if (axis < 0) { axis = a.Shape.Length + axis; } result = result ?? NN.Zeros <Real>(GetAggregatorResultShape(a, axis, keepDims)); bool firstTime = true; foreach (var row in a.UnsafeRows(axis, keepDims)) { if (firstTime) { result._ = row; firstTime = false; } else { NN.Apply(result, row, (x, y) => Math.Min(x, y), result: result); } } return(result); }
public Tsne(Array <float> X_, int dims, float perplexity) { X_.AssertOfDim(2); int n = X_.Shape[0]; X = T.Shared(X_, "X"); Y = T.Shared(NN.Random.Uniform(-1f, 1f, n, dims), "Y"); YMomentum = T.Shared(NN.Zeros(n, dims), "YMomentum"); dYLast = T.Shared(NN.Zeros(n, dims), "dYLast"); // ones everywhere, zero on the diag mask = T.Shared(NN.Ones(n, n) - NN.Eye(n), "mask"); // Compute pairwise affinities var sum_Y = T.Sum(Y * Y, 1, keepDims: true); var num = 1 / (1 - T.DimShuffle((2 * T.Dot(Y, Y, transposeY: true) + sum_Y), 1, 0) + sum_Y); // set the diag to zero num *= mask; var Q = num / T.Sum(num); //Q = T.Max(Q, 1e-12f); var P_ = x2p(X_, 1e-5f, perplexity); P_ = P_ * 4f; // early exaggeration P_ = NN.Apply(P_, x => Math.Max(x, 1e-12f)); P = T.Shared(P_, "P"); KL_Loss = T.Sum(P * T.Log(P / Q)); dY = T.Function(output: T.Grad(KL_Loss, Y)); Loss = T.Function(output: KL_Loss); var updates = MomentumUpdate(Y, YMomentum, dYLast, T.Grad(KL_Loss, Y), 500); Train = T.Function(updates); }
public void CompareElementWisePerformance() { Trace.Listeners.Add(new ConsoleTraceListener()); Func <float, float, float> f = (x, y) => x + y; var clock = new Stopwatch(); #if DEBUG Trace.WriteLine($"Testing on DEBUG"); #else Trace.WriteLine($"Testing on RELEASE"); #endif Trace.WriteLine($"Testing on {Blas.NThreads} threads"); for (int i = 0; i < 300; ++i) { int n = i + 1; var a = NN.Random.Uniform(-1f, 1f, n, n); var b = NN.Random.Uniform(-1f, 1f, n, n); var r = NN.Zeros(n, n); var size = a.Size; // estimating loop count for this size NN.MIN_SIZE_FOR_PARELLELISM = size * 2; var loopCount = 0; clock.Restart(); while (clock.ElapsedMilliseconds < 1000) { NN.Apply(a, b, f, result: r); ++loopCount; } Trace.WriteLine($"doing {loopCount} loops for size {size}"); // profiling Normal clock.Restart(); for (int _ = 0; _ < loopCount; _++) { NN.Apply(a, b, f, result: r); } var time = clock.ElapsedMilliseconds; var avg = (double)time / loopCount; // profiling Parrellized NN.MIN_SIZE_FOR_PARELLELISM = 0; clock.Restart(); for (int _ = 0; _ < loopCount; _++) { NN.Apply(a, b, f, result: r); } var timePar = clock.ElapsedMilliseconds; var avgPar = (double)timePar / loopCount; clock.Restart(); for (int _ = 0; _ < loopCount; _++) { a.Add(b, result: r); } var timeAdd = clock.ElapsedMilliseconds; var avgAdd = (double)timeAdd / loopCount; clock.Restart(); for (int _ = 0; _ < loopCount; _++) { Blas.vadd(size, a.Values, 0, b.Values, 0, r.Values, 0); } var timeBlas = clock.ElapsedMilliseconds; var avgBlas = (double)timeBlas / loopCount; var message = $"On size {size}, avg time: {avg:F4}ms \t with parallelism {avgPar:F4}ms \t with Add {avgAdd:F4}ms \t with Blas {avgBlas:F4}ms."; Trace.WriteLine(message); } throw new Exception("see output for profiler results"); }