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::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"); ////mexPrintMsg("labels_dim.", labels_dim[0]); ////mexPrintMsg("data_.size()", data_.size()); size_t classes_num = labels_dim[1]; mexAssert(classes_num == layers_.back()->length_, "Labels and last layer must have equal number of classes"); labels_ = mexGetMatrix(mx_labels); classcoefs_.init(1, classes_num, 1); if (params_.balance_) { Mat labels_mean = Mean(labels_, 1); for (size_t i = 0; i < classes_num; ++i) { mexAssert(labels_mean(i) > 0, "Balancing impossible: one of the classes is not presented"); (classcoefs_(i) /= labels_mean(i)) /= classes_num; } } if (layers_.back()->function_ == "SVM") { (labels_ *= 2) -= 1; } }
void Net::InitWeights(const mxArray *mx_weights_in) { bool isgen = false; size_t num_weights = NumWeights(); MatCPU weights_cpu; if (mx_weights_in != NULL) { // training, testing mexAssert(num_weights == mexGetNumel(mx_weights_in), "In InitWeights the vector of weights has the wrong length!"); mexGetMatrix(mx_weights_in, weights_cpu); } else { // genweights isgen = true; weights_cpu.resize(num_weights, 1); } weights_mat_.resize(num_weights, 1); // we can attach (in CPU version), // but don't want to change the initial weights weights_mat_ = weights_cpu; weights_.Init(weights_mat_); size_t offset = 0; for (size_t i = 0; i < layers_.size(); ++i) { layers_[i]->InitWeights(weights_, offset, isgen); } }
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 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); } }