Compare commits
No commits in common. "0dd9cade424673717b67c4063c8377002f9a6bc3" and "b9a8d3ffbc11407b66d60369ff17c3a8b572089b" have entirely different histories.
0dd9cade42
...
b9a8d3ffbc
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(COSC-4P80-Assignment-3 VERSION 0.0.24)
|
project(COSC-4P80-Assignment-3 VERSION 0.0.22)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
||||||
|
@ -14,6 +14,12 @@ FetchContent_Declare(implot
|
||||||
FIND_PACKAGE_ARGS)
|
FIND_PACKAGE_ARGS)
|
||||||
FetchContent_MakeAvailable(implot)
|
FetchContent_MakeAvailable(implot)
|
||||||
|
|
||||||
|
FetchContent_Declare(matplotplusplus
|
||||||
|
GIT_REPOSITORY https://github.com/alandefreitas/matplotplusplus
|
||||||
|
GIT_TAG v1.2.1
|
||||||
|
FIND_PACKAGE_ARGS)
|
||||||
|
FetchContent_MakeAvailable(matplotplusplus)
|
||||||
|
|
||||||
add_subdirectory(lib/blt-with-graphics)
|
add_subdirectory(lib/blt-with-graphics)
|
||||||
|
|
||||||
include_directories(include/)
|
include_directories(include/)
|
||||||
|
@ -26,7 +32,7 @@ add_executable(COSC-4P80-Assignment-3 ${PROJECT_BUILD_FILES} ${IM_PLOT_FILES})
|
||||||
target_compile_options(COSC-4P80-Assignment-3 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
target_compile_options(COSC-4P80-Assignment-3 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
||||||
target_link_options(COSC-4P80-Assignment-3 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
target_link_options(COSC-4P80-Assignment-3 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
||||||
|
|
||||||
target_link_libraries(COSC-4P80-Assignment-3 PRIVATE BLT_WITH_GRAPHICS)
|
target_link_libraries(COSC-4P80-Assignment-3 PRIVATE BLT_WITH_GRAPHICS matplot)
|
||||||
|
|
||||||
if (${ENABLE_ADDRSAN} MATCHES ON)
|
if (${ENABLE_ADDRSAN} MATCHES ON)
|
||||||
target_compile_options(COSC-4P80-Assignment-3 PRIVATE -fsanitize=address)
|
target_compile_options(COSC-4P80-Assignment-3 PRIVATE -fsanitize=address)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
BIN
errors25.png
BIN
errors25.png
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
BIN
heatmap.png
BIN
heatmap.png
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
|
@ -94,6 +94,7 @@ namespace assign3
|
||||||
som = std::make_unique<som_t>(motor_data.files[currently_selected_network], som_width, som_height, max_epochs,
|
som = std::make_unique<som_t>(motor_data.files[currently_selected_network], som_width, som_height, max_epochs,
|
||||||
distance_function.get(), topology_function.get(), static_cast<shape_t>(selected_som_mode),
|
distance_function.get(), topology_function.get(), static_cast<shape_t>(selected_som_mode),
|
||||||
static_cast<init_t>(selected_init_type), normalize_init);
|
static_cast<init_t>(selected_init_type), normalize_init);
|
||||||
|
som->compute_neuron_activations();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -44,8 +44,6 @@ namespace assign3
|
||||||
|
|
||||||
Scalar quantization_error();
|
Scalar quantization_error();
|
||||||
|
|
||||||
void compute_errors();
|
|
||||||
|
|
||||||
void compute_neuron_activations(Scalar distance = 2, Scalar activation = 0.5);
|
void compute_neuron_activations(Scalar distance = 2, Scalar activation = 0.5);
|
||||||
|
|
||||||
void write_activations(std::ostream& out);
|
void write_activations(std::ostream& out);
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import matplotlib
|
|
||||||
import matplotlib as mpl
|
|
||||||
import sys
|
|
||||||
|
|
||||||
filename = sys.argv[1]
|
|
||||||
size = sys.argv[2]
|
|
||||||
|
|
||||||
df = pd.read_csv(filename, header=None)
|
|
||||||
|
|
||||||
height, width = df.shape
|
|
||||||
|
|
||||||
data = df.to_numpy()
|
|
||||||
|
|
||||||
plt.imshow(data, cmap='coolwarm_r', interpolation='nearest')
|
|
||||||
|
|
||||||
plt.xticks(np.arange(width), np.arange(width))
|
|
||||||
plt.yticks(np.arange(height), np.arange(height))
|
|
||||||
|
|
||||||
plt.xlabel('X Pos')
|
|
||||||
plt.ylabel('Y Pos')
|
|
||||||
plt.title('Heatmap of Motor Data (Bins: {})'.format(size))
|
|
||||||
|
|
||||||
plt.gca().invert_yaxis()
|
|
||||||
|
|
||||||
plt.colorbar()
|
|
||||||
|
|
||||||
plt.savefig("heatmap.png")
|
|
|
@ -1,61 +0,0 @@
|
||||||
import pandas as pd
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import numpy as np
|
|
||||||
import sys
|
|
||||||
|
|
||||||
file1 = sys.argv[1]
|
|
||||||
file2 = sys.argv[2]
|
|
||||||
bins = sys.argv[3]
|
|
||||||
split = sys.argv[4]
|
|
||||||
|
|
||||||
df1 = pd.read_csv(file1)
|
|
||||||
df2 = pd.read_csv(file2)
|
|
||||||
|
|
||||||
data1 = df1.to_numpy()
|
|
||||||
data2 = df2.to_numpy()
|
|
||||||
|
|
||||||
y_min = np.min(data2)
|
|
||||||
y_max = np.max(data2)
|
|
||||||
|
|
||||||
if split.lower() == "false":
|
|
||||||
fig, ax1 = plt.subplots()
|
|
||||||
|
|
||||||
ax1.plot(data1, color='b', label='Topological Error')
|
|
||||||
ax1.set_xlabel('Epoch')
|
|
||||||
ax1.set_ylabel('Error %', color='b')
|
|
||||||
ax1.tick_params(axis='y', labelcolor='b')
|
|
||||||
ax1.set_ylim(0, 1)
|
|
||||||
#ax1.set_xlim(0, data1.size)
|
|
||||||
|
|
||||||
ax2 = ax1.twinx()
|
|
||||||
|
|
||||||
ax2.plot(data2, color='r', label='Quantization Error')
|
|
||||||
ax2.set_ylabel('Incorrect BMU', color='r')
|
|
||||||
ax2.tick_params(axis='y', labelcolor='r')
|
|
||||||
ax2.set_ylim(y_min, y_max)
|
|
||||||
|
|
||||||
ax1.set_title('Topological and Quantization Error (Bins: {})'.format(bins))
|
|
||||||
|
|
||||||
plt.savefig("errors{}.png".format(bins))
|
|
||||||
else:
|
|
||||||
plt.plot(data1, color='b', label='Topological Error')
|
|
||||||
plt.xlabel('Epoch')
|
|
||||||
plt.ylabel('Error %', color='b')
|
|
||||||
plt.tick_params(axis='y', labelcolor='b')
|
|
||||||
plt.ylim(0, 1)
|
|
||||||
|
|
||||||
plt.title("Topological Error (Bins: {})".format(bins))
|
|
||||||
|
|
||||||
plt.savefig("errors-topological{}.png".format(bins))
|
|
||||||
|
|
||||||
plt.plot(data2, color='b', label='Quantization Error')
|
|
||||||
plt.xlabel('Epoch')
|
|
||||||
plt.ylabel('Incorrect BMU', color='b')
|
|
||||||
plt.tick_params(axis='y', labelcolor='b')
|
|
||||||
plt.ylim(y_min, y_max)
|
|
||||||
|
|
||||||
plt.title("Quantization Error (Bins: {})".format(bins))
|
|
||||||
|
|
||||||
plt.savefig("errors-quantization{}.png".format(bins))
|
|
||||||
|
|
||||||
|
|
66
src/main.cpp
66
src/main.cpp
|
@ -10,6 +10,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <matplot/matplot.h>
|
||||||
|
|
||||||
using namespace assign3;
|
using namespace assign3;
|
||||||
|
|
||||||
|
@ -77,6 +78,11 @@ void action_start_graphics(const std::vector<std::string>& argv_vector)
|
||||||
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1).setMaximized(true));
|
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1).setMaximized(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct activation
|
||||||
|
{
|
||||||
|
Scalar x, y, act;
|
||||||
|
};
|
||||||
|
|
||||||
struct task_t // NOLINT
|
struct task_t // NOLINT
|
||||||
{
|
{
|
||||||
data_file_t* file;
|
data_file_t* file;
|
||||||
|
@ -95,7 +101,7 @@ struct task_t // NOLINT
|
||||||
gaussian_function_t topology_func{};
|
gaussian_function_t topology_func{};
|
||||||
std::vector<std::vector<Scalar>> topological_errors{};
|
std::vector<std::vector<Scalar>> topological_errors{};
|
||||||
std::vector<std::vector<Scalar>> quantization_errors{};
|
std::vector<std::vector<Scalar>> quantization_errors{};
|
||||||
std::vector<std::vector<Scalar>> activations{};
|
std::vector<std::vector<activation>> activations{};
|
||||||
};
|
};
|
||||||
|
|
||||||
void action_test(const std::vector<std::string>& argv_vector)
|
void action_test(const std::vector<std::string>& argv_vector)
|
||||||
|
@ -119,7 +125,7 @@ void action_test(const std::vector<std::string>& argv_vector)
|
||||||
|
|
||||||
static blt::size_t runs = 30;
|
static blt::size_t runs = 30;
|
||||||
|
|
||||||
for (blt::size_t _ = 0; _ < std::thread::hardware_concurrency(); _++)
|
for (blt::size_t i = 0; i < std::thread::hardware_concurrency(); i++)
|
||||||
{
|
{
|
||||||
threads.emplace_back([&task_mutex, &tasks]() {
|
threads.emplace_back([&task_mutex, &tasks]() {
|
||||||
do
|
do
|
||||||
|
@ -133,7 +139,7 @@ void action_test(const std::vector<std::string>& argv_vector)
|
||||||
tasks.pop_back();
|
tasks.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (blt::size_t run = 0; run < runs; run++)
|
for (blt::size_t i = 0; i < runs; i++)
|
||||||
{
|
{
|
||||||
gaussian_function_t func{};
|
gaussian_function_t func{};
|
||||||
auto dist = distance_function_t::from_shape(task.shape, task.width, task.height);
|
auto dist = distance_function_t::from_shape(task.shape, task.width, task.height);
|
||||||
|
@ -141,13 +147,13 @@ void action_test(const std::vector<std::string>& argv_vector)
|
||||||
&task.topology_func, task.shape, task.init, false);
|
&task.topology_func, task.shape, task.init, false);
|
||||||
while (som->get_current_epoch() < som->get_max_epochs())
|
while (som->get_current_epoch() < som->get_max_epochs())
|
||||||
som->train_epoch(task.initial_learn_rate);
|
som->train_epoch(task.initial_learn_rate);
|
||||||
|
som->compute_neuron_activations();
|
||||||
|
|
||||||
task.topological_errors.push_back(som->get_topological_errors());
|
task.topological_errors.push_back(som->get_topological_errors());
|
||||||
task.quantization_errors.push_back(som->get_quantization_errors());
|
task.quantization_errors.push_back(som->get_quantization_errors());
|
||||||
|
std::vector<activation> acts;
|
||||||
std::vector<Scalar> acts;
|
for (const auto& neuron : som->get_array().get_map())
|
||||||
for (const auto& v : som->get_array().get_map())
|
acts.push_back({neuron.get_x(), neuron.get_y(), neuron.get_activation()});
|
||||||
acts.push_back(v.get_activation());
|
|
||||||
task.activations.emplace_back(std::move(acts));
|
task.activations.emplace_back(std::move(acts));
|
||||||
}
|
}
|
||||||
std::stringstream paths;
|
std::stringstream paths;
|
||||||
|
@ -164,7 +170,7 @@ void action_test(const std::vector<std::string>& argv_vector)
|
||||||
|
|
||||||
std::vector<Scalar> average_topological_errors;
|
std::vector<Scalar> average_topological_errors;
|
||||||
std::vector<Scalar> average_quantization_errors;
|
std::vector<Scalar> average_quantization_errors;
|
||||||
std::vector<Scalar> average_activations;
|
std::vector<activation> average_activations;
|
||||||
|
|
||||||
average_topological_errors.resize(task.topological_errors.begin()->size());
|
average_topological_errors.resize(task.topological_errors.begin()->size());
|
||||||
average_quantization_errors.resize(task.quantization_errors.begin()->size());
|
average_quantization_errors.resize(task.quantization_errors.begin()->size());
|
||||||
|
@ -178,30 +184,30 @@ void action_test(const std::vector<std::string>& argv_vector)
|
||||||
average_quantization_errors[index] += v;
|
average_quantization_errors[index] += v;
|
||||||
for (const auto& vec : task.activations)
|
for (const auto& vec : task.activations)
|
||||||
for (auto [index, v] : blt::enumerate(vec))
|
for (auto [index, v] : blt::enumerate(vec))
|
||||||
average_activations[index] += v;
|
average_activations[index].act += v.act;
|
||||||
|
|
||||||
std::ofstream topological{path + "topological_avg.csv"};
|
for (auto& v : average_topological_errors)
|
||||||
std::ofstream quantization{path + "quantization_avg.csv"};
|
v /= static_cast<Scalar>(runs);
|
||||||
std::ofstream activations{path + "activations_avg.csv"};
|
for (auto& v : average_quantization_errors)
|
||||||
|
v /= static_cast<Scalar>(runs);
|
||||||
|
for (auto& v : average_activations)
|
||||||
|
v.act /= static_cast<Scalar>(runs);
|
||||||
|
|
||||||
topological << "error\n";
|
auto f = matplot::figure();
|
||||||
quantization << "error\n";
|
f->tiledlayout(2, 1);
|
||||||
for (auto [i, v] : blt::enumerate(average_topological_errors))
|
auto axis = f->add_axes();
|
||||||
{
|
axis->hold(true);
|
||||||
topological << v / static_cast<Scalar>(runs) << '\n';
|
axis->plot(matplot::linspace(0, static_cast<double>(task.max_epochs)), average_topological_errors)->display_name("Topological Error");
|
||||||
}
|
axis->title("Error");
|
||||||
for (auto [i, v] : blt::enumerate(average_quantization_errors))
|
axis->xlabel("Epoch");
|
||||||
{
|
axis->ylabel("Error");
|
||||||
quantization << v / static_cast<Scalar>(runs) << '\n';
|
axis->grid(true);
|
||||||
}
|
axis->plot(matplot::linspace(0, static_cast<double>(task.max_epochs)), average_quantization_errors)->display_name("Quantization Error");
|
||||||
for (auto [i, v] : blt::enumerate(average_activations))
|
f->title("Topological and Quantization Errors, " + std::to_string(runs) + " Runs");
|
||||||
{
|
|
||||||
activations << v / static_cast<Scalar>(runs);
|
f->save((path + "errors_plot.eps"), "postscript");
|
||||||
if (i % task.width == task.width-1)
|
f->save((path + "errors_plot.tex"), "epslatex");
|
||||||
activations << '\n';
|
f->save((path + "errors_plot.png"), "png");
|
||||||
else
|
|
||||||
activations << ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
BLT_INFO("Task '%s' Complete", path.c_str());
|
BLT_INFO("Task '%s' Complete", path.c_str());
|
||||||
|
|
||||||
|
|
|
@ -242,7 +242,10 @@ namespace assign3
|
||||||
if (running)
|
if (running)
|
||||||
{
|
{
|
||||||
if (som->get_current_epoch() < som->get_max_epochs())
|
if (som->get_current_epoch() < som->get_max_epochs())
|
||||||
|
{
|
||||||
som->train_epoch(initial_learn_rate);
|
som->train_epoch(initial_learn_rate);
|
||||||
|
som->compute_neuron_activations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
13
src/som.cpp
13
src/som.cpp
|
@ -34,7 +34,8 @@ namespace assign3
|
||||||
{
|
{
|
||||||
for (auto& v : array.get_map())
|
for (auto& v : array.get_map())
|
||||||
v.randomize(std::random_device{}(), init, normalize, file);
|
v.randomize(std::random_device{}(), init, normalize, file);
|
||||||
compute_errors();
|
topological_errors.push_back(topological_error());
|
||||||
|
quantization_errors.push_back(quantization_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
void som_t::train_epoch(Scalar initial_learn_rate)
|
void som_t::train_epoch(Scalar initial_learn_rate)
|
||||||
|
@ -66,7 +67,8 @@ namespace assign3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_epoch++;
|
current_epoch++;
|
||||||
compute_errors();
|
topological_errors.push_back(topological_error());
|
||||||
|
quantization_errors.push_back(quantization_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
blt::size_t som_t::get_closest_neuron(const std::vector<Scalar>& data)
|
blt::size_t som_t::get_closest_neuron(const std::vector<Scalar>& data)
|
||||||
|
@ -267,12 +269,5 @@ namespace assign3
|
||||||
return incorrect;
|
return incorrect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void som_t::compute_errors()
|
|
||||||
{
|
|
||||||
compute_neuron_activations();
|
|
||||||
topological_errors.push_back(topological_error());
|
|
||||||
quantization_errors.push_back(quantization_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue