• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // A set of lightweight wrappers which simplify access to Feature protos.
17 //
18 // TensorFlow Example proto uses associative maps on top of oneof fields.
19 // SequenceExample proto uses associative map of FeatureList.
20 // So accessing feature values is not very convenient.
21 //
22 // For example, to read a first value of integer feature "tag":
23 //   int id = example.features().feature().at("tag").int64_list().value(0)
24 //
25 // to add a value:
26 //   auto features = example->mutable_features();
27 //   (*features->mutable_feature())["tag"].mutable_int64_list()->add_value(id)
28 //
29 // For float features you have to use float_list, for string - bytes_list.
30 //
31 // To do the same with this library:
32 //   int id = GetFeatureValues<int64>("tag", example).Get(0);
33 //   GetFeatureValues<int64>("tag", &example)->Add(id);
34 //
35 // Modification of bytes features is slightly different:
36 //   auto tag = GetFeatureValues<string>("tag", &example);
37 //   *tag->Add() = "lorem ipsum";
38 //
39 // To copy multiple values into a feature:
40 //   AppendFeatureValues({1,2,3}, "tag", &example);
41 //
42 // GetFeatureValues gives you access to underlying data - RepeatedField object
43 // (RepeatedPtrField for byte list). So refer to its documentation of
44 // RepeatedField for full list of supported methods.
45 //
46 // NOTE: Due to the nature of oneof proto fields setting a feature of one type
47 // automatically clears all values stored as another type with the same feature
48 // key.
49 //
50 // This library also has tools to work with SequenceExample protos.
51 //
52 // To get a value from SequenceExample.context:
53 //   int id = GetFeatureValues<protobuf_int64>("tag", se.context()).Get(0);
54 // To add a value to the context:
55 //   GetFeatureValues<protobuf_int64>("tag", se.mutable_context())->Add(42);
56 //
57 // To add values to feature_lists:
58 //   AppendFeatureValues({4.0},
59 //                       GetFeatureList("images", &se)->Add());
60 //   AppendFeatureValues({5.0, 3.0},
61 //                       GetFeatureList("images", &se)->Add());
62 // This will create a feature list keyed as "images" with two features:
63 //   feature_lists {
64 //     feature_list {
65 //       key: "images"
66 //       value {
67 //         feature { float_list { value: [4.0] } }
68 //         feature { float_list { value: [5.0, 3.0] } }
69 //       }
70 //     } }
71 //
72 // Functions exposed by this library:
73 //   HasFeature<[FeatureType]>(key, proto) -> bool
74 //     Returns true if a feature with the specified key, and optionally
75 //     FeatureType, belongs to the Features or Example proto.
76 //   HasFeatureList(key, sequence_example) -> bool
77 //     Returns true if SequenceExample has a feature_list with the key.
78 //   GetFeatureValues<FeatureType>(key, proto) -> RepeatedField<FeatureType>
79 //     Returns values for the specified key and the FeatureType.
80 //     Supported types for the proto: Example, Features.
81 //   GetFeatureList(key, sequence_example) -> RepeatedPtrField<Feature>
82 //     Returns Feature protos associated with a key.
83 //   AppendFeatureValues(begin, end, feature)
84 //   AppendFeatureValues(container or initializer_list, feature)
85 //     Copies values into a Feature.
86 //   AppendFeatureValues(begin, end, key, proto)
87 //   AppendFeatureValues(container or initializer_list, key, proto)
88 //     Copies values into Features and Example protos with the specified key.
89 //
90 // Auxiliary functions, it is unlikely you'll need to use them directly:
91 //   GetFeatures(proto) -> Features
92 //     A convenience function to get Features proto.
93 //     Supported types for the proto: Example, Features.
94 //   GetFeature(key, proto) -> Feature*
95 //     Returns a Feature proto for the specified key, creates a new if
96 //     necessary. Supported types for the proto: Example, Features.
97 //   GetFeatureValues<FeatureType>(feature) -> RepeatedField<FeatureType>
98 //     Returns values of the feature for the FeatureType.
99 
100 #ifndef TENSORFLOW_CORE_EXAMPLE_FEATURE_UTIL_H_
101 #define TENSORFLOW_CORE_EXAMPLE_FEATURE_UTIL_H_
102 
103 #include <iterator>
104 #include <type_traits>
105 
106 #include "absl/base/macros.h"
107 #include "tensorflow/core/example/example.pb.h"
108 #include "tensorflow/core/example/feature.pb.h"
109 #include "tensorflow/core/lib/core/stringpiece.h"
110 #include "tensorflow/core/platform/protobuf.h"
111 #include "tensorflow/core/platform/types.h"
112 
113 namespace tensorflow {
114 
115 namespace internal {
116 
117 // TODO(gorban): Update all clients in a followup CL.
118 // Returns a reference to a feature corresponding to the name.
119 // Note: it will create a new Feature if it is missing in the example.
120 ABSL_DEPRECATED("Use GetFeature instead.")
121 Feature& ExampleFeature(const string& name, Example* example);
122 
123 // Specializations of RepeatedFieldTrait define a type of RepeatedField
124 // corresponding to a selected feature type.
125 template <typename FeatureType>
126 struct RepeatedFieldTrait;
127 
128 template <>
129 struct RepeatedFieldTrait<protobuf_int64> {
130   using Type = protobuf::RepeatedField<protobuf_int64>;
131 };
132 
133 template <>
134 struct RepeatedFieldTrait<float> {
135   using Type = protobuf::RepeatedField<float>;
136 };
137 
138 template <>
139 struct RepeatedFieldTrait<string> {
140   using Type = protobuf::RepeatedPtrField<string>;
141 };
142 
143 // Specializations of FeatureTrait define a type of feature corresponding to a
144 // selected value type.
145 template <typename ValueType, class Enable = void>
146 struct FeatureTrait;
147 
148 template <typename ValueType>
149 struct FeatureTrait<ValueType, typename std::enable_if<
150                                    std::is_integral<ValueType>::value>::type> {
151   using Type = protobuf_int64;
152 };
153 
154 template <typename ValueType>
155 struct FeatureTrait<
156     ValueType,
157     typename std::enable_if<std::is_floating_point<ValueType>::value>::type> {
158   using Type = float;
159 };
160 
161 template <typename T>
162 struct is_string
163     : public std::integral_constant<
164           bool,
165           std::is_same<char*, typename std::decay<T>::type>::value ||
166               std::is_same<const char*, typename std::decay<T>::type>::value> {
167 };
168 
169 template <>
170 struct is_string<string> : std::true_type {};
171 
172 template <>
173 struct is_string<::tensorflow::StringPiece> : std::true_type {};
174 
175 template <typename ValueType>
176 struct FeatureTrait<
177     ValueType, typename std::enable_if<is_string<ValueType>::value>::type> {
178   using Type = string;
179 };
180 
181 }  //  namespace internal
182 
183 // Returns true if sequence_example has a feature_list with the specified key.
184 bool HasFeatureList(const string& key, const SequenceExample& sequence_example);
185 
186 template <typename T>
187 struct TypeHasFeatures : std::false_type {};
188 
189 template <>
190 struct TypeHasFeatures<Example> : std::true_type {};
191 
192 template <>
193 struct TypeHasFeatures<Features> : std::true_type {};
194 
195 // A family of template functions to return mutable Features proto from a
196 // container proto. Supported ProtoTypes: Example, Features.
197 template <typename ProtoType>
198 typename std::enable_if<TypeHasFeatures<ProtoType>::value, Features*>::type
199 GetFeatures(ProtoType* proto);
200 
201 template <typename ProtoType>
202 typename std::enable_if<TypeHasFeatures<ProtoType>::value,
203                         const Features&>::type
204 GetFeatures(const ProtoType& proto);
205 
206 // Base declaration of a family of template functions to return a read only
207 // repeated field of feature values.
208 template <typename FeatureType>
209 const typename internal::RepeatedFieldTrait<FeatureType>::Type&
210 GetFeatureValues(const Feature& feature);
211 
212 // Returns a read only repeated field corresponding to a feature with the
213 // specified name and FeatureType. Supported ProtoTypes: Example, Features.
214 template <typename FeatureType, typename ProtoType>
215 const typename internal::RepeatedFieldTrait<FeatureType>::Type&
216 GetFeatureValues(const string& key, const ProtoType& proto) {
217   return GetFeatureValues<FeatureType>(GetFeatures(proto).feature().at(key));
218 }
219 
220 // Returns a mutable repeated field of a feature values.
221 template <typename FeatureType>
222 typename internal::RepeatedFieldTrait<FeatureType>::Type* GetFeatureValues(
223     Feature* feature);
224 
225 // Returns a mutable repeated field corresponding to a feature with the
226 // specified name and FeatureType. Supported ProtoTypes: Example, Features.
227 template <typename FeatureType, typename ProtoType>
228 typename internal::RepeatedFieldTrait<FeatureType>::Type* GetFeatureValues(
229     const string& key, ProtoType* proto) {
230   ::tensorflow::Feature& feature =
231       (*GetFeatures(proto)->mutable_feature())[key];
232   return GetFeatureValues<FeatureType>(&feature);
233 }
234 
235 // Returns a Feature proto for the specified key, creates a new if necessary.
236 // Supported types for the proto: Example, Features.
237 template <typename ProtoType>
238 Feature* GetFeature(const string& key, ProtoType* proto) {
239   return &(*GetFeatures(proto)->mutable_feature())[key];
240 }
241 
242 // Returns a repeated field with features corresponding to a feature_list key.
243 const protobuf::RepeatedPtrField<Feature>& GetFeatureList(
244     const string& key, const SequenceExample& sequence_example);
245 
246 // Returns a mutable repeated field with features corresponding to a
247 // feature_list key. It will create a new FeatureList if necessary.
248 protobuf::RepeatedPtrField<Feature>* GetFeatureList(
249     const string& feature_list_key, SequenceExample* sequence_example);
250 
251 template <typename IteratorType>
252 void AppendFeatureValues(IteratorType first, IteratorType last,
253                          Feature* feature) {
254   using FeatureType = typename internal::FeatureTrait<
255       typename std::iterator_traits<IteratorType>::value_type>::Type;
256   std::copy(first, last,
257             protobuf::RepeatedFieldBackInserter(
258                 GetFeatureValues<FeatureType>(feature)));
259 }
260 
261 template <typename ValueType>
262 void AppendFeatureValues(std::initializer_list<ValueType> container,
263                          Feature* feature) {
264   AppendFeatureValues(container.begin(), container.end(), feature);
265 }
266 
267 template <typename ContainerType>
268 void AppendFeatureValues(const ContainerType& container, Feature* feature) {
269   using IteratorType = typename ContainerType::const_iterator;
270   AppendFeatureValues<IteratorType>(container.begin(), container.end(),
271                                     feature);
272 }
273 
274 // Copies elements from the range, defined by [first, last) into the feature
275 // obtainable from the (proto, key) combination.
276 template <typename IteratorType, typename ProtoType>
277 void AppendFeatureValues(IteratorType first, IteratorType last,
278                          const string& key, ProtoType* proto) {
279   AppendFeatureValues(first, last, GetFeature(key, GetFeatures(proto)));
280 }
281 
282 // Copies all elements from the container into a feature.
283 template <typename ContainerType, typename ProtoType>
284 void AppendFeatureValues(const ContainerType& container, const string& key,
285                          ProtoType* proto) {
286   using IteratorType = typename ContainerType::const_iterator;
287   AppendFeatureValues<IteratorType>(container.begin(), container.end(), key,
288                                     proto);
289 }
290 
291 // Copies all elements from the initializer list into a Feature contained by
292 // Features or Example proto.
293 template <typename ValueType, typename ProtoType>
294 void AppendFeatureValues(std::initializer_list<ValueType> container,
295                          const string& key, ProtoType* proto) {
296   using IteratorType =
297       typename std::initializer_list<ValueType>::const_iterator;
298   AppendFeatureValues<IteratorType>(container.begin(), container.end(), key,
299                                     proto);
300 }
301 
302 // Returns true if a feature with the specified key belongs to the Features.
303 // The template parameter pack accepts zero or one template argument - which
304 // is FeatureType. If the FeatureType not specified (zero template arguments)
305 // the function will not check the feature type. Otherwise it will return false
306 // if the feature has a wrong type.
307 template <typename... FeatureType>
308 bool HasFeature(const string& key, const Features& features);
309 
310 // Returns true if a feature with the specified key belongs to the Example.
311 // Doesn't check feature type if used without FeatureType, otherwise the
312 // specialized versions return false if the feature has a wrong type.
313 template <typename... FeatureType>
314 bool HasFeature(const string& key, const Example& example) {
315   return HasFeature<FeatureType...>(key, GetFeatures(example));
316 }
317 
318 // TODO(gorban): update all clients in a followup CL.
319 template <typename... FeatureType>
320 ABSL_DEPRECATED("Use HasFeature instead.")
321 bool ExampleHasFeature(const string& key, const Example& example) {
322   return HasFeature<FeatureType...>(key, example);
323 }
324 
325 }  // namespace tensorflow
326 #endif  // TENSORFLOW_CORE_EXAMPLE_FEATURE_UTIL_H_
327