void Net::Train(const mxArray *mx_data, const mxArray *mx_labels) { //mexPrintMsg("Start training..."); ReadData(mx_data); ReadLabels(mx_labels); InitNorm(); std::srand(params_.seed_); size_t train_num = labels_.size1(); size_t numbatches = (size_t) ceil((ftype) train_num/params_.batchsize_); trainerror_.resize(params_.numepochs_, numbatches); for (size_t epoch = 0; epoch < params_.numepochs_; ++epoch) { std::vector<size_t> randind(train_num); for (size_t i = 0; i < train_num; ++i) { randind[i] = i; } if (params_.shuffle_) { std::random_shuffle(randind.begin(), randind.end()); } std::vector<size_t>::const_iterator iter = randind.begin(); for (size_t batch = 0; batch < numbatches; ++batch) { size_t batchsize = std::min(params_.batchsize_, (size_t)(randind.end() - iter)); std::vector<size_t> batch_ind = std::vector<size_t>(iter, iter + batchsize); iter = iter + batchsize; Mat data_batch = SubMat(data_, batch_ind, 1); Mat labels_batch = SubMat(labels_, batch_ind, 1); UpdateWeights(epoch, false); InitActiv(data_batch); Mat pred_batch; Forward(pred_batch, 1); InitDeriv(labels_batch, trainerror_(epoch, batch)); Backward(); CalcWeights(); UpdateWeights(epoch, true); if (params_.verbose_ == 2) { std::string info = std::string("Epoch: ") + std::to_string(epoch+1) + std::string(", batch: ") + std::to_string(batch+1); mexPrintMsg(info); } } // batch if (params_.verbose_ == 1) { std::string info = std::string("Epoch: ") + std::to_string(epoch+1); mexPrintMsg(info); } } // epoch //mexPrintMsg("Training finished"); }
void Net::Train(const mxArray *mx_data, const mxArray *mx_labels) { //mexPrintMsg("Start training..."); LayerFull *lastlayer = static_cast<LayerFull*>(layers_.back()); std::vector<size_t> labels_dim = mexGetDimensions(mx_labels); mexAssert(labels_dim.size() == 2, "The label array must have 2 dimensions"); mexAssert(labels_dim[0] == lastlayer->length_, "Labels and last layer must have equal number of classes"); size_t train_num = labels_dim[1]; Mat labels(labels_dim); mexGetMatrix(mx_labels, labels); classcoefs_.assign(labels_dim[0], 1); if (params_.balance_) { Mat labels_mean(labels_dim[0], 1); labels.Mean(2, labels_mean); for (size_t i = 0; i < labels_dim[0]; ++i) { mexAssert(labels_mean(i) > 0, "Balancing impossible: one of the classes is not presented"); (classcoefs_[i] /= labels_mean(i)) /= labels_dim[0]; } } if (lastlayer->function_ == "SVM") { (labels *= 2) -= 1; } 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 map = 0; map < mapnum; ++map) { const mxArray *mx_cell; if (mexIsCell(mx_data)) { mx_cell = mxGetCell(mx_data, map); } 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"); mexAssert(data_dim[2] == train_num, "All data maps and labels must have equal number of objects"); mexGetMatrix3D(mx_cell, data[map]); } size_t numbatches = ceil((double) train_num/params_.batchsize_); trainerror_.assign(params_.numepochs_ * numbatches, 0); for (size_t epoch = 0; epoch < params_.numepochs_; ++epoch) { std::vector<size_t> randind(train_num); for (size_t i = 0; i < train_num; ++i) { randind[i] = i; } if (params_.shuffle_) { std::random_shuffle(randind.begin(), randind.end()); } std::vector<size_t>::const_iterator iter = randind.begin(); for (size_t batch = 0; batch < numbatches; ++batch) { size_t batchsize = std::min(params_.batchsize_, (size_t)(randind.end() - iter)); std::vector<size_t> batch_ind = std::vector<size_t>(iter, iter + batchsize); iter = iter + batchsize; std::vector< std::vector<Mat> > data_batch(mapnum); for (size_t map = 0; map < mapnum; ++map) { data_batch[map].resize(batchsize); for (size_t i = 0; i < batchsize; ++i) { data_batch[map][i] = data[map][batch_ind[i]]; } } Mat labels_batch(labels_dim[0], batchsize); Mat pred_batch(labels_dim[0], batchsize); labels.SubMat(batch_ind, 2 ,labels_batch); UpdateWeights(false); Forward(data_batch, pred_batch, true); Backward(labels_batch, trainerror_[epoch * numbatches + batch]); UpdateWeights(true); if (params_.verbose_ == 2) { std::string info = std::string("Epoch: ") + std::to_string(epoch+1) + std::string(", batch: ") + std::to_string(batch+1); mexPrintMsg(info); } } // batch if (params_.verbose_ == 1) { std::string info = std::string("Epoch: ") + std::to_string(epoch+1); mexPrintMsg(info); } } // epoch //mexPrintMsg("Training finished"); }
void mexFunction(int nLhs, mxArray* pLhs[], int nRhs, const mxArray* pRhs[]) { mexAssert(NARGIN_MIN <= nRhs && nRhs <= NARGIN_MAX, "Number of input arguments in wrong!"); mexAssert(nLhs == NARGOUT, "Number of output arguments is wrong!" ); mexAssert(mexIsCell(IN_L), "Layers must be the cell array"); mexAssert(mexGetNumel(IN_L) == 2, "Layers array must contain 2 cells"); mexAssert(mexIsCell(IN_W), "Weights must be the cell array"); mexAssert(mexGetNumel(IN_W) == 2, "Weights array must contain 2 cells"); Net net; mxArray *mx_weights; net.InitLayers(mexGetCell(IN_L, 1)); net.InitWeights(mexGetCell(IN_W, 1), mx_weights); net.InitParams(IN_P); net.ReadLabels(IN_Y); const mxArray *mx_imweights = mexGetCell(IN_W, 0); size_t train_num = net.labels_.size1(); mexAssert(train_num == mexGetNumel(mx_imweights), "Weights and labels number must coincide"); bool is_multicoords = false; if (mexIsCell(IN_X)) { mexAssert(train_num == mexGetNumel(IN_X), "Coordinates and labels number must coincide"); is_multicoords = true; } Params params_ = net.params_; size_t numbatches = (size_t) ceil((ftype) train_num/params_.batchsize_); Mat trainerror_(params_.numepochs_, numbatches); Mat trainerror2_(params_.numepochs_, numbatches); trainerror2_.assign(0); std::vector<Net> imnets; imnets.resize(params_.batchsize_); for (size_t i = 0; i < params_.batchsize_; ++i) { imnets[i].InitLayers(mexGetCell(IN_L, 0)); if (!is_multicoords) { imnets[i].ReadData(IN_X); } else { imnets[i].ReadData(mexGetCell(IN_X, i)); // just to get pixels_num } } size_t pixels_num = imnets[0].data_.size1(); Layer *firstlayer = net.layers_[0]; size_t dimens_num = firstlayer->outputmaps_; mexAssert(imnets[0].layers_.back()->length_ == dimens_num, "Final layer length must coincide with the number of outputmaps"); mexAssert(pixels_num == firstlayer->mapsize_[0] * firstlayer->mapsize_[1], "Pixels number must coincide with the first layer elements number"); std::vector<size_t> pred_size(2); pred_size[0] = 1; pred_size[1] = pixels_num * dimens_num; Mat images_mat, labels_batch, pred_batch, pred_pixels; std::vector< std::vector<Mat> > images, images_der; for (size_t epoch = 0; epoch < params_.numepochs_; ++epoch) { std::vector<size_t> randind(train_num); for (size_t i = 0; i < train_num; ++i) { randind[i] = i; } if (params_.shuffle_) { std::random_shuffle(randind.begin(), randind.end()); } std::vector<size_t>::const_iterator iter = randind.begin(); for (size_t batch = 0; batch < numbatches; ++batch) { size_t batchsize = std::min(params_.batchsize_, (size_t)(randind.end() - iter)); std::vector<size_t> batch_ind = std::vector<size_t>(iter, iter + batchsize); iter = iter + batchsize; labels_batch = SubMat(net.labels_, batch_ind, 1); net.UpdateWeights(epoch, false); images_mat.resize(batchsize, pred_size[1]); InitMaps(images_mat, pred_size, images); // first pass for (size_t m = 0; m < batchsize; ++m) { imnets[m].InitWeights(mexGetCell(mx_imweights, batch_ind[m])); if (is_multicoords) { imnets[m].ReadData(mexGetCell(IN_X, batch_ind[m])); } imnets[m].InitActiv(imnets[m].data_); imnets[m].Forward(pred_pixels, 1); images[m][0].copy(Trans(pred_pixels).reshape(pred_size[0], pred_size[1])); } net.InitActiv(images_mat); net.Forward(pred_batch, 1); /* for (int i = 0; i < 5; ++i) { mexPrintMsg("pred_batch1", pred_batch(0, i)); }*/ // second pass net.InitDeriv(labels_batch, trainerror_(epoch, batch)); net.Backward(); net.CalcWeights(); InitMaps(firstlayer->deriv_mat_, pred_size, images_der); for (size_t m = 0; m < batchsize; ++m) { imnets[m].layers_.back()->deriv_mat_ = Trans(images_der[m][0].reshape(dimens_num, pixels_num)); imnets[m].Backward(); } // third pass ftype loss2 = 0, curloss = 0, invind = 0; std::vector<size_t> invalid; for (size_t m = 0; m < batchsize; ++m) { imnets[m].InitDeriv2(curloss); if (curloss > 0) { imnets[m].Forward(pred_pixels, 3); images[m][0].copy(Trans(pred_pixels).reshape(pred_size[0], pred_size[1])); loss2 += curloss; } else { invalid.push_back(m); } } if (invalid.size() < batchsize) { loss2 /= (batchsize - invalid.size()); trainerror2_(epoch, batch) = loss2; net.InitActiv(images_mat); net.Forward(pred_batch, 3); } net.CalcWeights2(invalid); // weights update net.UpdateWeights(epoch, true); if (params_.verbose_ == 2) { std::string info = std::string("Epoch: ") + std::to_string(epoch+1) + std::string(", batch: ") + std::to_string(batch+1); mexPrintMsg(info); } } // batch if (params_.verbose_ == 1) { std::string info = std::string("Epoch: ") + std::to_string(epoch+1); mexPrintMsg(info); } } // epoch //mexPrintMsg("Training finished"); //net.weights_.get().copy(net.weights_.der()); OUT_W = mexSetCellMat(1, 2); mexSetCell(OUT_W, 0, mexDuplicateArray(mx_imweights)); mexSetCell(OUT_W, 1, mx_weights); OUT_E = mexSetCellMat(1, 2); mexSetCell(OUT_E, 0, mexSetMatrix(trainerror_)); mexSetCell(OUT_E, 1, mexSetMatrix(trainerror2_)); }
void LayerJitt::Init(const mxArray *mx_layer, Layer *prev_layer) { //mexAssert(prev_layer->type_ == "i", "The 'j' type layer must be after the input one"); numdim_ = prev_layer->numdim_; outputmaps_ = prev_layer->outputmaps_; length_prev_ = prev_layer->length_prev_; mexAssert(mexIsField(mx_layer, "mapsize"), "The 'j' type layer must contain the 'mapsize' field"); std::vector<ftype> mapsize = mexGetVector(mexGetField(mx_layer, "mapsize")); mexAssert(mapsize.size() == numdim_, "Length of jitter mapsize vector and maps dimensionality must coincide"); mapsize_.resize(numdim_); length_ = outputmaps_; for (size_t i = 0; i < numdim_; ++i) { mexAssert(1 <= mapsize[i], "In 'j' layer mapsize must be positive"); mapsize_[i] = (size_t) mapsize[i]; length_ *= mapsize_[i]; } shift_.assign(numdim_, 0); if (mexIsField(mx_layer, "shift")) { shift_ = mexGetVector(mexGetField(mx_layer, "shift")); mexAssert(shift_.size() == numdim_, "Length of jitter shift vector and maps dimensionality must coincide"); for (size_t i = 0; i < numdim_; ++i) { mexAssert(0 <= shift_[i] && shift_[i] < mapsize_[i], "Shift in 'j' layer is out of range"); } } scale_.assign(numdim_, 1); if (mexIsField(mx_layer, "scale")) { scale_ = mexGetVector(mexGetField(mx_layer, "scale")); mexAssert(scale_.size() == numdim_, "Length of jitter scale vector and maps dimensionality must coincide"); for (size_t i = 0; i < numdim_; ++i) { mexAssert(1 <= scale_[i] && scale_[i] < mapsize_[i], "Scale in 'j' layer is out of range"); } } mirror_.assign(numdim_, false); if (mexIsField(mx_layer, "mirror")) { std::vector<ftype> mirror = mexGetVector(mexGetField(mx_layer, "mirror")); mexAssert(mirror.size() == numdim_, "Length of jitter scale vector and maps dimensionality must coincide"); for (size_t i = 0; i < numdim_; ++i) { mirror_[i] = (mirror[i] > 0); } } angle_ = 0; if (mexIsField(mx_layer, "angle")) { angle_ = mexGetScalar(mexGetField(mx_layer, "angle")); mexAssert(0 <= angle_ && angle_ <= 1, "Angle in 'j' layer must be between 0 and 1"); } defval_ = 0; if (mexIsField(mx_layer, "defval")) { defval_ = mexGetScalar(mexGetField(mx_layer, "defval")); } else { // check that the transformed image is always inside the original one std::vector<ftype> maxsize(numdim_, 0); for (size_t i = 0; i < numdim_; ++i) { maxsize[i] = (ftype) (mapsize_[i] - 1) * scale_[i]; } if (angle_ > 0) { ftype angle_inn = atan2((ftype) mapsize_[0], (ftype) mapsize_[1]) / kPi; ftype maxsin = 1; if (angle_inn + angle_ < 0.5) { maxsin = sin(kPi * (angle_inn + angle_)); } ftype maxcos = 1; if (angle_inn > angle_) { maxcos = cos(kPi * (angle_inn - angle_)); } ftype maxrad = sqrt(maxsize[0]*maxsize[0] + maxsize[1]*maxsize[1]); maxsize[0] = maxrad * maxsin; maxsize[1] = maxrad * maxcos; } std::vector<ftype> oldmapsize(numdim_, 0); for (size_t i = 0; i < numdim_; ++i) { oldmapsize[i] = (ftype) prev_layer->mapsize_[i]; } ftype min0 = (oldmapsize[0]/2 - 0.5) - maxsize[0]/2 - shift_[0]; ftype max0 = (oldmapsize[0]/2 - 0.5) + maxsize[0]/2 + shift_[0]; ftype min1 = (oldmapsize[1]/2 - 0.5) - maxsize[1]/2 - shift_[1]; ftype max1 = (oldmapsize[1]/2 - 0.5) + maxsize[1]/2 + shift_[1]; if (!(0 <= min0 && max0 < oldmapsize[0] && 0 <= min1 && max1 < oldmapsize[1])) { mexPrintMsg("min1", min0); mexPrintMsg("max1", max0); mexPrintMsg("min2", min1); mexPrintMsg("max2", max1); mexAssert(false, "For these jitter parameters the new image is out of the original image"); } } }
void LayerJitt::Init(const mxArray *mx_layer, const Layer *prev_layer) { dims_[1] = prev_layer->dims_[1]; std::vector<ftype> shift(2); shift[0] = 0; shift[1] = 0; if (mexIsField(mx_layer, "shift")) { shift = mexGetVector(mexGetField(mx_layer, "shift")); mexAssertMsg(shift.size() == 2, "Length of jitter shift vector and maps dimensionality must coincide"); for (size_t i = 0; i < 2; ++i) { mexAssertMsg(0 <= shift[i] && shift[i] < dims_[i+2], "Shift in 'jitt' layer is out of range"); } MatCPU shift_cpu(1, 2); shift_cpu.assign(shift); shift_ = shift_cpu; } std::vector<ftype> scale(2); scale[0] = 1; scale[1] = 1; if (mexIsField(mx_layer, "scale")) { scale = mexGetVector(mexGetField(mx_layer, "scale")); mexAssertMsg(scale.size() == 2, "Length of jitter scale vector and maps dimensionality must coincide"); for (size_t i = 0; i < 2; ++i) { mexAssertMsg(1 <= scale[i] && scale[i] < dims_[i+2], "Scale in 'j' layer is out of range"); } MatCPU scale_cpu(1, 2); scale_cpu.assign(scale); scale_ = scale_cpu; scale_.Log(); } if (mexIsField(mx_layer, "mirror")) { std::vector<ftype> mirror = mexGetVector(mexGetField(mx_layer, "mirror")); mexAssertMsg(mirror.size() == 2, "Length of jitter scale vector and maps dimensionality must coincide"); for (size_t i = 0; i < 2; ++i) { mexAssertMsg(mirror[i] == 0 || mirror[i] == 1, "Mirror must be either 0 or 1"); } MatCPU mirror_cpu(1, 2); mirror_cpu.assign(mirror); mirror_ = mirror_cpu; } if (mexIsField(mx_layer, "angle")) { angle_ = mexGetScalar(mexGetField(mx_layer, "angle")); mexAssertMsg(0 <= angle_ && angle_ <= 1, "Angle in 'j' layer must be between 0 and 1"); } if (mexIsField(mx_layer, "defval")) { defval_ = mexGetScalar(mexGetField(mx_layer, "defval")); } else { // check that the transformed image is always inside the original one std::vector<ftype> maxsize(2, 0); for (size_t i = 0; i < 2; ++i) { maxsize[i] = (ftype) (dims_[i+2] - 1) * scale[i]; } if (angle_ > 0) { ftype angle_inn = atan2((ftype) dims_[2], (ftype) dims_[3]) / kPi; ftype maxsin = 1; if (angle_inn + angle_ < 0.5) { maxsin = sin(kPi * (angle_inn + angle_)); } ftype maxcos = 1; if (angle_inn > angle_) { maxcos = cos(kPi * (angle_inn - angle_)); } ftype maxrad = (ftype) sqrt((double) (maxsize[0]*maxsize[0] + maxsize[1]*maxsize[1])); maxsize[0] = maxrad * maxsin; maxsize[1] = maxrad * maxcos; } std::vector<ftype> oldmapsize(2, 0); for (size_t i = 0; i < 2; ++i) { oldmapsize[i] = (ftype) prev_layer->dims_[i+2]; } ftype min0 = ((ftype) oldmapsize[0] / 2 - (ftype) 0.5) - (ftype) maxsize[0] / 2 - shift[0]; ftype max0 = ((ftype) oldmapsize[0] / 2 - (ftype) 0.5) + (ftype) maxsize[0] / 2 + shift[0]; ftype min1 = ((ftype) oldmapsize[1] / 2 - (ftype) 0.5) - (ftype) maxsize[1] / 2 - shift[1]; ftype max1 = ((ftype) oldmapsize[1] / 2 - (ftype) 0.5) + (ftype) maxsize[1] / 2 + shift[1]; if (!(0 <= min0 && max0 < oldmapsize[0] && 0 <= min1 && max1 < oldmapsize[1])) { mexPrintMsg("min1", min0); mexPrintMsg("max1", max0); mexPrintMsg("min2", min1); mexPrintMsg("max2", max1); mexAssertMsg(false, "For these jitter parameters the new image is out of the original image"); } } if (mexIsField(mx_layer, "eigenvectors")) { const mxArray* mx_ev = mexGetField(mx_layer, "eigenvectors"); std::vector<size_t> ev_dim = mexGetDimensions(mx_ev); mexAssertMsg(ev_dim.size() == 2, "The eigenvectors array must have 2 dimensions"); mexAssertMsg(ev_dim[0] == dims_[1] && ev_dim[1] == dims_[1], "The eigenvector matrix size is wrong"); MatCPU ev_cpu(dims_[1], dims_[1]); mexGetMatrix(mx_ev, ev_cpu); eigenvectors_.resize(dims_[1], dims_[1]); eigenvectors_ = ev_cpu; if (mexIsField(mx_layer, "noise_std")) { noise_std_ = mexGetScalar(mexGetField(mx_layer, "noise_std")); mexAssertMsg(noise_std_ >= 0, "noise_std must be nonnegative"); } else { mexAssertMsg(false, "noise_std is required with eigenvalues"); } } if (mexIsField(mx_layer, "randtest")) { randtest_ = (mexGetScalar(mexGetField(mx_layer, "randtest")) > 0); } }