Skip to content

Commit 91571b2

Browse files
committed
FEAT: Adding SGD, Adam, and RMSProp optimizers
- Moved zeroGrad to be part of Optimizer class - Renamed perceptron.cpp to xor.cpp - Modified xor example to run with SGD, Adam, or RMSProp optimizers
1 parent 52546fa commit 91571b2

File tree

8 files changed

+346
-25
lines changed

8 files changed

+346
-25
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ target_sources(afml
1919
src/nn/Modules/Module.cpp
2020
src/nn/Modules/Dropout.cpp
2121
src/nn/Init.cpp
22+
src/optim/Optimizers.cpp
2223
)
2324

2425
target_include_directories(afml

examples/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ endfunction(build_example)
1313
# build_example(Activations.cpp)
1414
# build_example(FFNet.cpp)
1515
# build_example(Node.cpp)
16-
build_example(perceptron.cpp)
16+
build_example(xor.cpp)
1717
# build_example(Weights.cpp)
1818
build_example(autograd.cpp)

examples/perceptron.cpp renamed to examples/xor.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,29 @@
99

1010
#include <af/autograd.h>
1111
#include <af/nn.h>
12+
#include <af/optim.h>
13+
14+
#include <string>
15+
#include <memory>
1216

1317
using namespace af;
1418
using namespace af::nn;
1519
using namespace af::autograd;
1620

17-
int main()
21+
int main(int argc, const char **args)
1822
{
23+
int optim_mode = 0;
24+
std::string optimizer_arg = std::string(args[1]);
25+
if (optimizer_arg == "--adam") {
26+
optim_mode = 1;
27+
} else if (optimizer_arg == "--rmsprop") {
28+
optim_mode = 2;
29+
}
30+
1931
const int inputSize = 2;
2032
const int outputSize = 1;
21-
const double lr = 0.1;
33+
const double lr = 0.01;
34+
const double mu = 0.1;
2235
const int numSamples = 4;
2336

2437
float hInput[] = {1, 1,
@@ -34,24 +47,35 @@ int main()
3447
auto in = af::array(inputSize, numSamples, hInput);
3548
auto out = af::array(outputSize, numSamples, hOutput);
3649

37-
nn::Sequential perceptron;
50+
nn::Sequential model;
3851

39-
perceptron.add(nn::Linear(inputSize, outputSize));
40-
perceptron.add(nn::Sigmoid());
52+
model.add(nn::Linear(inputSize, outputSize));
53+
model.add(nn::Sigmoid());
4154

4255
auto loss = nn::MeanSquaredError();
4356

57+
std::unique_ptr<optim::Optimizer> optim;
58+
59+
if (optimizer_arg == "--rmsprop") {
60+
optim = std::unique_ptr<optim::Optimizer>(new optim::RMSPropOptimizer(model.parameters(), lr));
61+
} else if (optimizer_arg == "--adam") {
62+
optim = std::unique_ptr<optim::Optimizer>(new optim::AdamOptimizer(model.parameters(), lr));
63+
} else {
64+
optim = std::unique_ptr<optim::Optimizer>(new optim::SGDOptimizer(model.parameters(), lr, mu));
65+
}
66+
4467
Variable result, l;
4568
for (int i = 0; i < 1000; i++) {
4669
for (int j = 0; j < numSamples; j++) {
47-
perceptron.train();
48-
perceptron.zeroGrad();
70+
71+
model.train();
72+
optim->zeroGrad();
4973

5074
af::array in_j = in(af::span, j);
5175
af::array out_j = out(af::span, j);
5276

5377
// Forward propagation
54-
result = perceptron(nn::input(in_j));
78+
result = model(nn::input(in_j));
5579

5680
// Calculate loss
5781
l = loss(result, nn::noGrad(out_j));
@@ -60,18 +84,14 @@ int main()
6084
l.backward();
6185

6286
// Update parameters
63-
// TODO: Should use optimizer
64-
for (auto &param : perceptron.parameters()) {
65-
param.array() -= lr * param.grad().array();
66-
param.array().eval();
67-
}
87+
optim->update();
6888
}
6989

7090
if ((i + 1) % 100 == 0) {
71-
perceptron.eval();
91+
model.eval();
7292

7393
// Forward propagation
74-
result = perceptron(nn::input(in));
94+
result = model(nn::input(in));
7595

7696
// Calculate loss
7797
// TODO: Use loss function

include/af/nn/Modules/Module.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ namespace af
3535

3636
std::vector<autograd::Variable> parameters();
3737

38-
void zeroGrad();
39-
4038
void train();
4139

4240
void eval();

include/af/optim.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*******************************************************
2+
* Copyright (c) 2017, ArrayFire
3+
* All rights reserved.
4+
*
5+
* This file is distributed under 3-clause BSD license.
6+
* The complete license agreement can be obtained at:
7+
* http://arrayfire.com/licenses/BSD-3-Clause
8+
********************************************************/
9+
#include <af/optim/Optimizers.hpp>

include/af/optim/Optimizers.hpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*******************************************************
2+
* Copyright (c) 2017, ArrayFire
3+
* All rights reserved.
4+
*
5+
* This file is distributed under 3-clause BSD license.
6+
* The complete license agreement can be obtained at:
7+
* http://arrayfire.com/licenses/BSD-3-Clause
8+
********************************************************/
9+
10+
#pragma once
11+
12+
#include <af/autograd/Variable.hpp>
13+
#include <arrayfire.h>
14+
15+
#include <vector>
16+
17+
namespace af
18+
{
19+
namespace optim
20+
{
21+
22+
class Optimizer
23+
{
24+
protected:
25+
std::vector<autograd::Variable> m_parameters;
26+
public:
27+
28+
Optimizer(const std::vector<autograd::Variable> &parameters);
29+
30+
virtual void update() = 0;
31+
32+
void zeroGrad();
33+
};
34+
35+
class SGDOptimizer : public Optimizer
36+
{
37+
bool m_use_nesterov;
38+
double m_lr;
39+
double m_mu;
40+
double m_wd;
41+
std::vector<af::array> m_velocities;
42+
public:
43+
SGDOptimizer(const std::vector<autograd::Variable> &parameters,
44+
double learning_rate, double momentum = 0,
45+
double weight_decay = 0,
46+
bool use_nesterov = false);
47+
void update();
48+
};
49+
50+
class AdamOptimizer : public Optimizer
51+
{
52+
double m_lr;
53+
double m_beta1;
54+
double m_beta2;
55+
double m_eps;
56+
double m_wd;
57+
int m_count;
58+
std::vector<af::array> m_biased_first;
59+
std::vector<af::array> m_biased_second;
60+
public:
61+
AdamOptimizer(const std::vector<autograd::Variable> &parameters,
62+
double learning_rate,
63+
double beta1 = 0.9,
64+
double beta2 = 0.999,
65+
double epsilon = 1E-8,
66+
double weight_decay = 0);
67+
void update();
68+
};
69+
70+
class RMSPropOptimizer : public Optimizer
71+
{
72+
bool m_use_first;
73+
double m_lr;
74+
double m_rho;
75+
double m_eps;
76+
double m_wd;
77+
std::vector<af::array> m_first;
78+
std::vector<af::array> m_second;
79+
public:
80+
RMSPropOptimizer(const std::vector<autograd::Variable> &parameters,
81+
double learning_rate,
82+
double rho = 0.99,
83+
double epsilon = 1E-8,
84+
double weight_decay = 0,
85+
bool use_first = false);
86+
void update();
87+
};
88+
89+
}
90+
}

src/nn/Modules/Module.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,6 @@ namespace af
5454
return m_parameters;
5555
}
5656

57-
void Module::zeroGrad()
58-
{
59-
for (auto &parameter : m_parameters) {
60-
parameter.zeroGrad();
61-
}
62-
}
63-
6457
Variable Module::operator()(const Variable &input)
6558
{
6659
return this->forward(input);

0 commit comments

Comments
 (0)