सहायता Kaggle पर TensorFlow साथ ग्रेट बैरियर रीफ की रक्षा चैलेंज में शामिल हों

एक्सटेंशन प्रकार

TensorFlow.org पर देखें GitHub पर स्रोत देखेंनोटबुक डाउनलोड करें

सेट अप

!pip install -q tf_nightly
import tensorflow as tf
import numpy as np
from typing import Tuple, List, Mapping, Union, Optional
import tempfile

एक्सटेंशन प्रकार

उपयोगकर्ता-परिभाषित प्रकार परियोजनाओं को अधिक पठनीय, मॉड्यूलर, रखरखाव योग्य बना सकते हैं। हालाँकि, अधिकांश TensorFlow API के पास उपयोगकर्ता-परिभाषित पायथन प्रकारों के लिए बहुत सीमित समर्थन है। यह (जैसे दोनों उच्च स्तरीय एपीआई शामिल Keras , tf.function , tf.SavedModel और (जैसे निचले स्तर एपीआई) tf.while_loop और tf.concat )। TensorFlow एक्सटेंशन प्रकारों उपयोगकर्ता परिभाषित वस्तु उन्मुख प्रकार है कि मूल TensorFlow के API काम बनाने के लिए इस्तेमाल किया जा सकता है। एक विस्तार प्रकार बनाने के लिए, बस के साथ एक अजगर वर्ग को परिभाषित tf.experimental.ExtensionType अपने आधार के रूप में, और प्रयोग प्रकार एनोटेशन प्रत्येक क्षेत्र के लिए प्रकार निर्दिष्ट करने।

class TensorGraph(tf.experimental.ExtensionType):
  """A collection of labeled nodes connected by weighted edges."""
  edge_weights: tf.Tensor               # shape=[num_nodes, num_nodes]
  node_labels: Mapping[str, tf.Tensor]  # shape=[num_nodes]; dtype=any

class MaskedTensor(tf.experimental.ExtensionType):
  """A tensor paired with a boolean mask, indicating which values are valid."""
  values: tf.Tensor
  mask: tf.Tensor       # shape=values.shape; false for missing/invalid values.

class CSRSparseMatrix(tf.experimental.ExtensionType):
  """Compressed sparse row matrix (https://en.wikipedia.org/wiki/Sparse_matrix)."""
  values: tf.Tensor     # shape=[num_nonzero]; dtype=any
  col_index: tf.Tensor  # shape=[num_nonzero]; dtype=int64
  row_index: tf.Tensor  # shape=[num_rows+1]; dtype=int64

tf.experimental.ExtensionType आधार वर्ग की तरह ही काम करता है typing.NamedTuple और @dataclasses.dataclass मानक अजगर पुस्तकालय से। विशेष रूप से, यह स्वचालित रूप से एक निर्माता और (जैसे विशेष तरीकों कहते हैं __repr__ और __eq__ ) फ़ील्ड प्रकार एनोटेशन पर आधारित है।

आमतौर पर, एक्सटेंशन प्रकार दो श्रेणियों में से एक में आते हैं:

  • डाटा संरचनाओं, जो समूह को एक साथ संबंधित मूल्यों का एक संग्रह है, और उन मूल्यों पर आधारित उपयोगी आपरेशन प्रदान कर सकते हैं। डाटा संरचनाओं (जैसे काफी सामान्य हो सकता है TensorGraph ऊपर के उदाहरण); या उन्हें एक विशिष्ट मॉडल के लिए अत्यधिक अनुकूलित किया जा सकता है।

  • प्रकार, जो विशेषज्ञ या की अवधारणा का विस्तार टेन्सर की तरह "टेन्सर।" इस श्रेणी में प्रकार एक है rank , एक shape , और आमतौर पर एक dtype ; और यह उन्हें टेन्सर आपरेशन (जैसे के साथ उपयोग करने के लिए समझ में आता है tf.stack , tf.add , या tf.matmul )। MaskedTensor और CSRSparseMatrix टेन्सर की तरह प्रकार के उदाहरण हैं।

समर्थित एपीआई

एक्सटेंशन प्रकार निम्नलिखित TensorFlow API द्वारा समर्थित हैं:

  • Keras: एक्सटेंशन प्रकार इनपुट और Keras के लिए आउटपुट के रूप में इस्तेमाल किया जा सकता Models और Layers
  • tf.data.Dataset: एक्सटेंशन प्रकार में शामिल किया जा सकता Datasets , और डाटासेट द्वारा दिया Iterators
  • Tensorflow हब: एक्सटेंशन प्रकार इनपुट और आउटपुट के लिए के रूप में इस्तेमाल किया जा सकता tf.hub मॉड्यूल।
  • SavedModel: एक्सटेंशन प्रकार इनपुट और आउटपुट के लिए के रूप में इस्तेमाल किया जा सकता SavedModel कार्य करता है।
  • tf.function: एक्सटेंशन प्रकार तर्कों और साथ लिपटे कार्यों के लिए वापसी मान के रूप में इस्तेमाल किया जा सकता @tf.function डेकोरेटर।
  • while लूप: एक्सटेंशन प्रकार में पाश चर के रूप में इस्तेमाल किया जा सकता tf.while_loop , और तर्क और जब लूप के शरीर के लिए बदले मूल्यों के रूप में इस्तेमाल किया जा सकता।
  • सशर्त: एक्सटेंशन प्रकार सशर्त का उपयोग कर चुना जा सकता है tf.cond और tf.case
  • py_function: एक्सटेंशन प्रकार तर्कों और के लिए बदले मूल्यों के रूप में इस्तेमाल किया जा सकता func के लिए तर्क tf.py_function
  • टेन्सर ऑप्स: एक्सटेंशन प्रकार सबसे अधिक TensorFlow ऑप्स कि टेन्सर आदानों (जैसे, स्वीकार समर्थन करने के लिए बढ़ाया जा सकता है tf.matmul , tf.gather , और tf.reduce_sum )। अधिक जानकारी के लिए नीचे दिए गए "डिस्पैच" अनुभाग देखें।
  • वितरण रणनीति: एक्सटेंशन प्रकार प्रति-प्रतिकृति मूल्यों के रूप में इस्तेमाल किया जा सकता।

अधिक विवरण के लिए, नीचे "ExtensionTypes का समर्थन करने वाले TensorFlow APIs" अनुभाग देखें।

आवश्यकताएं

फ़ील्ड प्रकार

सभी फ़ील्ड (उर्फ इंस्टेंस वैरिएबल) घोषित किए जाने चाहिए, और प्रत्येक फ़ील्ड के लिए एक प्रकार का एनोटेशन प्रदान किया जाना चाहिए। निम्नलिखित प्रकार के एनोटेशन समर्थित हैं:

प्रकार उदाहरण
पायथन पूर्णांक i: int
पायथन तैरता है f: float
पायथन स्ट्रिंग्स s: str
पायथन बूलियन b: bool
अजगर कोई नहीं n: None
टेंसर आकार shape: tf.TensorShape
टेंसर डीटाइप्स dtype: tf.DType
टेंसर t: tf.Tensor
एक्सटेंशन प्रकार mt: MyMaskedTensor
रैग्ड टेंसर rt: tf.RaggedTensor
विरल टेंसर st: tf.SparseTensor
अनुक्रमित स्लाइस s: tf.IndexedSlices
वैकल्पिक टेंसर o: tf.experimental.Optional
यूनियन टाइप करें int_or_float: typing.Union[int, float]
टुपल्स params: typing.Tuple[int, float, tf.Tensor, int]
वार-लंबाई टुपल्स lengths: typing.Tuple[int, ...]
मानचित्रण tags: typing.Mapping[str, tf.Tensor]
वैकल्पिक मान weight: typing.Optional[tf.Tensor]

अस्थिरता

एक्सटेंशन प्रकारों को अपरिवर्तनीय होना आवश्यक है। यह सुनिश्चित करता है कि उन्हें TensorFlow के ग्राफ़-ट्रेसिंग तंत्र द्वारा ठीक से ट्रैक किया जा सकता है। यदि आप स्वयं को एक एक्सटेंशन प्रकार मान को बदलना चाहते हैं, तो इसके बजाय मूल्यों को बदलने वाली विधियों को परिभाषित करने पर विचार करें। उदाहरण के लिए, बल्कि एक निर्णायक से set_mask विधि एक उत्परिवर्तित को MaskedTensor , आप एक निर्धारित कर सकते हैं replace_mask विधि है कि रिटर्न एक नया MaskedTensor :

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

  def replace_mask(self, new_mask):
      self.values.shape.assert_is_compatible_with(new_mask.shape)
      return MaskedTensor(self.values, new_mask)

कार्यक्षमता द्वारा जोड़ा ExtensionType

ExtensionType आधार वर्ग निम्नलिखित कार्यक्षमता प्रदान करता है:

  • एक निर्माता ( __init__ )।
  • एक मुद्रण योग्य प्रतिनिधित्व विधि ( __repr__ )।
  • समानता और असमानता ऑपरेटरों ( __eq__ )।
  • एक सत्यापन विधि ( __validate__ )।
  • लागू अपरिवर्तनीयता।
  • एक नेस्ट TypeSpec
  • टेंसर एपीआई प्रेषण समर्थन।

इस कार्यक्षमता को अनुकूलित करने के बारे में अधिक जानकारी के लिए नीचे "कस्टमाइज़िंग एक्सटेंशन टाइप" अनुभाग देखें।

निर्माता

निर्माता द्वारा जोड़ा ExtensionType नामांकित तर्क के रूप में प्रत्येक क्षेत्र (क्रम में वे कक्षा परिभाषा में सूचीबद्ध किया गया) लेता है। यह कंस्ट्रक्टर प्रत्येक पैरामीटर को टाइप-चेक करेगा, और जहां आवश्यक हो उन्हें परिवर्तित करेगा। विशेष रूप से, Tensor फ़ील्ड का उपयोग बदल रहे हैं tf.convert_to_tensor ; Tuple क्षेत्रों में बदल दिए जाते tuple रों; और Mapping क्षेत्रों अपरिवर्तनीय dicts करने के लिए परिवर्तित कर रहे हैं।

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

# Constructor takes one parameter for each field.
mt = MaskedTensor(values=[[1, 2, 3], [4, 5, 6]],
                  mask=[[True, True, False], [True, False, True]])

# Fields are type-checked and converted to the declared types.
# E.g., mt.values is converted to a Tensor.
print(mt.values)
tf.Tensor(
[[1 2 3]
 [4 5 6]], shape=(2, 3), dtype=int32)

निर्माता एक को जन्म देती है TypeError एक फ़ील्ड मान अपनी घोषित प्रकार में परिवर्तित नहीं किया जा सकता है अगर:

try:
  MaskedTensor([1, 2, 3], None)
except TypeError as e:
  print(f"Got expected TypeError: {e}")
Got expected TypeError: mask: expected a Tensor, got None

किसी फ़ील्ड के लिए डिफ़ॉल्ट मान को उसके मान को वर्ग स्तर पर सेट करके निर्दिष्ट किया जा सकता है:

class Pencil(tf.experimental.ExtensionType):
  color: str = "black"
  has_erasor: bool = True
  length: tf.Tensor = 1.0

Pencil()
Pencil(color='black', has_erasor=True, length=<tf.Tensor: shape=(), dtype=float32, numpy=1.0>)
Pencil(length=0.5, color="blue")
Pencil(color='blue', has_erasor=True, length=<tf.Tensor: shape=(), dtype=float32, numpy=0.5>)

प्रिंट करने योग्य प्रतिनिधित्व

ExtensionType एक डिफ़ॉल्ट प्रिंट करने योग्य प्रतिनिधित्व विधि (कहते हैं __repr__ ) वर्ग के नाम है और प्रत्येक क्षेत्र के लिए मूल्य भी शामिल है कि:

print(MaskedTensor(values=[1, 2, 3], mask=[True, True, False]))
MaskedTensor(values=<tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 2, 3], dtype=int32)>, mask=<tf.Tensor: shape=(3,), dtype=bool, numpy=array([ True,  True, False])>)

समानता ऑपरेटर

ExtensionType डिफ़ॉल्ट समानता ऑपरेटरों (कहते हैं __eq__ और __ne__ ) है कि पर विचार अगर वे एक ही प्रकार है और उनके सभी क्षेत्रों के बराबर हैं दो मूल्यों के बराबर। टेंसर फ़ील्ड को समान माना जाता है यदि उनका आकार समान होता है और सभी तत्वों के लिए समान रूप से समान होते हैं।

a = MaskedTensor([1, 2], [True, False])
b = MaskedTensor([[3, 4], [5, 6]], [[False, True], [True, True]])
print(f"a == a: {a==a}")
print(f"a == b: {a==b}")
print(f"a == a.values: {a==a.values}")
a == a: True
a == b: False
a == a.values: False

सत्यापन विधि

ExtensionType एक कहते हैं __validate__ विधि है, जो खेतों पर मान्यता जांच करने के लिए ओवरराइड किया जा सकता। इसे कंस्ट्रक्टर को बुलाए जाने के बाद चलाया जाता है, और फ़ील्ड्स को टाइप-चेक करने और उनके घोषित प्रकारों में बदलने के बाद, इसलिए यह मान सकता है कि सभी फ़ील्ड्स के घोषित प्रकार हैं।

वह उदाहरण निम्नलिखित अद्यतन करता MaskedTensor मान्य करने के लिए shape और dtype अपने खेतों की रों:

class MaskedTensor(tf.experimental.ExtensionType):
  """A tensor paired with a boolean mask, indicating which values are valid."""
  values: tf.Tensor
  mask: tf.Tensor
  def __validate__(self):
    self.values.shape.assert_is_compatible_with(self.mask.shape)
    assert self.mask.dtype.is_bool, 'mask.dtype must be bool'
try:
  MaskedTensor([1, 2, 3], [0, 1, 0])  # wrong dtype for mask.
except AssertionError as e:
  print(f"Got expected AssertionError: {e}")
Got expected AssertionError: mask.dtype must be bool
try:
  MaskedTensor([1, 2, 3], [True, False])  # shapes don't match.
except ValueError as e:
  print(f"Got expected ValueError: {e}")
Got expected ValueError: Shapes (3,) and (2,) are incompatible

लागू अपरिवर्तनीयता

ExtensionType ओवरराइड करता है __setattr__ और __delattr__ तरीकों उत्परिवर्तन को रोकने के लिए, यह सुनिश्चित करना कि एक्सटेंशन प्रकार मूल्यों अपरिवर्तनीय हैं।

mt = MaskedTensor([1, 2, 3], [True, False, True])
try:
  mt.mask = [True, True, True]
except AttributeError as e:
  print(f"Got expected AttributeError: {e}")
Got expected AttributeError: Cannot mutate attribute `mask` outside the custom constructor of ExtensionType.
try:
  mt.mask[0] = False
except TypeError as e:
  print(f"Got expected TypeError: {e}")
Got expected TypeError: 'tensorflow.python.framework.ops.EagerTensor' object does not support item assignment
try:
  del mt.mask
except AttributeError as e:
  print(f"Got expected AttributeError: {e}")
Got expected AttributeError: Cannot mutate attribute `mask` outside the custom constructor of ExtensionType.

नेस्टेड प्रकारSpec

प्रत्येक ExtensionType वर्ग को उससे संबंधित है TypeSpec वर्ग है, जो स्वचालित रूप से बनाया और के रूप में संग्रहीत किया जाता है <extension_type_name>.Spec

इस वर्ग के किसी भी नेस्टेड tensors के मान को छोड़कर एक मूल्य से सभी जानकारी कैप्चर करता है। विशेष रूप से, TypeSpec एक मूल्य के लिए अपने साथ किसी भी नेस्टेड टेन्सर, ExtensionType, या CompositeTensor की जगह द्वारा बनाई गई है TypeSpec

class Player(tf.experimental.ExtensionType):
  name: tf.Tensor
  attributes: Mapping[str, tf.Tensor]

anne = Player("Anne", {"height": 8.3, "speed": 28.1})
anne_spec = tf.type_spec_from_value(anne)
print(anne_spec.name)  # Records dtype and shape, but not the string value.
print(anne_spec.attributes)  # Records keys and TensorSpecs for values.
WARNING:tensorflow:Mapping types may not work well with tf.nest. Prefer using MutableMapping for <class 'tensorflow.python.framework.immutable_dict.ImmutableDict'>
TensorSpec(shape=(), dtype=tf.string, name=None)
ImmutableDict({'height': TensorSpec(shape=(), dtype=tf.float32, name=None), 'speed': TensorSpec(shape=(), dtype=tf.float32, name=None)})

TypeSpec मूल्यों को स्पष्ट रूप से निर्माण किया जा सकता है, या वे एक से बनाया जा सकता ExtensionType का उपयोग कर मूल्य tf.type_spec_from_value :

spec1 = Player.Spec(name=tf.TensorSpec([], tf.float32), attributes={})
spec2 = tf.type_spec_from_value(anne)

TypeSpec रों एक स्थिर घटक और एक गतिशील घटक में विभाजित मूल्यों के TensorFlow द्वारा किया जाता है:

  • स्थिर घटक (जो ग्राफ निर्माणाधीन समय में तय हो गई है) एक साथ इनकोडिंग tf.TypeSpec
  • गतिशील घटक (जो हर बार ग्राफ चलाया जाता है भिन्न हो सकते हैं) की एक सूची के रूप में एन्कोड किया गया है tf.Tensor रों।

उदाहरण के लिए, tf.function रच लेती है इसकी लिपटे समारोह जब भी एक तर्क एक पहले के अनदेखे है TypeSpec :

@tf.function
def anonymize_player(player):
  print("<<TRACING>>")
  return Player("<anonymous>", player.attributes)
# Function gets traced (first time the function has been called):
anonymize_player(Player("Anne", {"height": 8.3, "speed": 28.1}))
WARNING:tensorflow:Mapping types may not work well with tf.nest. Prefer using MutableMapping for <class 'tensorflow.python.framework.immutable_dict.ImmutableDict'>
WARNING:tensorflow:Mapping types may not work well with tf.nest. Prefer using MutableMapping for <class 'tensorflow.python.framework.immutable_dict.ImmutableDict'>
<<TRACING>>
Player(name=<tf.Tensor: shape=(), dtype=string, numpy=b'<anonymous>'>, attributes=ImmutableDict({'height': <tf.Tensor: shape=(), dtype=float32, numpy=8.3>, 'speed': <tf.Tensor: shape=(), dtype=float32, numpy=28.1>}))
# Function does NOT get traced (same TypeSpec: just tensor values changed)
anonymize_player(Player("Bart", {"height": 8.1, "speed": 25.3}))
Player(name=<tf.Tensor: shape=(), dtype=string, numpy=b'<anonymous>'>, attributes=ImmutableDict({'height': <tf.Tensor: shape=(), dtype=float32, numpy=8.1>, 'speed': <tf.Tensor: shape=(), dtype=float32, numpy=25.3>}))
# Function gets traced (new TypeSpec: keys for attributes changed):
anonymize_player(Player("Chuck", {"height": 11.0, "jump": 5.3}))
<<TRACING>>
Player(name=<tf.Tensor: shape=(), dtype=string, numpy=b'<anonymous>'>, attributes=ImmutableDict({'height': <tf.Tensor: shape=(), dtype=float32, numpy=11.0>, 'jump': <tf.Tensor: shape=(), dtype=float32, numpy=5.3>}))

अधिक जानकारी के लिए, tf.function गाइड

एक्सटेंशन प्रकार अनुकूलित करना

केवल फ़ील्ड और उनके प्रकार घोषित करने के अलावा, एक्सटेंशन प्रकार निम्न हो सकते हैं:

  • डिफ़ॉल्ट प्रिंट करने योग्य प्रतिनिधित्व (ओवरराइड __repr__ )।
  • विधियों को परिभाषित कीजिए।
  • क्लासमेथड्स और स्टेटिकमेथड्स को परिभाषित करें।
  • गुणों को परिभाषित करें।
  • डिफ़ॉल्ट निर्माता (ओवरराइड __init__ )।
  • डिफ़ॉल्ट समानता ऑपरेटर (ओवरराइड __eq__ )।
  • (जैसे ऑपरेटरों को परिभाषित करें __add__ और __lt__ )।
  • फ़ील्ड के लिए डिफ़ॉल्ट मान घोषित करें।
  • उपवर्गों को परिभाषित करें।

डिफ़ॉल्ट प्रिंट करने योग्य प्रतिनिधित्व को ओवरराइड करना

आप एक्सटेंशन प्रकारों के लिए इस डिफ़ॉल्ट स्ट्रिंग रूपांतरण ऑपरेटर को ओवरराइड कर सकते हैं। निम्न उदाहरण अद्यतन करता MaskedTensor अधिक पठनीय स्ट्रिंग प्रतिनिधित्व उत्पन्न करने के लिए जब मूल्यों उत्सुक मोड में मुद्रित कर रहे हैं वर्ग।

class MaskedTensor(tf.experimental.ExtensionType):
  """A tensor paired with a boolean mask, indicating which values are valid."""
  values: tf.Tensor
  mask: tf.Tensor       # shape=values.shape; false for invalid values.

  def __repr__(self):
    return masked_tensor_str(self.values, self.mask)

def masked_tensor_str(values, mask):
  if isinstance(values, tf.Tensor):
    if hasattr(values, 'numpy') and hasattr(mask, 'numpy'):
      return f'<MaskedTensor {masked_tensor_str(values.numpy(), mask.numpy())}>'
    else:
      return f'MaskedTensor(values={values}, mask={mask})'
  if len(values.shape) == 1:
    items = [repr(v) if m else '_' for (v, m) in zip(values, mask)]
  else:
    items = [masked_tensor_str(v, m) for (v, m) in zip(values, mask)]
  return '[%s]' % ', '.join(items)

mt = MaskedTensor(values=[[1, 2, 3], [4, 5, 6]],
                  mask=[[True, True, False], [True, False, True]])
print(mt)
<MaskedTensor [[1, 2, _], [4, _, 6]]>

परिभाषित करने के तरीके

किसी भी सामान्य पायथन वर्ग की तरह, एक्सटेंशन प्रकार विधियों को परिभाषित कर सकते हैं। उदाहरण के लिए, MaskedTensor प्रकार एक निर्धारित कर सकते हैं with_default विधि है कि रिटर्न की एक प्रति self नकाबपोश मूल्यों के साथ एक दिया द्वारा प्रतिस्थापित default मूल्य। तरीके वैकल्पिक रूप से एनोटेट किया जा सकता है @tf.function डेकोरेटर।

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

  def with_default(self, default):
    return tf.where(self.mask, self.values, default)

MaskedTensor([1, 2, 3], [True, False, True]).with_default(0)
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 0, 3], dtype=int32)>

क्लासमेथड्स और स्टेटिकमेथड्स को परिभाषित करना

एक्सटेंशन प्रकार का उपयोग तरीकों को परिभाषित कर सकते @classmethod और @staticmethod सज्जाकार। उदाहरण के लिए, MaskedTensor प्रकार एक कारखाने विधि निर्धारित कर सकते हैं कि मास्क दिए गए मान के साथ किसी भी तत्व:

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

  def __repr__(self):
    return masked_tensor_str(self.values, self.mask)

  @staticmethod
  def from_tensor_and_value_to_mask(values, value_to_mask):
    return MaskedTensor(values, values == value_to_mask)

x = tf.constant([[1, 0, 2], [3, 0, 0]])
MaskedTensor.from_tensor_and_value_to_mask(x, 0)
<MaskedTensor [[_, 0, _], [_, 0, 0]]>

गुणों को परिभाषित करना

एक्सटेंशन प्रकार का उपयोग गुण परिभाषित कर सकते हैं @property डेकोरेटर, बस किसी भी सामान्य अजगर वर्ग की तरह। उदाहरण के लिए, MaskedTensor प्रकार एक निर्धारित कर सकते हैं dtype संपत्ति मूल्यों की dtype के लिए एक आशुलिपि है कि:

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

  @property
  def dtype(self):
    return self.values.dtype

MaskedTensor([1, 2, 3], [True, False, True]).dtype
tf.int32

डिफ़ॉल्ट कंस्ट्रक्टर को ओवरराइड करना

आप एक्सटेंशन प्रकारों के लिए डिफ़ॉल्ट कंस्ट्रक्टर को ओवरराइड कर सकते हैं। कस्टम कंस्ट्रक्टर को प्रत्येक घोषित फ़ील्ड के लिए एक मान सेट करना होगा; और कस्टम कंस्ट्रक्टर के लौटने के बाद, सभी फ़ील्ड टाइप-चेक किए जाएंगे, और मानों को ऊपर वर्णित अनुसार परिवर्तित किया जाएगा।

class Toy(tf.experimental.ExtensionType):
  name: str
  price: tf.Tensor
  def __init__(self, name, price, discount=0):
    self.name = name
    self.price = price * (1 - discount)

print(Toy("ball", 5.0, discount=0.2))  # On sale -- 20% off!
Toy(name='ball', price=<tf.Tensor: shape=(), dtype=float32, numpy=4.0>)

वैकल्पिक रूप से, आप डिफ़ॉल्ट कंस्ट्रक्टर को यथावत छोड़ने पर विचार कर सकते हैं, लेकिन एक या अधिक फ़ैक्टरी विधियों को जोड़ सकते हैं। जैसे:

class Toy(tf.experimental.ExtensionType):
  name: str
  price: tf.Tensor

  @staticmethod
  def new_toy_with_discount(name, price, discount):
    return Toy(name, price * (1 - discount))

print(Toy.new_toy_with_discount("ball", 5.0, discount=0.2))
Toy(name='ball', price=<tf.Tensor: shape=(), dtype=float32, numpy=4.0>)

डिफ़ॉल्ट समानता ऑपरेटर अधिभावी ( __eq__ )

आप डिफ़ॉल्ट ओवरराइड कर सकते हैं __eq__ एक्सटेंशन प्रकारों के लिए ऑपरेटर। अनुवर्ती उदाहरण अद्यतन करता MaskedTensor जब समानता के लिए की तुलना नकाबपोश तत्वों की अनदेखी करने के।

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

  def __repr__(self):
    return masked_tensor_str(self.values, self.mask)

  def __eq__(self, other):
    result = tf.math.equal(self.values, other.values)
    result = result | ~(self.mask & other.mask)
    return tf.reduce_all(result)

x = MaskedTensor([1, 2, 3, 4], [True, True, False, True])
y = MaskedTensor([5, 2, 0, 4], [False, True, False, True])
print(x == y)
tf.Tensor(True, shape=(), dtype=bool)

आगे के संदर्भों का उपयोग करना

यदि किसी फ़ील्ड का प्रकार अभी तक परिभाषित नहीं किया गया है, तो आप इसके बजाय प्रकार के नाम वाली स्ट्रिंग का उपयोग कर सकते हैं। निम्न उदाहरण में, स्ट्रिंग "Node" पर टिप्पणी करने के लिए इस्तेमाल किया जाता है children क्षेत्र क्योंकि Node प्रकार नहीं किया गया है (पूरी तरह से) अभी तक परिभाषित किया।

class Node(tf.experimental.ExtensionType):
  value: tf.Tensor
  children: Tuple["Node", ...] = ()

Node(3, [Node(5), Node(2)])
Node(value=<tf.Tensor: shape=(), dtype=int32, numpy=3>, children=(Node(value=<tf.Tensor: shape=(), dtype=int32, numpy=5>, children=()), Node(value=<tf.Tensor: shape=(), dtype=int32, numpy=2>, children=())))

उपवर्गों को परिभाषित करना

मानक पायथन सिंटैक्स का उपयोग करके एक्सटेंशन प्रकारों को उपवर्गित किया जा सकता है। एक्सटेंशन प्रकार के उपवर्ग नए फ़ील्ड, विधियाँ और गुण जोड़ सकते हैं; और कंस्ट्रक्टर, प्रिंट करने योग्य प्रतिनिधित्व और समानता ऑपरेटर को ओवरराइड कर सकता है। निम्न उदाहरण एक बुनियादी परिभाषित करता है TensorGraph वर्ग का उपयोग करता है तीन कि Tensor क्षेत्रों नोड्स के बीच किनारों का एक सेट एन्कोड करने के लिए। यह तो एक उपवर्ग है कि एक कहते हैं परिभाषित करता है Tensor प्रत्येक नोड के लिए एक "सुविधा मूल्य" रिकॉर्ड करने के लिए क्षेत्र। उपवर्ग किनारों के साथ फीचर वैल्यू को प्रचारित करने के लिए एक विधि को भी परिभाषित करता है।

class TensorGraph(tf.experimental.ExtensionType):
  num_nodes: tf.Tensor
  edge_src: tf.Tensor   # edge_src[e] = index of src node for edge e.
  edge_dst: tf.Tensor   # edge_dst[e] = index of dst node for edge e.

class TensorGraphWithNodeFeature(TensorGraph):
  node_features: tf.Tensor  # node_features[n] = feature value for node n.

  def propagate_features(self, weight=1.0) -> 'TensorGraphWithNodeFeature':
    updates = tf.gather(self.node_features, self.edge_src) * weight
    new_node_features = tf.tensor_scatter_nd_add(
        self.node_features, tf.expand_dims(self.edge_dst, 1), updates)
    return TensorGraphWithNodeFeature(
        self.num_nodes, self.edge_src, self.edge_dst, new_node_features)

g = TensorGraphWithNodeFeature(  # Edges: 0->1, 4->3, 2->2, 2->1
    num_nodes=5, edge_src=[0, 4, 2, 2], edge_dst=[1, 3, 2, 1],
    node_features=[10.0, 0.0, 2.0, 5.0, -1.0, 0.0])

print("Original features:", g.node_features)
print("After propagating:", g.propagate_features().node_features)
Original features: tf.Tensor([10.  0.  2.  5. -1.  0.], shape=(6,), dtype=float32)
After propagating: tf.Tensor([10. 12.  4.  4. -1.  0.], shape=(6,), dtype=float32)

निजी क्षेत्रों को परिभाषित करना

एक एक्सटेंशन प्रकार के फ़ील्ड को अंडरस्कोर (मानक पायथन सम्मेलनों के बाद) के साथ उपसर्ग करके निजी चिह्नित किया जा सकता है। यह उस तरीके को प्रभावित नहीं करता है जिस तरह से TensorFlow किसी भी तरह से फ़ील्ड का इलाज करता है; लेकिन बस एक्सटेंशन प्रकार के किसी भी उपयोगकर्ता के लिए एक संकेत के रूप में कार्य करता है कि वे फ़ील्ड निजी हैं।

ExtensionType के अनुकूलित TypeSpec

प्रत्येक ExtensionType वर्ग को उससे संबंधित है TypeSpec वर्ग है, जो स्वचालित रूप से बनाया और के रूप में संग्रहीत किया जाता है <extension_type_name>.Spec । अधिक जानकारी के लिए, ऊपर "नेस्टेड टाइपस्पेक" अनुभाग देखें।

अनुकूलित करने के लिए TypeSpec , बस अपने नेस्टेड वर्ग नामित परिभाषित Spec , और ExtensionType कि उपयोग करेगा स्वचालित रूप से निर्माण के लिए आधार के रूप में TypeSpec । आप अनुकूलित कर सकते हैं Spec वर्ग द्वारा:

  • डिफ़ॉल्ट प्रिंट करने योग्य प्रतिनिधित्व को ओवरराइड करना।
  • डिफ़ॉल्ट कंस्ट्रक्टर को ओवरराइड करना।
  • विधियों, वर्ग विधियों, स्थैतिक विधियों और गुणों को परिभाषित करना।

निम्न उदाहरण अनुकूलित MaskedTensor.Spec यह आसान उपयोग करने के लिए बनाने के लिए वर्ग:

class MaskedTensor(tf.experimental.ExtensionType):
  values: tf.Tensor
  mask: tf.Tensor

  shape = property(lambda self: self.values.shape)
  dtype = property(lambda self: self.values.dtype)

  def __repr__(self):
    return masked_tensor_str(self.values, self.mask)

  def with_values(self, new_values):
    return MaskedTensor(new_values, self.mask)

  class Spec:
    def __init__(self, shape, dtype=tf.float32):
      self.values = tf.TensorSpec(shape, dtype)
      self.mask = tf.TensorSpec(shape, tf.bool)

    def __repr__(self):
      return f"MaskedTensor.Spec(shape={self.shape}, dtype={self.dtype})"

    shape = property(lambda self: self.values.shape)
    dtype = property(lambda self: self.values.dtype)

टेंसर एपीआई प्रेषण

एक्सटेंशन प्रकार, "टेन्सर की तरह" हो सकता है इस अर्थ में कि वे विशेषज्ञ या इंटरफ़ेस द्वारा परिभाषित विस्तार में tf.Tensor प्रकार। टेन्सर की तरह एक्सटेंशन प्रकारों के उदाहरण में शामिल RaggedTensor , SparseTensor , और MaskedTensorडिस्पैच सज्जाकार जब टेन्सर की तरह विस्तार प्रकार के लिए लागू TensorFlow आपरेशन के डिफ़ॉल्ट व्यवहार को ओवरराइड करने के लिए इस्तेमाल किया जा सकता। TensorFlow वर्तमान में तीन प्रेषण डेकोरेटर को परिभाषित करता है:

एकल एपीआई के लिए प्रेषण

tf.experimental.dispatch_for_api डेकोरेटर एक निर्दिष्ट TensorFlow आपरेशन के डिफ़ॉल्ट व्यवहार को जब यह निर्दिष्ट हस्ताक्षर के साथ कहा जाता है ओवरराइड करता है। उदाहरण के लिए, आप कैसे निर्दिष्ट करने के लिए इस डेकोरेटर का उपयोग कर सकते tf.stack संसाधित करना चाहिए MaskedTensor मान:

@tf.experimental.dispatch_for_api(tf.stack)
def masked_stack(values: List[MaskedTensor], axis = 0):
  return MaskedTensor(tf.stack([v.values for v in values], axis),
                      tf.stack([v.mask for v in values], axis))

इस के लिए डिफ़ॉल्ट कार्यान्वयन को ओवरराइड करता है tf.stack जब भी यह की सूची के साथ कहा जाता है MaskedTensor मूल्यों (के बाद से values तर्क के साथ टिप्पणी की जाती है typing.List[MaskedTensor] ):

x = MaskedTensor([1, 2, 3], [True, True, False])
y = MaskedTensor([4, 5, 6], [False, True, True])
tf.stack([x, y])
<MaskedTensor [[1, 2, _], [_, 5, 6]]>

अनुमति देने के लिए tf.stack मिश्रित की सूची संभाल करने के लिए MaskedTensor और Tensor मूल्यों, आप के लिए प्रकार एनोटेशन परिष्कृत कर सकते हैं values पैरामीटर और समारोह उचित रूप से के शरीर अद्यतन:

tf.experimental.unregister_dispatch_for(masked_stack)

def convert_to_masked_tensor(x):
  if isinstance(x, MaskedTensor):
    return x
  else:
    return MaskedTensor(x, tf.ones_like(x, tf.bool))

@tf.experimental.dispatch_for_api(tf.stack)
def masked_stack_v2(values: List[Union[MaskedTensor, tf.Tensor]], axis = 0):
  values = [convert_to_masked_tensor(v) for v in values]
  return MaskedTensor(tf.stack([v.values for v in values], axis),
                      tf.stack([v.mask for v in values], axis))
x = MaskedTensor([1, 2, 3], [True, True, False])
y = tf.constant([4, 5, 6])
tf.stack([x, y, x])
<MaskedTensor [[1, 2, _], [4, 5, 6], [1, 2, _]]>

कि अधिरोहित जा सकता है एपीआई की सूची के लिए, के लिए एपीआई दस्तावेज़ देखें tf.experimental.dispatch_for_api

सभी यूनरी एलिमेंटवाइज एपीआई के लिए डिस्पैच

tf.experimental.dispatch_for_unary_elementwise_apis डेकोरेटर ओवरराइड सभी एकल elementwise ऑप्स (जैसे के डिफ़ॉल्ट व्यवहार को tf.math.cos ) जब भी पहला तर्क (आम तौर पर नामित किया गया के लिए मूल्य x ) प्रकार एनोटेशन से मेल खाता है x_type । सजाए गए फ़ंक्शन को दो तर्क लेने चाहिए:

  • api_func : एक समारोह है कि एक एकल पैरामीटर और प्रदर्शन elementwise आपरेशन (जैसे, लेता tf.abs )।
  • x : elementwise संचालन के लिए पहला तर्क।

निम्न उदाहरण अपडेट हो जाता है सभी एकल elementwise संचालन को संभालने के लिए MaskedTensor के प्रकार:

@tf.experimental.dispatch_for_unary_elementwise_apis(MaskedTensor)
 def masked_tensor_unary_elementwise_api_handler(api_func, x):
   return MaskedTensor(api_func(x.values), x.mask)

यह समारोह अब इस्तेमाल किया जब भी एक एकल elementwise आपरेशन एक पर कहा जाता है हो जाएगा MaskedTensor

x = MaskedTensor([1, -2, -3], [True, False, True])
 print(tf.abs(x))
<MaskedTensor [1, _, 3]>
print(tf.ones_like(x, dtype=tf.float32))
<MaskedTensor [1.0, _, 1.0]>

बाइनरी सभी एलिमेंटवाइज एपीआई के लिए डिस्पैच

इसी तरह, tf.experimental.dispatch_for_binary_elementwise_apis सभी द्विआधारी elementwise संचालन को संभालने के लिए अद्यतन करने के लिए इस्तेमाल किया जा सकता MaskedTensor के प्रकार:

@tf.experimental.dispatch_for_binary_elementwise_apis(MaskedTensor, MaskedTensor)
def masked_tensor_binary_elementwise_api_handler(api_func, x, y):
  return MaskedTensor(api_func(x.values, y.values), x.mask & y.mask)
x = MaskedTensor([1, -2, -3], [True, False, True])
y = MaskedTensor([[4], [5]], [[True], [False]])
tf.math.add(x, y)
<MaskedTensor [[5, _, 1], [_, _, _]]>

Elementwise एपीआई कि अधिरोहित कर रहे हैं की सूची के लिए, के लिए एपीआई दस्तावेज़ देखें tf.experimental.dispatch_for_unary_elementwise_apis और tf.experimental.dispatch_for_binary_elementwise_apis

बैचेबल एक्सटेंशन प्रकार

एक ExtensionType batchable अगर एक उदाहरण मूल्यों का एक बैच का प्रतिनिधित्व करने के लिए किया जा सकता है। आमतौर पर, यह सब नेस्ट करने के लिए बैच आयाम जोड़कर पूरा किया है Tensor रों। निम्नलिखित TensorFlow API के लिए आवश्यक है कि कोई भी एक्सटेंशन प्रकार के इनपुट बैचेबल हों:

डिफ़ॉल्ट रूप से, BatchableExtensionType किसी भी नेस्टेड batching द्वारा बैच मूल्यों बनाता Tensor रों, CompositeTensor है, और ExtensionType रों। यदि यह आपके वर्ग के लिए उपयुक्त नहीं है, तो आप का उपयोग करने की आवश्यकता होगी tf.experimental.ExtensionTypeBatchEncoder इस डिफ़ॉल्ट व्यवहार को ओवरराइड करने के लिए। उदाहरण के लिए, यह का एक बैच बनाने के लिए उचित नहीं होगा tf.SparseTensor बस व्यक्ति विरल tensors 'stacking द्वारा मूल्यों values , indices , और dense_shape क्षेत्रों - ज्यादातर मामलों में, आप इन tensors ढेर नहीं कर सकते, क्योंकि वे असंगत आकार ; और यहां तक कि आप कर सकते हैं तो परिणाम एक मान्य नहीं होगा SparseTensor

बैचेबल एक्सटेंशन टाइप उदाहरण: नेटवर्क

उदाहरण के लिए, एक साधारण विचार करें Network लोड संतुलन के लिए इस्तेमाल किया वर्ग है, जो पटरियों कितना काम प्रत्येक नोड पर ऐसा करने के लिए छोड़ दिया जाता है, और कितना बैंडविड्थ नोड्स के बीच काम ले जाने के लिए उपलब्ध है:

class Network(tf.experimental.ExtensionType):  # This version is not batchable.
  work: tf.Tensor       # work[n] = work left to do at node n
  bandwidth: tf.Tensor  # bandwidth[n1, n2] = bandwidth from n1->n2

net1 = Network([5., 3, 8], [[0., 2, 0], [2, 0, 3], [0, 3, 0]])
net2 = Network([3., 4, 2], [[0., 2, 2], [2, 0, 2], [2, 2, 0]])

इस प्रकार batchable कराने के लिए, आधार प्रकार बदलने के BatchableExtensionType , और प्रत्येक क्षेत्र के आकार को समायोजित वैकल्पिक बैच आयाम शामिल करने के लिए। निम्न उदाहरण भी एक कहते हैं shape बैच आकार के keept ट्रैक करने के लिए क्षेत्र। यह shape क्षेत्र वजह से नहीं है tf.data.Dataset या tf.map_fn , लेकिन यह के लिए आवश्यक है tf.Keras

class Network(tf.experimental.BatchableExtensionType):
  shape: tf.TensorShape  # batch shape.  A single network has shape=[].
  work: tf.Tensor        # work[*shape, n] = work left to do at node n
  bandwidth: tf.Tensor   # bandwidth[*shape, n1, n2] = bandwidth from n1->n2

  def __init__(self, work, bandwidth):
    self.work = tf.convert_to_tensor(work)
    self.bandwidth = tf.convert_to_tensor(bandwidth)
    work_batch_shape = self.work.shape[:-1]
    bandwidth_batch_shape = self.bandwidth.shape[:-2]
    self.shape = work_batch_shape.merge_with(bandwidth_batch_shape)

  def __repr__(self):
    return network_repr(self)

def network_repr(network):
  work = network.work
  bandwidth = network.bandwidth
  if hasattr(work, 'numpy'):
    work = ' '.join(str(work.numpy()).split())
  if hasattr(bandwidth, 'numpy'):
    bandwidth = ' '.join(str(bandwidth.numpy()).split())
  return (f"<Network shape={network.shape} work={work} bandwidth={bandwidth}>")
net1 = Network([5., 3, 8], [[0., 2, 0], [2, 0, 3], [0, 3, 0]])
net2 = Network([3., 4, 2], [[0., 2, 2], [2, 0, 2], [2, 2, 0]])
batch_of_networks = Network(
    work=tf.stack([net1.work, net2.work]),
    bandwidth=tf.stack([net1.bandwidth, net2.bandwidth]))
print(f"net1={net1}")
print(f"net2={net2}")
print(f"batch={batch_of_networks}")
net1=<Network shape=() work=[5. 3. 8.] bandwidth=[[0. 2. 0.] [2. 0. 3.] [0. 3. 0.]]>
net2=<Network shape=() work=[3. 4. 2.] bandwidth=[[0. 2. 2.] [2. 0. 2.] [2. 2. 0.]]>
batch=<Network shape=(2,) work=[[5. 3. 8.] [3. 4. 2.]] bandwidth=[[[0. 2. 0.] [2. 0. 3.] [0. 3. 0.]] [[0. 2. 2.] [2. 0. 2.] [2. 2. 0.]]]>

इसके बाद आप उपयोग कर सकते हैं tf.data.Dataset नेटवर्क का एक बैच के माध्यम से पुनरावृति:

dataset = tf.data.Dataset.from_tensor_slices(batch_of_networks)
for i, network in enumerate(dataset):
  print(f"Batch element {i}: {network}")
Batch element 0: <Network shape=() work=[5. 3. 8.] bandwidth=[[0. 2. 0.] [2. 0. 3.] [0. 3. 0.]]>
Batch element 1: <Network shape=() work=[3. 4. 2.] bandwidth=[[0. 2. 2.] [2. 0. 2.] [2. 2. 0.]]>

और तुम भी उपयोग कर सकते हैं map_fn प्रत्येक बैच तत्व को एक समारोह को लागू करने के:

def balance_work_greedy(network):
  delta = (tf.expand_dims(network.work, -1) - tf.expand_dims(network.work, -2))
  delta /= 4
  delta = tf.maximum(tf.minimum(delta, network.bandwidth), -network.bandwidth)
  new_work = network.work + tf.reduce_sum(delta, -1)
  return Network(new_work, network.bandwidth)

tf.map_fn(balance_work_greedy, batch_of_networks)
<Network shape=(2,) work=[[5.5 1.25 9.25] [3. 4.75 1.25]] bandwidth=[[[0. 2. 0.] [2. 0. 3.] [0. 3. 0.]] [[0. 2. 2.] [2. 0. 2.] [2. 2. 0.]]]>

TensorFlow API जो एक्सटेंशन टाइप का समर्थन करते हैं

@tf.function

tf.function एक डेकोरेटर है कि अजगर काम करता है, जो काफी हद तक अपने TensorFlow कोड के प्रदर्शन में सुधार कर सकते हैं के लिए precomputes TensorFlow रेखांकन। एक्सटेंशन प्रकार मूल्यों पारदर्शी रूप से इस्तेमाल किया जा सकता @tf.function -decorated कार्य करता है।

class Pastry(tf.experimental.ExtensionType):
  sweetness: tf.Tensor  # 2d embedding that encodes sweetness
  chewiness: tf.Tensor  # 2d embedding that encodes chewiness

@tf.function
def combine_pastry_features(x: Pastry):
  return (x.sweetness + x.chewiness) / 2

cookie = Pastry(sweetness=[1.2, 0.4], chewiness=[0.8, 0.2])
combine_pastry_features(cookie)
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([1. , 0.3], dtype=float32)>

आप स्पष्ट रूप से निर्दिष्ट करना चाहते हैं input_signature के लिए tf.function , तो आप तो एक्सटेंशन प्रकार का उपयोग कर सकते हैं TypeSpec

pastry_spec = Pastry.Spec(tf.TensorSpec([2]), tf.TensorSpec(2))

@tf.function(input_signature=[pastry_spec])
def increase_sweetness(x: Pastry, delta=1.0):
  return Pastry(x.sweetness + delta, x.chewiness)

increase_sweetness(cookie)
Pastry(sweetness=<tf.Tensor: shape=(2,), dtype=float32, numpy=array([2.2, 1.4], dtype=float32)>, chewiness=<tf.Tensor: shape=(2,), dtype=float32, numpy=array([0.8, 0.2], dtype=float32)>)

ठोस कार्य

कंक्रीट कार्यों व्यक्ति का पता लगाया रेखांकन कि द्वारा बनाया जाता है संपुटित tf.function । विस्तार प्रकार ठोस कार्यों के साथ पारदर्शी रूप से उपयोग किए जा सकते हैं।

cf = combine_pastry_features.get_concrete_function(pastry_spec)
cf(cookie)
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([1. , 0.3], dtype=float32)>

नियंत्रण प्रवाह संचालन

एक्सटेंशन प्रकार TensorFlow के नियंत्रण-प्रवाह संचालन द्वारा समर्थित हैं:

# Example: using tf.cond to select between two MaskedTensors.  Note that the
# two MaskedTensors don't need to have the same shape.
a = MaskedTensor([1., 2, 3], [True, False, True])
b = MaskedTensor([22., 33, 108, 55], [True, True, True, False])
condition = tf.constant(True)
print(tf.cond(condition, lambda: a, lambda: b))
<MaskedTensor [1.0, _, 3.0]>
# Example: using tf.while_loop with MaskedTensor.
cond = lambda i, _: i < 10
def body(i, mt):
  return i + 1, mt.with_values(mt.values + 3 / 7)
print(tf.while_loop(cond, body, [0, b])[1])
<MaskedTensor [26.285717, 37.285698, 112.285736, _]>

ऑटोग्राफ नियंत्रण प्रवाह

एक्सटेंशन प्रकार भी tf.function (ऑटोग्राफ का उपयोग करके) में नियंत्रण प्रवाह विवरण द्वारा समर्थित हैं। निम्न उदाहरण में, if बयान और for बयानों स्वचालित रूप से करने के लिए परिवर्तित कर रहे हैं tf.cond और tf.while_loop संचालन, जो समर्थन एक्सटेंशन प्रकारों।

@tf.function
def fn(x, b):
  if b:
    x = MaskedTensor(x, tf.less(x, 0))
  else:
    x = MaskedTensor(x, tf.greater(x, 0))
  for i in tf.range(5 if b else 7):
    x = x.with_values(x.values + 1 / 2)
  return x

print(fn(tf.constant([1., -2, 3]), tf.constant(True)))
print(fn(tf.constant([1., -2, 3]), tf.constant(False)))
<MaskedTensor [_, 0.5, _]>
<MaskedTensor [4.5, _, 6.5]>

केरासो

tf.keras निर्माण और गहरी सीखने मॉडल प्रशिक्षण के लिए TensorFlow के उच्च स्तर एपीआई है। एक्सटेंशन प्रकार को केरस मॉडल के इनपुट के रूप में पारित किया जा सकता है, केरस परतों के बीच पारित किया जा सकता है, और केरस मॉडल द्वारा लौटाया जा सकता है। केरस वर्तमान में विस्तार प्रकारों पर दो आवश्यकताएं रखता है:

  • उन्हें बैच करने योग्य होना चाहिए (ऊपर "बैचेबल एक्सटेंशन टाइप" देखें)।
  • एक क्षेत्र या संपत्ति नामित होना आवश्यक है shapeshape[0] बैच आयाम माना जाता है।

निम्नलिखित दो उपखंड उदाहरण देते हैं कि कैसे केरस के साथ विस्तार प्रकारों का उपयोग किया जा सकता है।

Keras उदाहरण: Network

पहले उदाहरण के लिए, पर विचार Network वर्ग के ऊपर "Batchable ExtensionTypes" खंड में परिभाषित है, जो लोड नोड्स के बीच काम संतुलन के लिए इस्तेमाल किया जा सकता है। इसकी परिभाषा यहाँ दोहराई गई है:

class Network(tf.experimental.BatchableExtensionType):
  shape: tf.TensorShape  # batch shape.  A single network has shape=[].
  work: tf.Tensor        # work[*shape, n] = work left to do at node n
  bandwidth: tf.Tensor   # bandwidth[*shape, n1, n2] = bandwidth from n1->n2

  def __init__(self, work, bandwidth):
    self.work = tf.convert_to_tensor(work)
    self.bandwidth = tf.convert_to_tensor(bandwidth)
    work_batch_shape = self.work.shape[:-1]
    bandwidth_batch_shape = self.bandwidth.shape[:-2]
    self.shape = work_batch_shape.merge_with(bandwidth_batch_shape)

  def __repr__(self):
    return network_repr(self)
single_network = Network(  # A single network w/ 4 nodes.
    work=[8.0, 5, 12, 2],
    bandwidth=[[0.0, 1, 2, 2], [1, 0, 0, 2], [2, 0, 0, 1], [2, 2, 1, 0]])

batch_of_networks = Network(  # Batch of 2 networks, each w/ 2 nodes.
    work=[[8.0, 5], [3, 2]],
    bandwidth=[[[0.0, 1], [1, 0]], [[0, 2], [2, 0]]])

आप एक नया Keras परत है कि प्रक्रियाओं को परिभाषित कर सकते Network रों।

class BalanceNetworkLayer(tf.keras.layers.Layer):
  """Layer that balances work between nodes in a network.

  Shifts work from more busy nodes to less busy nodes, constrained by bandwidth.
  """
  def call(self, inputs):
    # This function is defined above, in "Batchable ExtensionTypes" section.
    return balance_work_greedy(inputs)

फिर आप एक साधारण मॉडल बनाने के लिए इस परत का उपयोग कर सकते हैं। एक को खिलाने के लिए ExtensionType एक मॉडल में, आप एक का उपयोग कर सकते tf.keras.layer.Input के साथ परत type_spec एक्सटेंशन प्रकार के लिए सेट TypeSpec । Keras मॉडल प्रक्रिया बैचों के लिए उपयोग किया जाएगा, तो type_spec बैच आयाम शामिल करना चाहिए।

input_spec = Network.Spec(shape=None,
                          work=tf.TensorSpec(None, tf.float32),
                          bandwidth=tf.TensorSpec(None, tf.float32))
model = tf.keras.Sequential([
    tf.keras.layers.Input(type_spec=input_spec),
    BalanceNetworkLayer(),
    ])

अंत में, आप मॉडल को एकल नेटवर्क और नेटवर्क के बैच पर लागू कर सकते हैं।

model(single_network)
<Network shape=() work=[ 9.25 5. 14. -1.25] bandwidth=[[0. 1. 2. 2.] [1. 0. 0. 2.] [2. 0. 0. 1.] [2. 2. 1. 0.]]>
model(batch_of_networks)
<Network shape=(2,) work=[[8.75 4.25] [3.25 1.75]] bandwidth=[[[0. 1.] [1. 0.]] [[0. 2.] [2. 0.]]]>

केरस उदाहरण: नकाबपोश टेंसर

इस उदाहरण में, MaskedTensor समर्थन करने के लिए बढ़ा दिया गया है Kerasshape एक संपत्ति से की जाती है कि के रूप में परिभाषित किया गया है values क्षेत्र। Keras है कि आप दोनों प्रकार के एक्सटेंशन और इसके लिए इस संपत्ति को जोड़ने की आवश्यकता है TypeSpecMaskedTensor भी एक को परिभाषित करता है __name__ चर, जिसके लिए आवश्यक हो जाएगा SavedModel क्रमबद्धता (नीचे)।

class MaskedTensor(tf.experimental.BatchableExtensionType):
  # __name__ is required for serialization in SavedModel; see below for details.
  __name__ = 'extension_type_colab.MaskedTensor'

  values: tf.Tensor
  mask: tf.Tensor

  shape = property(lambda self: self.values.shape)
  dtype = property(lambda self: self.values.dtype)

  def with_default(self, default):
    return tf.where(self.mask, self.values, default)

  def __repr__(self):
    return masked_tensor_str(self.values, self.mask)

  class Spec:
    def __init__(self, shape, dtype=tf.float32):
      self.values = tf.TensorSpec(shape, dtype)
      self.mask = tf.TensorSpec(shape, tf.bool)

    shape = property(lambda self: self.values.shape)
    dtype = property(lambda self: self.values.dtype)

    def with_shape(self):
      return MaskedTensor.Spec(tf.TensorSpec(shape, self.values.dtype),
                               tf.TensorSpec(shape, self.mask.dtype))

इसके बाद, प्रेषण डेकोरेटर का उपयोग कई TensorFlow API के डिफ़ॉल्ट व्यवहार को ओवरराइड करने के लिए किया जाता है। चूंकि इन एपीआई मानक Keras परतों (जैसे द्वारा उपयोग किया जाता Dense परत), इन अधिभावी हमारे साथ उन परतों का उपयोग करने की अनुमति देगा MaskedTensor । इस उदाहरण के प्रयोजनों के लिए, matmul नकाबपोश tensors के लिए (, के लिए उन्हें उत्पाद में शामिल नहीं यानी) शून्य के रूप में नकाबपोश मूल्यों के इलाज के लिए परिभाषित किया गया है।

@tf.experimental.dispatch_for_unary_elementwise_apis(MaskedTensor)
def unary_elementwise_op_handler(op, x):
 return MaskedTensor(op(x.values), x.mask)

@tf.experimental.dispatch_for_binary_elementwise_apis(
    Union[MaskedTensor, tf.Tensor],
    Union[MaskedTensor, tf.Tensor])
def binary_elementwise_op_handler(op, x, y):
  x = convert_to_masked_tensor(x)
  y = convert_to_masked_tensor(y)
  return MaskedTensor(op(x.values, y.values), x.mask & y.mask)

@tf.experimental.dispatch_for_api(tf.matmul)
def masked_matmul(a: MaskedTensor, b,
                  transpose_a=False, transpose_b=False,
                  adjoint_a=False, adjoint_b=False,
                  a_is_sparse=False, b_is_sparse=False,
                  output_type=None):
  if isinstance(a, MaskedTensor):
    a = a.with_default(0)
  if isinstance(b, MaskedTensor):
    b = b.with_default(0)
  return tf.matmul(a, b, transpose_a, transpose_b, adjoint_a,
                   adjoint_b, a_is_sparse, b_is_sparse, output_type)

फिर आप एक Keras मॉडल है कि स्वीकार निर्माण कर सकते हैं MaskedTensor आदानों, मानक Keras परतों का उपयोग:

input_spec = MaskedTensor.Spec([None, 2], tf.float32)

masked_tensor_model = tf.keras.Sequential([
    tf.keras.layers.Input(type_spec=input_spec),
    tf.keras.layers.Dense(16, activation="relu"),
    tf.keras.layers.Dense(1)])
masked_tensor_model.compile(loss='binary_crossentropy', optimizer='rmsprop')
a = MaskedTensor([[1., 2], [3, 4], [5, 6]],
                  [[True, False], [False, True], [True, True]])
masked_tensor_model.fit(a, tf.constant([[1], [0], [1]]), epochs=3)
print(masked_tensor_model(a))
Epoch 1/3
1/1 [==============================] - 1s 955ms/step - loss: 10.2833
Epoch 2/3
1/1 [==============================] - 0s 5ms/step - loss: 10.2833
Epoch 3/3
1/1 [==============================] - 0s 5ms/step - loss: 10.2833
tf.Tensor(
[[-0.09944128]
 [-0.7225147 ]
 [-1.3020657 ]], shape=(3, 1), dtype=float32)

सहेजा गया मॉडल

एक SavedModel दोनों वजन और अभिकलन सहित एक धारावाहिक TensorFlow कार्यक्रम, है। इसे केरस मॉडल या कस्टम मॉडल से बनाया जा सकता है। किसी भी मामले में, एक्सटेंशन प्रकारों को एक सहेजे गए मॉडल द्वारा परिभाषित कार्यों और विधियों के साथ पारदर्शी रूप से उपयोग किया जा सकता है।

SavedModel मॉडल, परतों, और कार्यों को बचा सकता है कि इस प्रक्रिया एक्सटेंशन प्रकार, जब तक एक्सटेंशन प्रकारों एक है __name__ क्षेत्र। इस नाम का उपयोग एक्सटेंशन प्रकार को पंजीकृत करने के लिए किया जाता है, इसलिए यह मॉडल लोड होने पर स्थित हो सकता है।

उदाहरण: केरस मॉडल को सहेजना

Keras मॉडल है कि एक्सटेंशन प्रकारों का उपयोग का उपयोग कर बचाया जा सकता है SavedModel

masked_tensor_model_path = tempfile.mkdtemp()
tf.saved_model.save(masked_tensor_model, masked_tensor_model_path)
imported_model = tf.saved_model.load(masked_tensor_model_path)
imported_model(a)
2021-11-06 01:25:14.285250: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Function `_wrapped_model` contains input name(s) args_0 with unsupported characters which will be renamed to args_0_1 in the SavedModel.
INFO:tensorflow:Assets written to: /tmp/tmp3ceuupv9/assets
INFO:tensorflow:Assets written to: /tmp/tmp3ceuupv9/assets
<tf.Tensor: shape=(3, 1), dtype=float32, numpy=
array([[-0.09944128],
       [-0.7225147 ],
       [-1.3020657 ]], dtype=float32)>

उदाहरण: एक कस्टम मॉडल सहेजना

SavedModel भी कस्टम को बचाने के लिए इस्तेमाल किया जा सकता tf.Module है कि इस प्रक्रिया एक्सटेंशन प्रकारों कार्यों के साथ उपवर्गों।

class CustomModule(tf.Module):
  def __init__(self, variable_value):
    super().__init__()
    self.v = tf.Variable(variable_value)

  @tf.function
  def grow(self, x: MaskedTensor):
    """Increase values in `x` by multiplying them by `self.v`."""
    return MaskedTensor(x.values * self.v, x.mask)

module = CustomModule(100.0)

module.grow.get_concrete_function(MaskedTensor.Spec(shape=None,
                                                    dtype=tf.float32))
custom_module_path = tempfile.mkdtemp()
tf.saved_model.save(module, custom_module_path)
imported_model = tf.saved_model.load(custom_module_path)
imported_model.grow(MaskedTensor([1., 2, 3], [False, True, False]))
INFO:tensorflow:Assets written to: /tmp/tmp2x8zq5kb/assets
INFO:tensorflow:Assets written to: /tmp/tmp2x8zq5kb/assets
<MaskedTensor [_, 200.0, _]>

एक सहेजा गया मॉडल लोड हो रहा है जब एक्सटेंशन टाइप अनुपलब्ध है

यदि आप एक लोड तो SavedModel एक का उपयोग करता है ExtensionType , लेकिन वह ExtensionType (यानी, आयात नहीं किया गया) उपलब्ध नहीं है, तो आप एक चेतावनी दिखाई देगी और TensorFlow एक "गुमनाम एक्सटेंशन प्रकार" वस्तु का ही उपयोग होगा। इस ऑब्जेक्ट में मूल प्रकार के समान फ़ील्ड होंगे, लेकिन इस प्रकार के लिए आपके द्वारा जोड़े गए किसी और अनुकूलन की कमी होगी, जैसे कि कस्टम विधियाँ या गुण।

TensorFlow सर्विंग के साथ एक्सटेंशन टाइप का उपयोग करना

वर्तमान में, TensorFlow की सेवा (और SavedModel "हस्ताक्षर" शब्दकोश के अन्य उपभोक्ताओं) की आवश्यकता होती है कि सभी इनपुट और आउटपुट कच्चे tensors हो। यदि आप एक्सटेंशन प्रकारों का उपयोग करने वाले मॉडल के साथ TensorFlow सर्विंग का उपयोग करना चाहते हैं, तो आप रैपर विधियों को जोड़ सकते हैं जो टेंसर से एक्सटेंशन प्रकार मान बनाते या विघटित करते हैं। जैसे:

class CustomModuleWrapper(tf.Module):
  def __init__(self, variable_value):
    super().__init__()
    self.v = tf.Variable(variable_value)

  @tf.function
  def var_weighted_mean(self, x: MaskedTensor):
    """Mean value of unmasked values in x, weighted by self.v."""
    x = MaskedTensor(x.values * self.v, x.mask)
    return (tf.reduce_sum(x.with_default(0)) /
            tf.reduce_sum(tf.cast(x.mask, x.dtype)))

  @tf.function()
  def var_weighted_mean_wrapper(self, x_values, x_mask):
    """Raw tensor wrapper for var_weighted_mean."""
    return self.var_weighted_mean(MaskedTensor(x_values, x_mask))

module = CustomModuleWrapper([3., 2., 8., 5.])

module.var_weighted_mean_wrapper.get_concrete_function(
    tf.TensorSpec(None, tf.float32), tf.TensorSpec(None, tf.bool))
custom_module_path = tempfile.mkdtemp()
tf.saved_model.save(module, custom_module_path)
imported_model = tf.saved_model.load(custom_module_path)
x = MaskedTensor([1., 2., 3., 4.], [False, True, False, True])
imported_model.var_weighted_mean_wrapper(x.values, x.mask)
INFO:tensorflow:Assets written to: /tmp/tmpxhh4zh0i/assets
INFO:tensorflow:Assets written to: /tmp/tmpxhh4zh0i/assets
<tf.Tensor: shape=(), dtype=float32, numpy=12.0>

डेटासेट

tf.data एक API कि आप सरल से जटिल इनपुट पाइपलाइनों, पुन: प्रयोज्य टुकड़े का निर्माण करने में सक्षम बनाता है। इसके मूल डेटा संरचना है tf.data.Dataset , जो तत्वों का एक दृश्य है, जिसमें प्रत्येक तत्व एक या अधिक घटक होते हैं प्रतिनिधित्व करता है।

एक्सटेंशन प्रकारों के साथ डेटासेट बनाना

डेटासेट का उपयोग कर एक्सटेंशन प्रकार मूल्यों से बनाया जा सकता है Dataset.from_tensors , Dataset.from_tensor_slices , या Dataset.from_generator :

ds = tf.data.Dataset.from_tensors(Pastry(5, 5))
iter(ds).next()
Pastry(sweetness=<tf.Tensor: shape=(), dtype=int32, numpy=5>, chewiness=<tf.Tensor: shape=(), dtype=int32, numpy=5>)
mt = MaskedTensor(tf.reshape(range(20), [5, 4]), tf.ones([5, 4]))
ds = tf.data.Dataset.from_tensor_slices(mt)
for value in ds:
  print(value)
<MaskedTensor [0, 1, 2, 3]>
<MaskedTensor [4, 5, 6, 7]>
<MaskedTensor [8, 9, 10, 11]>
<MaskedTensor [12, 13, 14, 15]>
<MaskedTensor [16, 17, 18, 19]>
def value_gen():
  for i in range(2, 7):
    yield MaskedTensor(range(10), [j%i != 0 for j in range(10)])

ds = tf.data.Dataset.from_generator(
    value_gen, output_signature=MaskedTensor.Spec(shape=[10], dtype=tf.int32))
for value in ds:
  print(value)
<MaskedTensor [_, 1, _, 3, _, 5, _, 7, _, 9]>
<MaskedTensor [_, 1, 2, _, 4, 5, _, 7, 8, _]>
<MaskedTensor [_, 1, 2, 3, _, 5, 6, 7, _, 9]>
<MaskedTensor [_, 1, 2, 3, 4, _, 6, 7, 8, 9]>
<MaskedTensor [_, 1, 2, 3, 4, 5, _, 7, 8, 9]>

एक्सटेंशन प्रकार वाले डेटासेट को बैचना और अनबैच करना

एक्सटेंशन प्रकारों के साथ डेटासेट का उपयोग कर batchand और unbatched हो सकता है Dataset.batch ए डी एन Dataset.unbatch

batched_ds = ds.batch(2)
for value in batched_ds:
  print(value)
<MaskedTensor [[_, 1, _, 3, _, 5, _, 7, _, 9], [_, 1, 2, _, 4, 5, _, 7, 8, _]]>
<MaskedTensor [[_, 1, 2, 3, _, 5, 6, 7, _, 9], [_, 1, 2, 3, 4, _, 6, 7, 8, 9]]>
<MaskedTensor [[_, 1, 2, 3, 4, 5, _, 7, 8, 9]]>
unbatched_ds = batched_ds.unbatch()
for value in unbatched_ds:
  print(value)
<MaskedTensor [_, 1, _, 3, _, 5, _, 7, _, 9]>
<MaskedTensor [_, 1, 2, _, 4, 5, _, 7, 8, _]>
<MaskedTensor [_, 1, 2, 3, _, 5, 6, 7, _, 9]>
<MaskedTensor [_, 1, 2, 3, 4, _, 6, 7, 8, 9]>
<MaskedTensor [_, 1, 2, 3, 4, 5, _, 7, 8, 9]>