1 /* Copyright 2020 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/c/experimental/saved_model/core/ops/restore_ops.h"
17 
18 #include "tensorflow/c/eager/abstract_tensor_handle.h"
19 #include "tensorflow/c/eager/immediate_execution_context.h"
20 #include "tensorflow/c/eager/immediate_execution_operation.h"
21 #include "tensorflow/c/eager/immediate_execution_tensor_handle.h"
22 #include "tensorflow/c/tensor_interface.h"
23 #include "tensorflow/core/framework/tensor.h"
24 #include "tensorflow/core/framework/types.pb.h"
25 #include "tensorflow/core/lib/llvm_rtti/llvm_rtti.h"
26 #include "tensorflow/core/platform/errors.h"
27 #include "tensorflow/core/platform/types.h"
28 
29 namespace tensorflow {
30 namespace internal {
31 
32 namespace {
33 
34 // Creates a scalar string tensorhandle containing a single string `s`
CreateStringScalarTensorHandle(ImmediateExecutionContext * ctx,const std::string & s,ImmediateTensorHandlePtr * out)35 Status CreateStringScalarTensorHandle(ImmediateExecutionContext* ctx,
36                                       const std::string& s,
37                                       ImmediateTensorHandlePtr* out) {
38   AbstractTensorPtr tensor(ctx->CreateStringScalar(s));
39   if (tensor.get() == nullptr) {
40     return errors::Internal(
41         "Failed to create scalar string tensor for checkpoint restore");
42   }
43 
44   out->reset(ctx->CreateLocalHandle(tensor.get()));
45   return Status();
46 }
47 
48 // Creates a Rank 1 string tensorhandle containing a single string `s`
CreateStringVectorTensorHandle(ImmediateExecutionContext * ctx,const std::string & s,ImmediateTensorHandlePtr * out)49 Status CreateStringVectorTensorHandle(ImmediateExecutionContext* ctx,
50                                       const std::string& s,
51                                       ImmediateTensorHandlePtr* out) {
52   int64 flat_shape[] = {1};
53   AbstractTensorPtr tensor(ctx->CreateTensor(DT_STRING, flat_shape));
54   if (tensor.get() == nullptr) {
55     return errors::Internal(
56         "Failed to create vector string tensor for checkpoint restore");
57   }
58   // Use placement new to construct the string, since we don't have
59   // access to Tensor::flat. This is conceptually equivalent to:
60   // tensor.flat<tstring>()(0) = s
61   new (tensor->Data()) tstring(s);
62 
63   out->reset(ctx->CreateLocalHandle(tensor.get()));
64   return Status();
65 }
66 
67 }  // namespace
68 
SingleRestore(ImmediateExecutionContext * ctx,const std::string & prefix,const std::string & checkpoint_key,DataType dtype,ImmediateTensorHandlePtr * out)69 Status SingleRestore(ImmediateExecutionContext* ctx, const std::string& prefix,
70                      const std::string& checkpoint_key, DataType dtype,
71                      ImmediateTensorHandlePtr* out) {
72   // Create the EagerOp
73   ImmediateOpPtr restore_op(ctx->CreateOperation());
74   TF_RETURN_IF_ERROR(restore_op->Reset("RestoreV2", "/cpu:0"));
75   TF_RETURN_IF_ERROR(restore_op->SetAttrTypeList("dtypes", &dtype, 1));
76 
77   ImmediateTensorHandlePtr prefix_handle;
78   TF_RETURN_IF_ERROR(
79       CreateStringScalarTensorHandle(ctx, prefix, &prefix_handle));
80 
81   ImmediateTensorHandlePtr names_handle;
82   TF_RETURN_IF_ERROR(
83       CreateStringVectorTensorHandle(ctx, checkpoint_key, &names_handle));
84 
85   // Note that empty string is the slice spec used for a non-partitioned
86   // ResourceVariable:
87   // https://github.com/tensorflow/tensorflow/blob/06ff30f7ea35098cb68a231a9eb7ff3ff4be4e1e/tensorflow/python/training/saving/saveable_object_util.py#L194
88   ImmediateTensorHandlePtr shapes_and_slices_handle;
89   TF_RETURN_IF_ERROR(
90       CreateStringVectorTensorHandle(ctx, "", &shapes_and_slices_handle));
91 
92   TF_RETURN_IF_ERROR(restore_op->AddInput(prefix_handle.get()));
93   TF_RETURN_IF_ERROR(restore_op->AddInput(names_handle.get()));
94   TF_RETURN_IF_ERROR(restore_op->AddInput(shapes_and_slices_handle.get()));
95 
96   AbstractTensorHandle* restored_handle = nullptr;
97   int num_retvals = 1;
98   TF_RETURN_IF_ERROR(restore_op->Execute(
99       absl::MakeSpan(&restored_handle, num_retvals), &num_retvals));
100   AbstractTensorHandlePtr owned_restored_handle(restored_handle);
101   if (!tensorflow::isa<ImmediateExecutionTensorHandle>(
102           owned_restored_handle.get())) {
103     return errors::Internal("Unexpected tensor handle kind.");
104   }
105   out->reset(reinterpret_cast<ImmediateExecutionTensorHandle*>(
106       owned_restored_handle.release()));
107   return Status();
108 }
109 
110 }  // namespace internal
111 }  // namespace tensorflow
112