[layer] perform layer context check on first forward
authorParichay Kapoor <pk.kapoor@samsung.com>
Thu, 2 Dec 2021 08:37:50 +0000 (17:37 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Fri, 3 Dec 2021 05:46:00 +0000 (14:46 +0900)
This patch enables layer context check on the first forward itself,
which revealed a bug in forward which was earlier being shown in the
calcGradient in mol attention layer.
Added the corresponding fix for mol attention layer.

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
nntrainer/layers/attention_layer.cpp
nntrainer/layers/layer_context.cpp
nntrainer/layers/mol_attention_layer.cpp
nntrainer/layers/mol_attention_layer.h
nntrainer/layers/time_dist.cpp
test/input_gen/genModelTests_v2.py
test/input_gen/genModelsRecurrent_v2.py
test/unittest/layers/layers_golden_tests.cpp
test/unittest/layers/unittest_layer_node.cpp
test/unittest/layers/unittest_layers_mol_attention.cpp

index 90d30000e5335f28a2c84961e84e8c84d27b4844..1b247b49f610c5a890989208825a79d35646ffd9 100644 (file)
@@ -31,8 +31,12 @@ void AttentionLayer::finalizeCommon(InitLayerContext &context) {
     throw std::runtime_error("Attention layer needs 2-3 inputs.");
 
   auto const &all_dims = context.getInputDimensions();
+  auto const &query_dim = all_dims[AttentionParams::query];
   auto const &value_dim = all_dims[AttentionParams::value];
 
+  NNTR_THROW_IF(query_dim.width() != value_dim.width(), std::invalid_argument)
+    << "Query and Value dimension mismatch for layer " << context.getName();
+
   wt_idx[AttentionParams::query] = AttentionParams::query;
   wt_idx[AttentionParams::value] = AttentionParams::value;
   wt_idx[AttentionParams::key] = AttentionParams::value;
index c6edba79bf4d700ce4a7ec58b1429e1a5ecbcb0f..3826d256b8466ceb4a38d3c4f74d26074f25f496 100644 (file)
@@ -367,7 +367,10 @@ bool RunLayerContext::validate(bool skip_input, bool skip_label) {
    * references which leads to nasty bugs. This validation ensures that the
    * tensors are not set mistakenly by verifying their unique names
    */
+  bool ret = true;
 #ifdef DEBUG
+  std::function<bool(const Var_Grad *, bool)> matcher;
+
   if (tensor_map.empty() || !tensor_map[inputs[0]->getName()]) {
     auto filler = [this](const auto &vec) {
       for (auto const &val : vec) {
@@ -381,52 +384,46 @@ bool RunLayerContext::validate(bool skip_input, bool skip_label) {
     filler(inputs);
     filler(outputs);
     filler(tensors);
-  } else {
-    auto matcher = [this](const Var_Grad *val, bool skip_grad = false) {
-      if (val->getName().empty() ||
-          (val->hasGradient() && val->getGradientName().empty()))
-        return false;
-
-      if (tensor_map.find(val->getName()) == tensor_map.end())
-        /**
-         * Disabled because of in-place input layer. Enable this later.
-         * tensor_map[val->getName()] != val->getVariableRef().getData())
-         */
-        return false;
-
-      if (skip_grad &&
-          (tensor_map.find(val->getGradientName()) == tensor_map.end()))
-        return false;
-
-      return true;
-    };
-
-    auto matcher_w = [this, matcher](const std::vector<Weight *> &vec) {
-      return std::all_of(vec.begin(), vec.end(), matcher);
-    };
-
-    auto matcher_vw = [this, matcher](const std::vector<Var_Grad *> &vec,
-                                      bool skip_grad = false) {
-      return std::all_of(vec.begin(), vec.end(),
-                         std::bind(matcher, std::placeholders::_1, skip_grad));
-      auto ret = true;
-      for (auto const &val : vec)
-        ret &= matcher(val, skip_grad);
-      return ret;
-    };
-
-    /** match the tensor map from the next validations */
-
-    auto ret = matcher_w(weights) & matcher_vw(tensors) &
-               matcher_vw(outputs, skip_label);
-    if (!skip_input)
-      ret &= matcher_vw(inputs);
-
-    return ret;
   }
+
+  matcher = [this](const Var_Grad *val, bool skip_grad) -> bool {
+    if (val->getName().empty() ||
+        (val->hasGradient() && val->getGradientName().empty()))
+      return false;
+
+    if (tensor_map.find(val->getName()) == tensor_map.end())
+      /**
+       * Disabled because of in-place input layer. Enable this later.
+       * tensor_map[val->getName()] != val->getVariableRef().getData())
+       */
+      return false;
+
+    if (skip_grad &&
+        (tensor_map.find(val->getGradientName()) == tensor_map.end()))
+      return false;
+
+    return true;
+  };
+
+  auto matcher_w = [this, &matcher](const std::vector<Weight *> &vec) {
+    return std::all_of(vec.begin(), vec.end(),
+                       std::bind(matcher, std::placeholders::_1, false));
+  };
+
+  auto matcher_vw = [this, &matcher](const std::vector<Var_Grad *> &vec,
+                                     bool skip_grad = false) {
+    return std::all_of(vec.begin(), vec.end(),
+                       std::bind(matcher, std::placeholders::_1, skip_grad));
+  };
+
+  /** match the tensor map from the next validations */
+  ret =
+    matcher_w(weights) & matcher_vw(tensors) & matcher_vw(outputs, skip_label);
+  if (!skip_input)
+    ret &= matcher_vw(inputs);
 #endif
 
-  return true;
+  return ret;
 }
 
 } // namespace nntrainer
index fcc10b99d20a46e779c97eb83fd4c6267940f3c9..c5e35a11f940eb6d2671341150ea9b7d48fde0c7 100644 (file)
@@ -52,6 +52,7 @@ void MoLAttentionLayer::finalize(InitLayerContext &context) {
   auto const &all_dims = context.getInputDimensions();
   auto const &query_dim = all_dims[AttentionParams::query];
   auto const &value_dim = all_dims[AttentionParams::value];
+  auto const &state_dim = all_dims[AttentionParams::state];
 
   wt_idx[AttentionParams::query] = AttentionParams::query;
   wt_idx[AttentionParams::value] = AttentionParams::value;
@@ -61,6 +62,9 @@ void MoLAttentionLayer::finalize(InitLayerContext &context) {
   tanh.setActiFunc(ActivationType::ACT_TANH);
   sigmoid.setActiFunc(ActivationType::ACT_SIGMOID);
 
+  NNTR_THROW_IF(query_dim.width() != value_dim.width(), std::invalid_argument)
+    << "Query and Value dimension mismatch for layer " << context.getName();
+
   NNTR_THROW_IF(std::get<props::Unit>(mol_props).empty(), std::invalid_argument)
     << "Number of units not provided for layer " << context.getName();
   auto unit = std::get<props::Unit>(mol_props).get();
@@ -70,6 +74,10 @@ void MoLAttentionLayer::finalize(InitLayerContext &context) {
     << "MoL_K property not provided for layer " << context.getName();
   auto mol_k = std::get<props::MoL_K>(mol_props).get();
 
+  NNTR_THROW_IF(mol_k != state_dim.width(), std::invalid_argument)
+    << "MoL_K property mismatches the provided state dimension for layer"
+    << context.getName();
+
   auto &weight_regularizer =
     std::get<props::WeightRegularizer>(*layer_impl_props);
   auto &weight_regularizer_constant =
@@ -99,7 +107,7 @@ void MoLAttentionLayer::finalize(InitLayerContext &context) {
                           false, TensorLifespan::ITERATION_LIFESPAN);
 
   TensorDim fc_proj_out_dim = fc_out_dim;
-  fc_out_dim.width(fc_proj_w_dim.width());
+  fc_proj_out_dim.width(fc_proj_w_dim.width());
   wt_idx[AttentionParams::fc_proj_out] = context.requestTensor(
     fc_proj_out_dim, "fc_proj_out", Tensor::Initializer::NONE, false,
     TensorLifespan::ITERATION_LIFESPAN);
@@ -157,12 +165,12 @@ void MoLAttentionLayer::forwarding(RunLayerContext &context, bool training) {
   /** reset helper state */
   helper_exec = false;
 
-  fc_out = query.dot(fc_w);
+  query.dot(fc_w, fc_out);
   fc_out.add_i(fc_bias);
 
   tanh.run_fn(fc_out, fc_tanh);
 
-  fc_proj_out = fc_tanh.dot(fc_proj_w);
+  fc_tanh.dot(fc_proj_w, fc_proj_out);
 
   Tensor kappa_src, beta_src, alpha_src;
   kappa_src.copy_with_stride(
@@ -222,6 +230,7 @@ void MoLAttentionLayer::forwarding(RunLayerContext &context, bool training) {
 
 void MoLAttentionLayer::calcDerivativeHelper(RunLayerContext &context,
                                              Tensor &dstate) {
+  /** optimize temporary tensor usage here */
   Tensor &query = context.getInput(wt_idx[AttentionParams::query]);
   Tensor &value = context.getInput(wt_idx[AttentionParams::value]);
 
@@ -359,7 +368,7 @@ void MoLAttentionLayer::calcGradient(RunLayerContext &context) {
 
 void MoLAttentionLayer::setProperty(const std::vector<std::string> &values) {
   auto remain_props = loadProperties(values, mol_props);
-  AttentionLayer::setProperty(remain_props);
+  LayerImpl::setProperty(remain_props);
 }
 
 void MoLAttentionLayer::setBatch(RunLayerContext &context, unsigned int batch) {
@@ -375,7 +384,6 @@ void MoLAttentionLayer::setBatch(RunLayerContext &context, unsigned int batch) {
 
 void MoLAttentionLayer::exportTo(Exporter &exporter,
                                  const ExportMethods &method) const {
-  AttentionLayer::exportTo(exporter, method);
   LayerImpl::exportTo(exporter, method);
   exporter.saveResult(mol_props, method, this);
 }
index 1f545021d2ed4da1b2c356c27d325cf6a8478c6c..e41e5f471b0eda73cb378228b8ba4a57485701dc 100644 (file)
@@ -24,7 +24,7 @@ namespace nntrainer {
  * @class   MoL Attention Layer
  * @brief   Mixture of Logistics Attention Layer
  */
-class MoLAttentionLayer : public AttentionLayer, public LayerImpl {
+class MoLAttentionLayer : public LayerImpl {
 public:
   /**
    * @brief     Constructor of MoL Attention Layer
index 8e6655bf0b2e8eafb41a4450418516879c65a0bd..1e41b8bad980674145d9b0fb3d86d0f60516dc87 100644 (file)
@@ -95,6 +95,7 @@ Tensor TimeDistLayer::transposeTensor(Tensor &m) {
   Tensor in = m.transpose("1:0:2");
   in.reshape({dim[2], dim[1], dim[0], dim[3]});
   m.reshape(dim);
+  in.setName(m.getName() + "_trans");
 
   return in;
 }
@@ -202,7 +203,9 @@ void TimeDistLayer::forwarding(RunLayerContext &context, bool training) {
   // TODO: This transposed Input Tensor could be resued for backwarding
   Tensor in = transposeTensor(input_);
 
-  Tensor out = Tensor({ho_dim[2], 1, ho_dim[0], ho_dim[3]}, true);
+  Tensor out =
+    Tensor({ho_dim[2], 1, ho_dim[0], ho_dim[3]}, true,
+           Tensor::Initializer::NONE, context.getName() + ":inter_output");
 
   TensorDim i_dim = in_dim;
   i_dim.channel(1);
@@ -234,18 +237,18 @@ void TimeDistLayer::forwarding(RunLayerContext &context, bool training) {
     //
     Tensor label_iter;
 
-    Tensor in_iter =
-      in.getSharedDataTensor(i_dim, i * in_dim.batch() * in_dim.width());
-    Tensor out_iter =
-      out.getSharedDataTensor(h_dim, i * ho_dim.batch() * ho_dim.width());
+    Tensor in_iter = in.getSharedDataTensor(
+      i_dim, i * in_dim.batch() * in_dim.width(), true, in.getName());
+    Tensor out_iter = out.getSharedDataTensor(
+      h_dim, i * ho_dim.batch() * ho_dim.width(), true, out.getName());
 
     in_var.initializeVariable(in_iter);
     out_var.initializeVariable(out_iter);
 
     if (dist_layer->requireLabel() &&
         context.isLabelAvailable(SINGLE_INOUT_IDX)) {
-      label_iter =
-        h_g.getSharedDataTensor(h_dim, i * ho_dim.batch() * ho_dim.width());
+      label_iter = h_g.getSharedDataTensor(
+        h_dim, i * ho_dim.batch() * ho_dim.width(), true, h_g.getName());
       out_var.initializeGradient(label_iter);
     }
 
@@ -280,14 +283,14 @@ void TimeDistLayer::calcDerivative(RunLayerContext &context) {
   fillTensorsFromContext(context);
 
   for (unsigned int i = 0; i < der_dim[0]; ++i) {
-    Tensor ret_iter =
-      ret_.getSharedDataTensor(r_dim, i * r_dim.batch() * r_dim.width());
-    Tensor in_iter =
-      input_.getSharedDataTensor(r_dim, i * r_dim.batch() * r_dim.width());
-    Tensor d_iter =
-      derivative_.getSharedDataTensor(d_dim, i * d_dim.batch() * d_dim.width());
-    Tensor hval_iter =
-      hval_.getSharedDataTensor(d_dim, i * d_dim.batch() * d_dim.width());
+    Tensor ret_iter = ret_.getSharedDataTensor(
+      r_dim, i * r_dim.batch() * r_dim.width(), true, ret_.getName());
+    Tensor in_iter = input_.getSharedDataTensor(
+      r_dim, i * r_dim.batch() * r_dim.width(), true, input_.getName());
+    Tensor d_iter = derivative_.getSharedDataTensor(
+      d_dim, i * d_dim.batch() * d_dim.width(), true, derivative_.getName());
+    Tensor hval_iter = hval_.getSharedDataTensor(
+      d_dim, i * d_dim.batch() * d_dim.width(), true, hval_.getName());
 
     in_var.initializeGradient(ret_iter);
     in_var.initializeVariable(in_iter);
@@ -334,10 +337,10 @@ void TimeDistLayer::calcGradient(RunLayerContext &context) {
   fillTensorsFromContext(context);
 
   for (unsigned int i = 0; i < der_dim[0]; ++i) {
-    Tensor in_iter =
-      input_.getSharedDataTensor(i_dim, i * i_dim.batch() * i_dim.width());
-    Tensor d_iter =
-      derivative_.getSharedDataTensor(d_dim, i * d_dim.batch() * d_dim.width());
+    Tensor in_iter = input_.getSharedDataTensor(
+      i_dim, i * i_dim.batch() * i_dim.width(), true, input_.getName());
+    Tensor d_iter = derivative_.getSharedDataTensor(
+      d_dim, i * d_dim.batch() * d_dim.width(), true, derivative_.getName());
 
     Var_Grad in_var(i_dim, Tensor::Initializer::NONE, true, false, "input");
     Var_Grad out_var(d_dim, Tensor::Initializer::NONE, true, false, "output");
index 8c5941f02f956772920a3e726864af51f2fb964a..89ef073d9a4395a20f8488d63950267e76dd736f 100644 (file)
@@ -76,3 +76,5 @@ if __name__ == "__main__":
         label_dims=[(3,1,6)],
         name="mol_attention",
     )
+
+    # inspect_file("mol_attention.nnmodelgolden")
index 0d7f31c41da0a5de8c1d672036266f726da62e8e..18f62d723acff3326bd6ad4bf0ad48d2972e9a04 100644 (file)
@@ -190,5 +190,6 @@ if __name__ == "__main__":
         input_dims=[(3, 2)],
         label_dims=[(3, 2, 2)],
         name="grucell_stacked",
+    )
 
     # inspect_file("lstm_single.nnmodelgolden")
index 6b8e89484cdbbf1188c2aba7f033d298abe4ff63..7856e9dfab5fa229f992ff4c27cff4b8f17be1c1 100644 (file)
@@ -63,7 +63,7 @@ static TensorPacks prepareTensors(const InitLayerContext &context,
     vg.reserve(dims.size());
 
     for (auto &dim : dims) {
-      vg.emplace_back(dim, Tensor::Initializer::NONE, true, true);
+      vg.emplace_back(dim, Tensor::Initializer::NONE, true, true, "golden");
       sizeCheckedReadTensor(vg.back().getVariableRef(), file,
                             vg.back().getName());
     }
index 7e7fe22dc085ad4f3a14e940c08f0c46cb943150..7a3a2e160051f26f1b27c776d663598853739c1e 100644 (file)
@@ -81,8 +81,9 @@ TEST(nntrainer_LayerNode, finalize_05_n) {
   auto lnode = nntrainer::createLayerNode(nntrainer::FullyConnectedLayer::type);
   lnode->setProperty({"input_shape=1:1:1", "name=abc", "unit=4"});
   EXPECT_NO_THROW(lnode->finalize());
-  nntrainer::Var_Grad input =
-    nntrainer::Var_Grad(nntrainer::TensorDim({1, 1, 1, 1}));
+  nntrainer::Var_Grad input = nntrainer::Var_Grad(
+    nntrainer::TensorDim({1, 1, 1, 1}), nntrainer::Tensor::Initializer::NONE,
+    true, false, "dummy");
   lnode->configureRunContext({}, {&input}, {}, {});
   EXPECT_ANY_THROW(lnode->finalize());
 }
index 5a0fe429c61da4dbfdf6d2a4565c5a61d073634c..8515ee4a611f1d03038a60085224ed02ff72206f 100644 (file)
@@ -18,7 +18,7 @@
 
 auto semantic_mol_attention = LayerSemanticsParamType(
   nntrainer::createLayer<nntrainer::MoLAttentionLayer>,
-  nntrainer::MoLAttentionLayer::type, {"unit=5", "mol_k=4"}, 0, false, 3);
+  nntrainer::MoLAttentionLayer::type, {"unit=5", "mol_k=1"}, 0, false, 3);
 
 INSTANTIATE_TEST_CASE_P(MoLAttention, LayerSemantics,
                         ::testing::Values(semantic_mol_attention));