Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhylkaaa committed May 20, 2020
1 parent ba1a62b commit 1f19d9e
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 47 deletions.
6 changes: 0 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ Simple implementation of Multi-layer perceptron using Vulkan Compute API.

## Usage
For now example of usage can be found in `main.cpp`.<br>
To use this you should compile shaders following name convention:
```$bash
#in shaders folder
$ glslc -o d_softmax.comp.spv d_softmax.comp
$ glslc -o dense.comp.spv dense.comp
```

To compile and run use:
```bash
Expand Down
4 changes: 2 additions & 2 deletions includes/MLP.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class MLP {
public:
MLP();

MLP(uint32_t input_size, uint32_t batch_size, const std::vector<int>& layer_dims, const std::vector<std::string>& activations);
MLP(uint32_t input_size, uint32_t batch_size, const std::vector<uint32_t>& layer_dims, const std::vector<std::string>& activations);

void add(int layer_dim, const std::string& activation, uint32_t input_size=0, uint32_t batch_size=0);
void add(uint32_t layer_dim, const std::string& activation, uint32_t input_size=0, uint32_t batch_size=0);

void forward_initialize();
void forward(const std::vector<std::vector<float>>& batch);
Expand Down
200 changes: 163 additions & 37 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,192 @@
#include <vulkan_init.h>
#include <classification_trainer.h>
#include <fstream>
#include <sstream>

int main() {
int find_arg(char **argv, int argc, const std::string& arg_name){
for(int i = 0;i<argc;i++){
if(std::string(argv[i]).find(arg_name) != std::string::npos){
return i;
}
}
return -1;
}

void get_dataset(char **argv, int argc, std::string &data_path, std::string &labels_path, bool is_train=false) {
std::string data_arg;
std::string labels_arg;

if(is_train){
data_arg = "--train_data_path";
labels_arg = "--train_labels_path";
} else {
data_arg = "--val_data_path";
labels_arg = "--val_labels_path";
}

std::vector<int> layers{512, 10};
std::vector<std::string> activations{"relu", "softmax"};
MLP mlp = MLP(784, 32, layers, activations);
int data_pos = find_arg(argv, argc, data_arg);
int labels_pos = find_arg(argv, argc, labels_arg);

mlp.forward_initialize();
if(data_pos == -1){
std::stringstream ss;
ss<<"can't find parameter "<<data_arg;
throw std::runtime_error(ss.str());
}

std::vector<example> train_dataset;
if(labels_pos == -1){
std::stringstream ss;
ss<<"can't find parameter "<<labels_arg;
throw std::runtime_error(ss.str());
}

std::vector<std::vector<float>> val_x;
std::vector<std::vector<float>> val_y;
data_path = std::string(argv[data_pos+1]);
labels_path = std::string(argv[labels_pos+1]);
}

std::ifstream train_image_input("../train_MNIST_images.txt");
std::ifstream val_image_input("../val_MNIST_images.txt", std::ios::in);
void get_layers(char** argv, int argc, std::vector<uint32_t>& layers){
int pos = find_arg(argv, argc, "--layers=");
if(pos == -1){
throw std::runtime_error("can't fine --layers= parameter");
}
int offset = 9; // len of --layers=

std::ifstream train_label_input("../train_MNIST_labels.txt", std::ios::in);
std::ifstream val_label_input("../val_MNIST_labels.txt", std::ios::in);
std::string param(argv[pos]);
int next_delim = param.find(',', offset);

if(!train_image_input.is_open() || !val_image_input.is_open() || !train_label_input.is_open() ||
!val_label_input.is_open())throw std::runtime_error("can't read training data");
while(offset != std::string::npos){
layers.push_back(std::stoul(param.substr(offset, next_delim-offset)));

for(int i = 0;i<20000;i++){
std::vector<float> train_x(784);
std::vector<float> v_x(784);
if(next_delim != std::string::npos)offset = next_delim + 1;
else offset = next_delim;

std::vector<float> train_y(10);
std::vector<float> v_y(10);
for(int j = 0;j<784;j++){
train_image_input>>train_x[j];
if(i<10000)val_image_input>>v_x[j];
}
next_delim = param.find(',', offset);
}
}

for(int j = 0;j<10;j++){
train_label_input>>train_y[j];
if(i<10000)val_label_input>>v_y[j];
}
void get_activations(char** argv, int argc, std::vector<std::string>& activations){
int pos = find_arg(argv, argc, "--activations=");
if(pos == -1){
throw std::runtime_error("can't fine --activations= parameter");
}
int offset = 14; // len of activations or --activations=

std::string param(argv[pos]);
int next_delim = param.find(',', offset);

while(offset != std::string::npos){
activations.push_back(param.substr(offset, next_delim-offset));

example train_e{.x=train_x, .y=train_y};
if(next_delim != std::string::npos)offset = next_delim + 1;
else offset = next_delim;

train_dataset.push_back(train_e);
if(i<10000){
val_x.push_back(v_x);
val_y.push_back(v_y);
next_delim = param.find(',', offset);
}
}

void get_num_parameter(char **argv, int argc, const std::string& param_name, int &param) {
int pos = find_arg(argv, argc, param_name);
if(pos == -1){
std::stringstream ss;
ss<<"can't find parameter "<<param_name;
throw std::runtime_error(ss.str());
}
param = std::stoi(std::string(argv[pos + 1]));
}

void get_num_parameter(char **argv, int argc, const std::string& param_name, float &param) {
int pos = find_arg(argv, argc, param_name);
if(pos == -1){
std::stringstream ss;
ss<<"can't find parameter "<<param_name;
throw std::runtime_error(ss.str());
}
param = std::stof(std::string(argv[pos + 1]));
}

void read_data(const std::string& data_path, uint32_t data_size, uint32_t data_dim, std::vector<std::vector<float>>& data){
std::ifstream data_input(data_path);

if(!data_input.is_open())throw std::runtime_error("can't read data");

data = std::move(std::vector(data_size, std::vector<float>(data_dim)));

for(int i = 0;i<data_size;i++){
for(int j = 0;j<data_dim;j++){
data_input>>data[i][j];
}
}
}

int main(int argc, char** argv) {
std::vector<uint32_t> layers;
get_layers(argv, argc, layers);

std::vector<std::string> activations;
get_activations(argv, argc, activations);

int train_dataset_size;
std::string train_data_path;
std::string train_labels_path;

int x_dim;
int y_dim;

get_num_parameter(argv, argc, "--x_dim", x_dim);
get_num_parameter(argv, argc, "--y_dim", y_dim);

get_num_parameter(argv, argc, "--train_dataset_size", train_dataset_size);

get_dataset(argv, argc, train_data_path, train_labels_path, true);

int val_dataset_size;
std::string val_data_path;
std::string val_labels_path;

get_num_parameter(argv, argc, "--val_dataset_size", val_dataset_size);
get_dataset(argv, argc, val_data_path, val_labels_path);

int batch_size;
get_num_parameter(argv, argc, "--batch_size", batch_size);

int optimization_steps;
get_num_parameter(argv, argc, "--optimization_steps", optimization_steps);

float rl;
get_num_parameter(argv, argc, "--learning_rate", rl);

MLP mlp = MLP(x_dim, batch_size, layers, activations);

mlp.forward_initialize();
std::vector<example> train_dataset(train_dataset_size);


std::vector<std::vector<float>> train_x;
std::vector<std::vector<float>> val_x;
std::vector<std::vector<float>> train_y;
std::vector<std::vector<float>> val_y;

read_data(train_data_path, train_dataset_size, x_dim, train_x);
read_data(train_labels_path, train_dataset_size, y_dim, train_y);

read_data(val_data_path, val_dataset_size, x_dim, val_x);
read_data(val_labels_path, val_dataset_size, y_dim, val_y);

for(int i = 0;i<train_dataset_size;i++){
train_dataset[i] = std::move(example{.x=train_x[i], .y=train_y[i]});
}

std::cout<<"accuracy before training: "<<mlp.evaluate(val_x, val_y)<<std::endl;

std::unordered_map<std::string, float> params;
params["learning_rate"] = 0.3;
std::unordered_map<std::string, float> optimizer_params;
optimizer_params["learning_rate"] = rl;

ClassificationTrainer trainer = ClassificationTrainer(&mlp, train_dataset, params);
ClassificationTrainer trainer = ClassificationTrainer(&mlp, train_dataset, optimizer_params);

std::vector<float> loss_history;

trainer.train(1000, loss_history, 1);
trainer.train(optimization_steps, loss_history, 1);

std::cout<<"accuracy after training: "<<mlp.evaluate(val_x, val_y)<<std::endl;

return 0;
}
}
6 changes: 4 additions & 2 deletions src/MLP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@

#include <MLP.h>

MLP::MLP(uint32_t input_size, uint32_t batch_size, const std::vector<int> &layer_dims, const std::vector<std::string> &activations) {
MLP::MLP(uint32_t input_size, uint32_t batch_size, const std::vector<uint32_t> &layer_dims, const std::vector<std::string> &activations) {
setup_vulkan(instance, debugMessenger, physicalDevice, queueFamilyIndex, device, queue);

if(layer_dims.size() != activations.size())throw std::invalid_argument("layers should have same size as activations");

for(int i = 0;i<layer_dims.size();i++){
add(layer_dims[i], activations[i], input_size, batch_size);
}
}

void MLP::add(int layer_dim, const std::string &activation, uint32_t input_size, uint32_t batch_size) {
void MLP::add(uint32_t layer_dim, const std::string &activation, uint32_t input_size, uint32_t batch_size) {
if(layers.empty() && (input_size == 0 || batch_size == 0)){
throw std::invalid_argument("first layer should specify input and batch size greater than 0");
}
Expand Down
1 change: 1 addition & 0 deletions src/classification_trainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ClassificationTrainer::ClassificationTrainer(MLP* mlp,
this->mlp = mlp;

if(get_layers().empty())throw std::invalid_argument("model should contain some layers");
if(dynamic_cast<SoftmaxLayer*>((get_layers().back())) == nullptr)throw std::invalid_argument("last activation should be softmax");

this->dataset = dataset;

Expand Down

0 comments on commit 1f19d9e

Please sign in to comment.