public static void FindsABParamsUsingLevenbergMarquardtForDefaultSettings() { const float expectedA = 1.5769434603113077f; const float expectedB = 0.8950608779109733f; var(a, b) = Umap.FindABParams(1, 0.1f); Assert.True(AreCloseEnough(a, expectedA)); Assert.True(AreCloseEnough(b, expectedB)); bool AreCloseEnough(float x, float y) => Math.Abs(x - y) < 0.01; }
public static void FindsNearestNeighbors() { var nNeighbors = 10; var umap = new Umap(random: new DeterministicRandomGenerator(42), numberOfNeighbors: nNeighbors); var(knnIndices, knnDistances) = umap.NearestNeighbors(TestData, progress => { }); Assert.Equal(knnDistances.Length, TestData.Length); Assert.Equal(knnIndices.Length, TestData.Length); Assert.Equal(knnDistances[0].Length, nNeighbors); Assert.Equal(knnIndices[0].Length, nNeighbors); }
// Main static void Main(string[] args) { // Download the MNIST data from Mr. YannAndréLeCun's web site using (var wc = new WebClient()) { if (!File.Exists(LABEL_FILE_NAME)) { wc.DownloadFile(LABEL_FILE_URL, LABEL_FILE_NAME); } if (!File.Exists(IMAGE_FILE_NAME)) { wc.DownloadFile(IMAGE_FILE_URL, IMAGE_FILE_NAME); } } // Load the MNIST labels var labels = GetLabels().ToArray(); // Load the MNIST image data var pixels = GetImages().ToArray(); // Dimension reduction with UMAP var umap = new Umap(); var epochs = umap.InitializeFit(pixels); for (var i = 0; i < epochs; ++i) { umap.Step(); } var embedding = umap.GetEmbedding().AsEnumerable(); // Convert the embedding into chart data var graph = new Graph.Scatter() { x = embedding.Select((o) => o[0]), y = embedding.Select((o) => o[1]), text = labels.Select((o) => o.ToString()), mode = "markers", marker = new Graph.Marker { color = labels, colorscale = "Rainbow", showscale = true }, }; var chart = Chart.Plot(graph); chart.WithTitle("MNIST Embedded via UMAP"); chart.WithXTitle("X"); chart.WithYTitle("Y"); chart.WithSize(800, 800); chart.Show(); }
public static void StepMethod3D() { var umap = new Umap(random: new DeterministicRandomGenerator(42), dimensions: 3); var nEpochs = umap.InitializeFit(TestData); for (var i = 0; i < nEpochs; i++) { umap.Step(); } var embedding = umap.GetEmbedding(); Assert.Equal(500, nEpochs); AssertNestedFloatArraysEquivalent(TestResults3D, embedding); }
static void Main() { // Note: The MNIST data here consist of normalized vectors (so the CosineForNormalizedVectors distance function can be safely used) var data = MessagePackSerializer.Deserialize <LabelledVector[]>(File.ReadAllBytes("MNIST-LabelledVectorArray-60000x100.msgpack")); data = data.Take(10_000).ToArray(); var timer = Stopwatch.StartNew(); var umap = new Umap(distance: Umap.DistanceFunctions.CosineForNormalizedVectors); Console.WriteLine("Initialize fit.."); var nEpochs = umap.InitializeFit(data.Select(entry => entry.Vector).ToArray()); Console.WriteLine("- Done"); Console.WriteLine(); Console.WriteLine("Calculating.."); for (var i = 0; i < nEpochs; i++) { umap.Step(); if ((i % 10) == 0) { Console.WriteLine($"- Completed {i + 1} of {nEpochs}"); } } Console.WriteLine("- Done"); var embeddings = umap.GetEmbedding() .Select(vector => new { X = vector[0], Y = vector[1] }) .ToArray(); timer.Stop(); Console.WriteLine("Time taken: " + timer.Elapsed); // Fit the vectors to a 0-1 range (this isn't necessary if feeding these values down from a server to a browser to draw with Plotly because ronend because Plotly scales the axes to the data) var minX = embeddings.Min(vector => vector.X); var rangeX = embeddings.Max(vector => vector.X) - minX; var minY = embeddings.Min(vector => vector.Y); var rangeY = embeddings.Max(vector => vector.Y) - minY; var scaledEmbeddings = embeddings .Select(vector => new { X = (vector.X - minX) / rangeX, Y = (vector.Y - minY) / rangeY }) .ToArray(); const int width = 1600; const int height = 1200; using (var bitmap = new Bitmap(width, height)) { using (var g = Graphics.FromImage(bitmap)) { g.FillRectangle(Brushes.DarkBlue, 0, 0, width, height); g.SmoothingMode = SmoothingMode.HighQuality; g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; using (var font = new Font("Tahoma", 6)) { foreach (var(vector, uid) in scaledEmbeddings.Zip(data, (vector, entry) => (vector, entry.UID))) { g.DrawString(uid, font, Brushes.White, vector.X * width, vector.Y * height); } } } bitmap.Save("Output-Label.png"); } var colors = "#006400,#00008b,#b03060,#ff4500,#ffd700,#7fff00,#00ffff,#ff00ff,#6495ed,#ffdab9" .Split(',') .Select(c => ColorTranslator.FromHtml(c)) .Select(c => new SolidBrush(c)) .ToArray(); using (var bitmap = new Bitmap(width, height)) { using (var g = Graphics.FromImage(bitmap)) { g.FillRectangle(Brushes.White, 0, 0, width, height); g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; foreach (var(vector, uid) in scaledEmbeddings.Zip(data, (vector, entry) => (vector, entry.UID))) { g.FillEllipse(colors[int.Parse(uid)], vector.X * width, vector.Y * height, 5, 5); } } bitmap.Save("Output-Color.png"); } Console.WriteLine("Generated visualisation images"); Console.WriteLine("Press [Enter] to terminate.."); Console.ReadLine(); }