-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathregression.cpp
98 lines (77 loc) · 2.59 KB
/
regression.cpp
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
#include "toytorch.h"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// https://github.com/pytorch/examples/blob/main/cpp/regression/regression.cpp
#define POLY_DEGREE 4
// Builds features i.e. a matrix with columns [x, x^2, x^3, x^4].
toytorch::Tensor make_features(toytorch::Tensor x) {
x = x.unsqueeze(1);
std::vector<toytorch::Tensor> xs;
for (int64_t i = 0; i < POLY_DEGREE; ++i)
xs.push_back(x.pow(i + 1));
return toytorch::cat(xs, 1);
}
// Approximated function.
toytorch::Tensor f(
toytorch::Tensor x,
toytorch::Tensor W_target,
toytorch::Tensor b_target) {
return matmul(x, W_target) + b_target;
}
// Creates a string description of a polynomial.
std::string poly_desc(toytorch::Tensor W, toytorch::Tensor b) {
auto size = W.shape()[0];
std::ostringstream stream;
stream << "y = ";
for (int64_t i = 0; i < size; ++i)
stream << W[i] << " x^" << size - i << " ";
stream << "+ " << b[0];
return stream.str();
}
// Builds a batch i.e. (x, f(x)) pair.
std::pair<toytorch::Tensor, toytorch::Tensor> get_batch(
toytorch::Tensor W_target,
toytorch::Tensor b_target,
int batch_size = 32) {
auto random = toytorch::randn({batch_size});
auto x = make_features(random); // x : [32, 4]
auto y = f(x, W_target, b_target);//
return std::make_pair(x, y);
}
int main() {
// This are the real parameters that we need to prodict
auto W_target = toytorch::randn({POLY_DEGREE, 1}) * 5;
auto b_target = toytorch::randn({1}) * 5;
// Define a linear layer to approximate the W_target and b_target
auto fc = toytorch::nn::Linear(W_target.shape()[0], 1);
toytorch::optim::SGD optim(fc.parameters(), toytorch::optim::SGDOptions(1e-3));
float loss = 0;
int64_t batch_idx = 0;
while (++batch_idx) {
// Get data
toytorch::Tensor batch_x, batch_y;
std::tie(batch_x, batch_y) = get_batch(W_target, b_target);
// Reset gradients
optim.zero_grad();
// Forward pass
auto loss_tensor = toytorch::smooth_l1_loss(fc.forward(batch_x), batch_y);
loss = loss_tensor[0];
// Backward pass
loss_tensor.backward();
// Apply gradients
optim.step();
// std::cout << "loss:" << loss << std::endl;
// Stop criterion
if (loss < 1e-3f)
break;
}
std::cout << "Loss: " << loss << " after " << batch_idx << " batches"
<< std::endl;
std::cout << "==> Learned function:\t"
<< poly_desc(fc.weights().view({-1}), fc.bias()) << std::endl;
std::cout << "==> Actual function:\t"
<< poly_desc(W_target.view({-1}), b_target) << std::endl;
return 0;
}