void Net::ReadLabels(const mxArray *mx_labels) { std::vector<size_t> labels_dim = mexGetDimensions(mx_labels); mexAssert(labels_dim.size() == 2, "The label array must have 2 dimensions"); size_t samples_num = labels_dim[0]; size_t classes_num = labels_dim[1]; mexAssert(classes_num == layers_.back()->length_, "Labels and last layer must have equal number of classes"); MatCPU labels_norm; // order_ == false mexGetMatrix(mx_labels, labels_norm); if (params_.balance_) { MatCPU labels_mean(1, classes_num); Mean(labels_norm, labels_mean, 1); mexAssert(!labels_mean.hasZeros(), "Balancing impossible: one of the classes is not presented"); MatCPU cpucoeffs(1, classes_num); cpucoeffs.assign(1); cpucoeffs /= labels_mean; classcoefs_.resize(1, classes_num); classcoefs_ = cpucoeffs; classcoefs_ /= (ftype) classes_num; } labels_.resize(samples_num, classes_num); labels_.reorder(true, false); // order_ == true; labels_ = labels_norm; }
void Net::Classify(const mxArray *mx_data, Mat &pred) { //mexPrintMsg("Start classification..."); size_t mapnum = 1; if (mexIsCell(mx_data)) { mapnum = mexGetNumel(mx_data); } mexAssert(mapnum == layers_.front()->outputmaps_, "Data must have the same number of cells as outputmaps on the first layer"); std::vector< std::vector<Mat> > data(mapnum); for (size_t i = 0; i < mapnum; ++i) { const mxArray *mx_cell; if (mexIsCell(mx_data)) { mx_cell = mxGetCell(mx_data, i); } else { mx_cell = mx_data; } std::vector<size_t> data_dim = mexGetDimensions(mx_cell); mexAssert(data_dim.size() == 3, "The data array must have 3 dimensions"); mexAssert(data_dim[0] == layers_.front()->mapsize_[0] && data_dim[1] == layers_.front()->mapsize_[1], "Data and the first layer must have equal sizes"); mexGetMatrix3D(mx_cell, data[i]); } Forward(data, pred, false); //mexPrintMsg("Classification finished"); }
void Net::ReadData(const mxArray *mx_data) { LayerInput *firstlayer = static_cast<LayerInput*>(layers_[0]); std::vector<size_t> data_dim = mexGetDimensions(mx_data); size_t mapsize1, mapsize2; if (kMapsOrder == kMatlabOrder) { mapsize1 = data_dim[0]; mapsize2 = data_dim[1]; } else { mapsize1 = data_dim[1]; mapsize2 = data_dim[0]; } mexAssert(mapsize1 == firstlayer->mapsize_[0] && mapsize2 == firstlayer->mapsize_[1], "Data and the first layer must have equal sizes"); size_t outputmaps = 1; if (data_dim.size() > 2) { outputmaps = data_dim[2]; } mexAssert(outputmaps == firstlayer->outputmaps_, "Data's 3rd dimension must be equal to the outputmaps on the input layer"); size_t samples_num = 1; if (data_dim.size() > 3) { samples_num = data_dim[3]; } ftype *data_ptr = mexGetPointer(mx_data); // transposed array data_.attach(data_ptr, samples_num, mapsize1 * mapsize2 * outputmaps, 1, true); if (firstlayer->norm_ > 0) { MatCPU norm_data(data_.size1(), data_.size2()); norm_data.reorder(true, false); norm_data = data_; norm_data.Normalize(firstlayer->norm_); Swap(data_, norm_data); } }
void LayerScal::Init(const mxArray *mx_layer, Layer *prev_layer) { mexAssert(prev_layer->type_ != "f", "The 's' type layer cannot be after 'f' type layer"); mexAssert(mexIsField(mx_layer, "scale"), "The 's' type layer must contain the 'scale' field"); mapsize_.resize(prev_layer->mapsize_.size()); std::vector<double> scale = mexGetVector(mexGetField(mx_layer, "scale")); mexAssert(scale.size() == mapsize_.size(), "Length of scale vector and maps dimensionality must coincide"); scale_.resize(scale.size()); for (size_t i = 0; i < mapsize_.size(); ++i) { scale_[i] = (size_t) scale[i]; mexAssert(1 <= scale_[i], "Scale size on the 's' layer must be greater or equal to 1"); mapsize_[i] = ceil((double) prev_layer->mapsize_[i] / scale_[i]); } outputmaps_ = prev_layer->outputmaps_; if (!mexIsField(mx_layer, "function")) { function_ = "mean"; } else { function_ = mexGetString(mexGetField(mx_layer, "function")); } std::string errmsg = function_ + " - unknown function for the layer"; mexAssert(function_ == "max" || function_ == "mean", errmsg); activ_.resize(outputmaps_); deriv_.resize(outputmaps_); }
void Mat::MaxTrim(Mat &trimmed, std::vector<size_t> &coords) const { mexAssert(trimmed.size1() <= mat_.size1(), "In 'Mat::Trim' the trimmed image is larger than original"); mexAssert(trimmed.size2() <= mat_.size2(), "In 'Mat::Trim' the trimmed image is larger than original"); size_t lv = std::floor((double) (trimmed.size1() - 1)/2); size_t lh = std::floor((double) (trimmed.size2() - 1)/2); double maxval = mat_(lv, lh); coords[0] = lv; coords[1] = lh; for (size_t i = lv; i < lv + mat_.size1() - trimmed.size1(); ++i) { for (size_t j = lh; j < lh + mat_.size2() - trimmed.size2(); ++j) { if (maxval < mat_(i, j)) { maxval = mat_(i, j); coords[0] = i; coords[1] = j; } } } for (size_t i = 0; i < trimmed.size1(); ++i) { for (size_t j = 0; j < trimmed.size2(); ++j) { trimmed(i, j) = mat_(coords[0]+i-lv, coords[1]+j-lh); } } }
void Net::InitLayers(const mxArray *mx_layers) { //mexPrintMsg("Start layers initialization..."); std::srand((unsigned) std::time(0)); size_t layers_num = mexGetNumel(mx_layers); mexAssert(layers_num >= 2, "The net must contain at least 2 layers"); const mxArray *mx_layer = mexGetCell(mx_layers, 0); std::string layer_type = mexGetString(mexGetField(mx_layer, "type")); mexAssert(layer_type == "i", "The first layer must be the type of 'i'"); layers_.resize(layers_num); layers_[0] = new LayerInput(); //mexPrintMsg("Initializing layer of type", layer_type); layers_.front()->Init(mx_layer, NULL); for (size_t i = 1; i < layers_num; ++i) { Layer *prev_layer = layers_[i-1]; mx_layer = mexGetCell(mx_layers, i); layer_type = mexGetString(mexGetField(mx_layer, "type")); if (layer_type == "c") { layers_[i] = new LayerConv(); } else if (layer_type == "s") { layers_[i] = new LayerScal(); } else if (layer_type == "f") { layers_[i] = new LayerFull(); } else { mexAssert(false, layer_type + " - unknown type of the layer"); } //mexPrintMsg("Initializing layer of type", layer_type); layers_[i]->Init(mx_layer, prev_layer); } mexAssert(layer_type == "f", "The last layer must be the type of 'f'"); //mexPrintMsg("Layers initialization finished"); }
Mat& Mat::ReshapeFrom(const std::vector< std::vector<Mat> > &squeezed) { // stretches 1, 3 and 4 dimensions size_to the 1st one. The 2nd dimension stays the same. size_t outputmaps = squeezed.size(); mexAssert(outputmaps > 0, "In 'Mat::ReshapeFrom' the number of output maps is zero"); size_t batchsize = squeezed[0].size(); mexAssert(batchsize > 0, "In 'Mat::ReshapeFrom' the number of batches is zero"); size_t mapsize[2]; mapsize[0] = squeezed[0][0].size1(); mapsize[1] = squeezed[0][0].size2(); size_t numel = mapsize[0] * mapsize[1]; mat_.resize(outputmaps * numel, batchsize); for (size_t j = 0; j < outputmaps; ++j) { for (size_t k = 0; k < batchsize; ++k) { mexAssert(squeezed[j][k].size1() == mapsize[0], "In 'Mat::ReshapeFrom' the first dimension is not constant"); mexAssert(squeezed[j][k].size2() == mapsize[1], "In 'Mat::ReshapeFrom' the second dimension is not constant"); for (size_t u = 0; u < mapsize[0]; ++u) { for (size_t v = 0; v < mapsize[1]; ++v) { size_t ind = j*numel + u*mapsize[1] + v; mat_(ind, k) = squeezed[j][k](u, v); } } } } return *this; }
Mat& Mat::AddVect(const Mat &vect, size_t dim) { if (dim == 1) { mexAssert(vect.size2() == 1, "In 'Mat::AddVect' the second dimension must be 1"); mexAssert(mat_.size1() == vect.size1(), "In 'Mat::AddVect' the second dimension of matrix and length of vector are of the different size"); for (size_t i = 0; i < mat_.size1(); ++i) { for (size_t j = 0; j < mat_.size2(); ++j) { mat_(i, j) += vect(i, 0); } } } else if (dim == 2) { mexAssert(vect.size1() == 1, "In 'Mat::AddVect' the first dimension must be 1"); mexAssert(mat_.size2() == vect.size2(), "In 'Mat::AddVect' the first dimension of matrix and length of vector are of the different size"); for (size_t i = 0; i < mat_.size1(); ++i) { for (size_t j = 0; j < mat_.size2(); ++j) { mat_(i, j) += vect(0, j); } } } else { mexAssert(false, "In Mat::AddVect the dimension parameter must be either 1 or 2"); } return *this; }
Mat SubMat(const Mat &a, const std::vector<size_t> &ind, size_t dim) { mexAssert(ind.size() > 0, "In SubMat the index vector is empty"); Mat submat; if (dim == 1) { size_t maxind = *(std::max_element(ind.begin(), ind.end())); mexAssert(maxind < a.size1_, "In SubMat one of the indices is larger than the array size"); submat.resize(ind.size(), a.size2_); for (size_t i = 0; i < ind.size(); ++i) { for (size_t j = 0; j < a.size2(); ++j) { submat(i, j) = a(ind[i], j); } } } else if (dim == 2) { size_t maxind = *(std::max_element(ind.begin(), ind.end())); mexAssert(maxind < a.size2_, "In SubMat one of the indices is larger than the array size"); submat.resize(a.size1_, ind.size()); for (size_t i = 0; i < a.size1_; ++i) { for (size_t j = 0; j < ind.size(); ++j) { submat(i, j) = a(i, ind[j]); } } } else { mexAssert(false, "In Mat::SubMat the second parameter must be either 1 or 2"); } return submat; }
void Mat::SubMat(const std::vector<size_t> ind, size_t dim, Mat &submat) const { mexAssert(ind.size() > 0, "In SubMat the index vector is empty"); size_t minind = *(std::min_element(ind.begin(), ind.end())); mexAssert(minind >= 0, "In SubMat one of the indices is less than zero"); if (dim == 1) { size_t maxind = *(std::max_element(ind.begin(), ind.end())); mexAssert(maxind < mat_.size1(), "In SubMat one of the indices is larger than the array size"); submat.resize(ind.size(), mat_.size2()); for (size_t i = 0; i < ind.size(); ++i) { for (size_t j = 0; j < mat_.size2(); ++j) { submat(i, j) = mat_(ind[i], j); } } } else if (dim == 2) { size_t maxind = *(std::max_element(ind.begin(), ind.end())); mexAssert(maxind < mat_.size2(), "In SubMat one of the indices is larger than the array size"); submat.resize(mat_.size1(), ind.size()); for (size_t i = 0; i < mat_.size1(); ++i) { for (size_t j = 0; j < ind.size(); ++j) { submat(i, j) = mat_(i, ind[j]); } } } else { mexAssert(false, "In Mat::SubMat the second parameter must be either 1 or 2"); } }
void Net::InitDeriv(const Mat &labels_batch, ftype &loss) { size_t batchsize = labels_batch.size1(); size_t classes_num = labels_batch.size2(); Layer *lastlayer = layers_.back(); mexAssert(batchsize == lastlayer->batchsize_, "The number of objects in data and label batches is different"); mexAssert(classes_num == lastlayer->length_, "Labels in batch and last layer must have equal number of classes"); if (lastlayer->function_ == "SVM") { Mat lossmat = lastlayer->activ_mat_; ((lossmat *= labels_batch) *= -1) += 1; lossmat.CondAssign(lossmat, 0, false, 0); lastlayer->deriv_mat_ = lossmat; (lastlayer->deriv_mat_ *= labels_batch) *= -2; // correct loss also contains weightsT * weights / C, but it is too long to calculate it loss = (lossmat *= lossmat).Sum() / batchsize; } else if (lastlayer->function_ == "soft" || lastlayer->function_ == "sigm") { lastlayer->deriv_mat_ = lastlayer->activ_mat_; lastlayer->deriv_mat_ -= labels_batch; Mat lossmat = lastlayer->deriv_mat_; loss = (lossmat *= lastlayer->deriv_mat_).Sum() / (2 * batchsize); } lastlayer->deriv_mat_.MultVect(classcoefs_, 1); lastlayer->deriv_mat_.Validate(); }
Net::Net() { mexAssert(kDefaultOrder == false, "kDefaultOrder should be false"); mexAssert(kMapsOrder == kDefaultOrder, "kMapsOrder should be also false"); #if COMP_REGIME == 2 // GPU mexAssert(PRECISION == 1, "In the GPU version PRECISION should be 1"); MatGPU::CudaInit(); #endif }
void mexFunction(int nLhs, mxArray* pLhs[], int nRhs, const mxArray* pRhs[]) { mexAssert(nRhs == NARGIN, "Number of input arguments in wrong!"); mexAssert(nLhs == NARGOUT, "Number of output arguments is wrong!" ); Net net; net.InitLayers(IN_L); net.InitParams(IN_P); net.InitWeights(NULL); net.GetWeights(OUT_W); }
void Net::ReadData(const mxArray *mx_data) { std::vector<size_t> data_dim = mexGetDimensions(mx_data); mexAssert(data_dim.size() == 4, "The data array must have 4 dimensions"); mexAssert(data_dim[0] == layers_[0]->mapsize_[0] && data_dim[1] == layers_[0]->mapsize_[1], "Data and the first layer must have equal sizes"); mexAssert(data_dim[2] == layers_[0]->outputmaps_, "Data's 3rd dimension must be equal to the outputmaps on the input layer"); mexAssert(data_dim[3] > 0, "Input data array is empty"); ftype *data = mexGetPointer(mx_data); data_.attach(data, data_dim[3], data_dim[0] * data_dim[1] * data_dim[2]); }
void mexFunction(int nLhs, mxArray* pLhs[], int nRhs, const mxArray* pRhs[]) { mexAssert(nRhs == NARGIN, "Number of input arguments in wrong!"); mexAssert(nLhs == NARGOUT, "Number of output arguments is wrong!" ); size_t seed = (size_t) mexGetScalar(IN_S); Net net; net.InitRand(seed); net.InitLayers(IN_L); net.InitWeights(NULL); net.GetWeights(OUT_W); }
std::vector<size_t> Mat::MaxInd(size_t dim) const { std::vector<size_t> arrmax; if (dim == 1) { arrmax.assign(mat_.size2(), 0); for (size_t i = 0; i < mat_.size1(); ++i) { for (size_t j = 0; j < mat_.size2(); ++j) { if (mat_(i, j) > mat_(arrmax[j], j)) { arrmax[j] = i; } } } } else if (dim == 2) { arrmax.assign(mat_.size1(), 0); for (size_t i = 0; i < mat_.size1(); ++i) { for (size_t j = 0; j < mat_.size2(); ++j) { if (mat_(i, j) > mat_(i, arrmax[i])) { arrmax[i] = j; } } } } else { mexAssert(false, "In Mat::MaxInd the dimension parameter must be either 1 or 2"); } return arrmax; }
void MaxTrim(const Mat &image, std::vector<size_t> &coords, Mat &trimmed) { mexAssert(trimmed.size1_ <= image.size1_ && trimmed.size2_ <= image.size2_, "In 'MaxTrim' the trimmed image is larger than original"); size_t lv = std::floor((ftype) (trimmed.size1_ - 1)/2); size_t lh = std::floor((ftype) (trimmed.size2_ - 1)/2); ftype maxval = image(lv, lh); coords[0] = lv; coords[1] = lh; for (size_t i = lv; i < lv + image.size1_ - trimmed.size1_; ++i) { for (size_t j = lh; j < lh + image.size2_ - trimmed.size2_; ++j) { if (maxval < image(i, j)) { maxval = image(i, j); coords[0] = i; coords[1] = j; } } } for (size_t i = 0; i < trimmed.size1_; ++i) { for (size_t j = 0; j < trimmed.size2_; ++j) { trimmed(i, j) = image(coords[0]+i-lv, coords[1]+j-lh); } } }
Mat& Mat::reshape(size_t size1, size_t size2) { mexAssert(size1_ * size2_ == size1 * size2, "In Mat::reshape the sizes do not correspond"); size1_ = size1; size2_ = size2; return *this; }
void MaxScale(const Mat &image, const Mat &maxmat, Mat &scaled) { mexAssert(scaled.size1_ * scaled.size2_ == maxmat.size1_, "In 'MaxScale' sizes of matrices do not correspond"); for (size_t i = 0; i < maxmat.size1_; ++i) { scaled(maxmat(i, 0), maxmat(i, 1)) = image(maxmat(i, 2), maxmat(i, 3)); } }
Mat& Mat::CondProd(const Mat &condmat, ftype threshold, bool incase, ftype a) { mexAssert(size1_ == condmat.size1_ && size2_ == condmat.size2_, "In Mat::CondProd the sizes of matrices do not correspond"); for (size_t i = 0; i < size1_ * size2_ ; ++i) { if (incase == (condmat.data_[i] > threshold)) data_[i] *= a; // xor } return *this; }
Mat& Mat::SigmDer(const Mat& a) { mexAssert(size1_ == a.size1_ && size2_ == a.size2_, "In 'Mat::SigmDer' the matrices are of the different size"); for (size_t i = 0; i < size1_ * size2_; ++i) { data_[i] *= a.data_[i] * (1 - a.data_[i]); } return *this; }
Mat& Mat::operator /= (const Mat &a) { mexAssert(size1_ == a.size1_ && size2_ == a.size2_, "In 'Mat::/=' the matrices are of the different size"); for (size_t i = 0; i < size1_ * size2_; ++i) { data_[i] /= a.data_[i]; } return *this; }
Mat& Mat::operator -= (const Mat &a) { mexAssert(size1_ == a.size1_ && size2_ == a.size2_, "In Mat::-= the sizes of matrices do not correspond"); for (size_t i = 0; i < size1_ * size2_; ++i) { data_[i] -= a.data_[i]; } return *this; }
void MaxScaleDer(const Mat&scaled, const Mat &maxmat, Mat &restored) { mexAssert(scaled.size1_ * scaled.size2_ == maxmat.size1_, "In 'MaxScaleDer' sizes of matrices do not correspond"); restored.assign(0); for (size_t i = 0; i < maxmat.size1_; ++i) { restored(maxmat(i, 2), maxmat(i, 3)) += scaled(maxmat(i, 0), maxmat(i, 1)); } }
void LayerTrim::Init(const mxArray *mx_layer, Layer *prev_layer) { mexAssert(prev_layer->type_ != "f", "The 't' type layer cannot be after 'f' type layer"); numdim_ = prev_layer->numdim_; outputmaps_ = prev_layer->outputmaps_; length_prev_ = prev_layer->outputmaps_; mexAssert(mexIsField(mx_layer, "mapsize"), "The 't' type layer must contain the 'mapsize' field"); std::vector<ftype> mapsize = mexGetVector(mexGetField(mx_layer, "mapsize")); mexAssert(mapsize.size() == numdim_, "Length of the trim vector and maps dimensionality must coincide"); mapsize_.resize(numdim_); length_ = outputmaps_; for (size_t i = 0; i < numdim_; ++i) { mexAssert(mapsize[i] <= prev_layer->mapsize_[i], "In 't' layer new mapsize cannot be larger than the old one"); mapsize_[i] = (size_t) mapsize[i]; length_ *= mapsize_[i]; } }
void LayerConv::CalcWeights(Layer *prev_layer, int passnum) { StartTimer(); if (passnum < 2) return; Mat weights_der; if (passnum == 2) { weights_der.attach(weights_.der()); } else if (passnum == 3) { weights_der.attach(weights_.der2()); } #if COMP_REGIME != 2 std::vector< std::vector<Mat> > prev_activ, filters_der, deriv; InitMaps(prev_layer->activ_mat_, prev_layer->mapsize_, prev_activ); InitMaps(weights_der, filtersize_, filters_der); InitMaps(deriv_mat_, mapsize_, deriv); size_t i,j; int k; //#pragma omp parallel{ //for num_threads(12) private(fil_der) for (i = 0; i < outputmaps_; ++i) { for (j = 0; j < prev_layer->outputmaps_; ++j) { Mat fil_der(filtersize_); fil_der.assign(0); #if COMP_REGIME == 1 #endif for (k = 0; k < batchsize_; ++k) { Mat ker_mat(filtersize_); Filter(prev_activ[k][j], deriv[k][i], padding_, false, ker_mat); #if COMP_REGIME == 1 //#pragma omp critical #endif fil_der += ker_mat; } filters_der[i][j] = fil_der; } } #else // GPU WeightActs(prev_layer->activ_mat_, deriv_mat_, weights_der, prev_layer->mapsize_, filtersize_[0], padding_[0], sum_width_, !unshared_); #endif weights_der /= (ftype) batchsize_; weights_der.Validate(); if (passnum == 2) { mexAssert(deriv_mat_.order() == false, "deriv_mat_.order() should be false"); if (!unshared_) { deriv_mat_.reshape(batchsize_ * deriv_mat_.size2() / outputmaps_, outputmaps_); Sum(deriv_mat_, biases_.der(), 1); deriv_mat_.reshape(batchsize_, deriv_mat_.size1() * outputmaps_ / batchsize_); } else { Sum(deriv_mat_, biases_.der(), 1); } (biases_.der() /= (ftype) batchsize_) *= bias_coef_; biases_.der().Validate(); } MeasureTime("CalcWeights Conv Layer",2); }
void Mat::MaxRestore(Mat &restored, const std::vector<size_t> &coords) const { mexAssert(restored.size1() >= mat_.size1(), "In 'Mat::MaxRestore' the restored image is smaller than original"); mexAssert(restored.size2() >= mat_.size2(), "In 'Mat::MaxRestore' the restored image is smaller than original"); size_t lv = std::floor((double) (mat_.size1() - 1)/2); size_t lh = std::floor((double) (mat_.size2() - 1)/2); for (size_t i = 0; i < restored.size1(); ++i) { for (size_t j = 0; j < restored.size2(); ++j) { if (coords[0] <= i + lv && i + lv < coords[0] + mat_.size1() && coords[1] <= j + lh && j + lh < coords[1] + mat_.size2()) { restored(i, j) = mat_(i+lv-coords[0], j+lh-coords[1]); } else { restored(i, j) = 0; } } } }
const double& Mat::operator () (size_t ind) const { if (mat_.size1() == 1) { return mat_(0, ind); } else if (mat_.size2() == 1) { return mat_(ind, 0); } else { mexAssert(false, "In 'Mat::(ind)' matrix is not really a vector"); } }
Mat::Mat(const std::vector<size_t> &newsize) { //mexPrintMsg("Array constructor 2"); mexAssert(newsize.size() == 2, "In Mat::Mat the size vector length != 2"); data_ = new ftype[newsize[0] * newsize[1]]; size1_ = newsize[0]; size2_ = newsize[1]; owner_ = true; //mexPrintMsg("Array constructor 2 end"); }
void Net::InitWeights(const mxArray *mx_weights_in) { // testing size_t num_weights = NumWeights(); mexAssert(num_weights == mexGetNumel(mx_weights_in), "In InitWeights the vector of weights has the wrong length!"); weights_.Init(mexGetPointer(mx_weights_in), num_weights); size_t offset = 0; for (size_t i = 0; i < layers_.size(); ++i) { layers_[i]->InitWeights(weights_, offset, false); } }