* 17. name : string (type)
* 18. num_inputs : unsigned int (minimum 1)
* 19. num_outputs : unsigned int (minimum 1)
- * 20. batch_size : unsigned int (minimum 1)
- * 21. momentum : float,
- * 22. moving_mean_initializer : string (type),
- * 23. moving_variance_initializer : string (type),
- * 24. gamma_initializer : string (type),
- * 25. beta_initializer" : string (type)
+ * 20. momentum : float,
+ * 21. moving_mean_initializer : string (type),
+ * 22. moving_variance_initializer : string (type),
+ * 23. gamma_initializer : string (type),
+ * 24. beta_initializer" : string (type)
*/
enum class PropertyType {
input_shape = 0,
name = 17,
num_inputs = 18,
num_outputs = 19,
- batch_size = 20,
- momentum = 21,
- moving_mean_initializer = 22,
- moving_variance_initializer = 23,
- gamma_initializer = 24,
- beta_initializer = 25,
+ momentum = 20,
+ moving_mean_initializer = 21,
+ moving_variance_initializer = 22,
+ gamma_initializer = 23,
+ beta_initializer = 24,
unknown
};
/**
* @brief Set the batch for the layer
* @param batch Batch value to be set
- * @note This denotes the maximum batch size of input. The actual batchsize
- * of the data can be smaller in case of validation or testing
+ * @todo Make this private. Only model should be able to do this.
*/
void setBatch(unsigned int batch) {
input_dim.setTensorDim(0, batch);
* @retval #ML_ERROR_INVALID_PARAMETER invalid parameter.
*/
int setTrainConfig(std::vector<std::string> values);
+
+ /**
+ * @brief Update batch size of the model as well as its layers/dataset
+ */
+ void setBatchSize(unsigned int batch_size);
};
} /* namespace nntrainer */
void read(std::ifstream &file);
/**
- * @brief return argument index which value is max
+ * @brief return argument index which value is max by batch
* @retval unsigned int argument index
*/
- unsigned int argmax() const;
+ std::vector<unsigned int> argmax() const;
/**
* @brief return a copy of the Tensor Dim
}
sharedConstTensor AdditionLayer::forwarding(sharedConstTensor in) {
- hidden = Tensor(in->batch(), output_dim.channel(), output_dim.height(),
- output_dim.width());
+ hidden = Tensor(input_dim);
hidden.setZero();
for (unsigned int idx = 0; idx < num_inputs; ++idx) {
}
TensorDim hidden_dim = output_dim;
- hidden_dim.batch(in->batch());
hidden = Tensor(hidden_dim);
hidden.setZero();
kdim.getFeatureLen() * sizeof(float));
}
- for (unsigned int b = 0; b < input.batch(); ++b) {
+ for (unsigned int b = 0; b < input_dim.batch(); ++b) {
std::vector<float> out(output_dim.getFeatureLen());
Tensor inSub(TensorDim(1, input.channel(), input.height(), input.width()),
input.getAddress(b * input.getDim().getFeatureLen()));
input = *in;
hidden = input;
- /// @note in->batch can be different from input_dim.batch();
- hidden.reshape({in->batch(), output_dim.channel(), output_dim.height(),
- output_dim.width()});
+ hidden.reshape(output_dim);
return MAKE_SHARED_TENSOR(hidden);
}
throw_status(status);
}
break;
- case PropertyType::batch_size:
- if (!value.empty()) {
- unsigned int batch_size;
- status = setUint(batch_size, value);
- throw_status(status);
- input_dim.batch(batch_size);
- }
- break;
case PropertyType::activation:
if (!value.empty()) {
status = setActivation((ActivationType)parseType(value, TOKEN_ACTI));
unsigned int type = parseNetProperty(key);
switch (static_cast<PropertyType>(type)) {
- case PropertyType::batch_size: {
- status = setUint(batch_size, value);
- NN_RETURN_STATUS();
- /** TODO: increase buffer size if it is smaller than batch size.
- * also if this is set with default batch size, then make it
- * smaller/larger
- */
- } break;
case PropertyType::loss: {
status = setFloat(loss, value);
NN_RETURN_STATUS();
continue_train = cont_train;
opt.setProperty({values[i]});
} break;
+ case PropertyType::batch_size: {
+ status = setUint(batch_size, value);
+ NN_RETURN_STATUS();
+ /** TODO: increase buffer size if it is smaller than batch size.
+ * also if this is set with default batch size, then make it
+ * smaller/larger
+ */
+ } break;
default:
ml_loge("Error: Unknown Network Property Key");
status = ML_ERROR_INVALID_PARAMETER;
}
}
- layers[i]->setBatch(batch_size);
status = layers[i]->initialize();
switch (l.getType()) {
ml_logi("read modelfile: %s", save_path.c_str());
}
+void NeuralNetwork::setBatchSize(unsigned int batch) {
+ batch_size = batch;
+ for (auto const &layer : layers)
+ layer->setBatch(batch_size);
+
+ if (data_buffer && data_buffer->setBatchSize(batch_size) != ML_ERROR_NONE)
+ throw std::invalid_argument("Error setting batchsize for the dataset");
+}
+
sharedConstTensor NeuralNetwork::inference(const Tensor X) {
+ if (batch_size != X.batch()) {
+ /**
+ * Note that inference resets batch_size of the previous train configuration
+ * Next train must set its batch_size if inference is run with this model.
+ */
+ setBatchSize(X.batch());
+ }
+
sharedConstTensor out;
try {
out = forwarding(MAKE_SHARED_TENSOR(X));
return ML_ERROR_INVALID_PARAMETER;
}
- /** Setup data buffer properties */
- status = data_buffer->setBatchSize(batch_size);
+ status = setTrainConfig(values);
NN_RETURN_STATUS();
+ /** set batch size just before training */
+ setBatchSize(batch_size);
+
+ /** Setup data buffer properties */
status =
data_buffer->setClassNum(layers.back()->getOutputDimension().width());
NN_RETURN_STATUS();
status = data_buffer->init();
NN_RETURN_STATUS();
- status = setTrainConfig(values);
- NN_RETURN_STATUS();
-
return train_run();
}
while (true) {
vec_4d in, label;
if (data_buffer->getDataFromBuffer(nntrainer::BUF_VAL, in, label)) {
- for (unsigned int b = 0; b < batch_size; ++b) {
- sharedTensor X = MAKE_SHARED_TENSOR(Tensor({in[b]}));
- sharedTensor Y2 = MAKE_SHARED_TENSOR(Tensor({label[b]}));
- sharedConstTensor Y = forwarding(X, Y2);
- if (Y->argmax() == Y2->argmax())
+ sharedTensor X = MAKE_SHARED_TENSOR(Tensor({in}));
+ sharedTensor Y2 = MAKE_SHARED_TENSOR(Tensor({label}));
+ sharedConstTensor Y = forwarding(X, Y2);
+ auto model_out = Y->argmax();
+ auto label_out = Y2->argmax();
+ for (unsigned int b = 0; b < batch_size; b++) {
+ if (model_out[b] == label_out[b])
right++;
- validation.loss += getLoss();
- tcases++;
}
+ validation.loss += getLoss();
+ tcases++;
} else {
data_buffer->clear(nntrainer::BUF_VAL);
break;
return status;
}
validation.loss /= (float)(tcases);
- validation.accuracy = right / (float)(tcases)*100.0f;
+ validation.accuracy = right / (float)(tcases * batch_size) * 100.0f;
std::cout << " >> [ Accuracy: " << validation.accuracy
<< "% - Validation Loss : " << validation.loss << " ] ";
}
* name = 17
* num_inputs = 18
* num_outputs = 19
- * batch_size = 20
- * momentum = 21
- * moving_mean_initializer = 22
- * moving_variance_initializer = 23
- * gamma_initializer = 24
- * beta_initializer = 25
+ * momentum = 20
+ * moving_mean_initializer = 21
+ * moving_variance_initializer = 22
+ * gamma_initializer = 23
+ * beta_initializer = 24
*
* InputLayer has 0, 1, 2, 3 properties.
* FullyConnectedLayer has 1, 4, 6, 7, 8, 9 properties.
* Pooling2DLayer has 12, 13, 14, 15 properties.
* BatchNormalizationLayer has 0, 1, 5, 6, 7 properties.
*/
-static std::array<std::string, 27> property_string = {
+static std::array<std::string, 26> property_string = {
"input_shape",
"normalization",
"standardization",
"name",
"num_inputs",
"num_outputs",
- "batch_size",
"momentum",
"moving_mean_initializer",
"moving_variance_initializer",
input = *in;
TensorDim hidden_dim = output_dim;
- hidden_dim.batch(in->batch());
hidden = Tensor(hidden_dim);
hidden.setZero();
- for (unsigned int b = 0; b < input.batch(); ++b) {
+ for (unsigned int b = 0; b < input_dim.batch(); ++b) {
Tensor in_padded = zero_pad(b, input, padding);
Tensor result = pooling2d(b, in_padded);
memcpy(hidden.getAddress(b * hidden.getDim().getFeatureLen()),
void Tensor::setZero() { setValue(0); }
-unsigned int Tensor::argmax() const {
+std::vector<unsigned int> Tensor::argmax() const {
const float *data = getData();
- auto max_iter = std::max_element(data, data + length());
- return std::distance(data, max_iter);
+ std::vector<unsigned int> result;
+ unsigned int batch_size = batch();
+ unsigned int feature_len = dim.getFeatureLen();
+
+ result.reserve(batch_size);
+
+ for (unsigned int b = 0; b < batch_size; b++) {
+ auto max_iter =
+ std::max_element(data + b * feature_len, data + (b + 1) * feature_len);
+ result[b] = std::distance(data, max_iter);
+ }
+
+ return result;
}
float Tensor::l2norm() const {
return status;
}
- virtual int reinitialize(const std::string str) {
+ virtual int reinitialize(const std::string str, int batch_size = 1) {
resetLayer();
int status = setProperty(str);
EXPECT_EQ(status, ML_ERROR_NONE);
+ setBatch(batch_size);
status = reinitialize();
EXPECT_EQ(status, ML_ERROR_NONE);
return status;
layer.setInputDimension(dim);
}
+ void setBatch(unsigned int batch) { layer.setBatch(batch); }
+
void matchOutput(const nntrainer::Tensor &result,
const nntrainer::Tensor &golden) {
const float *out_ptr, *golden_ptr;
protected:
virtual void prepareLayer() {
setInputDim("3:28:28");
- setProperty("batch_size=1");
+ setBatch(1);
}
};
nntrainer::TensorDim dim;
int status = ML_ERROR_NONE;
- status = setProperty("batch_size=5");
+ setBatch(5);
EXPECT_EQ(status, ML_ERROR_NONE);
dim = layer.getInputDimension();
protected:
virtual void prepareLayer() {
setInputDim("1:28:28");
- setProperty("batch_size=32");
+ setBatch(5);
setProperty("unit=1");
}
};
virtual void prepareLayer() {
setInputDim("1:1:12");
- setProperty("batch_size=3");
+ setBatch(3);
setProperty("unit=15");
setProperty("bias_initializer=zeros");
}
}
virtual void prepareLayer() {
- setProperty(
- "input_shape=1:1:12 | epsilon=0.001 | batch_size=3 | momentum=0.90");
+ setProperty("input_shape=1:1:12 | epsilon=0.001 | momentum=0.90");
+ setBatch(3);
setOptimizer(nntrainer::OptType::sgd, "learning_rate=1");
}
};
}
virtual void prepareLayer() {
- setProperty(
- "input_shape=2:4:5 | epsilon=0.001 | batch_size=3 | momentum=0.90");
+ setProperty("input_shape=2:4:5 | epsilon=0.001 | momentum=0.90");
+ setBatch(3);
setOptimizer(nntrainer::OptType::sgd, "learning_rate=1");
}
};
}
virtual void prepareLayer() {
- setProperty(
- "input_shape=2:4:5 | epsilon=0.001 | batch_size=1 | momentum=0.90");
+ setProperty("input_shape=2:4:5 | epsilon=0.001 | momentum=0.90");
+ setBatch(1);
setOptimizer(nntrainer::OptType::sgd, "learning_rate=1");
}
};
virtual void prepareLayer() {
int status =
- setProperty("input_shape=3:28:28 | batch_size=32 |"
+ setProperty("input_shape=3:28:28 |"
"bias_initializer=zeros |"
"activation=sigmoid |"
"weight_regularizer=l2norm |"
"filters=12 | kernel_size= 5,5 | stride=3,3 | padding=1,1");
EXPECT_EQ(status, ML_ERROR_NONE);
+ setBatch(32);
}
nntrainer::Tensor result;
* @brief Convolution 2D Layer
*/
TEST_F(nntrainer_Conv2DLayer, forwarding_01_p) {
- reinitialize("input_shape=3:7:7 | batch_size=1 |"
+ reinitialize("input_shape=3:7:7 |"
"bias_initializer = zeros |"
"weight_initializer=xavier_uniform |"
"filters=2 | kernel_size=3,3 | stride=1, 1 | padding=0,0");
TEST_F(nntrainer_Conv2DLayer, forwarding_02_p) {
status =
- reinitialize("input_shape=3:7:7 | batch_size=2 |"
+ reinitialize("input_shape=3:7:7 |"
"bias_initializer = zeros |"
"weight_initializer=xavier_uniform |"
- "filters=3 | kernel_size=3,3 | stride=1, 1 | padding=0,0");
+ "filters=3 | kernel_size=3,3 | stride=1, 1 | padding=0,0",
+ 2);
ASSERT_EQ(in.getDim(), nntrainer::TensorDim(2, 3, 7, 7));
ASSERT_EQ(out.getDim(), nntrainer::TensorDim(2, 3, 5, 5));
}
TEST_F(nntrainer_Conv2DLayer, backwarding_01_p) {
- status = reinitialize("input_shape=3:7:7 | batch_size=1 |"
+ status = reinitialize("input_shape=3:7:7 |"
"bias_initializer=zeros |"
"weight_initializer=xavier_uniform |"
"filters=2 |"
}
TEST_F(nntrainer_Conv2DLayer, backwarding_04_p) {
- status = reinitialize("input_shape=6:24:24 | batch_size=1 |"
+ status = reinitialize("input_shape=6:24:24 |"
"bias_initializer=zeros |"
"weight_initializer=xavier_uniform |"
"filters=12 |"
}
TEST_F(nntrainer_Conv2DLayer, backwarding_02_p) {
- status = reinitialize("input_shape=3:7:7 | batch_size=2 |"
+ status = reinitialize("input_shape=3:7:7 |"
"bias_initializer=zeros |"
"weight_initializer=xavier_uniform |"
"filters=3 |"
"kernel_size= 3,3 |"
"stride=1, 1 |"
- "padding=0,0");
+ "padding=0,0",
+ 2);
setOptimizer(nntrainer::OptType::sgd, "learning_rate=1.0");
#ifdef USE_BLAS
TEST_F(nntrainer_Conv2DLayer, backwarding_03_p) {
- status = reinitialize("input_shape=3:28:28 | batch_size=1 |"
+ status = reinitialize("input_shape=3:28:28 |"
"bias_initializer=zeros |"
"weight_initializer=zeros |"
"filters=6 |"
"padding=0, 0");
nntrainer::Conv2DLayer layer1;
- status = layer1.setProperty(
- {"input_shape=3:28:28", "batch_size=1", "bias_initializer=zeros",
- "weight_initializer=zeros", "filters=6", "kernel_size= 5,5", "stride=1, 1",
- "padding=0, 0"});
+ status =
+ layer1.setProperty({"input_shape=3:28:28", "bias_initializer=zeros",
+ "weight_initializer=zeros", "filters=6",
+ "kernel_size= 5,5", "stride=1, 1", "padding=0, 0"});
EXPECT_EQ(status, ML_ERROR_NONE);
+ layer1.setBatch(1);
status = layer1.initialize();
EXPECT_EQ(status, ML_ERROR_NONE);
nntrainer::Conv2DLayer layer2;
status = layer2.setProperty(
- {"batch_size=1", "bias_initializer=zeros", "weight_initializer=zeros",
- "filters=12", "kernel_size= 1,1", "stride=1, 1", "padding=0, 0"});
+ {"bias_initializer=zeros", "weight_initializer=zeros", "filters=12",
+ "kernel_size= 1,1", "stride=1, 1", "padding=0, 0"});
EXPECT_EQ(status, ML_ERROR_NONE);
+ layer2.setBatch(1);
layer2.setInputDimension(layer1.getOutputDimension());
status = layer2.initialize();
EXPECT_EQ(status, ML_ERROR_NONE);
TEST_F(nntrainer_Pooling2DLayer, setProperty_01_p) {
setInputDim("3:5:5");
- setProperty("batch_size=2");
+ setBatch(2);
setProperty("pool_size=2,2 | stride=1,1 | padding=0,0 | pooling=average");
}
TEST_F(nntrainer_Pooling2DLayer, setProperty_02_n) {
setInputDim("3:5:5");
- setProperty("batch_size=2");
+ setBatch(2);
int status = layer.setProperty({"pool_size="});
EXPECT_EQ(status, ML_ERROR_INVALID_PARAMETER);
}
TEST_F(nntrainer_Pooling2DLayer, forwarding_05_p) {
resetLayer();
setInputDim("2:5:5");
- setProperty("batch_size=2");
+ setBatch(2);
setProperty("pooling=global_max");
reinitialize();
TEST_F(nntrainer_Pooling2DLayer, forwarding_06_p) {
resetLayer();
setInputDim("2:5:5");
- setProperty("batch_size=2");
+ setBatch(2);
setProperty("pooling=global_average");
reinitialize();
protected:
virtual void prepareLayer() {
setInputDim("2:4:4");
- layer.setBatch(1);
+ setBatch(1);
}
};
*/
TEST_F(nntrainer_FlattenLayer, forwarding_02_p) {
setInputDim("2:4:4");
- layer.setBatch(2);
+ setBatch(2);
reinitialize();
EXPECT_EQ(out.getDim(), nntrainer::TensorDim(2, 1, 1, 32));
*/
TEST_F(nntrainer_FlattenLayer, backwarding_02_p) {
setInputDim("2:4:4");
- layer.setBatch(2);
+ setBatch(2);
reinitialize();
EXPECT_EQ(out.getDim(), nntrainer::TensorDim(2, 1, 1, 32));
: public nntrainer_abstractLayer<nntrainer::AdditionLayer> {
protected:
virtual void prepareLayer() {
- setInputDim("32:3:28:28");
+ setInputDim("3:28:28");
+ setBatch(32);
setProperty("num_inputs=1");
}
};
in = nntrainer::Tensor();
- EXPECT_THROW(layer.forwarding(input), std::logic_error);
+ EXPECT_THROW(layer.forwarding(input), std::runtime_error);
}
TEST_F(nntrainer_AdditionLayer, forwarding_02_n) {