endif
ifndef NNTRAINER_ROOT
-NNTRAINER_ROOT := $(LOCAL_PATH)/../../../jni/libs/arm64-v8a
+NNTRAINER_ROOT := $(LOCAL_PATH)/../../../libs/arm64-v8a
NNTRAINER_INCLUDES := $(LOCAL_PATH)/../../../nntrainer/include/
endif
endif
ifndef NNTRAINER_ROOT
-NNTRAINER_ROOT := $(LOCAL_PATH)/../../../jni/libs/arm64-v8a
+NNTRAINER_ROOT := $(LOCAL_PATH)/../../../libs/arm64-v8a
NNTRAINER_INCLUDES := $(LOCAL_PATH)/../../../nntrainer/include
endif
endif
ifndef NNTRAINER_ROOT
-NNTRAINER_ROOT := $(LOCAL_PATH)/../../../jni/libs/arm64-v8a
+NNTRAINER_ROOT := $(LOCAL_PATH)/../../../libs/arm64-v8a
NNTRAINER_INCLUDE := $(LOCAL_PATH)/../../../nntrainer/include
endif
endif
ifndef NNTRAINER_ROOT
-NNTRAINER_ROOT := $(LOCAL_PATH)/../../../../jni/libs/arm64-v8a
+NNTRAINER_ROOT := $(LOCAL_PATH)/../../../../libs/arm64-v8a
NNTRAINER_INCLUDES := $(LOCAL_PATH)/../../../../nntrainer/include
endif
endif
ifndef NNTRAINER_ROOT
-NNTRAINER_ROOT := $(LOCAL_PATH)/../../../jni/libs/arm64-v8a
+NNTRAINER_ROOT := $(LOCAL_PATH)/../../../libs/arm64-v8a
NNTRAINER_INCLUDES := $(LOCAL_PATH)/../../../nntrainer/include
endif
int ml_nnmodel_train_with_file(ml_nnmodel_h model, ...);
/**
+ * @brief train the neural network model.
+ * @details Use this function to train neural network model
+ * @since_tizen 6.x
+ * @param[in] model The NNTrainer model handler from the given description.
+ * @param[in] train_func function pointer for train
+ * @param[in] val_func function pointer for val
+ * @param[in] test_func function pointer for test
+ * @param[in] ... hyper parmeter for train model
+ * @return @c 0 on success. Otherwise a negative error value.
+ * @retval #ML_ERROR_NONE Successful.
+ * @retval #ML_ERROR_INVALID_PARAMETER Invalid Parameter.
+ */
+int ml_nnmodel_train_with_generator(ml_nnmodel_h model,
+ bool (*train_func)(float *, float *, int *),
+ bool (*val_func)(float *, float *, int *),
+ bool (*test_func)(float *, float *, int *),
+ ...);
+
+/**
* @brief Destructs the neural network model.
* @details Use this function to delete Neural Netowrk Model.
* @since_tizen 6.x
return status;
}
+int ml_nnmodel_train_with_generator(ml_nnmodel_h model,
+ bool (*train_func)(float *, float *, int *),
+ bool (*val_func)(float *, float *, int *),
+ bool (*test_func)(float *, float *, int *),
+ ...) {
+ int status = ML_ERROR_NONE;
+ ml_nnmodel *nnmodel;
+ const char *data;
+
+ std::vector<std::string> arg_list;
+ va_list arguments;
+ va_start(arguments, (test_func));
+ while ((data = va_arg(arguments, const char *))) {
+ arg_list.push_back(data);
+ }
+
+ va_end(arguments);
+
+ ML_NNTRAINER_CHECK_MODEL_VALIDATION(nnmodel, model);
+ std::shared_ptr<nntrainer::NeuralNetwork> NN;
+ NN = nnmodel->network;
+
+ status = NN->train((train_func), (val_func), (test_func), arg_list);
+ return status;
+}
+
int ml_nnmodel_destruct(ml_nnmodel_h model) {
int status = ML_ERROR_NONE;
ml_nnmodel *nnmodel;
std::shared_ptr<nntrainer::NeuralNetwork> NN;
NN = nnmodel->network;
NN->finalize();
+
delete nnmodel;
return status;
'-Waddress',
'-Wno-multichar',
'-Wvla',
- '-Wpointer-arith'
+ '-Wpointer-arith',
+ '-Wno-error=varargs'
]
warning_c_flags = [
'-Wnested-externs',
'-Waggregate-return',
'-Wold-style-definition',
- '-Wdeclaration-after-statement'
+ '-Wdeclaration-after-statement',
+ '-Wno-error=varargs'
]
foreach extra_arg : warning_flags
typedef enum {
DATA_NOT_READY = 0,
DATA_READY = 1,
- DATA_ERROR = 2,
+ DATA_END = 2,
+ DATA_ERROR = 3,
} DataStatus;
namespace nntrainer {
virtual int clear();
/**
- * @brief get Status of Buffer. if number of rest data
- * is samller than minibatch, the return false
- * @param[in] BufferType training, validation, test
- * @retval DataStatus
- */
- DataStatus getStatus(BufferType type);
-
- /**
* @brief get Data from Data Buffer using databuffer param
* @param[in] BufferType training, validation, test
* @param[in] outVec feature data ( minibatch size )
*/
bool *getValidation() { return validation; }
+ /**
+ * @brief status of thread
+ */
+ DataStatus trainReadyFlag;
+ DataStatus valReadyFlag;
+ DataStatus testReadyFlag;
+
protected:
/**
* @brief Data Queues for each data set
/**
* @brief feature size
*/
- /* unsigned int input_size; */
TensorDim input_dim;
/**
std::condition_variable cv_val;
std::condition_variable cv_test;
-DataStatus trainReadyFlag;
-DataStatus valReadyFlag;
-DataStatus testReadyFlag;
-
int DataBuffer::rangeRandom(int min, int max) {
int n = max - min + 1;
int remainder = RAND_MAX % n;
return status;
}
-DataStatus DataBuffer::getStatus(BufferType type) {
- DataStatus ret = DATA_READY;
- if (globalExceptionPtr)
- ret = DATA_ERROR;
-
- switch (type) {
- case BUF_TRAIN:
- if ((train_data.size() < mini_batch) && trainReadyFlag)
- ret = DATA_NOT_READY;
- break;
- case BUF_VAL:
- if ((val_data.size() < mini_batch) && valReadyFlag)
- ret = DATA_NOT_READY;
- break;
- case BUF_TEST:
- if ((test_data.size() < mini_batch) && testReadyFlag)
- ret = DATA_NOT_READY;
- break;
- default:
- ml_loge("Error: Not Supported Data Type");
- ret = DATA_ERROR;
- break;
- }
- return ret;
-}
-
bool DataBuffer::getDataFromBuffer(BufferType type, vec_3d &outVec,
vec_3d &outLabel) {
int nomI;
switch (type) {
case BUF_TRAIN: {
std::vector<int> list;
+ std::unique_lock<std::mutex> ultrain(readyTrainData);
+ cv_train.wait(ultrain, [this]() -> int { return trainReadyFlag; });
- if (getStatus(BUF_TRAIN) != DATA_READY)
- return false;
-
- {
- std::unique_lock<std::mutex> ultrain(readyTrainData);
- cv_train.wait(ultrain, []() -> int { return trainReadyFlag; });
- }
-
- if (trainReadyFlag == DATA_ERROR) {
+ if (trainReadyFlag == DATA_ERROR || trainReadyFlag == DATA_END) {
return false;
}
- data_lock.lock();
for (k = 0; k < mini_batch; ++k) {
- nomI = rangeRandom(0, train_data.size() - 1);
+ nomI = rangeRandom(0, train_bufsize - 1);
std::vector<std::vector<float>> v_height;
for (j = 0; j < height; ++j) {
J = j * width;
outVec.push_back(v_height);
outLabel.push_back({train_data_label[nomI]});
}
+
+ data_lock.lock();
+
for (i = 0; i < mini_batch; ++i) {
train_data.erase(train_data.begin() + list[i]);
train_data_label.erase(train_data_label.begin() + list[i]);
} break;
case BUF_VAL: {
std::vector<int> list;
- if (getStatus(BUF_VAL) != DATA_READY)
+ std::unique_lock<std::mutex> ulval(readyValData);
+ cv_val.wait(ulval, [this]() -> bool { return valReadyFlag; });
+ if (valReadyFlag == DATA_ERROR || valReadyFlag == DATA_END) {
return false;
-
- {
- std::unique_lock<std::mutex> ulval(readyValData);
- cv_val.wait(ulval, []() -> bool { return valReadyFlag; });
}
- data_lock.lock();
for (k = 0; k < mini_batch; ++k) {
- nomI = rangeRandom(0, val_data.size() - 1);
+ nomI = rangeRandom(0, val_bufsize - 1);
std::vector<std::vector<float>> v_height;
for (j = 0; j < height; ++j) {
J = j * width;
outVec.push_back(v_height);
outLabel.push_back({val_data_label[nomI]});
}
+
+ data_lock.lock();
+
for (i = 0; i < mini_batch; ++i) {
val_data.erase(val_data.begin() + list[i]);
val_data_label.erase(val_data_label.begin() + list[i]);
cur_val_bufsize--;
}
+
} break;
case BUF_TEST: {
std::vector<int> list;
- if (getStatus(BUF_TEST) != DATA_READY)
- return false;
+ std::unique_lock<std::mutex> ultest(readyTestData);
+ cv_test.wait(ultest, [this]() -> bool { return testReadyFlag; });
- {
- std::unique_lock<std::mutex> ultest(readyTestData);
- cv_test.wait(ultest, []() -> bool { return testReadyFlag; });
+ if (testReadyFlag == DATA_ERROR || testReadyFlag == DATA_END) {
+ return false;
}
- data_lock.lock();
for (k = 0; k < mini_batch; ++k) {
- nomI = rangeRandom(0, test_data.size() - 1);
+ nomI = rangeRandom(0, test_bufsize - 1);
std::vector<std::vector<float>> v_height;
for (j = 0; j < height; ++j) {
J = j * width;
outVec.push_back(v_height);
outLabel.push_back({test_data_label[nomI]});
}
+
+ data_lock.lock();
for (i = 0; i < mini_batch; ++i) {
test_data.erase(test_data.begin() + list[i]);
test_data_label.erase(test_data_label.begin() + list[i]);
if (validation[DATA_TRAIN] && max_train < train_bufsize) {
ml_logw("Warning: Total number of train is less than train buffer size. "
"Train buffer size is set as total number of train");
- train_bufsize = max_train;
+ train_bufsize = mini_batch;
}
if (validation[DATA_VAL] && max_val < val_bufsize) {
ml_logw(
"Warning: Total number of validation is less than validation buffer "
"size. Validation buffer size is set as total number of validation");
- val_bufsize = max_val;
+ val_bufsize = mini_batch;
}
if (validation[DATA_TEST] && max_test < test_bufsize) {
ml_logw("Warning: Total number of test is less than test buffer size. Test "
"buffer size is set as total number of test");
- test_bufsize = max_test;
+ test_bufsize = mini_batch;
}
return status;
for (unsigned int i = 0; i < max_size; ++i) {
mark[i] = i;
}
- while ((*running) && mark.size() != 0) {
+
+ while ((*running)) {
+ if (mark.size() == 0) {
+ NN_EXCEPTION_NOTI(DATA_END);
+ break;
+ }
+ trainReadyFlag = DATA_NOT_READY;
+ valReadyFlag = DATA_NOT_READY;
+ testReadyFlag = DATA_NOT_READY;
if (buf_size - (*cur_size) > 0 && (*rest_size) > 0) {
std::vector<float> vec;
std::vector<float> veclabel;
(*cur_size)++;
data_lock.unlock();
}
-
if (buf_size == (*cur_size)) {
NN_EXCEPTION_NOTI(DATA_READY);
}
}
+
file.close();
}
return ML_ERROR_INVALID_PARAMETER;
}
+ if (train_bufsize > mini_batch) {
+ train_bufsize = mini_batch;
+ }
+
+ if (val_bufsize > mini_batch) {
+ val_bufsize = mini_batch;
+ }
+
+ if (test_bufsize > mini_batch) {
+ test_bufsize = mini_batch;
+ }
+
this->train_running = true;
this->val_running = true;
this->test_running = true;
NN_EXCEPTION_NOTI(DATA_ERROR);
return;
}
+ bool endflag = false;
float *vec =
(float *)malloc(sizeof(float) * input_dim.batch() * input_dim.channel() *
(float *)malloc(sizeof(float) * input_dim.batch() * class_num);
while ((*running)) {
+ trainReadyFlag = DATA_NOT_READY;
+ valReadyFlag = DATA_NOT_READY;
+ testReadyFlag = DATA_NOT_READY;
if (buf_size - (*cur_size) > 0) {
- bool endflag = callback(vec, veclabel, &status);
- if (!endflag)
- break;
+ endflag = callback(vec, veclabel, &status);
- for (unsigned int i = 0; i < input_dim.batch(); ++i) {
- std::vector<float> v;
- std::vector<float> vl;
- unsigned int I =
- i * input_dim.channel() * input_dim.height() * input_dim.width();
- for (unsigned int j = 0; j < input_dim.channel(); ++j) {
- unsigned int J = j * input_dim.height() * input_dim.width();
- for (unsigned int k = 0; k < input_dim.height() * input_dim.width();
- ++k) {
- unsigned int K = I + J + k;
- v.push_back(vec[K]);
+ if (endflag) {
+ for (unsigned int i = 0; i < input_dim.batch(); ++i) {
+ std::vector<float> v;
+ std::vector<float> vl;
+ unsigned int I =
+ i * input_dim.channel() * input_dim.height() * input_dim.width();
+ for (unsigned int j = 0; j < input_dim.channel(); ++j) {
+ unsigned int J = j * input_dim.height() * input_dim.width();
+ for (unsigned int k = 0; k < input_dim.height() * input_dim.width();
+ ++k) {
+ unsigned int K = I + J + k;
+ v.push_back(vec[K]);
+ }
}
- }
- I = i * class_num;
- for (unsigned int j = 0; j < class_num; ++j) {
- vl.push_back(veclabel[I + j]);
- }
+ I = i * class_num;
+ for (unsigned int j = 0; j < class_num; ++j) {
+ vl.push_back(veclabel[I + j]);
+ }
- data_lock.lock();
- data->push_back(v);
- datalabel->push_back(vl);
- (*cur_size)++;
- data_lock.unlock();
+ data_lock.lock();
+ data->push_back(v);
+ datalabel->push_back(vl);
+ (*cur_size)++;
+ data_lock.unlock();
+ }
}
}
- if (buf_size == (*cur_size)) {
+ if (buf_size == (*cur_size) || !endflag) {
switch (type) {
case BUF_TRAIN: {
std::lock_guard<std::mutex> lgtrain(readyTrainData);
- trainReadyFlag = DATA_READY;
- cv_train.notify_all();
+ if (!endflag) {
+ trainReadyFlag = DATA_END;
+ cv_train.notify_all();
+ free(vec);
+ free(veclabel);
+ return;
+ } else {
+ trainReadyFlag = DATA_READY;
+ cv_train.notify_all();
+ }
+
} break;
case BUF_VAL: {
std::lock_guard<std::mutex> lgval(readyValData);
- valReadyFlag = DATA_READY;
- cv_val.notify_all();
+ if (!endflag) {
+ valReadyFlag = DATA_END;
+ cv_train.notify_all();
+ free(vec);
+ free(veclabel);
+ return;
+ } else {
+ valReadyFlag = DATA_READY;
+ cv_val.notify_all();
+ }
+
} break;
case BUF_TEST: {
std::lock_guard<std::mutex> lgtest(readyTestData);
- testReadyFlag = DATA_READY;
- cv_test.notify_all();
+ if (!endflag) {
+ testReadyFlag = DATA_END;
+ cv_test.notify_all();
+ free(vec);
+ free(veclabel);
+ return;
+ } else {
+ testReadyFlag = DATA_READY;
+ cv_test.notify_all();
+ }
+
} break;
default:
break;
int NeuralNetwork::train_run() {
int status = ML_ERROR_NONE;
- if (data_buffer->getValidation()[2]) {
- status = data_buffer->run(nntrainer::BUF_TEST);
- if (status != ML_ERROR_NONE) {
- data_buffer->clear(BUF_TEST);
- return status;
- }
- }
-
float training_loss = 0.0;
for (unsigned int i = 0; i < epoch; ++i) {
int count = 0;
return status;
}
+ if (data_buffer->getValidation()[nntrainer::BUF_TEST]) {
+ status = data_buffer->run(nntrainer::BUF_TEST);
+ if (status != ML_ERROR_NONE) {
+ data_buffer->clear(BUF_TEST);
+ return status;
+ }
+ }
+
while (true) {
vec_3d in, label;
if (data_buffer->getDataFromBuffer(nntrainer::BUF_TRAIN, in, label)) {
std::cout << "#" << i + 1 << "/" << epoch
<< " - Training Loss: " << training_loss;
- if (data_buffer->getValidation()[1]) {
+ if (data_buffer->getValidation()[nntrainer::BUF_VAL]) {
int right = 0;
float valloss = 0.0;
int tcases = 0;
*/
void replaceString(const std::string &from, const std::string &to,
const std::string n);
+
+/**
+ * @brief get data which size is mini batch for train
+ * @param[out] outVec
+ * @param[out] outLabel
+ * @param[out] status for error handling
+ * @retval true/false
+ */
+bool getMiniBatch_train(float *outVec, float *outLabel, int *status);
+
+/**
+ * @brief get data which size is mini batch for val
+ * @param[out] outVec
+ * @param[out] outLabel
+ * @param[out] status for error handling
+ * @retval true/false
+ */
+bool getMiniBatch_val(float *outVec, float *outLabel, int *status);
+
#endif /* __cplusplus */
#endif /* __NNTRAINER_TEST_UTIL_H__ */
*/
#include "nntrainer_test_util.h"
+#include <climits>
#include <iostream>
+#define num_class 10
+#define mini_batch 16
+#define feature_size 62720
+
+static bool *duplicate;
+static bool *valduplicate;
+static bool alloc_train = false;
+static bool alloc_val = false;
+
/**
* @brief replace string and save it in file
*/
data_file << s;
data_file.close();
}
+
+/**
+ * @brief Generate Random integer value between min to max
+ * @param[in] min : minimum value
+ * @param[in] max : maximum value
+ * @retval min < random value < max
+ */
+static int rangeRandom(int min, int max) {
+ int n = max - min + 1;
+ int remainder = RAND_MAX % n;
+ int x;
+ do {
+ x = rand();
+ } while (x >= RAND_MAX - remainder);
+ return min + x % n;
+}
+
+/**
+ * @brief load data at specific position of file
+ * @param[in] F ifstream (input file)
+ * @param[out] outVec
+ * @param[out] outLabel
+ * @param[in] id th data to get
+ * @retval true/false false : end of data
+ */
+static bool getData(std::ifstream &F, std::vector<float> &outVec,
+ std::vector<float> &outLabel, int id) {
+ F.clear();
+ F.seekg(0, std::ios_base::end);
+ uint64_t file_length = F.tellg();
+ if (id < 0)
+ return false;
+ uint64_t position = (feature_size + num_class) * id * sizeof(float);
+
+ if (position > file_length || position > ULLONG_MAX) {
+ return false;
+ }
+ F.seekg(position, std::ios::beg);
+ for (unsigned int i = 0; i < feature_size; i++)
+ F.read((char *)&outVec[i], sizeof(float));
+ for (unsigned int i = 0; i < num_class; i++)
+ F.read((char *)&outLabel[i], sizeof(float));
+
+ return true;
+}
+
+/**
+ * @brief get data which size is mini batch for train
+ * @param[out] outVec
+ * @param[out] outLabel
+ * @param[out] status for error handling
+ * @retval true/false
+ */
+bool getMiniBatch_train(float *outVec, float *outLabel, int *status) {
+ std::vector<int> memI;
+ std::vector<int> memJ;
+ unsigned int count = 0;
+ unsigned int data_size = 0;
+
+ std::string filename = "trainingSet.dat";
+ std::ifstream F(filename, std::ios::in | std::ios::binary);
+
+ if (F.good()) {
+ F.seekg(0, std::ios::end);
+ long file_size = F.tellg();
+ data_size = static_cast<unsigned int>(
+ file_size / ((num_class + feature_size) * sizeof(float)));
+ }
+
+ if (!alloc_train) {
+ duplicate = (bool *)malloc(sizeof(bool) * data_size);
+ for (unsigned int i = 0; i < data_size; ++i) {
+ duplicate[i] = false;
+ }
+ alloc_train = true;
+ }
+
+ for (unsigned int i = 0; i < data_size; i++) {
+ if (!duplicate[i])
+ count++;
+ }
+
+ if (count < mini_batch) {
+ free(duplicate);
+ alloc_train = false;
+ return false;
+ }
+
+ count = 0;
+ while (count < mini_batch) {
+ int nomI = rangeRandom(0, data_size - 1);
+ if (!duplicate[nomI]) {
+ memI.push_back(nomI);
+ duplicate[nomI] = true;
+ count++;
+ }
+ }
+
+ for (unsigned int i = 0; i < count; i++) {
+ std::vector<float> o;
+ std::vector<float> l;
+
+ o.resize(feature_size);
+ l.resize(num_class);
+
+ getData(F, o, l, memI[i]);
+
+ for (unsigned int j = 0; j < feature_size; ++j)
+ outVec[i * feature_size + j] = o[j];
+ for (unsigned int j = 0; j < num_class; ++j)
+ outLabel[i * num_class + j] = l[j];
+ }
+
+ F.close();
+ return true;
+}
+
+/**
+ * @brief get data which size is mini batch for validation
+ * @param[out] outVec
+ * @param[out] outLabel
+ * @param[out] status for error handling
+ * @retval true/false false : end of data
+ */
+bool getMiniBatch_val(float *outVec, float *outLabel, int *status) {
+
+ std::vector<int> memI;
+ std::vector<int> memJ;
+ unsigned int count = 0;
+ unsigned int data_size = 0;
+
+ std::string filename = "trainingSet.dat";
+ std::ifstream F(filename, std::ios::in | std::ios::binary);
+
+ if (F.good()) {
+ F.seekg(0, std::ios::end);
+ long file_size = F.tellg();
+ data_size = static_cast<unsigned int>(
+ file_size / ((num_class + feature_size) * sizeof(float)));
+ }
+
+ if (!alloc_val) {
+ valduplicate = (bool *)malloc(sizeof(bool) * data_size);
+ for (unsigned int i = 0; i < data_size; ++i) {
+ valduplicate[i] = false;
+ }
+ alloc_val = true;
+ }
+
+ for (unsigned int i = 0; i < data_size; i++) {
+ if (!valduplicate[i])
+ count++;
+ }
+
+ if (count < mini_batch) {
+ free(valduplicate);
+ alloc_val = false;
+ return false;
+ }
+
+ count = 0;
+ while (count < mini_batch) {
+ int nomI = rangeRandom(0, data_size - 1);
+ if (!valduplicate[nomI]) {
+ memI.push_back(nomI);
+ valduplicate[nomI] = true;
+ count++;
+ }
+ }
+
+ for (unsigned int i = 0; i < count; i++) {
+ std::vector<float> o;
+ std::vector<float> l;
+
+ o.resize(feature_size);
+ l.resize(num_class);
+
+ getData(F, o, l, memI[i]);
+
+ for (unsigned int j = 0; j < feature_size; ++j)
+ outVec[i * feature_size + j] = o[j];
+ for (unsigned int j = 0; j < num_class; ++j)
+ outLabel[i * num_class + j] = l[j];
+ }
+
+ F.close();
+ return true;
+}
EXPECT_EQ(status, ML_ERROR_NONE);
status = ml_nnoptimizer_delete(optimizer);
EXPECT_EQ(status, ML_ERROR_NONE);
+ status = ml_nnmodel_destruct(model);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+}
+
+/**
+ * @brief Neural Network Model Optimizer Test
+ */
+TEST(nntrainer_capi_nnmodel, train_with_generator_01_p) {
+ int status = ML_ERROR_NONE;
+
+ ml_nnmodel_h model;
+ ml_nnlayer_h layers[2];
+ ml_nnopt_h optimizer;
+
+ status = ml_nnmodel_construct(&model);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnlayer_create(&layers[0], ML_LAYER_TYPE_INPUT);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status =
+ ml_nnlayer_set_property(layers[0], "input_shape= 16:1:1:62720",
+ "normalization=true", "bias_zero=true", NULL);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnmodel_add_layer(model, layers[0]);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnlayer_create(&layers[1], ML_LAYER_TYPE_FC);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnlayer_set_property(layers[1], "unit= 10", "activation=softmax",
+ "bias_zero=true", "weight_decay=l2norm",
+ "weight_decay_lambda=0.005",
+ "weight_ini=xavier_uniform", NULL);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnmodel_add_layer(model, layers[1]);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnoptimizer_create(&optimizer, "adam");
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnoptimizer_set_property(
+ optimizer, "learning_rate=0.0001", "decay_rate=0.96", "decay_steps=1000",
+ "beta1=0.002", "beta2=0.001", "epsilon=1e-7", NULL);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ status = ml_nnmodel_compile(model, optimizer, "loss=cross", NULL);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+ status = ml_nnmodel_train_with_generator(
+ model, getMiniBatch_train, getMiniBatch_val, NULL, "epochs=1",
+ "batch_size=16", "buffer_size=100", "model_file=model.bin", NULL);
+
+ EXPECT_EQ(status, ML_ERROR_NONE);
+ status = ml_nnlayer_delete(layers[0]);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+ status = ml_nnlayer_delete(layers[1]);
+ EXPECT_EQ(status, ML_ERROR_NONE);
+ status = ml_nnoptimizer_delete(optimizer);
+ EXPECT_EQ(status, ML_ERROR_NONE);
status = ml_nnmodel_destruct(model);
EXPECT_EQ(status, ML_ERROR_NONE);