jacobian

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 7445f69987923b959916c1b5c5cf210b559c4d4c
parent d10ede5930bca16e38440e74602f20a3ebd02c04
Author: David Freifeld <freifeld.david@gmail.com>
Date:   Tue, 24 Nov 2020 23:05:36 -0800

Indendation + debugging

Diffstat:
Msrc/cnn.cpp | 176++++++++++++++++++++++++++++++++++++++++----------------------------------------
1 file changed, 88 insertions(+), 88 deletions(-)

diff --git a/src/cnn.cpp b/src/cnn.cpp @@ -19,7 +19,7 @@ #define checknan(x, loc) #endif -// NOTE: Below two functions not mine, from https://compvisionlab.wordpress.com/2014/01/01/c-code-for-reading-mnist-data-set/ +// NOTE: Below three functions not mine, from https://compvisionlab.wordpress.com/2014/01/01/c-code-for-reading-mnist-data-set/ int ReverseInt (int i) { unsigned char ch1, ch2, ch3, ch4; @@ -96,20 +96,20 @@ unsigned char* read_mnist_labels(std::string full_path, int number_of_labels) { ConvLayer::ConvLayer(int x, int y, int stride, int kern_x, int kern_y, int pad) :padding(pad), stride_len(stride) { - pad*=2; - input = new Eigen::MatrixXf (x+pad,y+pad); - for (int i = 0; i < (x+pad)*(y+pad); i++) { - (*input)((int)i / (y+pad),i%(y+pad)) = 0; - } - kernel = new Eigen::MatrixXf (kern_x, kern_y); - for (int i = 0; i < kern_x*kern_y; i++) { - (*kernel)((int)i / kern_y,i%kern_y) = (float) rand() / RAND_MAX; - } - output = new Eigen::MatrixXf ((x-kern_x+1+pad/stride_len), (y-kern_y+1+pad/stride_len)); - for (int i = 0; i < (x-kern_y+1+pad/stride_len)*(y-kern_x+1+pad/stride_len); i++) { - (*output)((int)i / (y-kern_y+1+pad/stride_len),i%(y-kern_y+1+pad/stride_len)) = 0; - } - bias = 0; + pad*=2; + input = new Eigen::MatrixXf (x+pad,y+pad); + for (int i = 0; i < (x+pad)*(y+pad); i++) { + (*input)((int)i / (y+pad),i%(y+pad)) = 0; + } + kernel = new Eigen::MatrixXf (kern_x, kern_y); + for (int i = 0; i < kern_x*kern_y; i++) { + (*kernel)((int)i / kern_y,i%kern_y) = (float) rand() / RAND_MAX; + } + output = new Eigen::MatrixXf ((x-kern_x+1+pad/stride_len), (y-kern_y+1+pad/stride_len)); + for (int i = 0; i < (x-kern_y+1+pad/stride_len)*(y-kern_x+1+pad/stride_len); i++) { + (*output)((int)i / (y-kern_y+1+pad/stride_len),i%(y-kern_y+1+pad/stride_len)) = 0; + } + bias = 0; }; void ConvLayer::convolute() @@ -238,81 +238,83 @@ void ConvNet::list_net() void ConvNet::backpropagate() { -std::vector<Eigen::MatrixXf> gradients; - std::vector<Eigen::MatrixXf> deltas; - Eigen::MatrixXf error (layers[length-1].contents->rows(), layers[length-1].contents->cols()); - for (int i = 0; i < error.rows(); i++) { - for (int j = 0; j < error.cols(); j++) { - float truth; - if (j==(*labels)(i,0)) truth = 1; - else truth = 0; - error(i,j) = (*layers[length-1].contents)(i,j) - truth; - checknan(error(i,j), "gradient of final layer"); - } - } - gradients.push_back(error); - deltas.push_back((*layers[length-2].contents).transpose() * gradients[0]); - int counter = 1; - for (int i = length-2; i >= 1; i--) { - gradients.push_back((gradients[counter-1] * layers[i].weights->transpose()).cwiseProduct(*layers[i].dZ)); - deltas.push_back(layers[i-1].contents->transpose() * gradients[counter]); - counter++; - } - for (int i = 0; i < length-1; i++) { - update(deltas, i); - if (reg_type == 2) *layers[length-2-i].weights -= ((lambda/batch_size) * (*layers[length-2-i].weights)); - else if (reg_type == 1) *layers[length-2-i].weights -= ((lambda/(2*batch_size)) * l1_deriv(*layers[length-2-i].weights)); - *layers[length-1-i].bias -= bias_lr * gradients[i]; - if (strcmp(layers[length-2-i].activation_str, "prelu") == 0) { - float sum = 0; - for (int j = 0; j < layers[length-2-i].contents->rows(); j++) { - for (int k = 0; k < layers[length-2-i].contents->cols(); k++) { - if ((*layers[length-2-i].contents)(j,k)/layers[length-2-i].alpha <= 0) { - // Choice of using index i+1 here is questionable. TODO: REVIEW - sum += gradients[i+1](j,k) * (*layers[length-2-i].contents)(j,k)/layers[length-2-i].alpha; - } + std::vector<Eigen::MatrixXf> gradients; + std::vector<Eigen::MatrixXf> deltas; + Eigen::MatrixXf error (layers[length-1].contents->rows(), layers[length-1].contents->cols()); + for (int i = 0; i < error.rows(); i++) { + for (int j = 0; j < error.cols(); j++) { + float truth; + if (j==(*labels)(i,0)) truth = 1; + else truth = 0; + error(i,j) = (*layers[length-1].contents)(i,j) - truth; + checknan(error(i,j), "gradient of final layer"); } - } - layers[length-2-i].alpha += learning_rate * sum; - float a = layers[length-2-i].alpha; - layers[length-2-i].activation = [a](float x) -> float - { - if (x > 0) return x; - else return a * x; - }; - layers[length-2-i].activation_deriv = [a](float x) -> float - { - if (x > 0) return 1; - else return a; - }; } - } - Eigen::Map<Eigen::MatrixXf> reshaped(gradients[gradients.size()-1].data(), conv_layers[conv_layers.size()-1].output->rows(),conv_layers[conv_layers.size()-1].output->cols()); - gradients[gradients.size()-1] = reshaped; - std::vector<Eigen::MatrixXf> conv_deltas; - conv_deltas.emplace_back(conv_layers[conv_layers.size()-1].input->rows() - gradients[length-1].rows()+1, conv_layers[conv_layers.size()-1].input->cols() - gradients[length-1].cols()+1); - for (int i = 0; i < conv_deltas[0].cols(); i+=conv_layers[conv_layers.size()-1].stride_len) { - for (int j = 0; j < conv_deltas[0].rows(); j+=conv_layers[conv_layers.size()-1].stride_len) { - // TODO: Investigate legitimacy of tranpose | -t :quality: - conv_deltas[0](j,i) = (gradients[length-1] * (conv_layers[conv_layers.size()-1].input->block(j, i, gradients[length-1].rows(), gradients[length-1].cols())).transpose()).sum(); + gradients.push_back(error); + deltas.push_back((*layers[length-2].contents).transpose() * gradients[0]); + int counter = 1; + for (int i = length-2; i >= 1; i--) { + gradients.push_back((gradients[counter-1] * layers[i].weights->transpose()).cwiseProduct(*layers[i].dZ)); + deltas.push_back(layers[i-1].contents->transpose() * gradients[counter]); + counter++; } - } - std::cout << *conv_layers[conv_layers.size()-1].kernel << "\n\n" << conv_deltas[conv_deltas.size()-1]; - *conv_layers[conv_layers.size()-1].kernel -= conv_deltas[0]; - conv_layers[conv_layers.size()-1].bias -= gradients[gradients.size()-1].sum(); - counter = 1; - std::cout << "?\n"; - for (int i = conv_layers.size()-2; i > 0; i--) { - conv_deltas.emplace_back(conv_layers[i].input->rows() - conv_deltas[counter-1].rows()+1 ,conv_layers[i].input->cols() - conv_deltas[counter-1].cols()+1); - for (int j = 0; j < conv_deltas[counter].cols(); j+=conv_layers[i].stride_len) { - for (int k = 0; k < conv_deltas[counter].rows(); k+=conv_layers[i].stride_len) { - conv_deltas[i](k,j) -= (conv_deltas[counter-1] * (conv_layers[i].input->block(j, i, conv_deltas[counter-1].rows(), conv_deltas[counter-1].cols()))).sum(); - } + for (int i = 0; i < length-1; i++) { + update(deltas, i); + if (reg_type == 2) *layers[length-2-i].weights -= ((lambda/batch_size) * (*layers[length-2-i].weights)); + else if (reg_type == 1) *layers[length-2-i].weights -= ((lambda/(2*batch_size)) * l1_deriv(*layers[length-2-i].weights)); + *layers[length-1-i].bias -= bias_lr * gradients[i]; + if (strcmp(layers[length-2-i].activation_str, "prelu") == 0) { + float sum = 0; + for (int j = 0; j < layers[length-2-i].contents->rows(); j++) { + for (int k = 0; k < layers[length-2-i].contents->cols(); k++) { + if ((*layers[length-2-i].contents)(j,k)/layers[length-2-i].alpha <= 0) { + // Choice of using index i+1 here is questionable. TODO: REVIEW + sum += gradients[i+1](j,k) * (*layers[length-2-i].contents)(j,k)/layers[length-2-i].alpha; + } + } + } + layers[length-2-i].alpha += learning_rate * sum; + float a = layers[length-2-i].alpha; + layers[length-2-i].activation = [a](float x) -> float + { + if (x > 0) return x; + else return a * x; + }; + layers[length-2-i].activation_deriv = [a](float x) -> float + { + if (x > 0) return 1; + else return a; + }; + } + } + std::cout << conv_layers[conv_layers.size()-1].output->rows() << "\n"; + Eigen::Map<Eigen::MatrixXf> reshaped(gradients[gradients.size()-1].data(), conv_layers[conv_layers.size()-1].output->rows(),conv_layers[conv_layers.size()-1].output->cols()); + gradients[gradients.size()-1] = reshaped; + std::vector<Eigen::MatrixXf> conv_deltas; + std::cout << conv_layers[conv_layers.size()-1].input->rows() << " " << 15 - gradients[length-1].rows()+1 << "\n\n" << 15 - gradients[length-1].cols()+1 << "\n"; + conv_deltas.emplace_back(15 - gradients[length-1].rows()+1, 15 - gradients[length-1].cols()+1); + for (int i = 0; i < conv_deltas[0].cols(); i+=conv_layers[conv_layers.size()-1].stride_len) { + for (int j = 0; j < conv_deltas[0].rows(); j+=conv_layers[conv_layers.size()-1].stride_len) { + // TODO: Investigate legitimacy of transpose | -t :quality: + conv_deltas[0](j,i) = (gradients[length-1] * (conv_layers[conv_layers.size()-1].input->block(j, i, gradients[length-1].rows(), gradients[length-1].cols())).transpose()).sum(); + } } - *conv_layers[i].kernel -= conv_deltas[counter]; + std::cout << *conv_layers[conv_layers.size()-1].kernel << "\n\n" << conv_deltas[0]; + *conv_layers[conv_layers.size()-1].kernel -= conv_deltas[0]; conv_layers[conv_layers.size()-1].bias -= gradients[gradients.size()-1].sum(); - counter++; - } + counter = 1; + std::cout << "?\n"; + for (int i = conv_layers.size()-2; i > 0; i--) { + conv_deltas.emplace_back(conv_layers[i].input->rows() - conv_deltas[counter-1].rows()+1 ,conv_layers[i].input->cols() - conv_deltas[counter-1].cols()+1); + for (int j = 0; j < conv_deltas[counter].cols(); j+=conv_layers[i].stride_len) { + for (int k = 0; k < conv_deltas[counter].rows(); k+=conv_layers[i].stride_len) { + conv_deltas[i](k,j) -= (conv_deltas[counter-1] * (conv_layers[i].input->block(j, i, conv_deltas[counter-1].rows(), conv_deltas[counter-1].cols()))).sum(); + } + } + *conv_layers[i].kernel -= conv_deltas[counter]; + conv_layers[conv_layers.size()-1].bias -= gradients[gradients.size()-1].sum(); + counter++; + } } void ConvNet::train() @@ -325,13 +327,10 @@ void ConvNet::train() } process(); feedforward(); - // if (batches == 0) list_net(); backpropagate(); cost_sum += cost(); acc_sum += accuracy(); batches++; - // if (batches == 1) (1); - // if (batches > 15) exit(1); } epoch_acc = 1.0/(100) * acc_sum; epoch_cost = 1.0/(100) * cost_sum; @@ -348,6 +347,7 @@ int main() net.add_conv_layer(28,28,1,9,9,0); // net.add_pool_layer(20,20,1,6,6,0); net.add_conv_layer(15,15,1,6,6,0); + std::cout << net.conv_layers[net.conv_layers.size()-1].output->rows() << "\n"; //net.add_pool_layer(10,10,1,2,2,0); net.add_layer(400, "sigmoid", sigmoid, sigmoid_deriv); net.add_layer(5, "lecun_tanh", lecun_tanh, lecun_tanh_deriv);