I wrote a `Matrix` struct and a neural net that uses it. Why is this slow? Gprof blames `Matrix::operator()(int, int)` which I suppose is my constructor, and `Matrix::operator*(Matrix)` and `vector<float>::operator[]`. #include <iostream> //#include <C:/Users/David/Google Drive/Coding/neural_c/Launcher.h> #include <fstream> #include <assert.h> #include <functional> #include <vector> #include <math.h> #include <algorithm> #include <random> #include <time.h> using namespace std; #define debug(x) cout << #x << " = " << x << endl #define debug_(x) cout << #x << " = " << x << " : " #define linearize(r, c) r + rows*c default_random_engine generator(time(NULL)); normal_distribution<float> _rng(0, 1); auto rng = [](){return _rng(generator);}; auto logistic = [](float x){return 1/(1+exp(-x));}; auto square = [](float x){return x*x;}; struct Matrix{ int rows, cols, size; int label=-1; vector<float> data; Matrix(int r=1, int c=1){ //column major rows = r; cols = c; size = r*c; data.resize(size); } Matrix one_to_many(){ Matrix m(10); m.data[label] = 1; return m; } // // Matrix(const Matrix &m){ // rows = m.rows; // cols = m.cols; // size = m.size; // data.resize(size); // copy(m.data.begin(), m.data.end(), data.begin()); // } void randomize(){ for (int i=0; i<size; i++) data[i] = rng(); } float &operator()(int r, int c) { //assert(0<=r && r<rows && 0<=c && c<cols); return data[linearize(r,c)]; //return data[r+rows*c]; } float &operator[](int i){//linear access assert(0<=i && i<size); return data[i]; } Matrix operator*(Matrix m) { //assert(cols==m.rows); Matrix product(rows, m.cols); for (int r=0; r<product.rows; r++) for (int c=0; c<product.cols; c++) for (int i=0; i<cols; i++) product(r,c) += (*this)(r, i) * m(i, c); return product; } Matrix operator*(float f){ Matrix product(rows, cols); #pragma omp parallel for for (int i=0; i<size; i++) product[i] = (*this)[i]*f; return product; } float sum(){ float sum=0; //#pragma omp parallel for reduction(+:sum) for (int i=0; i<size; i++) sum += (*this)[i]; return sum; } float abs_sum(){ float sum=0; //#pragma omp parallel for reduction(+:sum) for (int i=0; i<size; i++) sum += abs((*this)[i]); return sum; } Matrix operator+(Matrix &m){ Matrix sum(rows, cols); #pragma omp parallel for for (int i=0; i<size; i++) sum[i] = (*this)[i] + m[i]; return sum; } Matrix operator-(Matrix &m){ //return m; Matrix negated=m*-1; return (*this) + negated; } bool operator==(Matrix &m){ for (int i=0; i<size; i++) if (data[i] != m.data[i]) return false; return true; } template<typename Func> void apply(Func f){ //#pragma omp parallel for for (int i=0; i<size; i++) (*this)[i] = f((*this)[i]); } void print(){ for (int r=0; r<rows; r++){ for (int c=0; c<cols; c++) cout << (*this)(r, c) << " "; cout << endl; } cout << endl; } void square_print(){ Matrix square(sqrt(size), sqrt(size)); square.data = data; square.print(); } }; struct Net{ vector<Matrix> weights; Net(vector<int> sizes){ for (int i=0; i<sizes.size()-1; i++){ weights.push_back(Matrix(sizes[i+1], sizes[i])); } for (Matrix& weight: weights) weight.randomize(); } Matrix operator()(const Matrix &x){ //return x; //for (int i=0; i<10000; i++){x[0]+=.00001;} Matrix activation = x; for (int i=0; i<weights.size()-1; i++){ activation = weights[0]*activation; activation.apply(logistic); } return weights[weights.size()-1]*activation; } float difference_squared(Matrix x, Matrix t){ Matrix y=(*this)(x); // 5/13 Matrix difference_squared = t-y; // 4/12 difference_squared.apply(square); return difference_squared.sum(); } float difference_squared(vector<Matrix> X, vector<Matrix> T){ float total=0; for (int i=0; i<X.size(); i++) total += difference_squared(X[i], T[i]); return total; } float error_normalized(Matrix x, Matrix t){ float dif_sq = difference_squared(x, t); float t_average_magnitude = t.abs_sum() / t.size; return pow(dif_sq, .5) / t_average_magnitude; } float error_normalized(vector<Matrix> X, vector<Matrix> T){ float total=0; for (int i=0; i<X.size(); i++) total += error_normalized(X[i], T[i]); return total/X.size(); } float learn(Matrix x, Matrix t, float learning_rate=.0001, float dw=.001){ float error, error_shifted, partial_derivative; for (int layer=0; layer<weights.size(); layer++) for (int i=0; i<weights[layer].size; i++){ error = difference_squared(x, t); weights[layer].data[i] += dw; error_shifted = difference_squared(x, t); weights[layer].data[i] -= dw; partial_derivative = (error_shifted - error) / dw; weights[layer].data[i] -= learning_rate * partial_derivative; } return error; } void print(){ for (Matrix m: weights){ m.print(); cout << "\n"; } } }; vector<Matrix> read_data(int images=1000){ ifstream in("mnist_train.csv"); vector<Matrix> data; for (int image=0; image<images; image++){ Matrix datum(28*28); int temp=-1; in >> datum.label; for(int i=0; i<28*28; i++) in >> datum.data[i]; data.push_back(datum); } return data; } int main(){ vector<Matrix> images = read_data(10); vector<Matrix> labels; for (Matrix image: images){ labels.push_back(image.one_to_many()); assert(labels[labels.size()-1].abs_sum()==1); // image.square_print(); //labels[labels.size()-1].print(); } printf("data read\n"); Net brain({28*28, 3, 10}); printf("brain created!\n"); // int epochs=3; debug(brain.difference_squared(images, labels)); for (int epoch=0; epoch<epochs; epoch++){ for (int i=0; i<images.size(); i++) brain.learn(images[i], labels[i], .01); debug_(epoch); debug(brain.difference_squared(images, labels)); //debug(brain.error_normalized(images, labels)); } printf("trained\n"); printf("done\n"); } //alias c="g++ neural.cpp -o neural.exe -O3 -fopenmp --std=c++11;time ./neural.exe"