mirror of
https://github.com/davidalbertonogueira/MLP.git
synced 2025-12-16 20:07:07 +03:00
added posibility to change internal weights of the network directly
assigning the values
This commit is contained in:
1
.settings/.gitignore
vendored
Normal file
1
.settings/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/language.settings.xml
|
||||
3
Makefile
3
Makefile
@@ -14,7 +14,8 @@ AUXLIBS =
|
||||
INCLUDES = -I$(LOCALDEPSINCLUDES) -I$(AUXINCLUDES)
|
||||
LIBS = -L$(AUXLIBS)
|
||||
#LIBS += -L/usr/local/lib/
|
||||
CFLAGS = -std=gnu++11 -std=c++11 -Wall -O3 -fmessage-length=0 -fPIC $(INCLUDES)
|
||||
#rlunaro: removed optimization for tests: -O3
|
||||
CFLAGS = -std=gnu++11 -std=c++11 -Wall -fmessage-length=0 -fPIC $(INCLUDES)
|
||||
CFLAGS += $(DEBUG)
|
||||
LFLAGS = $(LIBS)
|
||||
#For verbosity
|
||||
|
||||
5
src/.gitignore
vendored
Normal file
5
src/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/IrisDatasetTest.o
|
||||
/LayerTest.o
|
||||
/MLP.o
|
||||
/MLPTest.o
|
||||
/NodeTest.o
|
||||
24
src/Layer.h
24
src/Layer.h
@@ -68,6 +68,14 @@ public:
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal list of nodes, but modifiable.
|
||||
*/
|
||||
std::vector<Node> & GetNodesChangeable() {
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
|
||||
void GetOutputAfterActivationFunction(const std::vector<double> &input,
|
||||
std::vector<double> * output) const {
|
||||
assert(input.size() == m_num_inputs_per_node);
|
||||
@@ -116,6 +124,22 @@ public:
|
||||
};
|
||||
|
||||
|
||||
void SetWeights( std::vector<std::vector<double>> & weights )
|
||||
{
|
||||
if( 0 <= weights.size() && weights.size() <= m_num_nodes )
|
||||
{
|
||||
// traverse the list of nodes
|
||||
size_t node_i = 0;
|
||||
for( Node & node : m_nodes )
|
||||
{
|
||||
node.SetWeights( weights[node_i] );
|
||||
node_i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new std::logic_error("Incorrect layer number in SetWeights call");
|
||||
};
|
||||
|
||||
void SaveLayer(FILE * file) const {
|
||||
fwrite(&m_num_nodes, sizeof(m_num_nodes), 1, file);
|
||||
fwrite(&m_num_inputs_per_node, sizeof(m_num_inputs_per_node), 1, file);
|
||||
|
||||
43
src/MLP.cpp
43
src/MLP.cpp
@@ -48,7 +48,7 @@ void MLP::CreateMLP(const std::vector<uint64_t> & layers_nodes,
|
||||
m_num_outputs = m_layers_nodes[m_layers_nodes.size() - 1];
|
||||
m_num_hidden_layers = m_layers_nodes.size() - 2;
|
||||
|
||||
for (int i = 0; i < m_layers_nodes.size() - 1; i++) {
|
||||
for (size_t i = 0; i < m_layers_nodes.size() - 1; i++) {
|
||||
m_layers.emplace_back(Layer(m_layers_nodes[i],
|
||||
m_layers_nodes[i + 1],
|
||||
layers_activfuncs[i],
|
||||
@@ -65,7 +65,7 @@ void MLP::SaveMLPNetwork(const std::string & filename)const {
|
||||
fwrite(&m_num_hidden_layers, sizeof(m_num_hidden_layers), 1, file);
|
||||
if (!m_layers_nodes.empty())
|
||||
fwrite(&m_layers_nodes[0], sizeof(m_layers_nodes[0]), m_layers_nodes.size(), file);
|
||||
for (int i = 0; i < m_layers.size(); i++) {
|
||||
for (size_t i = 0; i < m_layers.size(); i++) {
|
||||
m_layers[i].SaveLayer(file);
|
||||
}
|
||||
fclose(file);
|
||||
@@ -83,7 +83,7 @@ void MLP::LoadMLPNetwork(const std::string & filename) {
|
||||
if (!m_layers_nodes.empty())
|
||||
fread(&m_layers_nodes[0], sizeof(m_layers_nodes[0]), m_layers_nodes.size(), file);
|
||||
m_layers.resize(m_layers_nodes.size() - 1);
|
||||
for (int i = 0; i < m_layers.size(); i++) {
|
||||
for (size_t i = 0; i < m_layers.size(); i++) {
|
||||
m_layers[i].LoadLayer(file);
|
||||
}
|
||||
fclose(file);
|
||||
@@ -103,7 +103,7 @@ void MLP::GetOutput(const std::vector<double> &input,
|
||||
std::vector<double> temp_out(temp_size, 0.0);
|
||||
temp_in = input;
|
||||
|
||||
for (int i = 0; i < m_layers.size(); ++i) {
|
||||
for (size_t i = 0; i < m_layers.size(); ++i) {
|
||||
if (i > 0) {
|
||||
//Store this layer activation
|
||||
if (all_layers_activations != nullptr)
|
||||
@@ -260,3 +260,38 @@ void MLP::Train(const std::vector<TrainingSample> &training_sample_set_with_bias
|
||||
};
|
||||
|
||||
|
||||
size_t MLP::GetNumLayers()
|
||||
{
|
||||
return m_layers.size();
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> MLP::GetLayerWeights( size_t layer_i )
|
||||
{
|
||||
std::vector<std::vector<double>> ret_val;
|
||||
// check parameters
|
||||
if( 0 <= layer_i && layer_i < m_layers.size() )
|
||||
{
|
||||
Layer current_layer = m_layers[layer_i];
|
||||
for( Node & node : current_layer.GetNodesChangeable() )
|
||||
{
|
||||
ret_val.push_back( node.GetWeights() );
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
else
|
||||
throw new std::logic_error("Incorrect layer number in GetLayerWeights call");
|
||||
|
||||
}
|
||||
|
||||
void MLP::SetLayerWeights( size_t layer_i, std::vector<std::vector<double>> & weights )
|
||||
{
|
||||
// check parameters
|
||||
if( 0 <= layer_i && layer_i < m_layers.size() )
|
||||
{
|
||||
m_layers[layer_i].SetWeights( weights );
|
||||
}
|
||||
else
|
||||
throw new std::logic_error("Incorrect layer number in SetLayerWeights call");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
|
||||
class MLP {
|
||||
public:
|
||||
@@ -40,6 +41,9 @@ public:
|
||||
int max_iterations = 5000,
|
||||
double min_error_cost = 0.001,
|
||||
bool output_log = true);
|
||||
size_t GetNumLayers();
|
||||
std::vector<std::vector<double>> GetLayerWeights( size_t layer_i );
|
||||
void SetLayerWeights( size_t layer_i, std::vector<std::vector<double>> & weights );
|
||||
|
||||
protected:
|
||||
void UpdateWeights(const std::vector<std::vector<double>> & all_layers_activations,
|
||||
|
||||
@@ -317,6 +317,70 @@ UNIT(LearnX2) {
|
||||
LOG(INFO) << "Trained with success." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UNIT(GetWeightsSetWeights) {
|
||||
LOG(INFO) << "Train X2 function, read internal weights" << std::endl;
|
||||
|
||||
std::vector<TrainingSample> training_set =
|
||||
{
|
||||
{ { 0, 0 },{ 0.0 } },
|
||||
{ { 0, 1 },{ 1.0 } },
|
||||
{ { 1, 0 },{ 0.0 } },
|
||||
{ { 1, 1 },{ 1.0 } }
|
||||
};
|
||||
bool bias_already_in = false;
|
||||
std::vector<TrainingSample> training_sample_set_with_bias(training_set);
|
||||
//set up bias
|
||||
if (!bias_already_in) {
|
||||
for (auto & training_sample_with_bias : training_sample_set_with_bias) {
|
||||
training_sample_with_bias.AddBiasValue(1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t num_features = training_sample_set_with_bias[0].GetInputVectorSize();
|
||||
size_t num_outputs = training_sample_set_with_bias[0].GetOutputVectorSize();
|
||||
MLP my_mlp({ num_features, 2, num_outputs }, { "sigmoid", "linear" });
|
||||
//Train MLP
|
||||
my_mlp.Train(training_sample_set_with_bias, 0.5, 500, 0.25);
|
||||
|
||||
// get layer weights
|
||||
std::vector<std::vector<double>> weights = my_mlp.GetLayerWeights( 1 );
|
||||
|
||||
// the expected value of the internal weights
|
||||
// after training are 1.65693 -0.538749
|
||||
ASSERT_TRUE( 1.6 <= weights[0][0] && weights[0][0] <= 1.7 );
|
||||
ASSERT_TRUE( -0.6 <= weights[0][1] && weights[0][1] <= -0.5 );
|
||||
|
||||
// now, we are going to inject a weight value of 0.0
|
||||
// and check that the new output value is nonsense
|
||||
std::vector<std::vector<double>> zeroWeights = { { 0.0, 0.0 } };
|
||||
|
||||
my_mlp.SetLayerWeights( 1, zeroWeights );
|
||||
|
||||
/*
|
||||
*
|
||||
* PREDICTED OUTPUT IS NOW: 0.335394
|
||||
PREDICTED OUTPUT IS NOW: 1.13887
|
||||
PREDICTED OUTPUT IS NOW: 0.180468
|
||||
PREDICTED OUTPUT IS NOW: 1.00535
|
||||
*
|
||||
*/
|
||||
for (const auto & training_sample : training_sample_set_with_bias) {
|
||||
std::vector<double> output;
|
||||
my_mlp.GetOutput(training_sample.input_vector(), &output);
|
||||
for (size_t i = 0; i < num_outputs; i++) {
|
||||
bool predicted_output = output[i] > 0.5 ? true : false;
|
||||
std::cout << "PREDICTED OUTPUT IS NOW: " << output[i] << std::endl;
|
||||
bool correct_output = training_sample.output_vector()[i] > 0.5 ? true : false;
|
||||
ASSERT_TRUE(predicted_output == correct_output);
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Trained with success." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
START_EASYLOGGINGPP(argc, argv);
|
||||
microunit::UnitTester::Run();
|
||||
|
||||
11
src/Node.h
11
src/Node.h
@@ -15,6 +15,7 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cassert> // for assert()
|
||||
#include <exception>
|
||||
|
||||
#define CONSTANT_WEIGHT_INITIALIZATION 0
|
||||
|
||||
@@ -81,6 +82,14 @@ public:
|
||||
return m_weights;
|
||||
}
|
||||
|
||||
void SetWeights( std::vector<double> & weights ){
|
||||
// check size of the weights vector
|
||||
if( weights.size() == m_num_inputs )
|
||||
m_weights = weights;
|
||||
else
|
||||
throw new std::logic_error("Incorrect weight size in SetWeights call");
|
||||
}
|
||||
|
||||
size_t GetWeightsVectorSize() const {
|
||||
return m_weights.size();
|
||||
}
|
||||
@@ -146,4 +155,4 @@ protected:
|
||||
std::vector<double> m_weights;
|
||||
};
|
||||
|
||||
#endif //NODE_H
|
||||
#endif //NODE_H
|
||||
|
||||
Reference in New Issue
Block a user