From 63abdc782c1911c89cab60a7f472552826185b3e Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 9 Dec 2018 15:20:29 +0100 Subject: [PATCH] Adding a weight for each input dimension --- src/classifier/SOM.cpp | 23 +++++++++++++++++------ src/classifier/SOM.hpp | 8 ++++++-- tools/classifier/LmsClassifier.cpp | 1 + 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/classifier/SOM.cpp b/src/classifier/SOM.cpp index d495b49e..32e1c67b 100644 --- a/src/classifier/SOM.cpp +++ b/src/classifier/SOM.cpp @@ -50,13 +50,16 @@ defaultLearningFactor(Network::Progress progress) } InputVector::value_type -euclidianSquareDistance(const InputVector& a, const InputVector& b) +euclidianSquareDistance(const InputVector& a, const InputVector& b, const InputVector& weights) { + checkSameDimensions(a, b); + checkSameDimensions(a, weights); + InputVector::value_type res = 0; for (std::size_t i = 0; i < a.size(); ++i) { - res += (a[i] - b[i]) * (a[i] - b[i]); + res += (a[i] - b[i]) * (a[i] - b[i]) * weights[i]; } return res; @@ -159,6 +162,7 @@ Network::Network(std::size_t width, std::size_t height, std::size_t inputDimCoun : _width(width), _height(height), _inputDimCount(inputDimCount), +_weights(inputDimCount, static_cast(1)), _distanceFunc(euclidianSquareDistance), _learningFactorFunc(defaultLearningFactor), _neighborhoodFunc(defaultNeighborhoodFunc) @@ -180,6 +184,13 @@ _neighborhoodFunc(defaultNeighborhoodFunc) } } +void +Network::setDataWeights(const InputVector& weights) +{ + checkSameDimensions(weights, _inputDimCount); + + _weights = weights; +} InputVector& Network::getRefVector(std::size_t x, std::size_t y) @@ -217,7 +228,7 @@ Network::getClosestRefVector(const InputVector& data) const auto it = std::min_element(_refVectors.begin(), _refVectors.end(), [&](const auto& a, const auto& b) { - return (_distanceFunc(a, data) < _distanceFunc(b, data)); + return (_distanceFunc(a, data, _weights) < _distanceFunc(b, data, _weights)); }); auto index = std::distance(_refVectors.begin(), it); @@ -271,12 +282,12 @@ Network::train(const std::vector& inputData, std::size_t nbIteratio inputDataShuffled.push_back(&input); } - std::random_device randomDevice; - std::mt19937 generator(randomDevice()); + auto now = std::chrono::system_clock::now(); + std::mt19937 randGenerator(std::chrono::duration_cast(now.time_since_epoch()).count()); for (std::size_t i = 0; i < nbIterations; ++i) { - std::shuffle(inputDataShuffled.begin(), inputDataShuffled.end(), generator); + std::shuffle(inputDataShuffled.begin(), inputDataShuffled.end(), randGenerator); for (auto input : inputDataShuffled) { diff --git a/src/classifier/SOM.hpp b/src/classifier/SOM.hpp index f9346f93..2d60ff47 100644 --- a/src/classifier/SOM.hpp +++ b/src/classifier/SOM.hpp @@ -52,6 +52,9 @@ class Network Network(std::size_t width, std::size_t height, std::size_t inputDimCount); + // Set weight for each dimension (default is 1 for each weight) + void setDataWeights(const InputVector& weights); + // data must be normalized void train(const std::vector& dataSamples, std::size_t nbIterations); @@ -64,7 +67,7 @@ class Network // i is the current iteration // refVector(i+1) = refVector(i) + LearningFactor(i) * NeighborhoodFunc(i) * (MatchingRefVector - refVector) - using DistanceFunc = std::function; + using DistanceFunc = std::function; void setDistanceFunc(DistanceFunc distanceFunc); struct Progress @@ -91,7 +94,8 @@ class Network std::size_t _height; std::size_t _inputDimCount; - std::vector _refVectors; // indexed reference vectors + InputVector _weights; + std::vector _refVectors; // reference vectors DistanceFunc _distanceFunc; LearningFactorFunc _learningFactorFunc; diff --git a/tools/classifier/LmsClassifier.cpp b/tools/classifier/LmsClassifier.cpp index 36568e42..620cd956 100644 --- a/tools/classifier/LmsClassifier.cpp +++ b/tools/classifier/LmsClassifier.cpp @@ -29,6 +29,7 @@ int main(int argc, char *argv[]) { 80, -1 }, { 80, -0.75 }, { 240, 0.5 }, + { 240, -0.5 }, { 120, -0.5 }, { 140, -0.5 }, };