History

initial release

Yusong Gao committed 2 years ago

Commit d0d49a9No parent (first commit)21 files · +8268 −0Browse files

Showing the changes to example/tinytorch_example.cpp (1 of 21 files). Show all

Unified · Split

example/tinytorch_example.cpp+149−0
@@ -0,0 +1,149 @@
1#include <cstddef>
2#include <iostream>
3#include <vector>
4
5#include "../tinytorch.hpp"
6
7namespace tt = tinytorch;
8using namespace std; // NOLINT
9
10// let's create a neural network to approximate the following function
11int classify_fruit(float color, float size, float weight) {
12 // color in [0, 1] where 0 represents green and 1 represents red
13 // size in [0, 1] where 0 represents small and 1 represents large
14 // weight in [0, 1] where 0 represents light and 1 represents heavy
15 // y in [0, 3] representing three types of fruits: apple, orange, and banana
16
17 double y = 0.8 * color + 1.0 * size + 1.0 * weight;
18
19 if (y < 0.9) {
20 return 0; // Apple
21 } else if (y < 1.8) {
22 return 1; // Orange
23 } else {
24 return 2; // Banana
25 }
26}
27
28tuple<vector<float>, int> generate_case() {
29 float x0 = (float)rand() / RAND_MAX;
30 float x1 = (float)rand() / RAND_MAX;
31 float x2 = (float)rand() / RAND_MAX;
32 int y = classify_fruit(x0, x1, x2);
33 return {{x0, x1, x2}, y};
34}
35
36tuple<vector<vector<float>>, vector<int>, vector<vector<float>>, vector<int>> generate_dataset(
37 int train_size, int val_size) {
38 vector<vector<float>> train_inputs, val_inputs;
39 vector<int> train_targets, val_targets;
40 for (int i = 0; i < train_size; i++) {
41 auto [x, y] = generate_case();
42 train_inputs.push_back(x);
43 train_targets.push_back(y);
44 }
45 for (int i = 0; i < val_size; i++) {
46 auto [x, y] = generate_case();
47 val_inputs.push_back(x);
48 val_targets.push_back(y);
49 }
50 return {train_inputs, train_targets, val_inputs, val_targets};
51}
52
53int main() {
54 // create a context to hold all the tensors
55 tt::TensorContext ctx((size_t)1024 * 1024);
56
57 // generate some random data
58 int train_size = 10000, val_size = 100;
59 auto [train_inputs, train_targets, val_inputs, val_targets] =
60 generate_dataset(train_size, val_size);
61
62 // create a simple one hidden layer neural network
63 int variables = 3; // number of input variables
64 int neurons = 32; // number of neurons in the hidden layer
65 int classes = 3; // number of classes
66
67 // input and target tensors
68 auto &x = *ctx.NewTensor({1, variables});
69 auto &y = *ctx.NewTensor({1}, tt::kI32);
70 // parameters
71 auto &W1 = *ctx.NewTensor({neurons, variables})->RandomNorm();
72 auto &b1 = *ctx.NewTensor({neurons})->RandomNorm();
73 auto &W2 = *ctx.NewTensor({classes, neurons})->RandomNorm();
74 auto &b2 = *ctx.NewTensor({classes})->RandomNorm();
75 vector<tt::Tensor *> params = {&W1, &b1, &W2, &b2};
76 // create the computation graph
77 auto &hidden = (x.MatMul(W1) + b1).Gelu();
78 auto &logits = hidden.MatMul(W2) + b2;
79 auto &probs = logits.Softmax();
80 auto &loss = probs.CrossEntropy(y);
81
82 float learning_rate = 0.001;
83 float training_loss = 0;
84
85 // train the model
86 for (int step = 0; step < 30000; step++) {
87 if (step % 1000 == 0) {
88 // evaluate the model on the validation set
89 float val_loss = 0;
90 for (int i = 0; i < val_size; i++) {
91 x.Fill(val_inputs[i]);
92 y.Fill(val_targets[i]);
93 loss.Forward();
94 val_loss += loss.Flatten()[0];
95 }
96 std::cout << "step " << step << ", val_loss: " << val_loss / val_size << std::endl;
97 }
98
99 // pick a random training case
100 int casei = rand() % train_size;
101 x.Fill(train_inputs[casei]);
102 y.Fill(train_targets[casei]);
103
104 // forward and backward
105 loss.Forward();
106 loss.ZeroGrad();
107 loss.Backward();
108
109 // update the parameters
110 for (auto param : params) {
111 auto weights = (float *)param->data();
112 auto grads = (float *)param->grad()->data();
113 for (int i = 0; i < param->NumElements(); i++) {
114 weights[i] -= learning_rate * grads[i];
115 }
116 }
117
118 training_loss = loss.Flatten()[0];
119 }
120
121 std::cout << "training loss: " << training_loss << std::endl;
122
123 // test the model
124 for (int i = 0; i < 30; i++) {
125 auto [testx, y_truth] = generate_case();
126 x.Fill(testx);
127 probs.Forward();
128
129 // find the class with the highest probability
130 auto probs_data = probs.Flatten();
131 int y_pred = 0;
132 for (int j = 0; j < classes; j++) {
133 if (probs_data[j] > probs_data[y_pred]) {
134 y_pred = j;
135 }
136 }
137
138 std::cout << "test case " << i << ", x: " << testx[0] << ", " << testx[1] << ", "
139 << testx[2] << ", y_truth: " << y_truth << ", y_pred: " << y_pred;
140 if (y_truth == y_pred) {
141 std::cout << " (correct)";
142 } else {
143 std::cout << " (wrong)";
144 }
145 std::cout << endl;
146 }
147
148 return 0;
149}