-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
207 lines (182 loc) · 5.46 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//// main.cpp
#include "Matrix.h"
#include "iostream"
#include "Activation.h"
#include "Dense.h"
#include "MlpNetwork.h"
#include <iostream>
#include <fstream>
#define QUIT "q"
#define INSERT_IMAGE_PATH "Please insert image path:"
#define ERROR_INAVLID_PARAMETER "Error: invalid Parameters file for layer: "
#define ERROR_INVALID_INPUT "Error: Failed to retrieve input. Exiting.."
#define ERROR_INVALID_IMG "Error: invalid image path or size: "
#define USAGE_MSG "Usage:\n" \
"\t./mlpnetwork w1 w2 w3 w4 b1 b2 b3 b4\n" \
"\twi - the i'th layer's weights\n" \
"\tbi - the i'th layer's biases"
#define USAGE_ERR "Error: wrong number of arguments."
#define ARGS_START_IDX 1
#define ARGS_COUNT (ARGS_START_IDX + (MLP_SIZE * 2))
#define WEIGHTS_START_IDX ARGS_START_IDX
#define BIAS_START_IDX (ARGS_START_IDX + MLP_SIZE)
/**
* Prints program usage to stdout.
* @param argc number of arguments given in the program
* @throw std::domain_error in case of wrong number of arguments
*/
void usage (int argc) noexcept (false)
{
if (argc != ARGS_COUNT)
{
throw std::domain_error (USAGE_ERR);
}
std::cout << USAGE_MSG << std::endl;
}
/**
* Given a binary file path and a matrix,
* reads the content of the file into the matrix.
* file must match matrix in size in order to read successfully.
* @param filePath - path of the binary file to read
* @param mat - matrix to read the file into.
* @return boolean status
* true - success
* false - failure
*/
bool readFileToMatrix (const std::string &filePath, Matrix &mat)
{
std::ifstream file(filePath, std::ios::in | std::ios::binary);
if (!file.is_open())
{
return false;
}
// Check if the file size matches the expected size
file.seekg(0,std::ios::end);
std::streampos fileSize = file.tellg();
if (fileSize != sizeof(float) * mat.get_rows() * mat.get_cols())
{
return false;
}
file.seekg(0, std::ios::beg);
// Read data into float matrix
for (int i = 0; i < mat.get_cols()*mat.get_rows(); ++i)
{
float value;
file.read(reinterpret_cast<char*>(&value), sizeof(float));
mat[i] = value;
}
file.close();
return true;
}
/**
* Loads MLP parameters from weights & biases paths
* to Weights[] and Biases[].
* Throws an exception upon failures.
* @param paths array of programs arguments, expected to be mlp parameters
* path.
* @param weights array of matrix, weigths[i] is the i'th layer weights matrix
* @param biases array of matrix, biases[i] is the i'th layer bias matrix
* (which is actually a vector)
* @throw std::invalid_argument in case of problem with a certain argument
*/
void loadParameters (char *paths[ARGS_COUNT], Matrix weights[MLP_SIZE],
Matrix biases[MLP_SIZE]) noexcept (false)
{
for (int i = 0; i < MLP_SIZE; i++)
{
weights[i] = Matrix (weights_dims[i].rows, weights_dims[i].cols);
biases[i] = Matrix (bias_dims[i].rows, bias_dims[i].cols);
std::string weightsPath (paths[WEIGHTS_START_IDX + i]);
std::string biasPath (paths[BIAS_START_IDX + i]);
if (!(readFileToMatrix (weightsPath, weights[i]) &&
readFileToMatrix (biasPath, biases[i])))
{
auto msg = ERROR_INAVLID_PARAMETER + std::to_string (i + 1);
throw std::invalid_argument (msg);
}
}
}
/**
* This programs Command line interface for the mlp network.
* Looping on: {
* Retrieve user input
* Feed input to mlpNetwork
* print image & netowrk prediction
* }
* Throws an exception on fatal errors: unable to read user input path.
* @param mlp MlpNetwork to use in order to predict img.
* @throw std::invalid_argument in case of problem with the user input path
*/
void mlpCli (MlpNetwork &mlp) noexcept (false)
{
Matrix img (img_dims.rows, img_dims.cols);
std::string imgPath;
std::cout << INSERT_IMAGE_PATH << std::endl;
std::cin >> imgPath;
if (!std::cin.good ())
{
throw std::invalid_argument (ERROR_INVALID_INPUT);
}
while (imgPath != QUIT)
{
if (readFileToMatrix (imgPath, img))
{
Matrix imgVec = img;
digit output = mlp (imgVec.vectorize ());
std::cout << "Image processed:" << std::endl
<< img << std::endl;
std::cout << "Mlp result: " << output.value <<
" at probability: " << output.probability << std::endl;
}
else
{
throw std::invalid_argument (ERROR_INVALID_IMG + imgPath);
}
std::cout << INSERT_IMAGE_PATH << std::endl;
std::cin >> imgPath;
if (!std::cin.good ())
{
throw std::invalid_argument (ERROR_INVALID_INPUT);
}
}
}
/**
* Program's main
* @param argc count of args
* @param argv args values
* @return program exit status code
*/
int main (int argc, char **argv)
{
try
{
usage (argc);
}
catch (const std::domain_error &domainError)
{
std::cerr << domainError.what () << std::endl;
return EXIT_FAILURE;
}
Matrix weights[MLP_SIZE];
Matrix biases[MLP_SIZE];
try
{
loadParameters (argv, weights, biases);
}
catch (const std::invalid_argument &invalidArgument)
{
std::cerr << invalidArgument.what () << std::endl;
return EXIT_FAILURE;
}
MlpNetwork mlp (weights, biases);
try
{
mlpCli (mlp);
}
catch (const std::invalid_argument &invalidArgument)
{
std::cerr << invalidArgument.what () << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}