Uzantı türleri

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyinNot defterini indir

Kurmak

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

Uzantı türleri

Kullanıcı tanımlı türler projeleri daha okunabilir, modüler ve sürdürülebilir hale getirebilir. Ancak çoğu TensorFlow API'si, kullanıcı tanımlı Python türleri için çok sınırlı desteğe sahiptir. Buna hem yüksek seviyeli API'ler ( Keras , tf.function , tf.SavedModel gibi) hem de alt seviye API'ler ( tf.while_loop ve tf.concat gibi) dahildir. TensorFlow uzantı türleri , TensorFlow'un API'leriyle sorunsuz bir şekilde çalışan kullanıcı tanımlı nesne yönelimli türler oluşturmak için kullanılabilir. Bir uzantı türü oluşturmak için, temel olarak tf.experimental.ExtensionType olan bir Python sınıfı tanımlamanız ve her alanın türünü belirtmek için tür açıklamalarını kullanmanız yeterlidir.

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 temel sınıfı, standart Python kitaplığından.NamedTuple ve @dataclasses.dataclass typing.NamedTuple benzer şekilde çalışır. Özellikle, alan türü açıklamalarına göre otomatik olarak bir kurucu ve özel yöntemler ( __repr__ ve __eq__ gibi) ekler.

Tipik olarak, uzantı türleri iki kategoriden birine girme eğilimindedir:

  • İlgili değerler koleksiyonunu bir araya getiren ve bu değerlere dayalı olarak faydalı işlemler sağlayabilen veri yapıları . Veri yapıları oldukça genel olabilir (yukarıdaki TensorGraph örneği gibi); veya belirli bir modele göre son derece özelleştirilebilirler.

  • "Tensor" kavramını uzmanlaştıran veya genişleten tensör benzeri türler . Bu kategorideki türlerin bir rank , bir shape ve genellikle bir dtype ; ve bunları Tensor işlemleriyle kullanmak mantıklıdır ( tf.stack , tf.add veya tf.matmul gibi). MaskedTensor ve CSRSparseMatrix , tensör benzeri türlerin örnekleridir.

Desteklenen API'ler

Uzantı türleri, aşağıdaki TensorFlow API'leri tarafından desteklenir:

  • Keras : Uzantı türleri, Keras Models ve Layers için girdi ve çıktı olarak kullanılabilir.
  • tf.data.Dataset : Uzantı türleri Datasets dahil edilebilir ve veri kümesi Iterators tarafından döndürülebilir .
  • Tensorflow hub : Uzantı türleri tf.hub modülleri için giriş ve çıkış olarak kullanılabilir.
  • SavedModel : Uzantı türleri SavedModel işlevleri için giriş ve çıkış olarak kullanılabilir.
  • tf.function : Uzantı türleri, @tf.function dekoratörüyle sarılmış işlevler için argümanlar ve dönüş değerleri olarak kullanılabilir.
  • while döngüleri : Uzantı türleri tf.while_loop içinde döngü değişkenleri olarak kullanılabilir ve while döngüsünün gövdesi için bağımsız değişkenler ve dönüş değerleri olarak kullanılabilir.
  • koşullular : Uzantı türleri tf.cond ve tf.case kullanılarak koşullu olarak seçilebilir.
  • py_function : Uzantı türleri bağımsız değişkenler olarak kullanılabilir ve func bağımsız değişkeni için tf.py_function değer döndürür.
  • Tensör işlemleri : Uzantı türleri, Tensor girdilerini kabul eden çoğu TensorFlow işlemini destekleyecek şekilde genişletilebilir (örneğin, tf.matmul , tf.gather ve tf.reduce_sum ). Daha fazla bilgi için aşağıdaki " Sevk " bölümüne bakın.
  • dağıtım stratejisi : Uzantı türleri, çoğaltma başına değerler olarak kullanılabilir.

Daha fazla ayrıntı için aşağıdaki "Uzantı Türlerini destekleyen TensorFlow API'leri" bölümüne bakın.

Gereksinimler

Alan türleri

Tüm alanlar (örnek değişkenleri olarak da bilinir) bildirilmelidir ve her alan için bir tür ek açıklaması sağlanmalıdır. Aşağıdaki tür ek açıklamaları desteklenir:

Tip Örnek
Python tamsayıları i: int
Python yüzer f: float
Python dizeleri s: str
Python boole değerleri b: bool
Python Yok n: None
Tensör şekilleri shape: tf.TensorShape
Tensör tipleri dtype: tf.DType
Tensörler t: tf.Tensor
Uzantı türleri mt: MyMaskedTensor
Düzensiz Tensörler rt: tf.RaggedTensor
Seyrek Tensörler st: tf.SparseTensor
Dizine Eklenen Dilimler s: tf.IndexedSlices
Opsiyonel Tensörler o: tf.experimental.Optional
Tip birlikleri int_or_float: typing.Union[int, float]
demetler params: typing.Tuple[int, float, tf.Tensor, int]
Var uzunluklu demetler lengths: typing.Tuple[int, ...]
Eşlemeler tags: typing.Mapping[str, tf.Tensor]
İsteğe bağlı değerler weight: typing.Optional[tf.Tensor]

değişebilirlik

Uzantı türlerinin değişmez olması gerekir. Bu, TensorFlow'un grafik izleme mekanizmaları tarafından düzgün bir şekilde izlenebilmelerini sağlar. Bir uzantı türü değerini değiştirmek istediğinizi fark ederseniz, bunun yerine değerleri dönüştüren yöntemler tanımlamayı düşünün. Örneğin, bir MaskedTensor mutasyona uğratmak için bir set_mask yöntemi tanımlamak yerine, yeni bir MaskedTensor döndüren bir replace_mask yöntemi tanımlayabilirsiniz:

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 tarafından eklenen işlevsellik

ExtensionType temel sınıfı aşağıdaki işlevleri sağlar:

  • Bir yapıcı ( __init__ ).
  • Yazdırılabilir bir temsil yöntemi ( __repr__ ).
  • Eşitlik ve eşitsizlik operatörleri ( __eq__ ).
  • Bir doğrulama yöntemi ( __validate__ ).
  • Zorunlu değişmezlik.
  • İç içe bir TypeSpec .
  • Tensor API gönderme desteği.

Bu işlevi özelleştirme hakkında daha fazla bilgi için aşağıdaki "Uzantı Türlerini Özelleştirme" bölümüne bakın.

yapıcı

ExtensionType tarafından eklenen yapıcı, her alanı adlandırılmış bir bağımsız değişken olarak alır (sınıf tanımında listelendikleri sırayla). Bu kurucu, her parametreyi tip-kontrol edecek ve gerektiğinde onları dönüştürecektir. Özellikle, Tensor alanları tf.convert_to_tensor kullanılarak dönüştürülür; Tuple alanları, tuple s'ye dönüştürülür; ve Mapping alanları değişmez diktelere dönüştürülür.

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)
tutucu4 l10n-yer
tf.Tensor(
[[1 2 3]
 [4 5 6]], shape=(2, 3), dtype=int32)

Alan değeri bildirilen türe dönüştürülemezse, yapıcı bir TypeError oluşturur:

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

Bir alanın varsayılan değeri, değeri sınıf düzeyinde ayarlanarak belirlenebilir:

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>)
yer tutucu9 l10n-yer
Pencil(length=0.5, color="blue")
Pencil(color='blue', has_erasor=True, length=<tf.Tensor: shape=(), dtype=float32, numpy=0.5>)

Yazdırılabilir gösterim

ExtensionType , sınıf adını ve her alanın değerini içeren varsayılan yazdırılabilir bir temsil yöntemi ( __repr__ ) ekler:

print(MaskedTensor(values=[1, 2, 3], mask=[True, True, False]))
tutucu12 l10n-yer
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])>)

eşitlik operatörleri

ExtensionType , aynı türe sahiplerse ve tüm alanları eşitse iki değeri eşit kabul eden varsayılan eşitlik operatörleri ( __eq__ ve __ne__ ) ekler. Tensör alanları, aynı şekle sahipse ve tüm elemanlar için eleman bazında eşitse eşit kabul edilir.

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}")
tutucu14 l10n-yer
a == a: True
a == b: False
a == a.values: False

doğrulama yöntemi

ExtensionType , alanlarda doğrulama kontrolleri yapmak için geçersiz kılınabilen bir __validate__ yöntemi ekler. Yapıcı çağrıldıktan sonra ve alanlar tip kontrolü yapıldıktan ve beyan edilen tiplerine dönüştürüldükten sonra çalıştırılır, böylece tüm alanların beyan edilmiş tiplerine sahip olduğunu varsayabilir.

Aşağıdaki örnek, alanlarının shape s ve dtype s değerlerini doğrulamak için MaskedTensor günceller:

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

Zorunlu değişmezlik

ExtensionType , mutasyonu önlemek için __setattr__ ve __delattr__ yöntemlerini geçersiz kılar ve uzantı türü değerlerinin değişmez olmasını sağlar.

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.

İç İçe TipÖzellik

Her ExtensionType sınıfı, otomatik olarak oluşturulan ve <extension_type_name>.Spec olarak depolanan karşılık gelen bir TypeSpec sınıfına sahiptir.

Bu sınıf, iç içe geçmiş tensörlerin değerleri dışındaki tüm bilgileri bir değerden yakalar. Özellikle, bir değer için TypeSpec , iç içe geçmiş herhangi bir Tensor, ExtensionType veya CompositeTensor ile TypeSpec değiştirilerek oluşturulur.

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.
tutucu28 l10n-yer
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 değerleri açıkça oluşturulabilir veya tf.type_spec_from_value kullanılarak bir ExtensionType değerinden oluşturulabilir:

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

TypeSpec ler, değerleri statik bir bileşene ve bir dinamik bileşene bölmek için TensorFlow tarafından kullanılır:

  • Statik bileşen (grafik oluşturma zamanında sabitlenir) bir tf.TypeSpec ile kodlanmıştır.
  • Dinamik bileşen (grafik her çalıştırıldığında değişebilen), tf.Tensor s listesi olarak kodlanmıştır.

Örneğin, bir bağımsız değişkenin daha önce görülmeyen bir TypeSpec olduğunda, tf.function sarılmış işlevinin izini sürer:

@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>}))

Daha fazla bilgi için tf.function Guide'a bakın.

Uzantı Türlerini Özelleştirme

Yalnızca alanları ve türlerini bildirmeye ek olarak, uzantı türleri şunları yapabilir:

  • Varsayılan yazdırılabilir gösterimi ( __repr__ ) geçersiz kılın.
  • Yöntemleri tanımlayın.
  • Sınıf yöntemlerini ve statik yöntemleri tanımlayın.
  • Özellikleri tanımlayın.
  • Varsayılan yapıcıyı ( __init__ ) geçersiz kılın.
  • Varsayılan eşitlik operatörünü ( __eq__ ) geçersiz kılın.
  • Operatörleri tanımlayın ( __add__ ve __lt__ gibi).
  • Alanlar için varsayılan değerler bildirin.
  • Alt sınıfları tanımlayın.

Varsayılan yazdırılabilir gösterimi geçersiz kılma

Uzantı türleri için bu varsayılan dize dönüştürme operatörünü geçersiz kılabilirsiniz. Aşağıdaki örnek, değerler Eager modunda yazdırıldığında daha okunabilir bir dize temsili oluşturmak için MaskedTensor sınıfını günceller.

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)
tutucu38 l10n-yer
<MaskedTensor [[1, 2, _], [4, _, 6]]>

yöntemleri tanımlama

Uzantı türleri, herhangi bir normal Python sınıfı gibi yöntemleri tanımlayabilir. Örneğin, MaskedTensor türü, belirli bir default değerle değiştirilen maskelenmiş değerlerle self bir kopyasını döndüren bir with_default yöntemi tanımlayabilir. Yöntemlere isteğe bağlı olarak @tf.function dekoratörü ile açıklama eklenebilir.

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)
tutucu40 l10n-yer
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 0, 3], dtype=int32)>

Sınıf yöntemlerini ve statik yöntemleri tanımlama

Uzantı türleri, @classmethod ve @staticmethod dekoratörlerini kullanarak yöntemleri tanımlayabilir. Örneğin, MaskedTensor türü, herhangi bir öğeyi belirli bir değerle maskeleyen bir fabrika yöntemi tanımlayabilir:

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)
tutucu42 l10n-yer
<MaskedTensor [[_, 0, _], [_, 0, 0]]>

özellikleri tanımlama

Uzantı türleri, herhangi bir normal Python sınıfı gibi, @property dekoratörünü kullanarak özellikleri tanımlayabilir. Örneğin, MaskedTensor türü, değerlerin türü için bir kısayol olan bir dtype özelliği tanımlayabilir:

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
tutucu44 l10n-yer
tf.int32

Varsayılan yapıcıyı geçersiz kılma

Uzantı türleri için varsayılan kurucuyu geçersiz kılabilirsiniz. Özel oluşturucular, beyan edilen her alan için bir değer belirlemelidir; ve özel kurucu geri döndükten sonra, tüm alanların tipi kontrol edilecek ve değerler yukarıda açıklandığı gibi dönüştürülecektir.

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!
tutucu46 l10n-yer
Toy(name='ball', price=<tf.Tensor: shape=(), dtype=float32, numpy=4.0>)

Alternatif olarak, varsayılan kurucuyu olduğu gibi bırakmayı, ancak bir veya daha fazla fabrika yöntemi eklemeyi düşünebilirsiniz. Örneğin:

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))
tutucu48 l10n-yer
Toy(name='ball', price=<tf.Tensor: shape=(), dtype=float32, numpy=4.0>)

Varsayılan eşitlik operatörünü geçersiz kılma ( __eq__ )

Uzantı türleri için varsayılan __eq__ operatörünü geçersiz kılabilirsiniz. Aşağıdaki örnek, eşitlik için karşılaştırırken maskelenmiş öğeleri yok sayacak şekilde MaskedTensor günceller.

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)
tutucu50 l10n-yer
tf.Tensor(True, shape=(), dtype=bool)

İleri referansları kullanma

Bir alanın türü henüz tanımlanmadıysa, bunun yerine türün adını içeren bir dize kullanabilirsiniz. Aşağıdaki örnekte, Node türü henüz (tam olarak) tanımlanmadığından alt alana açıklama eklemek için " children "Node" dizesi kullanılmıştır.

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

Node(3, [Node(5), Node(2)])
tutucu52 l10n-yer
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=())))

Alt sınıfları tanımlama

Uzantı türleri, standart Python sözdizimi kullanılarak alt sınıflara ayrılabilir. Uzantı türü alt sınıfları yeni alanlar, yöntemler ve özellikler ekleyebilir; ve yapıcıyı, yazdırılabilir gösterimi ve eşitlik operatörünü geçersiz kılabilir. Aşağıdaki örnek, düğümler arasındaki bir dizi kenarı kodlamak için üç Tensor alanı kullanan temel bir TensorGraph sınıfını tanımlar. Ardından, her düğüm için bir "özellik değeri" kaydetmek için bir Tensor alanı ekleyen bir alt sınıf tanımlar. Alt sınıf ayrıca özellik değerlerini kenarlar boyunca yaymak için bir yöntem tanımlar.

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)
tutucu54 l10n-yer
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)

Özel alanları tanımlama

Bir uzantı türünün alanları, bir alt çizgi ile önek eklenerek özel olarak işaretlenebilir (standart Python kurallarına göre). Bu, TensorFlow'un alanları herhangi bir şekilde ele alma şeklini etkilemez; ancak uzantı türündeki tüm kullanıcılara bu alanların özel olduğuna dair bir sinyal görevi görür.

ExtensionType'ın TypeSpec Özelleştirme

Her ExtensionType sınıfı, otomatik olarak oluşturulan ve <extension_type_name>.Spec olarak depolanan karşılık gelen bir TypeSpec sınıfına sahiptir. Daha fazla bilgi için yukarıdaki "İç içe TypeSpec" bölümüne bakın.

TypeSpec özelleştirmek için, Spec adlı kendi iç içe sınıfınızı tanımlamanız yeterlidir; ExtensionType bunu otomatik olarak oluşturulan TypeSpec için temel olarak kullanır. Spec sınıfını şu şekilde özelleştirebilirsiniz:

  • Varsayılan yazdırılabilir gösterimi geçersiz kılma.
  • Varsayılan yapıcıyı geçersiz kılma.
  • Yöntemleri, sınıf yöntemlerini, statik yöntemleri ve özellikleri tanımlama.

Aşağıdaki örnek, kullanımı kolaylaştırmak için MaskedTensor.Spec sınıfını özelleştirir:

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)

Tensör API gönderimi

Uzantı türleri, tf.Tensor türü tarafından tanımlanan arabirimi uzmanlaştırmaları veya genişletmeleri anlamında "tensör benzeri" olabilir. Tensör benzeri uzantı türlerinin örnekleri arasında RaggedTensor , SparseTensor ve MaskedTensor . Gönderim dekoratörleri , tensör benzeri uzantı türlerine uygulandığında TensorFlow işlemlerinin varsayılan davranışını geçersiz kılmak için kullanılabilir. TensorFlow şu anda üç dağıtım dekoratörü tanımlamaktadır:

Tek bir API için sevk

tf.experimental.dispatch_for_api dekoratörü, belirtilen imza ile çağrıldığında belirtilen bir TensorFlow işleminin varsayılan davranışını geçersiz kılar. Örneğin, tf.stack'in MaskedTensor değerlerini nasıl tf.stack gerektiğini belirtmek için bu dekoratörü kullanabilirsiniz:

@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))

Bu, bir MaskedTensor değerleri listesiyle çağrıldığında tf.stack için varsayılan uygulamayı geçersiz kılar (çünkü values bağımsız değişkeni typing.List[MaskedTensor] ile açıklamalıdır):

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

tf.stack karışık MaskedTensor ve Tensor değerlerinin listelerini işlemesine izin vermek için, values parametresi için tür açıklamasını hassaslaştırabilir ve işlevin gövdesini uygun şekilde güncelleyebilirsiniz:

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])
tutucu60 l10n-yer
<MaskedTensor [[1, 2, _], [4, 5, 6], [1, 2, _]]>

Geçersiz kılınabilecek API'lerin listesi için tf.experimental.dispatch_for_api için API belgelerine bakın.

Tüm unary elementwise API'leri için sevk

tf.experimental.dispatch_for_unary_elementwise_apis dekoratörü, ilk bağımsız değişkenin değeri (tipik olarak x olarak adlandırılır) tür ek açıklaması x_type ile eşleştiğinde, tüm tekli öğesel işlemlerin ( tf.math.cos gibi) varsayılan davranışını geçersiz kılar. Dekore edilmiş işlev iki argüman almalıdır:

  • api_func : Tek bir parametre alan ve eleman bazında işlemi gerçekleştiren bir fonksiyon (örneğin, tf.abs ).
  • x : Elementwise işleminin ilk argümanı.

Aşağıdaki örnek, MaskedTensor türünü işlemek için tüm tekli öğe işlemlerini günceller:

@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)

Bu işlev artık bir MaskedTensor üzerinde tekli eleman bazında bir işlem çağrıldığında kullanılacaktır.

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

Tüm elementwise API'leri için ikili gönderim

Benzer şekilde, tf.experimental.dispatch_for_binary_elementwise_apis , MaskedTensor türünü işlemek için tüm ikili öğe tabanlı işlemleri güncellemek için kullanılabilir:

@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)
-yer tutucu68 l10n-yer
<MaskedTensor [[5, _, 1], [_, _, _]]>

Geçersiz kılınan öğe tabanlı API'lerin listesi için tf.experimental.dispatch_for_unary_elementwise_apis ve tf.experimental.dispatch_for_binary_elementwise_apis için API belgelerine bakın.

Toplu Uzantı Türleri

Bir dizi değeri temsil etmek için tek bir örnek kullanılabiliyorsa, ExtensionType toplu işlenebilir . Tipik olarak bu, tüm iç içe Tensor toplu boyutlar eklenerek gerçekleştirilir. Aşağıdaki TensorFlow API'leri, herhangi bir uzantı türü girdisinin toplu hale getirilebilir olmasını gerektirir:

Varsayılan olarak BatchableExtensionType , iç içe geçmiş Tensor s, CompositeTensor s ve ExtensionType s'yi toplu işleyerek toplu değerler oluşturur. Bu, sınıfınız için uygun değilse, bu varsayılan davranışı geçersiz kılmak için tf.experimental.ExtensionTypeBatchEncoder kullanmanız gerekecektir. Örneğin, ayrı ayrı seyrek tensörlerin values , indices ve dense_shape alanlarını basitçe istifleyerek bir tf.SparseTensor değerleri toplu işi oluşturmak uygun olmaz - çoğu durumda, uyumsuz şekillere sahip oldukları için bu tensörleri istifleyemezsiniz. ; ve yapabilseniz bile sonuç geçerli bir SparseTensor .

BatchableExtensionType örneği: Ağ

Örnek olarak, yük dengeleme için kullanılan, her düğümde ne kadar iş kaldığını ve işi düğümler arasında taşımak için ne kadar bant genişliğinin mevcut olduğunu izleyen basit bir Network sınıfını ele alalım:

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]])

Bu türü toplu hale getirmek için temel türü BatchableExtensionType olarak değiştirin ve her alanın şeklini isteğe bağlı toplu iş boyutlarını içerecek şekilde ayarlayın. Aşağıdaki örnek, toplu iş şeklini takip etmek için bir shape alanı da ekler. Bu shape alanı tf.data.Dataset veya tf.map_fn tarafından gerekli değildir, ancak tf.Keras tarafından gereklidir.

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}")
-yer tutucu72 l10n-yer
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.]]]>

Ardından, bir grup ağda yineleme yapmak için tf.data.Dataset kullanabilirsiniz:

dataset = tf.data.Dataset.from_tensor_slices(batch_of_networks)
for i, network in enumerate(dataset):
  print(f"Batch element {i}: {network}")
tutucu74 l10n-yer
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.]]>

Ayrıca her toplu iş öğesine bir işlev uygulamak için map_fn de kullanabilirsiniz:

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)
tutucu76 l10n-yer
<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.]]]>

ExtensionTypes'ı destekleyen TensorFlow API'leri

@tf.fonksiyon

tf.function , TensorFlow kodunuzun performansını önemli ölçüde artırabilen Python işlevleri için TensorFlow grafiklerini önceden hesaplayan bir dekoratördür. Uzantı tipi değerleri, @tf.function -decorated fonksiyonları ile şeffaf olarak kullanılabilir.

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)
tutucu78 l10n-yer
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([1. , 0.3], dtype=float32)>

input_signature için tf.function açıkça belirtmek istiyorsanız, uzantı türünün TypeSpec kullanarak bunu yapabilirsiniz.

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)
tutucu80 l10n-yer
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)>)

somut fonksiyonlar

Somut işlevler, tf.function tarafından oluşturulan tek tek izlenen grafikleri kapsar. Uzatma türleri, somut işlevlerle şeffaf bir şekilde kullanılabilir.

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

Kontrol akışı işlemleri

Uzantı türleri, TensorFlow'un kontrol akışı işlemleri tarafından desteklenir:

# 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]>
yer tutucu85 l10n-yer
# 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, _]>

İmza kontrol akışı

Uzantı türleri, tf.function içindeki (imza kullanılarak) kontrol akışı ifadeleri tarafından da desteklenir. Aşağıdaki örnekte, if deyimi ve for deyimleri, uzantı türlerini destekleyen tf.cond ve tf.while_loop işlemlerine otomatik olarak dönüştürülür.

@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)))
tutucu88 l10n-yer
<MaskedTensor [_, 0.5, _]>
<MaskedTensor [4.5, _, 6.5]>

Keras

tf.keras , derin öğrenme modelleri oluşturmak ve eğitmek için TensorFlow'un üst düzey API'sidir. Uzantı türleri bir Keras modeline girdi olarak geçirilebilir, Keras katmanları arasında geçirilebilir ve Keras modelleri tarafından döndürülebilir. Keras şu anda uzantı türlerine iki gereksinim getiriyor:

  • Toplu hale getirilebilir olmalıdırlar (yukarıdaki "Toplu Uzantı Türleri" bölümüne bakın).
  • shape adında bir alan veya özelliğe sahip olmalıdır. shape[0] 'in parti boyutu olduğu varsayılır.

Aşağıdaki iki alt bölümde, Keras ile uzantı türlerinin nasıl kullanılabileceğini gösteren örnekler verilmektedir.

Keras örneği: Network

İlk örnek için, düğümler arasında yük dengeleme çalışması için kullanılabilecek, yukarıdaki "Toplu Uzantı Türleri" bölümünde tanımlanan Network sınıfını düşünün. Tanımı burada tekrarlanır:

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)
tutucu90 l10n-yer
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]]])

Network leri işleyen yeni bir Keras katmanı tanımlayabilirsiniz.

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)

Daha sonra basit bir model oluşturmak için bu katmanları kullanabilirsiniz. Bir ExtensionType Türü'nü bir modele beslemek için, uzantı türünün TypeSpec type_spec ayarlanmış bir tf.keras.layer.Input katmanı kullanabilirsiniz. Partileri işlemek için Keras modeli kullanılacaksa, type_spec toplu iş boyutunu içermelidir.

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(),
    ])

Son olarak, modeli tek bir ağa ve bir grup ağa uygulayabilirsiniz.

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.]]>
yer tutucu95 l10n-yer
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.]]]>

Keras örneği: MaskedTensor

Bu örnekte, MaskedTensor Keras şekilde genişletilmiştir. shape , values alanından hesaplanan bir özellik olarak tanımlanır. Keras, bu özelliği hem uzantı türüne hem de TypeSpec eklemenizi gerektirir. MaskedTensor ayrıca SavedModel serileştirme için gerekli olacak bir __name__ değişkeni tanımlar (aşağıda).

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))

Ardından, birkaç TensorFlow API'sinin varsayılan davranışını geçersiz kılmak için gönderme dekoratörleri kullanılır. Bu API'ler standart Keras katmanları ( Dense katmanı gibi) tarafından kullanıldığından, bunları geçersiz kılmak, bu katmanları MaskedTensor ile kullanmamıza izin verecektir. Bu örneğin amaçları doğrultusunda, maskeli tensörler için matmul , maskelenmiş değerleri sıfır olarak ele almak (yani bunları ürüne dahil etmemek) için tanımlanmıştır.

@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)

Ardından, standart Keras katmanlarını kullanarak MaskedTensor girdilerini kabul eden bir Keras modeli oluşturabilirsiniz:

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))
-yer tutucu101 l10n-yer
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)

Kayıtlı Model

SavedModel , hem ağırlıkları hem de hesaplamayı içeren serileştirilmiş bir TensorFlow programıdır. Bir Keras modelinden veya özel bir modelden oluşturulabilir. Her iki durumda da uzantı türleri, SavedModel tarafından tanımlanan işlevler ve yöntemlerle şeffaf bir şekilde kullanılabilir.

SavedModel, uzantı türleri bir __name__ alanına sahip olduğu sürece uzantı türlerini işleyen modelleri, katmanları ve işlevleri kaydedebilir. Bu ad, uzantı türünü kaydetmek için kullanılır, böylece model yüklendiğinde bulunabilir.

Örnek: bir Keras modelini kaydetme

Uzantı türlerini kullanan SavedModel modelleri SavedModel kullanılarak kaydedilebilir.

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)
tutucu103 l10n-yer
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)>

Örnek: özel bir modeli kaydetme

SavedModel, uzantı türlerini işleyen işlevlerle özel tf.Module alt sınıflarını kaydetmek için de kullanılabilir.

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]))
tutucu105 l10n-yer
INFO:tensorflow:Assets written to: /tmp/tmp2x8zq5kb/assets
INFO:tensorflow:Assets written to: /tmp/tmp2x8zq5kb/assets
<MaskedTensor [_, 200.0, _]>

ExtensionType kullanılamadığında SavedModel yükleme

ExtensionType kullanan ancak bu ExtensionType mevcut olmayan (yani içe aktarılmamış) bir SavedModel yüklerseniz, bir uyarı görürsünüz ve TensorFlow "anonim uzantı türü" nesnesini kullanmaya geri döner. Bu nesne, orijinal türle aynı alanlara sahip olacak, ancak tür için eklediğiniz özel yöntemler veya özellikler gibi başka özelleştirmelerden yoksun olacak.

TensorFlow sunumuyla ExtensionTypes'ı kullanma

Şu anda, TensorFlow hizmeti (ve SavedModel "imzalar" sözlüğünün diğer tüketicileri), tüm girdilerin ve çıktıların ham tensör olmasını gerektirir. Uzantı türlerini kullanan bir modelle TensorFlow hizmetini kullanmak istiyorsanız, uzantı türü değerlerini tensörlerden oluşturan veya ayrıştıran sarmalayıcı yöntemler ekleyebilirsiniz. Örneğin:

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)
tutucu107 l10n-yer
INFO:tensorflow:Assets written to: /tmp/tmpxhh4zh0i/assets
INFO:tensorflow:Assets written to: /tmp/tmpxhh4zh0i/assets
<tf.Tensor: shape=(), dtype=float32, numpy=12.0>

veri kümeleri

tf.data , basit, yeniden kullanılabilir parçalardan karmaşık girdi ardışık düzenleri oluşturmanıza olanak sağlayan bir API'dir. Temel veri yapısı, her öğenin bir veya daha fazla bileşenden oluştuğu bir dizi öğeyi temsil eden tf.data.Dataset .

Uzantı türleriyle Veri Kümeleri Oluşturma

Veri kümeleri, Dataset.from_tensors , Dataset.from_tensor_slices veya Dataset.from_generator kullanılarak uzantı türü değerlerinden oluşturulabilir:

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]>

Uzantı türleriyle Veri Kümelerini toplu işleme ve toplulaştırmayı kaldırma

Uzantı türlerine sahip veri kümeleri, Dataset.batch ve Dataset.unbatch kullanılarak toplu ve toplu işlenmemiş olabilir.

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]]>
yer tutucu116 l10n-yer
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]>