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
Linear(const Scope & scope,Input x,Input w,Input b)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
GetColocationConstraints(const Output & tensor,std::vector<string> * constraints)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
TEST(CCOpTest,Basic)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
TEST(CCOpTest,Attrs)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
TEST(CCOpTest,SplitConcat)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
TEST(CCOpTest,CompositeOp)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
TEST(CCOpTest,MultiOutput)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
TEST(CCOpTest,ExampleTrainer)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
TEST(CCOpTest,ThrowAwayOp)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
TEST(CCOpTest,ControlDeps)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
TEST(CCOpTest,KernelLabel)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
TEST(CCOpTest,ColocateWith)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
TEST(CCOpTest,TemplatedConst)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
TEST(CCOpTest,EmptyConst)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
TEST(CCOpTest,InvalidFinalize)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