Home | History | Annotate | Download | only in kernels
      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 #include "tensorflow/core/kernels/immutable_constant_op.h"
     16 
     17 #include <algorithm>
     18 #include <tuple>
     19 
     20 #include "tensorflow/cc/ops/standard_ops.h"
     21 #include "tensorflow/core/framework/allocator.h"
     22 #include "tensorflow/core/framework/tensor.h"
     23 #include "tensorflow/core/graph/graph_def_builder.h"
     24 #include "tensorflow/core/lib/core/status_test_util.h"
     25 #include "tensorflow/core/lib/io/path.h"
     26 #include "tensorflow/core/platform/test.h"
     27 #include "tensorflow/core/platform/test_benchmark.h"
     28 #include "tensorflow/core/public/session.h"
     29 
     30 namespace tensorflow {
     31 namespace {
     32 // A safe alignment that equal to memmapped page alignment on many modern
     33 // architectures.
     34 constexpr size_t kTestAlignment = 4096;
     35 constexpr size_t kTestTensorSize = 4;
     36 constexpr size_t kTestTensorSizeBytes = kTestTensorSize * sizeof(float);
     37 
     38 // A test ReadOnlyMemoryRegion implementation.
     39 class TestReadOnlyMemoryRegion : public ReadOnlyMemoryRegion {
     40  public:
     41   TestReadOnlyMemoryRegion() = delete;
     42   explicit TestReadOnlyMemoryRegion(uint64 length)
     43       : memptr_(cpu_allocator()->AllocateRaw(kTestAlignment, length)),
     44         length_(length) {}
     45   ~TestReadOnlyMemoryRegion() override {
     46     cpu_allocator()->DeallocateRaw(memptr_);
     47   }
     48   const void* data() override { return memptr_; }
     49   float* GetWritableDataStart() { return reinterpret_cast<float*>(memptr_); }
     50   uint64 length() override { return length_; }
     51 
     52  protected:
     53   void* memptr_;
     54   uint64 length_;
     55 };
     56 
     57 // A mock file system and environment class that creates ReadOnlyMemoryRegion
     58 // from allocated memory.
     59 class TestFileSystem : public NullFileSystem {
     60  public:
     61   ~TestFileSystem() override = default;
     62   Status NewReadOnlyMemoryRegionFromFile(
     63       const string& fname,
     64       std::unique_ptr<ReadOnlyMemoryRegion>* result) override {
     65     float val = 0;
     66     StringPiece scheme, host, path;
     67     io::ParseURI(fname, &scheme, &host, &path);
     68     // For the tests create in-memory regions with float values equal to the
     69     // region name.
     70     if (path == "/2") {
     71       val = 2.0f;
     72     } else if (path == "/3") {
     73       val = 3.0f;
     74     } else {
     75       val = 0.0f;
     76     }
     77 
     78     auto region = new TestReadOnlyMemoryRegion(kTestTensorSizeBytes);
     79     std::fill_n(region->GetWritableDataStart(), kTestTensorSize, val);
     80     result->reset(region);
     81     return Status::OK();
     82   }
     83 };
     84 
     85 REGISTER_FILE_SYSTEM("test", TestFileSystem);
     86 
     87 struct ImmutableConstantOpTest {};
     88 
     89 TEST(ImmutableConstantOpTest, Simple) {
     90   const TensorShape kTestTensorShape({4, 1});
     91   const TensorShape kTestTensorShapeT({1, 4});
     92   auto root = Scope::NewRootScope().ExitOnError();
     93   auto node1 =
     94       ops::ImmutableConst(root, DT_FLOAT, kTestTensorShape, "test:///2");
     95   auto node2 =
     96       ops::ImmutableConst(root, DT_FLOAT, kTestTensorShapeT, "test:///3");
     97   auto result = ops::MatMul(root, node1, node2);
     98   GraphDef graph_def;
     99   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
    100   SessionOptions session_options;
    101   session_options.env = Env::Default();
    102   session_options.config.mutable_graph_options()
    103       ->mutable_optimizer_options()
    104       ->set_opt_level(OptimizerOptions_Level_L0);
    105   std::unique_ptr<Session> session(NewSession(session_options));
    106   ASSERT_TRUE(session != nullptr) << "Failed to create session";
    107   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
    108   std::vector<Tensor> outputs;
    109   TF_ASSERT_OK(session->Run({}, {result.node()->name() + ":0"}, {}, &outputs));
    110   ASSERT_EQ(outputs.size(), 1);
    111   EXPECT_EQ(outputs.front().flat<float>()(0), 2.0f * 3.0f);
    112   EXPECT_EQ(outputs.front().flat<float>()(1), 2.0f * 3.0f);
    113   EXPECT_EQ(outputs.front().flat<float>()(2), 2.0f * 3.0f);
    114   EXPECT_EQ(outputs.front().flat<float>()(kTestTensorSize - 1), 2.0f * 3.0f);
    115 }
    116 
    117 // Creates a test graph with two immutable_const tensors and a simple math
    118 // operation, one of nodes has wrong size, check that error properly reported.
    119 
    120 TEST(ImmutableConstantOpTest, ExecutionError) {
    121   const TensorShape kBadTensorShape({40, 100});
    122   const TensorShape kTestTensorShapeT({1, 4});
    123 
    124   auto root = Scope::DisabledShapeInferenceScope().ExitOnError();
    125   auto node1 =
    126       ops::ImmutableConst(root, DT_FLOAT, kBadTensorShape, "test:///2");
    127   auto node2 =
    128       ops::ImmutableConst(root, DT_FLOAT, kTestTensorShapeT, "test:///3");
    129   auto result = ops::MatMul(root, node1, node2);
    130   GraphDef graph_def;
    131   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
    132   SessionOptions session_options;
    133   session_options.env = Env::Default();
    134   std::unique_ptr<Session> session(NewSession(session_options));
    135   ASSERT_TRUE(session != nullptr) << "Failed to create session";
    136   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
    137   std::vector<Tensor> outputs;
    138   // Check that the run returned error.
    139   EXPECT_EQ(
    140       session->Run({}, {result.node()->name() + ":0"}, {}, &outputs).code(),
    141       error::INTERNAL);
    142 }
    143 
    144 Status CreateTempFile(Env* env, float value, uint64 size, string* filename) {
    145   const string dir = testing::TmpDir();
    146   *filename = io::JoinPath(dir, strings::StrCat("file_", value));
    147   std::unique_ptr<WritableFile> file;
    148   TF_RETURN_IF_ERROR(env->NewWritableFile(*filename, &file));
    149   for (uint64 i = 0; i < size; ++i) {
    150     StringPiece sp(static_cast<char*>(static_cast<void*>(&value)),
    151                    sizeof(value));
    152     TF_RETURN_IF_ERROR(file->Append(sp));
    153   }
    154   TF_RETURN_IF_ERROR(file->Close());
    155   return Status::OK();
    156 }
    157 
    158 TEST(ImmutableConstantOpTest, FromFile) {
    159   const TensorShape kFileTensorShape({1000, 1});
    160   Env* env = Env::Default();
    161   auto root = Scope::NewRootScope().ExitOnError();
    162 
    163   string two_file, three_file;
    164   TF_ASSERT_OK(CreateTempFile(env, 2.0f, 1000, &two_file));
    165   TF_ASSERT_OK(CreateTempFile(env, 3.0f, 1000, &three_file));
    166   auto node1 = ops::ImmutableConst(root, DT_FLOAT, kFileTensorShape, two_file);
    167   auto node2 =
    168       ops::ImmutableConst(root, DT_FLOAT, kFileTensorShape, three_file);
    169   auto result = ops::MatMul(root, node1, node2, ops::MatMul::TransposeB(true));
    170 
    171   GraphDef graph_def;
    172   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
    173   SessionOptions session_options;
    174   session_options.config.mutable_graph_options()
    175       ->mutable_optimizer_options()
    176       ->set_opt_level(OptimizerOptions_Level_L0);
    177   std::unique_ptr<Session> session(NewSession(session_options));
    178   ASSERT_TRUE(session != nullptr) << "Failed to create session";
    179   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
    180   std::vector<Tensor> outputs;
    181   TF_ASSERT_OK(session->Run({}, {result.node()->name() + ":0"}, {}, &outputs));
    182   ASSERT_EQ(outputs.size(), 1);
    183   EXPECT_EQ(outputs.front().flat<float>()(0), 2.0f * 3.0f);
    184   EXPECT_EQ(outputs.front().flat<float>()(1), 2.0f * 3.0f);
    185   EXPECT_EQ(outputs.front().flat<float>()(2), 2.0f * 3.0f);
    186 }
    187 
    188 }  // namespace
    189 }  // namespace tensorflow
    190