[APP] Change embeding to product rating
authorJihoon Lee <jhoon.it.lee@samsung.com>
Tue, 1 Jun 2021 12:11:36 +0000 (21:11 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Wed, 2 Jun 2021 04:39:41 +0000 (13:39 +0900)
This patch changes embedding application to product rating application
which is more practical use-case

**Changes proposed in this PR:**
- Update Readme
- Change directory and app name embedding->productratings
- tune model and sample dataset

**Self evaluation:**
1. Build test: [X]Passed [ ]Failed [ ]Skipped
2. Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: Jihoon Lee <jhoon.it.lee@samsung.com>
15 files changed:
Applications/Embedding/README.md [deleted file]
Applications/Embedding/jni/meson.build [deleted file]
Applications/Embedding/res/Embedding.ini [deleted file]
Applications/Embedding/res/Embedding_split.ini [deleted file]
Applications/Embedding/res/embedding_input.txt [deleted file]
Applications/ProductRatings/README.md [new file with mode: 0644]
Applications/ProductRatings/Tensorflow/embedding.py [moved from Applications/Embedding/Tensorflow/embedding.py with 100% similarity]
Applications/ProductRatings/jni/Android.mk [moved from Applications/Embedding/jni/Android.mk with 97% similarity]
Applications/ProductRatings/jni/Application.mk [moved from Applications/Embedding/jni/Application.mk with 100% similarity]
Applications/ProductRatings/jni/main.cpp [moved from Applications/Embedding/jni/main.cpp with 93% similarity]
Applications/ProductRatings/jni/meson.build [new file with mode: 0644]
Applications/ProductRatings/res/product_ratings_model.ini [new file with mode: 0644]
Applications/ProductRatings/res/sample_product_ratings.txt [new file with mode: 0644]
Applications/meson.build
nntrainer/models/neuralnet.cpp

diff --git a/Applications/Embedding/README.md b/Applications/Embedding/README.md
deleted file mode 100644 (file)
index c4a52a3..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-# Embedding
-
-This application contains embedding layer example with two example model.
-One with single input, another assuming there are two inputs(using split layer)
-
-## Example Model Structure
-
-There are two structure ready for the example
-
-1. Linear Embedding structure
- (Input:           10:1:1:4 )
- (Embedding:       10:1:4:8 )
- (Flatten:         10:1:1:32)
- (FullyConnected:  10:1:1:1 )
-
-2. Splitted data and seperate embedding structure
- (Input:           10:1:2:2 )
- (split:           10:1:1:1,                   10:1:1:1 )
- (Embedding1:      10:1:1:8 ), (Embedding2:    10:1:1:8 )
- (concat:          10:2:1:8 ),
- (Flatten:         10:1:1:16),
- (FullyConnected:  10:1:1:1 )
-
-## How to run a train epoch
-
-Once you compile, with `meson`, please file an issue if you have a problem running the example.
-
-```bash
-export ${res}
-$ cd ${build_dir}
-$ meson test app_embedding -v #this is for the first model structure
-$ meson test app_embedding_split -v #this is for the second model structure
-```
-
-Expected output is as below...
-
-```bash
-#1/100 - Training Loss: 0.692463 >> [ Accuracy: 100% - Validation Loss : 0.690833 ]
-...
-#100/100 - Training Loss: 0.535373 >> [ Accuracy: 100% - Validation Loss : 0.53367 ]
-```
diff --git a/Applications/Embedding/jni/meson.build b/Applications/Embedding/jni/meson.build
deleted file mode 100644 (file)
index e919b5d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-res_path = meson.current_source_dir() / '..' / 'res'
-run_command('cp', '-lr', res_path, nntr_app_resdir / 'Embedding')
-
-e = executable('nntrainer_embedding',
-  'main.cpp',
-  dependencies: [iniparser_dep, nntrainer_ccapi_dep, gtest_dep, nntrainer_dep],
-  install: get_option('install-app'),
-  install_dir: application_install_dir
-)
-
-test('app_embedding', e, args: ['train',
-  nntr_app_resdir / 'Embedding' / 'Embedding.ini',
-  nntr_app_resdir / 'Embedding' / 'embedding_input.txt']
-)
-
-# test split example
-test('app_embedding_split', e, args: ['train',
-  nntr_app_resdir / 'Embedding' / 'Embedding_split.ini',
-  nntr_app_resdir / 'Embedding' / 'embedding_input.txt']
-)
diff --git a/Applications/Embedding/res/Embedding.ini b/Applications/Embedding/res/Embedding.ini
deleted file mode 100644 (file)
index 1822edc..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# Model Section : Model
-[Model]
-Type = NeuralNetwork
-Epochs = 100           # Epochs
-Loss = cross           # Loss function : mse (mean squared error)
-                        #                       cross ( cross entropy )
-Save_Path = "embedding_model_split.bin" # model path to save / read
-batch_size = 10                # batch size
-
-[Optimizer]
-Type = adam
-beta1 = 0.9
-beta2 = 0.999
-Learning_rate = 0.001
-epsilon = 1e-7
-
-[embedding]
-Type = embedding
-in_dim = 15
-out_dim = 8
-in_length = 4
-
-[flatten]
-Type = flatten
-input_layers = embedding
-
-[outputlayer]
-Type = fully_connected
-input_layers = flatten
-Unit = 1
-Bias_initializer = zeros
-Activation = sigmoid
diff --git a/Applications/Embedding/res/Embedding_split.ini b/Applications/Embedding/res/Embedding_split.ini
deleted file mode 100644 (file)
index d9e3c20..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-# Model Section : Model
-[Model]
-Type = NeuralNetwork
-Epochs = 100           # Epochs
-Loss = cross           # Loss function : mse (mean squared error)
-                        #                       cross ( cross entropy )
-Save_Path = "embedding_model_split.bin" # model path to save / read
-batch_size = 10                # batch size
-
-[Optimizer]
-Type = adam
-beta1 = 0.9
-beta2 = 0.999
-Learning_rate = 0.001
-epsilon = 1e-7
-
-[input]
-Type = input
-input_shape = 1:2:2 # channel:height:width
-
-[split]
-Type = split
-split_dimension = 2 # split by height
-
-[embedding1]
-input_layers = split
-Type = embedding
-in_dim = 15
-out_dim = 8
-in_length = 1
-
-[embedding2]
-input_layers = split
-Type = embedding
-in_dim = 15
-out_dim = 8
-in_length = 1
-
-[concat]
-input_layers = embedding1, embedding2
-Type = concat
-
-[flatten]
-Type = flatten
-
-[outputlayer]
-Type = fully_connected
-input_layers = flatten
-Unit = 1
-Bias_initializer = zeros
-Activation = sigmoid
diff --git a/Applications/Embedding/res/embedding_input.txt b/Applications/Embedding/res/embedding_input.txt
deleted file mode 100644 (file)
index 76aee2b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-6 2 0 0 1
-3 1 0 0 1
-7 4 0 0 1
-8 1 0 0 1
-9 0 0 0 1
-10 0 0 0 0
-5 4 0 0 0
-11 3 0 0 0
-5 1 0 0 0
-12 13 2 14 0
diff --git a/Applications/ProductRatings/README.md b/Applications/ProductRatings/README.md
new file mode 100644 (file)
index 0000000..ff07890
--- /dev/null
@@ -0,0 +1,47 @@
+# Product Ratings
+
+This application contains a simple embedding-based model that predicts ratings given a user and a product.
+
+## The Model Structure
+
+ (Input:           1:2:2 ) # user_id, product_id
+ (split:           1:1:1,                   1:1:1 )
+ (user_embed:      1:1:5 ), (product_embed:    1:1:5 )
+ (concat:          2:1:5 ),
+ (Flatten:         1:1:10),
+ (FullyConnected:  1:1:128),
+ (Relu:            1:1:128),
+ (FullyConnected:  1:1:32),
+ (Relu:            1:1:32),
+ (FullyConnected:  1:1:1 ) # predicted ratings
+
+## Input Data Format
+
+Input data should be formatted as below
+
+```
+(int) (int) (float)
+(int) (int) (float)
+(int) (int) (float)
+(int) (int) (float)
+```
+Each represents user_id, product_id and ratings, respectively.
+
+Example, `product_ratings.txt` contains fake ratings on 5 userid X 5 products
+
+## How to run a train epoch
+
+Once you compile, with `meson`, you can run with `meson test nntrainer_product_ratings`.
+Please file an issue if you have a problem running the example.
+
+```bash
+$ meson test nntrainer_product_ratings -v -c ${build_dir}
+```
+
+Expected output is as below...
+
+```bash
+#1/100 - Training Loss: 0.692463 >> [ Accuracy: 100% - Validation Loss : 0.690833 ]
+...
+#100/100 - Training Loss: 0.535373 >> [ Accuracy: 100% - Validation Loss : 0.53367 ]
+```
similarity index 97%
rename from Applications/Embedding/jni/Android.mk
rename to Applications/ProductRatings/jni/Android.mk
index 704bb5f..c6b4bb5 100644 (file)
@@ -46,7 +46,7 @@ LOCAL_CFLAGS += -pthread -fexceptions
 LOCAL_LDFLAGS += -fexceptions
 LOCAL_MODULE_TAGS := optional
 LOCAL_ARM_MODE := arm
-LOCAL_MODULE := nntrainer_embedding
+LOCAL_MODULE := nntrainer_product_ratings
 LOCAL_LDLIBS := -llog -landroid
 
 LOCAL_SRC_FILES := main.cpp
similarity index 93%
rename from Applications/Embedding/jni/main.cpp
rename to Applications/ProductRatings/jni/main.cpp
index 04c8ace..f304696 100644 (file)
 
 std::string data_file;
 
-const unsigned int total_train_data_size = 10;
+const unsigned int total_train_data_size = 25;
 
 unsigned int train_count = 0;
 
 const unsigned int batch_size = 10;
 
-const unsigned int feature_size = 4;
+const unsigned int feature_size = 2;
 
-const unsigned int total_val_data_size = 10;
+const unsigned int total_val_data_size = 25;
 
 bool training = false;
 
@@ -79,8 +79,9 @@ bool getData(std::ifstream &F, std::vector<float> &outVec,
 
   F.putback(c);
 
-  if (!std::getline(F, temp))
+  if (!std::getline(F, temp)) {
     return false;
+  }
 
   std::istringstream buffer(temp);
   float x;
@@ -123,16 +124,15 @@ int getBatch_train(float **outVec, float **outLabel, bool *last,
     return 0;
   }
 
-  for (unsigned int i = train_count; i < train_count + batch_size; ++i) {
-
-    std::vector<float> o;
-    std::vector<float> l;
-    o.resize(feature_size);
-    l.resize(1);
+  std::vector<float> o;
+  std::vector<float> l;
+  o.resize(feature_size);
+  l.resize(1);
 
+  for (unsigned int i = train_count; i < train_count + batch_size; ++i) {
     if (!getData(dataFile, o, l, i)) {
       return -1;
-    };
+    }
 
     for (unsigned int j = 0; j < feature_size; ++j)
       outVec[0][count * feature_size + j] = o[j];
@@ -152,7 +152,10 @@ int getBatch_train(float **outVec, float **outLabel, bool *last,
  *            back propagation of NN
  * @param[in]  arg 1 : train / inference
  * @param[in]  arg 2 : configuration file path
- * @param[in]  arg 3 : resource path (dataset.txt or testset.txt)
+ * @param[in]  arg 3 : resource path (data) with below format
+ * (int) (int) (float) #first data
+ * ...
+ * in each row represents user id, product id, rating (0 to 10)
  */
 int main(int argc, char *argv[]) {
   if (argc < 4) {
diff --git a/Applications/ProductRatings/jni/meson.build b/Applications/ProductRatings/jni/meson.build
new file mode 100644 (file)
index 0000000..f5029fe
--- /dev/null
@@ -0,0 +1,15 @@
+res_path = meson.current_source_dir() / '..' / 'res'
+run_command('cp', '-lr', res_path, nntr_app_resdir / 'ProductRatings')
+
+e = executable('nntrainer_product_ratings',
+  'main.cpp',
+  dependencies: [iniparser_dep, nntrainer_ccapi_dep, gtest_dep, nntrainer_dep],
+  install: get_option('install-app'),
+  install_dir: application_install_dir
+)
+
+# test split example
+test('nntrainer_product_ratings', e, args: ['train',
+  nntr_app_resdir / 'ProductRatings' / 'product_ratings_model.ini',
+  nntr_app_resdir / 'ProductRatings' / 'sample_product_ratings.txt']
+)
diff --git a/Applications/ProductRatings/res/product_ratings_model.ini b/Applications/ProductRatings/res/product_ratings_model.ini
new file mode 100644 (file)
index 0000000..3616451
--- /dev/null
@@ -0,0 +1,59 @@
+# Model Section : Model
+[Model]
+Type = NeuralNetwork
+Epochs = 100           # Epochs
+Loss = mse     # Loss function : mse (mean squared error)
+                        #                       cross ( cross entropy )
+# Save_Path = "product_ratings_model.bin" # enable this to save result
+batch_size = 20                # batch size
+
+[Optimizer]
+Type = adam
+beta1 = 0.9
+beta2 = 0.999
+Learning_rate = 0.001
+epsilon = 1e-7
+
+[input]
+Type = input
+input_shape = 1:1:2 # channel:height:width
+
+[split]
+Type = split
+split_dimension = 3 # split by width
+
+[user_embed]
+input_layers = split
+Type = embedding
+in_dim = 6          # in dim must be more than len(set(user ids)) + 1
+out_dim = 5
+in_length = 1
+
+[product_embed]
+input_layers = split
+Type = embedding
+in_dim = 6          # in dim must be more than len(set(product ids)) + 1
+out_dim = 5
+in_length = 1
+
+[concat]
+input_layers = user_embed, product_embed
+Type = concat
+
+[flatten]
+Type = flatten
+
+[fc1]
+Type = fully_connected
+unit = 128
+activation = relu
+
+[fc2]
+Type = fully_connected
+unit = 32
+activation = relu
+
+[outputlayer]
+Type = fully_connected
+Unit = 1
+Bias_initializer = zeros
diff --git a/Applications/ProductRatings/res/sample_product_ratings.txt b/Applications/ProductRatings/res/sample_product_ratings.txt
new file mode 100644 (file)
index 0000000..4857779
--- /dev/null
@@ -0,0 +1,25 @@
+1 1 5
+1 2 3
+1 3 4
+1 4 1
+1 5 0
+2 1 4
+2 2 1
+2 3 1
+2 4 1
+2 5 2
+3 1 2
+3 2 3
+3 3 4
+3 4 9
+3 5 10
+4 1 10
+4 2 9
+4 3 8
+4 4 4
+4 5 2
+5 1 1
+5 2 3
+5 3 5
+5 4 7
+5 5 9
index f20ea5a..82a1c43 100644 (file)
@@ -12,7 +12,7 @@ subdir('ReinforcementLearning/DeepQ/jni')
 subdir('TransferLearning/CIFAR_Classification/jni')
 subdir('TransferLearning/Draw_Classification/jni')
 subdir('Custom')
-subdir('Embedding/jni')
+subdir('ProductRatings/jni')
 
 if get_option('enable-tflite-backbone')
   subdir('SimpleShot')
index 3eb4d00..5772ada 100644 (file)
@@ -616,9 +616,10 @@ int NeuralNetwork::train_run() {
         try {
           forwarding(true);
           backwarding(iter++);
-        } catch (...) {
+        } catch (std::exception &e) {
           data_buffer->clear(nntrainer::BufferType::BUF_TRAIN);
-          ml_loge("Error: training error in #%d/%d.", epoch_idx, epochs);
+          ml_loge("Error: training error in #%d/%d. %s", epoch_idx, epochs,
+                  e.what());
           throw;
         }
         std::cout << "#" << epoch_idx << "/" << epochs;