main
Brett 2024-11-19 19:34:37 -05:00
parent b9a8d3ffbc
commit 2cb87c6b08
10 changed files with 115 additions and 53 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(COSC-4P80-Assignment-3 VERSION 0.0.22) project(COSC-4P80-Assignment-3 VERSION 0.0.23)
include(FetchContent) include(FetchContent)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
@ -14,12 +14,6 @@ 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/)
@ -32,7 +26,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 matplot) target_link_libraries(COSC-4P80-Assignment-3 PRIVATE BLT_WITH_GRAPHICS)
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)

BIN
errors25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
heatmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -94,7 +94,6 @@ 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:

View File

@ -44,6 +44,8 @@ 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);

30
plot_heatmap.py Normal file
View File

@ -0,0 +1,30 @@
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")

41
plot_line_graph.py Normal file
View File

@ -0,0 +1,41 @@
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('Epochs')
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')

View File

@ -10,7 +10,6 @@
#include <mutex> #include <mutex>
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <matplot/matplot.h>
using namespace assign3; using namespace assign3;
@ -78,11 +77,6 @@ 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;
@ -101,7 +95,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<activation>> activations{}; std::vector<std::vector<Scalar>> activations{};
}; };
void action_test(const std::vector<std::string>& argv_vector) void action_test(const std::vector<std::string>& argv_vector)
@ -125,7 +119,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 i = 0; i < std::thread::hardware_concurrency(); i++) for (blt::size_t _ = 0; _ < std::thread::hardware_concurrency(); _++)
{ {
threads.emplace_back([&task_mutex, &tasks]() { threads.emplace_back([&task_mutex, &tasks]() {
do do
@ -139,7 +133,7 @@ void action_test(const std::vector<std::string>& argv_vector)
tasks.pop_back(); tasks.pop_back();
} }
for (blt::size_t i = 0; i < runs; i++) for (blt::size_t run = 0; run < runs; run++)
{ {
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);
@ -147,13 +141,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;
for (const auto& neuron : som->get_array().get_map()) std::vector<Scalar> acts;
acts.push_back({neuron.get_x(), neuron.get_y(), neuron.get_activation()}); for (const auto& v : som->get_array().get_map())
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;
@ -170,7 +164,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<activation> average_activations; std::vector<Scalar> 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());
@ -184,30 +178,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].act += v.act; average_activations[index] += v;
for (auto& v : average_topological_errors) std::ofstream topological{path + "topological_avg.csv"};
v /= static_cast<Scalar>(runs); std::ofstream quantization{path + "quantization_avg.csv"};
for (auto& v : average_quantization_errors) std::ofstream activations{path + "activations_avg.csv"};
v /= static_cast<Scalar>(runs);
for (auto& v : average_activations)
v.act /= static_cast<Scalar>(runs);
auto f = matplot::figure(); topological << "error\n";
f->tiledlayout(2, 1); quantization << "error\n";
auto axis = f->add_axes(); for (auto [i, v] : blt::enumerate(average_topological_errors))
axis->hold(true); {
axis->plot(matplot::linspace(0, static_cast<double>(task.max_epochs)), average_topological_errors)->display_name("Topological Error"); topological << v / static_cast<Scalar>(runs) << '\n';
axis->title("Error"); }
axis->xlabel("Epoch"); for (auto [i, v] : blt::enumerate(average_quantization_errors))
axis->ylabel("Error"); {
axis->grid(true); quantization << v / static_cast<Scalar>(runs) << '\n';
axis->plot(matplot::linspace(0, static_cast<double>(task.max_epochs)), average_quantization_errors)->display_name("Quantization Error"); }
f->title("Topological and Quantization Errors, " + std::to_string(runs) + " Runs"); for (auto [i, v] : blt::enumerate(average_activations))
{
f->save((path + "errors_plot.eps"), "postscript"); activations << v / static_cast<Scalar>(runs);
f->save((path + "errors_plot.tex"), "epslatex"); if (i % task.width == task.width-1)
f->save((path + "errors_plot.png"), "png"); activations << '\n';
else
activations << ',';
}
BLT_INFO("Task '%s' Complete", path.c_str()); BLT_INFO("Task '%s' Complete", path.c_str());

View File

@ -242,10 +242,7 @@ 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();
}
} }

View File

@ -34,8 +34,7 @@ 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);
topological_errors.push_back(topological_error()); compute_errors();
quantization_errors.push_back(quantization_error());
} }
void som_t::train_epoch(Scalar initial_learn_rate) void som_t::train_epoch(Scalar initial_learn_rate)
@ -67,8 +66,7 @@ namespace assign3
} }
} }
current_epoch++; current_epoch++;
topological_errors.push_back(topological_error()); compute_errors();
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)
@ -265,9 +263,16 @@ namespace assign3
continue; continue;
incorrect++; incorrect++;
} }
return incorrect; return incorrect;
} }
void som_t::compute_errors()
{
compute_neuron_activations();
topological_errors.push_back(topological_error());
quantization_errors.push_back(quantization_error());
}
} }