Home | History | Annotate | Download | only in framework
      1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #include "tensorflow/cc/client/client_session.h"
     17 #include "tensorflow/cc/framework/testutil.h"
     18 #include "tensorflow/cc/ops/standard_ops.h"
     19 #include "tensorflow/cc/ops/test_op.h"
     20 #include "tensorflow/core/framework/node_def_util.h"
     21 #include "tensorflow/core/framework/tensor_testutil.h"
     22 #include "tensorflow/core/lib/core/status_test_util.h"
     23 
     24 namespace tensorflow {
     25 namespace ops {
     26 namespace {
     27 
     28 Output Linear(const Scope& scope, Input x, Input w, Input b) {
     29   auto cop_scopes = scope.GetCompositeOpScopes("linear");
     30   auto m = MatMul(cop_scopes.child, x, w);
     31   return BiasAdd(cop_scopes.last, m, b);
     32 }
     33 
     34 void GetColocationConstraints(const Output& tensor,
     35                               std::vector<string>* constraints) {
     36   constraints->clear();
     37   TF_EXPECT_OK(GetNodeAttr(tensor.op().node()->attrs(), kColocationAttrName,
     38                            constraints));
     39 }
     40 
     41 TEST(CCOpTest, Basic) {
     42   Scope root = Scope::NewRootScope();
     43   auto c = Const(root, {{1, 1}});
     44   // NOTE: The recommended style for constructing ops is
     45   // auto v = OpConstructor(t0, t1, ..);
     46   // Since the wrappers are implemented as one class per op, the following
     47   // style is also possible :
     48   // PrimitiveOp p(t0, t1, ...);
     49   // It's being used here ONLY to ensure that, that style is tested.
     50   MatMul m(root, c, {{41}, {1}});
     51   TF_EXPECT_OK(root.status());
     52   Tensor out;
     53   test::GetTensor(root, m, &out);
     54   test::ExpectTensorEqual<int>(out, test::AsTensor<int>({42}, {1, 1}));
     55 }
     56 
     57 TEST(CCOpTest, Attrs) {
     58   Scope root = Scope::NewRootScope();
     59   auto m = MatMul(root, {{1}, {1}}, {{41}, {1}}, MatMul::TransposeA(true));
     60   TF_EXPECT_OK(root.status());
     61   Tensor out;
     62   test::GetTensor(root, m, &out);
     63   test::ExpectTensorEqual<int>(out, test::AsTensor<int>({42}, {1, 1}));
     64 }
     65 
     66 TEST(CCOpTest, SplitConcat) {
     67   Scope root = Scope::NewRootScope();
     68   Split p(root, 0, {{1}, {2}}, 2);
     69   auto c = Concat(root, {p[0], p[1]}, 0);
     70   TF_EXPECT_OK(root.status());
     71   Tensor out;
     72   test::GetTensor(root, c, &out);
     73   test::ExpectTensorEqual<int>(out, test::AsTensor<int>({1, 2}, {2, 1}));
     74 }
     75 
     76 TEST(CCOpTest, CompositeOp) {
     77   Scope root = Scope::NewRootScope();
     78   auto l = Linear(root.WithOpName("layer0"), {{10.0f, -3.0f}},
     79                   {{.8f, .5f}, {.1f, .6f}}, {-8.0f, 31.0f});
     80   TF_EXPECT_OK(root.status());
     81   EXPECT_EQ(l.node()->name(), "layer0");
     82   Tensor out;
     83   test::GetTensor(root, l, &out);
     84   test::ExpectClose(out, test::AsTensor<float>({-0.3, 34.2}, {1, 2}));
     85 }
     86 
     87 TEST(CCOpTest, MultiOutput) {
     88   Scope root = Scope::NewRootScope();
     89   auto u = Unique(root, {1, 2, 2, 4, 3, 2});
     90   std::vector<Tensor> outputs;
     91   test::GetTensors(root, {u.y, u.idx}, &outputs);
     92   test::ExpectTensorEqual<int>(outputs[0], test::AsTensor<int>({1, 2, 4, 3}));
     93   test::ExpectTensorEqual<int>(outputs[1],
     94                                test::AsTensor<int>({0, 1, 1, 2, 3, 1}));
     95 }
     96 
     97 TEST(CCOpTest, ExampleTrainer) {
     98   Scope root = Scope::NewRootScope();
     99   // a = [3 2; -1 0]
    100   auto a = Const(root, {{3.f, 2.f}, {-1.f, 0.f}});
    101   // x = [1.0; 1.0]
    102   auto x = Const(root.WithOpName("x"), {{1.f}, {1.f}});
    103   // y = a * x
    104   auto y = MatMul(root.WithOpName("y"), a, x);
    105   // y2 = y.^2
    106   auto y2 = Square(root, y);
    107   // y2_sum = sum(y2)
    108   auto y2_sum = Sum(root, y2, 0);
    109   // y_norm = sqrt(y2_sum)
    110   auto y_norm = Sqrt(root, y2_sum);
    111   // y_normalized = y ./ y_norm
    112   auto y_normalized = Div(root.WithOpName("y_normalized"), y, y_norm);
    113   Tensor out;
    114   test::GetTensor(root, y_normalized, &out);
    115   test::ExpectTensorNear<float>(
    116       out, test::AsTensor<float>({0.98058069, -0.19611613}, {2, 1}), 1e-5);
    117 }
    118 
    119 TEST(CCOpTest, ThrowAwayOp) {
    120   Scope root = Scope::NewRootScope();
    121   ThrowAway1(root, 1, 2.3f, 1, 1, 1, ThrowAway1::Builder(42));
    122   ThrowAway2(root, ThrowAway2::ThrowAway2_(3).Scope(1));
    123   TF_EXPECT_OK(root.status());
    124 }
    125 
    126 TEST(CCOpTest, ControlDeps) {
    127   Scope root = Scope::NewRootScope();
    128   auto v = Variable(root, {}, DT_FLOAT);
    129   auto assign = Assign(root, v, 41.0f);
    130   Scope with_control_deps = root.WithControlDependencies(assign);
    131   auto add = Add(with_control_deps, v, 1.0f);
    132   Scope no_control_deps = with_control_deps.WithNoControlDependencies();
    133   auto sub = Sub(no_control_deps, 3.0f, 2.0f);
    134   auto is_inited =
    135       IsVariableInitialized(no_control_deps.WithControlDependencies(sub), v);
    136 
    137   TF_EXPECT_OK(root.status());
    138 
    139   std::vector<Tensor> out;
    140 
    141   test::GetTensors(root, {add}, &out);
    142   test::ExpectTensorNear<float>(out[0], test::AsTensor<float>({42.0f}, {}),
    143                                 1e-5);
    144 
    145   out.clear();
    146   // Note : GetTensors creates a new session, so 'v' is uninitialized.
    147   // sub should have no control deps, so it should not cause the assign to run.
    148   // Hence is_inited should be false.
    149   test::GetTensors(root, {sub, is_inited}, &out);
    150   test::ExpectTensorNear<float>(out[0], test::AsTensor<float>({1.0f}, {}),
    151                                 1e-5);
    152   test::ExpectTensorEqual<bool>(out[1], test::AsTensor<bool>({false}, {}));
    153 }
    154 
    155 TEST(CCOpTest, KernelLabel) {
    156   Scope root = Scope::NewRootScope();
    157   auto add = Add(root.WithKernelLabel("AddWithKernelLabel"), 1.0f, 2.0f);
    158   TF_EXPECT_OK(root.status());
    159   AttrSlice attrs = add.z.op().node()->attrs();
    160   const auto* kernel_attr = attrs.Find("_kernel");
    161   ASSERT_TRUE(kernel_attr);
    162   TF_EXPECT_OK(AttrValueHasType(*kernel_attr, "string"));
    163   EXPECT_EQ(kernel_attr->s(), "AddWithKernelLabel");
    164 }
    165 
    166 TEST(CCOpTest, ColocateWith) {
    167   Scope root = Scope::NewRootScope();
    168   auto c1 = Const(root.WithOpName("c1"), 1);
    169   auto c2 = Const(root.WithOpName("c2").ColocateWith(c1), 2);
    170   std::vector<string> constraints;
    171   GetColocationConstraints(c2, &constraints);
    172   EXPECT_EQ(constraints[0], "loc:@c1");
    173 
    174   auto c3 = Const(root.WithOpName("c3").ColocateWith(c2), 3);
    175   GetColocationConstraints(c3, &constraints);
    176   EXPECT_EQ(constraints[0], "loc:@c1");
    177 
    178   auto a = Const(root.WithOpName("a"), 4);
    179   auto c4 = Const(root.WithOpName("c4").ColocateWith(a), 5);
    180   GetColocationConstraints(c4, &constraints);
    181   EXPECT_EQ(constraints[0], "loc:@a");
    182 
    183   auto c5 = Const(root.WithOpName("c5").ColocateWith(c3).ColocateWith(c4), 6);
    184   GetColocationConstraints(c5, &constraints);
    185   EXPECT_EQ(constraints[0], "loc:@a");
    186   EXPECT_EQ(constraints[1], "loc:@c1");
    187 
    188   Scope with_colocate = root.ColocateWith(c3).ColocateWith(c4);
    189   auto c6 = Const(with_colocate.WithOpName("c6").ClearColocation(), 7);
    190   EXPECT_FALSE(c6.op().node()->attrs().Find("_class"));
    191 }
    192 
    193 TEST(CCOpTest, TemplatedConst) {
    194   Scope root = Scope::NewRootScope();
    195   auto c1 = ops::Const<float>(root, {{3, 2}, {-1, 0}});
    196   TF_EXPECT_OK(root.status());
    197 
    198   Tensor out;
    199   test::GetTensor(root, c1, &out);
    200   test::ExpectTensorEqual<float>(
    201       out, test::AsTensor<float>({3.f, 2.f, -1.f, 0.f}, {2, 2}));
    202 
    203   auto c2 = ops::Const<string>(root, {{"this"}, {"is"}, {"a"}, {"constant"}});
    204   test::GetTensor(root, c2, &out);
    205   test::ExpectTensorEqual<string>(
    206       out, test::AsTensor<string>({"this", "is", "a", "constant"}, {4, 1}));
    207 }
    208 
    209 TEST(CCOpTest, EmptyConst) {
    210   Scope root = Scope::NewRootScope();
    211 
    212   auto c1 = ops::Const(root, {});
    213   TF_CHECK_OK(root.status());
    214 
    215   Tensor out;
    216   test::GetTensor(root, c1, &out);
    217   test::ExpectTensorEqual<float>(out, Tensor(DT_FLOAT, {0}));
    218 
    219   auto c2 = ops::Const(root, {{}});
    220   TF_CHECK_OK(root.status());
    221   test::GetTensor(root, c2, &out);
    222   test::ExpectTensorEqual<float>(out, Tensor(DT_FLOAT, {1, 0}));
    223 
    224   auto c3 = ops::Const(root, {{{}, {}}});
    225   TF_CHECK_OK(root.status());
    226   test::GetTensor(root, c3, &out);
    227   test::ExpectTensorEqual<float>(out, Tensor(DT_FLOAT, {1, 2, 0}));
    228 
    229   auto c4 = ops::Const<int>(root, {{{}}});
    230   TF_CHECK_OK(root.status());
    231   test::GetTensor(root, c4, &out);
    232   test::ExpectTensorEqual<int>(out, Tensor(DT_INT32, {1, 1, 0}));
    233 
    234   ops::Const(root, {{}, {{}}});
    235   EXPECT_FALSE(root.status().ok());
    236 }
    237 
    238 TEST(CCOpTest, InvalidFinalize) {
    239   Scope root = Scope::NewRootScope();
    240   auto read_up_to =
    241       ops::ReaderReadUpTo(root, Variable(root, {}, DT_STRING),
    242                           Variable(root, {}, DT_STRING), static_cast<int32>(2));
    243   EXPECT_FALSE(root.status().ok());
    244   auto err_msg = root.status().error_message();
    245   EXPECT_NE(err_msg.find("'num_records' passed int32 expected int64"),
    246             string::npos);
    247 }
    248 
    249 }  // namespace
    250 }  // namespace ops
    251 }  // namespace tensorflow
    252