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