Bonjour ! Je viens a vous car j’ai implémenté mon premier reseau de neurones suite a ce tutoriel bien foutu : https://www.youtube.com/watch?v=KkwX7FkLfug.
Par contre … que du mauvais resultats. Que j’itere 200 ou 20 000 fois sur mon dataset j’ai toujours les meme resultats : mes 4 neurones de sorties qui valent -9.25596e+64 ..
Avec quelques std::cout , je remarque que chacune de mes neurones d’une couche ont la meme valeur … ce qui est étrange vu que mes poids sont initialisées aléatoirement .... je continu de chercher la cause du probleme…
Pour commencer voici mon main :
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 | #include <iostream> #include "E:/NeuralNetwork/NeuralNetwork.hpp" int main(void) { // Topologie du réseau NeuralNetwork::Topology topologie{ 4, 4, 4 , 8 , 4 }; NeuralNetwork Brain{ topologie }; // Dataset d'entrée std::vector<NeuralNetwork::DataSet> dataset_; NeuralNetwork::DataSet datas_p1{0,0, 0,0}; // bloc plein NeuralNetwork::DataSet datas_p2{1,1, 1,1}; // bloc plein NeuralNetwork::DataSet datas_v1{1,0, 1,0}; // Vertical NeuralNetwork::DataSet datas_v2{0,1, 0,1}; // Vertical NeuralNetwork::DataSet datas_h1{1,1, 0,0}; // Horizontal NeuralNetwork::DataSet datas_h2{0,0, 1,1}; // Horizontal NeuralNetwork::DataSet datas_d1{1,0, 0,1}; // Diagonal NeuralNetwork::DataSet datas_d2{0,1, 1,0}; // Diagonal dataset_.push_back(datas_p1); dataset_.push_back(datas_p2); dataset_.push_back(datas_v1); dataset_.push_back(datas_v2); dataset_.push_back(datas_h1); dataset_.push_back(datas_h2); dataset_.push_back(datas_d1); dataset_.push_back(datas_d2); std::vector<NeuralNetwork::DataSet> expected_output{ { 1,0,0,0 }, { 1,0,0,0 }, { 0,1,0,0 }, { 0,1,0,0 }, { 0,0,1,0 }, { 0,0,1,0 }, { 0,0,0,1 }, { 0,0,0,1 }, }; for (size_t i = 0; i < 500 ; i++) { for (size_t d = 0; d < dataset_.size(); d++) { Brain.feedForward(dataset_[d]); Brain.backPropagate(expected_output[d]); } } NeuralNetwork::ResultSet results; Brain.feedForward(datas_d1); Brain.getResults(results); for (auto const & r : results) { std::cout << r << std::endl; } std::cin.get(); return 0; } |
Puis : NeuralNetwork.hpp
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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | #ifndef NEURALNETWORK_HPP #define NEURALNETWORK_HPP #include <vector> #include <utility> #include <random> #include <assert.h> class NeuralNetwork{ public: class Node; // definition de quelques types using DataSet = std::vector<double>; using ResultSet = std::vector<double>; using Topology = std::vector<size_t>; // Nombre de couches ( layer ) et de neurones par couche using Layer = std::vector<Node>; // Couche de Node ( neurone ) // Defini une connection jusqu'a une neurone de la couche suivante par un poid struct Connection{ // Constructeur par defaut Connection() : Connection{0.0} {} // Constructeur Connection(double w) : weigth_{w}, delta_weigth_{0.0} {} double weigth_; // Poid de la connection double delta_weigth_; }; // Defini une neurone class Node{ public: double eta_; //training rate double alpha_; // Constructeur Node(size_t output_size, size_t num){ // output_size = nombre de connection a la couche suivante for(size_t i = 0; i < output_size; i++){ // Pour chaque neurone de la couche suivante , on ajoute une connection a la neurone connections_.push_back(Connection(randomWeigth())); } nodenum_ = num; eta_ = 0.15; alpha_ = 0.5; }; void feedForward(const NeuralNetwork::Layer & prev_layer) { double sum = 0.0; for (size_t n = 0; n < prev_layer.size(); n++) { sum += (prev_layer[n].getOutput() * prev_layer[n].connections_[nodenum_].weigth_); } output_ = Node::activationFunction(sum); } void setOutput(double value) { output_ = value; } double getOutput() const { return output_; } void calculateGradients(double value) { double delta = value - output_; gradient_ = delta * Node::activationFunction(output_); }; double sumDOW(Layer const & layer) { double sum = 0.0; for (size_t n = 0; n < layer.size() - 1; n++) { sum += connections_[n].weigth_; } return sum; } void updateWeigths(Layer &prev_layer) { for (size_t n = 0; n < prev_layer.size(); n++) { Node & node = prev_layer[n]; double oldDelta = node.connections_[nodenum_].delta_weigth_; double newDelta = (eta_ * node.getOutput() * gradient_) + (alpha_ * oldDelta); node.connections_[nodenum_].delta_weigth_ = newDelta; node.connections_[nodenum_].weigth_ = newDelta; } } void calculateHiddenGradients(Layer const & layer) { double dow = sumDOW(layer); gradient_ = dow * Node::activationFunction(output_); } private: double output_; // Valeur de sorti de la neurone size_t nodenum_; std::vector<Connection> connections_; double gradient_; static double randomWeigth() { return rand() / double(RAND_MAX); } static double activationFunction(double sum) { return tanh(sum); } }; // Une neurone // Constructeur du réseau NeuralNetwork(Topology const &topo){ for(size_t j = 0; j < topo.size(); j++){ // Nombre de connections pour les neurones de cette couche // si c'est la derniere couche il y a 0 connections // sinon le nombre de connections = le nombre de neurones sur la prochaine couche auto conn_size = ( j == topo.size() - 1 ? 0 : topo[j+1]); // On ajoute une couche layers_.push_back(Layer()); auto & last_layer_added = layers_.back(); auto layer_size = topo[j]; //Pour chaque nombre de neurone dans la couche for(size_t i = 0; i <= layer_size ; i++){ // On ajoute une neurone avec le nombre de connections necessaire last_layer_added.push_back(Node(conn_size,i)); } last_layer_added.back().setOutput(1.0); } }; // FONCTION FEEDFORWARD void feedForward(DataSet const & inputs){ // Nombre de données == nombre entré premiere couche assert(inputs.size() == layers_[0].size() - 1); // Entrée des données dans la premiere couche for (size_t i = 0; i < inputs.size(); i++) { layers_[0][i].setOutput(inputs[i]); } // Feed des couches cachées for (size_t layer_num = 1; layer_num < layers_.size() - 1; layer_num++) { // Récuperation de la couche précédente Layer &prev_layer = layers_[layer_num - 1]; // Feed forward des données for (size_t n = 0; n < layers_[layer_num].size() - 1; n++) { layers_[layer_num][n].feedForward(prev_layer); } } } // FONCTION BACKPROPAGATE void backPropagate(DataSet const & inputs){ // derniere couche = couche de sortie Layer &outputLayer = layers_.back(); error_ = 0.0; for (size_t n = 0; n < outputLayer.size() - 1; n++) { double delta = inputs[n] - outputLayer[n].getOutput(); error_ += delta*delta; } error_ /= outputLayer.size() - 1; error_ = sqrt(error_); recentAverageError_ = (recentAverageError_ * error_) / (1.0); for (size_t n = 0; n < outputLayer.size() - 1; n++) { outputLayer[n].calculateGradients(inputs[n]); } for (size_t layer = layers_.size() - 2; layer = 0; layer++) { Layer & hiddenLayer = layers_[layer]; Layer & nextLayer = layers_[layer + 1]; for (size_t n = 0; n < hiddenLayer.size()-1; n++) { hiddenLayer[n].calculateHiddenGradients(nextLayer); } } for (size_t layer_num = layers_.size() - 1; layer_num > 0; layer_num--) { Layer &layer = layers_[layer_num]; Layer &prev_layer = layers_[layer_num - 1]; for (size_t n = 0; n < layer.size()-1; n++) { layer[n].updateWeigths(prev_layer); } } } void getResults(ResultSet & results) const { results.clear(); for (size_t n = 0; n < layers_.back().size() - 1; n++) { results.push_back(layers_.back()[n].getOutput()); } } private: std::vector<Layer> layers_; // layers_[LayerNum][NodeNum] double error_; double recentAverageError_; }; #endif ` |
Et la sortie :
1 2 3 4 | -9.2559e+61 -9.2559e+61 -9.2559e+61 -9.2559e+61 |
Si vous avez une idée d’ou cela peux venir …
+0
-0