Repository navigation
Expand file tree
/
Copy pathProgram.cs
More file actions
101 lines (89 loc) · 3.48 KB
/
Copy pathProgram.cs
File metadata and controls
101 lines (89 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
using DLFramework;
using DLFramework.Layers;
using DLFramework.Layers.Loss;
using DLFramework.Optimizers;
using LinearAlgebra;
/// <summary>
/// Fits y = sin(x) on [-pi, pi] with a small MLP trained end-to-end by the
/// TAS autograd engine, then draws the target curve and the network's
/// prediction side by side in the terminal. Regression, not classification:
/// note the output layer has no activation.
/// </summary>
class MainClass
{
public static void Main(string[] args)
{
int epochs = args.Length > 0 ? int.Parse(args[0]) : 4000;
var r = new Random(0);
//-----------DATA: n points of the sine curve
int n = 64;
var x = new Matrix(n, 1);
var y = new Matrix(n, 1);
for (int i = 0; i < n; i++)
{
x[i, 0] = -Math.PI + 2 * Math.PI * i / (n - 1);
y[i, 0] = Math.Sin(x[i, 0]);
}
var data = new Tensor(x);
var target = new Tensor(y);
//-----------MODEL: 1 -> 16 -> 16 -> 1, linear output for regression
var model = new Sequential();
model.Layers.Add(new Linear(1, 16, r));
model.Layers.Add(new SigmoidLayer());
model.Layers.Add(new Linear(16, 16, r));
model.Layers.Add(new SigmoidLayer());
model.Layers.Add(new Linear(16, 1, r));
var sgd = new StochasticGradientDescent(model.Parameters, alpha: 0.005);
var mse = new MeanSquaredError();
//-----------TRAIN
for (int epoch = 1; epoch <= epochs; epoch++)
{
var prediction = model.Forward(data);
var loss = mse.Forward(prediction, target);
loss.Backward();
sgd.Step();
if (epoch % (epochs / 8) == 0)
{
Console.WriteLine($"Epoch {epoch} | Loss per point: {loss.Data[0, 0] / n:0.00000}");
}
}
//-----------PLOT: target (·) vs what the network learned (*)
Console.WriteLine();
Plot(model, width: 64, height: 17);
}
static void Plot(Sequential model, int width, int height)
{
// One forward pass over an x grid covering the plot columns
var grid = new Matrix(width, 1);
for (int col = 0; col < width; col++)
{
grid[col, 0] = -Math.PI + 2 * Math.PI * col / (width - 1);
}
Matrix predicted = model.Forward(new Tensor(grid)).Data;
var canvas = new char[height, width];
for (int row = 0; row < height; row++)
for (int col = 0; col < width; col++)
canvas[row, col] = row == height / 2 ? '-' : ' ';
for (int col = 0; col < width; col++)
{
int targetRow = ToRow(Math.Sin(grid[col, 0]), height);
int predictedRow = ToRow(predicted[col, 0], height);
canvas[targetRow, col] = '·';
canvas[predictedRow, col] = canvas[predictedRow, col] == '·' ? '@' : '*';
}
Console.WriteLine($"y = sin(x) on [-pi, pi] (· target, * network, @ overlap)");
for (int row = 0; row < height; row++)
{
var line = new char[width];
for (int col = 0; col < width; col++) line[col] = canvas[row, col];
Console.WriteLine(new string(line));
}
}
/// <summary>Maps y in [-1.2, 1.2] to a canvas row (top row is +1.2).</summary>
static int ToRow(double value, int height)
{
int row = (int)Math.Round((1.2 - value) / 2.4 * (height - 1));
return Math.Max(0, Math.Min(height - 1, row));
}
}