• 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 //
73 // Functions exposed by this library:
74 //   HasFeature<[FeatureType]>(key, proto) -> bool
75 //     Returns true if a feature with the specified key, and optionally
76 //     FeatureType, belongs to the Features or Example proto.
77 //   HasFeatureList(key, sequence_example) -> bool
78 //     Returns true if SequenceExample has a feature_list with the key.
79 //
80 //   GetFeatureValues<FeatureType>(key, proto) -> RepeatedField<FeatureType>
81 //     Returns values for the specified key and the FeatureType.
82 //     Supported types for the proto: Example, Features.
83 //   GetFeatureList(key, sequence_example) -> RepeatedPtrField<Feature>
84 //     Returns Feature protos associated with a key.
85 //
86 //   AppendFeatureValues(begin, end, feature)
87 //   AppendFeatureValues(container or initializer_list, feature)
88 //     Copies values into a Feature.
89 //   AppendFeatureValues(begin, end, key, proto)
90 //   AppendFeatureValues(container or initializer_list, key, proto)
91 //     Copies values into Features and Example protos with the specified key.
92 //
93 //   ClearFeatureValues<FeatureType>(feature)
94 //     Clears the feature's repeated field of the given type.
95 //
96 //   SetFeatureValues(begin, end, feature)
97 //   SetFeatureValues(container or initializer_list, feature)
98 //     Clears a Feature, then copies values into it.
99 //   SetFeatureValues(begin, end, key, proto)
100 //   SetFeatureValues(container or initializer_list, key, proto)
101 //     Clears Features or Example protos with the specified key,
102 //     then copies values into them.
103 //
104 // Auxiliary functions, it is unlikely you'll need to use them directly:
105 //   GetFeatures(proto) -> Features
106 //     A convenience function to get Features proto.
107 //     Supported types for the proto: Example, Features.
108 //   GetFeature(key, proto) -> Feature
109 //     Returns a Feature proto for the specified key.
110 //     Supported types for the proto: Example, Features.
111 //   GetFeatureValues<FeatureType>(feature) -> RepeatedField<FeatureType>
112 //     Returns values of the feature for the FeatureType.
113 
114 #ifndef TENSORFLOW_CORE_EXAMPLE_FEATURE_UTIL_H_
115 #define TENSORFLOW_CORE_EXAMPLE_FEATURE_UTIL_H_
116 
117 #include <iterator>
118 #include <type_traits>
119 
120 #include "absl/base/macros.h"
121 #include "tensorflow/core/example/example.pb.h"
122 #include "tensorflow/core/example/feature.pb.h"
123 #include "tensorflow/core/platform/protobuf.h"
124 #include "tensorflow/core/platform/stringpiece.h"
125 #include "tensorflow/core/platform/types.h"
126 
127 namespace tensorflow {
128 
129 namespace internal {
130 
131 // TODO(gorban): Update all clients in a followup CL.
132 // Returns a reference to a feature corresponding to the name.
133 // Note: it will create a new Feature if it is missing in the example.
134 ABSL_DEPRECATED("Use GetFeature instead.")
135 Feature& ExampleFeature(const string& name, Example* example);
136 
137 // Specializations of RepeatedFieldTrait define a type of RepeatedField
138 // corresponding to a selected feature type.
139 template <typename FeatureType>
140 struct RepeatedFieldTrait;
141 
142 template <>
143 struct RepeatedFieldTrait<protobuf_int64> {
144   using Type = protobuf::RepeatedField<protobuf_int64>;
145 };
146 
147 template <>
148 struct RepeatedFieldTrait<float> {
149   using Type = protobuf::RepeatedField<float>;
150 };
151 
152 template <>
153 struct RepeatedFieldTrait<tstring> {
154   using Type = protobuf::RepeatedPtrField<string>;
155 };
156 
157 template <>
158 struct RepeatedFieldTrait<string> {
159   using Type = protobuf::RepeatedPtrField<string>;
160 };
161 
162 // Specializations of FeatureTrait define a type of feature corresponding to a
163 // selected value type.
164 template <typename ValueType, class Enable = void>
165 struct FeatureTrait;
166 
167 template <typename ValueType>
168 struct FeatureTrait<ValueType, typename std::enable_if<
169                                    std::is_integral<ValueType>::value>::type> {
170   using Type = protobuf_int64;
171 };
172 
173 template <typename ValueType>
174 struct FeatureTrait<
175     ValueType,
176     typename std::enable_if<std::is_floating_point<ValueType>::value>::type> {
177   using Type = float;
178 };
179 
180 template <typename T>
181 struct is_string
182     : public std::integral_constant<
183           bool,
184           std::is_same<char*, typename std::decay<T>::type>::value ||
185               std::is_same<const char*, typename std::decay<T>::type>::value> {
186 };
187 
188 template <>
189 struct is_string<string> : std::true_type {};
190 
191 template <>
192 struct is_string<::tensorflow::StringPiece> : std::true_type {};
193 
194 template <>
195 struct is_string<tstring> : std::true_type {};
196 
197 template <typename ValueType>
198 struct FeatureTrait<
199     ValueType, typename std::enable_if<is_string<ValueType>::value>::type> {
200   using Type = string;
201 };
202 
203 }  //  namespace internal
204 
205 // Returns true if sequence_example has a feature_list with the specified key.
206 bool HasFeatureList(const string& key, const SequenceExample& sequence_example);
207 
208 template <typename T>
209 struct TypeHasFeatures : std::false_type {};
210 
211 template <>
212 struct TypeHasFeatures<Example> : std::true_type {};
213 
214 template <>
215 struct TypeHasFeatures<Features> : std::true_type {};
216 
217 // A family of template functions to return mutable Features proto from a
218 // container proto. Supported ProtoTypes: Example, Features.
219 template <typename ProtoType>
220 typename std::enable_if<TypeHasFeatures<ProtoType>::value, Features*>::type
221 GetFeatures(ProtoType* proto);
222 
223 template <typename ProtoType>
224 typename std::enable_if<TypeHasFeatures<ProtoType>::value,
225                         const Features&>::type
226 GetFeatures(const ProtoType& proto);
227 
228 // Base declaration of a family of template functions to return a read only
229 // repeated field of feature values.
230 template <typename FeatureType>
231 const typename internal::RepeatedFieldTrait<FeatureType>::Type&
232 GetFeatureValues(const Feature& feature);
233 
234 // Returns a read only repeated field corresponding to a feature with the
235 // specified name and FeatureType. Supported ProtoTypes: Example, Features.
236 template <typename FeatureType, typename ProtoType>
237 const typename internal::RepeatedFieldTrait<FeatureType>::Type&
238 GetFeatureValues(const string& key, const ProtoType& proto) {
239   return GetFeatureValues<FeatureType>(GetFeatures(proto).feature().at(key));
240 }
241 
242 // Returns a mutable repeated field of a feature values.
243 template <typename FeatureType>
244 typename internal::RepeatedFieldTrait<FeatureType>::Type* GetFeatureValues(
245     Feature* feature);
246 
247 // Returns a mutable repeated field corresponding to a feature with the
248 // specified name and FeatureType. Supported ProtoTypes: Example, Features.
249 template <typename FeatureType, typename ProtoType>
250 typename internal::RepeatedFieldTrait<FeatureType>::Type* GetFeatureValues(
251     const string& key, ProtoType* proto) {
252   ::tensorflow::Feature& feature =
253       (*GetFeatures(proto)->mutable_feature())[key];
254   return GetFeatureValues<FeatureType>(&feature);
255 }
256 
257 // Returns a read-only Feature proto for the specified key, throws
258 // std::out_of_range if the key is not found. Supported types for the proto:
259 // Example, Features.
260 template <typename ProtoType>
261 const Feature& GetFeature(const string& key, const ProtoType& proto) {
262   return GetFeatures(proto).feature().at(key);
263 }
264 
265 // Returns a mutable Feature proto for the specified key, creates a new if
266 // necessary. Supported types for the proto: Example, Features.
267 template <typename ProtoType>
268 Feature* GetFeature(const string& key, ProtoType* proto) {
269   return &(*GetFeatures(proto)->mutable_feature())[key];
270 }
271 
272 // Returns a repeated field with features corresponding to a feature_list key.
273 const protobuf::RepeatedPtrField<Feature>& GetFeatureList(
274     const string& key, const SequenceExample& sequence_example);
275 
276 // Returns a mutable repeated field with features corresponding to a
277 // feature_list key. It will create a new FeatureList if necessary.
278 protobuf::RepeatedPtrField<Feature>* GetFeatureList(
279     const string& feature_list_key, SequenceExample* sequence_example);
280 
281 template <typename IteratorType>
282 void AppendFeatureValues(IteratorType first, IteratorType last,
283                          Feature* feature) {
284   using FeatureType = typename internal::FeatureTrait<
285       typename std::iterator_traits<IteratorType>::value_type>::Type;
286   std::copy(first, last,
287             protobuf::RepeatedFieldBackInserter(
288                 GetFeatureValues<FeatureType>(feature)));
289 }
290 
291 template <typename ValueType>
292 void AppendFeatureValues(std::initializer_list<ValueType> container,
293                          Feature* feature) {
294   AppendFeatureValues(container.begin(), container.end(), feature);
295 }
296 
297 template <typename ContainerType>
298 void AppendFeatureValues(const ContainerType& container, Feature* feature) {
299   using IteratorType = typename ContainerType::const_iterator;
300   AppendFeatureValues<IteratorType>(container.begin(), container.end(),
301                                     feature);
302 }
303 
304 // Copies elements from the range, defined by [first, last) into the feature
305 // obtainable from the (proto, key) combination.
306 template <typename IteratorType, typename ProtoType>
307 void AppendFeatureValues(IteratorType first, IteratorType last,
308                          const string& key, ProtoType* proto) {
309   AppendFeatureValues(first, last, GetFeature(key, GetFeatures(proto)));
310 }
311 
312 // Copies all elements from the container into a feature.
313 template <typename ContainerType, typename ProtoType>
314 void AppendFeatureValues(const ContainerType& container, const string& key,
315                          ProtoType* proto) {
316   using IteratorType = typename ContainerType::const_iterator;
317   AppendFeatureValues<IteratorType>(container.begin(), container.end(), key,
318                                     proto);
319 }
320 
321 // Copies all elements from the initializer list into a Feature contained by
322 // Features or Example proto.
323 template <typename ValueType, typename ProtoType>
324 void AppendFeatureValues(std::initializer_list<ValueType> container,
325                          const string& key, ProtoType* proto) {
326   using IteratorType =
327       typename std::initializer_list<ValueType>::const_iterator;
328   AppendFeatureValues<IteratorType>(container.begin(), container.end(), key,
329                                     proto);
330 }
331 
332 // Clears the feature's repeated field (int64, float, or string).
333 template <typename... FeatureType>
334 void ClearFeatureValues(Feature* feature);
335 
336 // Clears the feature's repeated field (int64, float, or string). Copies
337 // elements from the range, defined by [first, last) into the feature's repeated
338 // field.
339 template <typename IteratorType>
340 void SetFeatureValues(IteratorType first, IteratorType last, Feature* feature) {
341   using FeatureType = typename internal::FeatureTrait<
342       typename std::iterator_traits<IteratorType>::value_type>::Type;
343   ClearFeatureValues<FeatureType>(feature);
344   AppendFeatureValues(first, last, feature);
345 }
346 
347 // Clears the feature's repeated field (int64, float, or string). Copies all
348 // elements from the initializer list into the feature's repeated field.
349 template <typename ValueType>
350 void SetFeatureValues(std::initializer_list<ValueType> container,
351                       Feature* feature) {
352   SetFeatureValues(container.begin(), container.end(), feature);
353 }
354 
355 // Clears the feature's repeated field (int64, float, or string). Copies all
356 // elements from the container into the feature's repeated field.
357 template <typename ContainerType>
358 void SetFeatureValues(const ContainerType& container, Feature* feature) {
359   using IteratorType = typename ContainerType::const_iterator;
360   SetFeatureValues<IteratorType>(container.begin(), container.end(), feature);
361 }
362 
363 // Clears the feature's repeated field (int64, float, or string). Copies
364 // elements from the range, defined by [first, last) into the feature's repeated
365 // field.
366 template <typename IteratorType, typename ProtoType>
367 void SetFeatureValues(IteratorType first, IteratorType last, const string& key,
368                       ProtoType* proto) {
369   SetFeatureValues(first, last, GetFeature(key, GetFeatures(proto)));
370 }
371 
372 // Clears the feature's repeated field (int64, float, or string). Copies all
373 // elements from the container into the feature's repeated field.
374 template <typename ContainerType, typename ProtoType>
375 void SetFeatureValues(const ContainerType& container, const string& key,
376                       ProtoType* proto) {
377   using IteratorType = typename ContainerType::const_iterator;
378   SetFeatureValues<IteratorType>(container.begin(), container.end(), key,
379                                  proto);
380 }
381 
382 // Clears the feature's repeated field (int64, float, or string). Copies all
383 // elements from the initializer list into the feature's repeated field.
384 template <typename ValueType, typename ProtoType>
385 void SetFeatureValues(std::initializer_list<ValueType> container,
386                       const string& key, ProtoType* proto) {
387   using IteratorType =
388       typename std::initializer_list<ValueType>::const_iterator;
389   SetFeatureValues<IteratorType>(container.begin(), container.end(), key,
390                                  proto);
391 }
392 
393 // Returns true if a feature with the specified key belongs to the Features.
394 // The template parameter pack accepts zero or one template argument - which
395 // is FeatureType. If the FeatureType not specified (zero template arguments)
396 // the function will not check the feature type. Otherwise it will return false
397 // if the feature has a wrong type.
398 template <typename... FeatureType>
399 bool HasFeature(const string& key, const Features& features);
400 
401 // Returns true if a feature with the specified key belongs to the Example.
402 // Doesn't check feature type if used without FeatureType, otherwise the
403 // specialized versions return false if the feature has a wrong type.
404 template <typename... FeatureType>
405 bool HasFeature(const string& key, const Example& example) {
406   return HasFeature<FeatureType...>(key, GetFeatures(example));
407 }
408 
409 // TODO(gorban): update all clients in a followup CL.
410 template <typename... FeatureType>
411 ABSL_DEPRECATED("Use HasFeature instead.")
412 bool ExampleHasFeature(const string& key, const Example& example) {
413   return HasFeature<FeatureType...>(key, example);
414 }
415 
416 }  // namespace tensorflow
417 #endif  // TENSORFLOW_CORE_EXAMPLE_FEATURE_UTIL_H_
418