-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmulti_output.h
More file actions
160 lines (131 loc) · 4.94 KB
/
Copy pathmulti_output.h
File metadata and controls
160 lines (131 loc) · 4.94 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#pragma once
#include "helpers/errorcalculation.h"
#include "common/logger.h"
#include "neuralnetwork.h"
#include "helper.h"
#include <vector>
#include <cmath>
#include <iomanip>
/**
* ExampleMultiOutput
*
* This example demonstrates a neural network with multiple logical output layers
* using different activation functions:
* 1. Sigmoid Output: Classification (Is the input value positive?)
* 2. Tanh Output: Regression (Mapping input to a symmetric range [-1, 1])
*
* The network will learn to:
* - Output ~1.0 if x > 0, ~0.0 if x < 0 (Sigmoid)
* - Output tanh(x) as a regression value (Tanh)
*/
using namespace myoddweb::nn;
class ExampleMultiOutput
{
private:
static NeuralNetwork* create_neural_network(Logger::LogLevel log_level)
{
MYODDWEB_PROFILE_FUNCTION("ExampleMultiOutput");
// Input: 1 value
// Hidden: 8, 8
// Output: 2 (1 for Sigmoid, 1 for Tanh)
std::vector<unsigned> topology = { 1, 8, 8, 2 };
std::vector<LayerDetails> hidden_layers = {
LayerDetails(Layer::Architecture::FF, 8, activation(activation::method::tanh, 1.0), 0.0, 0.5, OptimiserType::NadamW, 0.9),
LayerDetails(Layer::Architecture::FF, 8, activation(activation::method::tanh, 1.0), 0.0, 0.5, OptimiserType::NadamW, 0.9)
};
// Define multiple output layers
auto output_layers = {
// First output: Sigmoid (Classification: Is positive?)
OutputLayerDetails(1, activation(activation::method::sigmoid, 1.0), ErrorCalculation::type::mse, { 0.0, 0.0, 1.0, 0.0, false, 1.0 }, 0.001, OptimiserType::NadamW, 0.99),
// Second output: Tanh (Regression: Scaled value)
OutputLayerDetails(1, activation(activation::method::tanh, 1.0), ErrorCalculation::type::mse, { 0.0, 0.0, 1.0, 0.0, false, 1.0 }, 0.001, OptimiserType::NadamW, 0.9)
};
auto options = NeuralNetworkOptions::create(topology)
.with_batch_size(16)
.with_output_layer_details(output_layers)
.with_log_level(log_level)
.with_learning_rate(0.01)
.with_number_of_epoch(1000)
.with_hidden_layers(hidden_layers)
.build();
return new NeuralNetwork(options);
}
static void generate_data(std::vector<std::vector<double>>& inputs, std::vector<std::vector<double>>& outputs, size_t count)
{
MYODDWEB_PROFILE_FUNCTION("ExampleMultiOutput");
inputs.reserve(count);
outputs.reserve(count);
for (size_t i = 0; i < count; ++i)
{
// Random value between -2.0 and 2.0
double x = ((double)rand() / RAND_MAX) * 4.0 - 2.0;
inputs.push_back({ x });
// Target 1: Is positive? (Sigmoid: 0 or 1)
double y1 = (x > 0) ? 1.0 : 0.0;
// Target 2: Tanh of x (Tanh: -1 to 1)
double y2 = std::tanh(x);
outputs.push_back({ y1, y2 });
}
}
static bool run_tests(NeuralNetwork& nn)
{
MYODDWEB_PROFILE_FUNCTION("ExampleMultiOutput");
Logger::info("Running validation tests...");
struct TestCase {
double input;
double exp_class;
double exp_reg;
};
std::vector<TestCase> tests = {
{ 1.5, 1.0, std::tanh(1.5) },
{ -1.5, 0.0, std::tanh(-1.5) },
{ 0.5, 1.0, std::tanh(0.5) },
{ -0.5, 0.0, std::tanh(-0.5) }
};
bool all_passed = true;
const double tolerance = 0.15;
for (const auto& test : tests)
{
auto result = nn.think({ test.input });
double got_class = result[0];
double got_reg = result[1];
bool class_ok = std::abs(got_class - test.exp_class) < tolerance;
bool reg_ok = std::abs(got_reg - test.exp_reg) < tolerance;
Logger::info("Input: ", std::fixed, std::setprecision(2), test.input,
" | Class: ", std::fixed, std::setprecision(4), got_class, " (exp ", test.exp_class, ") ", (class_ok ? "[OK]" : "[FAIL]"),
" | Reg: ", std::fixed, std::setprecision(4), got_reg, " (exp ", test.exp_reg, ") ", (reg_ok ? "[OK]" : "[FAIL]"));
if (!class_ok || !reg_ok)
{
all_passed = false;
}
}
return all_passed;
}
public:
static void MultiOutput(Logger::LogLevel log_level)
{
TEST_START("Multi-Output Layer (Sigmoid + Tanh) Example")
srand(42); // Seed for reproducible results
NeuralNetwork* nn = create_neural_network(log_level);
std::vector<std::vector<double>> training_inputs;
std::vector<std::vector<double>> training_outputs;
generate_data(training_inputs, training_outputs, 500);
Logger::info("Training network with multiple output layers...");
nn->train(training_inputs, training_outputs);
bool success = run_tests(*nn);
if (success)
{
Logger::info("*********************************");
Logger::info("* OVERALL STATUS: SUCCESS *");
Logger::info("*********************************");
}
else
{
Logger::error("*********************************");
Logger::error("* OVERALL STATUS: FAILURE *");
Logger::error("*********************************");
}
delete nn;
TEST_END
}
};