update python commit file for nix + changes to som. working now?
parent
3b13e48f36
commit
e589a07531
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.25)
|
||||
project(COSC-4P80-Assignment-3 VERSION 0.0.9)
|
||||
project(COSC-4P80-Assignment-3 VERSION 0.0.10)
|
||||
include(FetchContent)
|
||||
|
||||
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
||||
|
|
|
@ -36,28 +36,33 @@ namespace assign3
|
|||
map.emplace_back(dimensions, (j % 2 == 0 ? static_cast<Scalar>(i) : static_cast<Scalar>(i) + 0.5f), j);
|
||||
}
|
||||
|
||||
inline neuron_t& get(blt::size_t x, blt::size_t y)
|
||||
[[nodiscard]] std::pair<blt::size_t, blt::size_t> from_index(blt::size_t index) const
|
||||
{
|
||||
return {index % width, index / width};
|
||||
}
|
||||
|
||||
neuron_t& get(blt::size_t x, blt::size_t y)
|
||||
{ return map[y * width + x]; }
|
||||
|
||||
[[nodiscard]] inline const neuron_t& get(blt::size_t x, blt::size_t y) const
|
||||
[[nodiscard]] const neuron_t& get(blt::size_t x, blt::size_t y) const
|
||||
{ return map[y * width + x]; }
|
||||
|
||||
[[nodiscard]] inline blt::size_t get_width() const
|
||||
[[nodiscard]] blt::size_t get_width() const
|
||||
{ return width; }
|
||||
|
||||
[[nodiscard]] inline blt::size_t get_height() const
|
||||
[[nodiscard]] blt::size_t get_height() const
|
||||
{ return height; }
|
||||
|
||||
[[nodiscard]] inline std::vector<neuron_t>& get_map()
|
||||
[[nodiscard]] std::vector<neuron_t>& get_map()
|
||||
{ return map; }
|
||||
|
||||
[[nodiscard]] inline const std::vector<neuron_t>& get_map() const
|
||||
[[nodiscard]] const std::vector<neuron_t>& get_map() const
|
||||
{ return map; }
|
||||
|
||||
private:
|
||||
[[nodiscard]] inline blt::i64 wrap_width(blt::i64 x) const;
|
||||
[[nodiscard]] blt::i64 wrap_width(blt::i64 x) const;
|
||||
|
||||
[[nodiscard]] inline blt::i64 wrap_height(blt::i64 y) const;
|
||||
[[nodiscard]] blt::i64 wrap_height(blt::i64 y) const;
|
||||
|
||||
private:
|
||||
blt::i64 width, height;
|
||||
|
|
|
@ -33,16 +33,31 @@ namespace assign3
|
|||
* @return basis results
|
||||
*/
|
||||
[[nodiscard]] virtual Scalar call(Scalar dist, Scalar r) const = 0;
|
||||
|
||||
/**
|
||||
* produces a non-time scaled r value for making the function activate at target_strength when a point is half_distance between two nodes
|
||||
* so for the example of unit distance 1, half distance is 0.5, target_strength is 0.5
|
||||
* this function will produce a value which can be time scaled for achieving this result at t=0
|
||||
*
|
||||
* this function can return a 1 to indicate this function doesn't care for this.
|
||||
*/
|
||||
[[nodiscard]] virtual Scalar scale(Scalar half_distance, Scalar target_strength) const = 0;
|
||||
|
||||
virtual ~topology_function_t() = default;
|
||||
};
|
||||
|
||||
struct gaussian_function_t : public topology_function_t
|
||||
struct gaussian_function_t final : public topology_function_t
|
||||
{
|
||||
[[nodiscard]] Scalar call(Scalar dist, Scalar r) const final;
|
||||
|
||||
[[nodiscard]] Scalar scale(Scalar half_distance, Scalar target_strength) const final;
|
||||
};
|
||||
|
||||
struct distance_function_t
|
||||
{
|
||||
[[nodiscard]] virtual Scalar distance(blt::span<const Scalar> x, blt::span<const Scalar> y) const = 0;
|
||||
|
||||
virtual ~distance_function_t() = default;
|
||||
};
|
||||
|
||||
struct euclidean_distance_function_t : public distance_function_t
|
||||
|
|
|
@ -19,13 +19,24 @@
|
|||
#ifndef COSC_4P80_ASSIGNMENT_3_FWDECL_H
|
||||
#define COSC_4P80_ASSIGNMENT_3_FWDECL_H
|
||||
|
||||
#include <blt/std/types.h>
|
||||
|
||||
namespace assign3
|
||||
{
|
||||
using Scalar = float;
|
||||
|
||||
enum class shape
|
||||
inline constexpr blt::i32 RENDER_2D = 0x0;
|
||||
inline constexpr blt::i32 RENDER_3D = 0x1;
|
||||
|
||||
enum class shape : blt::i32
|
||||
{
|
||||
GRID, HONEYCOMB
|
||||
GRID = RENDER_2D,
|
||||
GRID_WRAP = RENDER_2D,
|
||||
GRID_OFFSET = RENDER_2D,
|
||||
GRID_OFFSET_WRAP = RENDER_2D,
|
||||
GAUSSIAN_DIST = RENDER_2D,
|
||||
TOROIDAL = RENDER_3D,
|
||||
CYLINDER = RENDER_3D
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ namespace assign3
|
|||
|
||||
blt::size_t get_closest_neuron(const std::vector<Scalar>& data);
|
||||
|
||||
Scalar find_closest_neighbour_distance(blt::size_t v0);
|
||||
|
||||
void train_epoch(Scalar initial_learn_rate, topology_function_t* basis_func);
|
||||
|
||||
[[nodiscard]] const array_t& get_array() const
|
||||
|
|
|
@ -28,6 +28,11 @@ namespace assign3
|
|||
return std::exp(-r * dist_sq);
|
||||
}
|
||||
|
||||
Scalar gaussian_function_t::scale(Scalar half_distance, Scalar target_strength) const
|
||||
{
|
||||
return -std::log(target_strength) / (half_distance * half_distance);
|
||||
}
|
||||
|
||||
Scalar euclidean_distance_function_t::distance(blt::span<const Scalar> x, blt::span<const Scalar> y) const
|
||||
{
|
||||
Scalar dist = 0;
|
||||
|
|
83
src/main.cpp
83
src/main.cpp
|
@ -8,6 +8,7 @@
|
|||
#include <assign3/file.h>
|
||||
#include <assign3/som.h>
|
||||
#include <imgui.h>
|
||||
#include <execution>
|
||||
|
||||
using namespace assign3;
|
||||
|
||||
|
@ -19,17 +20,38 @@ blt::gfx::resource_manager resources;
|
|||
blt::gfx::batch_renderer_2d renderer_2d(resources, global_matrices);
|
||||
blt::gfx::first_person_camera_2d camera;
|
||||
|
||||
blt::size_t som_width = 7;
|
||||
blt::size_t som_height = 7;
|
||||
blt::size_t max_epochs = 1000;
|
||||
blt::size_t som_width = 5;
|
||||
blt::size_t som_height = 5;
|
||||
blt::size_t max_epochs = 100;
|
||||
Scalar initial_learn_rate = 0.1;
|
||||
|
||||
int currently_selected_network = 0;
|
||||
std::vector<std::string> map_files_names;
|
||||
std::unique_ptr<topology_function_t> topology_function;
|
||||
|
||||
float neuron_scale = 35;
|
||||
float draw_width = neuron_scale * static_cast<float>(som_width);
|
||||
float draw_height = neuron_scale * static_cast<float>(som_height);
|
||||
float draw_width;
|
||||
float draw_height;
|
||||
|
||||
void update_graphics()
|
||||
{
|
||||
// find the min x / y for the currently drawn som as positions may depend on type.
|
||||
const auto x_comparator = [](const auto& a, const auto& b) {
|
||||
return a.get_x() < b.get_x();
|
||||
};
|
||||
const auto y_comparator = [](const auto& a, const auto& b) {
|
||||
return a.get_y() < b.get_y();
|
||||
};
|
||||
const auto& som_neurons = som->get_array().get_map();
|
||||
auto min_x = std::min_element(som_neurons.begin(), som_neurons.end(), x_comparator)->get_x();
|
||||
auto max_x = std::max_element(som_neurons.begin(), som_neurons.end(), x_comparator)->get_x();
|
||||
auto min_y = std::min_element(som_neurons.begin(), som_neurons.end(), y_comparator)->get_y();
|
||||
auto max_y = std::max_element(som_neurons.begin(), som_neurons.end(), y_comparator)->get_y();
|
||||
draw_width = (max_x - min_x) * neuron_scale;
|
||||
draw_height = (max_y - min_y) * neuron_scale;
|
||||
|
||||
topology_function = std::make_unique<gaussian_function_t>();
|
||||
}
|
||||
|
||||
void generate_network(int selection)
|
||||
{
|
||||
|
@ -65,6 +87,8 @@ void update(const blt::gfx::window_data& window_data)
|
|||
camera.update_view(global_matrices);
|
||||
global_matrices.update();
|
||||
|
||||
update_graphics();
|
||||
|
||||
if (ImGui::Begin("Controls"))
|
||||
{
|
||||
ImGui::Text("Network Select");
|
||||
|
@ -73,16 +97,14 @@ void update(const blt::gfx::window_data& window_data)
|
|||
|
||||
if (ImGui::Button("Run Epoch"))
|
||||
{
|
||||
static gaussian_function_t func;
|
||||
som->train_epoch(initial_learn_rate, &func);
|
||||
som->train_epoch(initial_learn_rate, topology_function.get());
|
||||
}
|
||||
static bool run;
|
||||
ImGui::Checkbox("Run to completion", &run);
|
||||
if (run)
|
||||
{
|
||||
static gaussian_function_t func;
|
||||
if (som->get_current_epoch() < som->get_max_epochs())
|
||||
som->train_epoch(initial_learn_rate, &func);
|
||||
som->train_epoch(initial_learn_rate, topology_function.get());
|
||||
}
|
||||
ImGui::Text("Epoch %ld / %ld", som->get_current_epoch(), som->get_max_epochs());
|
||||
}
|
||||
|
@ -156,6 +178,47 @@ void update(const blt::gfx::window_data& window_data)
|
|||
v.get_y() * neuron_scale + neuron_scale, neuron_scale});
|
||||
}
|
||||
|
||||
closest_type.clear();
|
||||
closest_type.resize(som->get_array().get_map().size());
|
||||
for (auto [i, v] : blt::enumerate(som->get_array().get_map()))
|
||||
{
|
||||
auto half = som->find_closest_neighbour_distance(i);
|
||||
auto scale = topology_function->scale(half * 0.5f, 0.5);
|
||||
for (const auto& data : current_data_file.data_points)
|
||||
{
|
||||
auto dist = v.dist(data.bins);
|
||||
auto ds = topology_function->call(dist, scale);
|
||||
// BLT_TRACE("%f, %f, %f", ds, dist, scale);
|
||||
if (data.is_bad)
|
||||
closest_type[i] -= ds;
|
||||
else
|
||||
closest_type[i] += ds;
|
||||
}
|
||||
}
|
||||
auto min_act = *std::min_element(closest_type.begin(), closest_type.end());
|
||||
auto max_act = *std::max_element(closest_type.begin(), closest_type.end());
|
||||
for (auto& v : closest_type)
|
||||
{
|
||||
auto n = 2 * (v - min_act) / (max_act - min_act) - 1;
|
||||
v = n;
|
||||
}
|
||||
BLT_TRACE("Min %f Max %f", min_act, max_act);
|
||||
|
||||
for (auto [i, v] : blt::enumerate(som->get_array().get_map()))
|
||||
{
|
||||
auto type = closest_type[i];
|
||||
|
||||
blt::vec4 color;
|
||||
if (type >= 0)
|
||||
color = blt::make_color(0, type, 0);
|
||||
else
|
||||
color = blt::make_color(-type, 0, 0);
|
||||
|
||||
renderer_2d.drawPointInternal(color,
|
||||
point2d_t{draw_width + neuron_scale * 2 + v.get_x() * neuron_scale + neuron_scale,
|
||||
draw_height + neuron_scale * 2 + v.get_y() * neuron_scale + neuron_scale, neuron_scale});
|
||||
}
|
||||
|
||||
renderer_2d.render(window_data.width, window_data.height);
|
||||
}
|
||||
|
||||
|
@ -178,5 +241,5 @@ int main(int argc, const char** argv)
|
|||
|
||||
files = assign3::data_file_t::load_data_files_from_path(args.get<std::string>("file"));
|
||||
|
||||
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1));
|
||||
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1).setMaximized(true));
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace assign3
|
|||
return *this;
|
||||
}
|
||||
|
||||
// apply the distance based on the update neuron function
|
||||
neuron_t& neuron_t::update(const std::vector<Scalar>& new_data, Scalar dist, Scalar eta)
|
||||
{
|
||||
static thread_local std::vector<Scalar> diff;
|
||||
|
@ -47,12 +48,14 @@ namespace assign3
|
|||
return *this;
|
||||
}
|
||||
|
||||
// distance between an input vector and the neuron, in the n-space
|
||||
Scalar neuron_t::dist(const std::vector<Scalar>& X) const
|
||||
{
|
||||
euclidean_distance_function_t dist_func;
|
||||
return dist_func.distance(data, X);
|
||||
}
|
||||
|
||||
// distance between two neurons, in 2d
|
||||
Scalar neuron_t::distance(const neuron_t& n1, const neuron_t& n2)
|
||||
{
|
||||
euclidean_distance_function_t dist_func;
|
||||
|
|
22
src/som.cpp
22
src/som.cpp
|
@ -21,6 +21,7 @@
|
|||
#include <blt/std/random.h>
|
||||
#include <blt/iterator/enumerate.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace assign3
|
||||
{
|
||||
|
@ -46,11 +47,17 @@ namespace assign3
|
|||
auto v0 = array.get_map()[v0_idx];
|
||||
v0.update(current_data.bins, 1, eta);
|
||||
|
||||
// find the closest neighbour neuron to v0
|
||||
auto distance_min = find_closest_neighbour_distance(v0_idx);
|
||||
// this will find the required scaling factor to make a point in the middle between v0 and its closest neighbour activate 50%
|
||||
// from the perspective of the gaussian function
|
||||
auto scale = basis_func->scale(distance_min * 0.5f, 0.5);
|
||||
|
||||
for (auto [i, n] : blt::enumerate(array.get_map()))
|
||||
{
|
||||
if (i == v0_idx)
|
||||
continue;
|
||||
auto dist = basis_func->call(neuron_t::distance(v0, n), time_ratio);
|
||||
auto dist = basis_func->call(neuron_t::distance(v0, n), time_ratio * scale);
|
||||
n.update(current_data.bins, dist, eta);
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +69,6 @@ namespace assign3
|
|||
{
|
||||
blt::size_t index = 0;
|
||||
Scalar distance = std::numeric_limits<Scalar>::max();
|
||||
|
||||
for (auto [i, d] : blt::enumerate(array.get_map()))
|
||||
{
|
||||
auto dist = d.dist(data);
|
||||
|
@ -72,9 +78,19 @@ namespace assign3
|
|||
distance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
Scalar som_t::find_closest_neighbour_distance(blt::size_t v0)
|
||||
{
|
||||
Scalar distance_min = std::numeric_limits<Scalar>::max();
|
||||
for (const auto& [i, n] : blt::enumerate(array.get_map()))
|
||||
{
|
||||
if (i != v0)
|
||||
distance_min = std::min(distance_min, neuron_t::distance(array.get_map()[v0], n));
|
||||
}
|
||||
return distance_min;
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue