Yardım Kaggle üzerinde TensorFlow ile Büyük Bariyer Resifi korumak Meydan Üyelik

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. Bu, (örneğin her iki üst düzey API'ler içerir Keras , tf.function , tf.SavedModel ve (örneğin, daha düşük seviyeli API'leri) tf.while_loop ve tf.concat ). TensorFlow uzantı çeşitleri bu sorunsuz TensorFlow API'leri ile çalışma kullanıcı tanımlı nesne yönelimli türleri oluşturmak için de kullanılabilir. Uzatma türünü oluşturmak için, bir Python sınıfı tanımlamak tf.experimental.ExtensionType üssü olarak ve kullanımı tipi ek açıklamaları her bir alan için türünü belirtmek için.

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

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

  • Veri yapıları, grup birlikte bağlı bir değerler toplama ve bu değerlere dayalı olarak faydalı işlemleri sağlayabilir. Veri yapıları (örneğin, oldukça genel olabilir TensorGraph örneğin yukarıdaki gibidir); veya belirli bir modele göre son derece özelleştirilebilirler.

  • Uzmanlaşmak ya kavramını genişletmek türleri, tensör benzeri "Tensörünün." Bu kategoride Tipleri bir var rank , bir shape ve genellikle bir dtype ; ve (örneğin tensör işlemleri ile bunların kullanımı mantıklı tf.stack , tf.add veya tf.matmul ). MaskedTensor ve CSRSparseMatrix tensör benzeri türde örnekleridir.

Desteklenen API'ler

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

  • Keras: Uzatma türleri Keras için giriş ve çıkış olarak kullanılabilir Models ve Layers .
  • tf.data.Dataset: Uzatma tipleri dahil edilebilir Datasets ve veri kümesi tarafından döndürülen Iterators .
  • Tensorflow göbek: Uzatma tipleri için giriş ve çıkışlar olarak kullanılabilir tf.hub modüllerin.
  • SavedModel: Uzatma türleri için giriş ve çıkış olarak kullanılabilir SavedModel fonksiyonları.
  • tf.function: Uzatma türleri ile sarılmış fonksiyonlar için bağımsız değişken ve dönüş değerleri olarak kullanılabilir @tf.function dekoratör.
  • ise döngüler: Uzatma türleri döngü değişken olarak kullanılabilen tf.while_loop ve süre-döngüsünün gövdesi için bağımsız değişken ve geri dönüş değerleri olarak kullanılabilir.
  • conditionals: Uzatma tipleri şartlı kullanılarak seçilebilir tf.cond ve tf.case .
  • py_function: Uzatma tipleri için argümanlar ve dönüş değerleri olarak kullanılabilir func için argüman tf.py_function .
  • Tensör ops: Uzatma tipleri tensör girişlerini (örneğin, kabul en TensorFlow op desteklemek için uzatılabilir 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: Uzatma tipleri başına kopya değerleri 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 booleanları 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 Alınmış 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, yerine bir tanımlamak yerine set_mask bir mutasyona yöntemi MaskedTensor , bir tanımlayabiliriz replace_mask yöntemi döndürdüğü yeni 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)

İşlevsellik tarafından eklenen ExtensionType

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

  • Bir yapıcı ( __init__ ).
  • Basılabilir temsil yöntemi ( __repr__ ).
  • Eşitlik ve eşitsizlik operatörleri ( __eq__ ).
  • Bir doğrulama yöntemi ( __validate__ ).
  • Zorunlu değişmezlik.
  • Bir iç içe TypeSpec .
  • Tensör 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ı

Tarafından eklenen yapıcı ExtensionType adlandırılmış değişken olarak, her bir alan (sırayla, sınıf tanımında listelenmiş) alır. Bu kurucu, her bir parametreyi tip-kontrol edecek ve gerektiğinde onları dönüştürecektir. Özellikle, Tensor alanları kullanılarak dönüştürülür tf.convert_to_tensor ; Tuple alanları dönüştürülür tuple ler; ve Mapping alanlar değişmez dicts 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)
tf.Tensor(
[[1 2 3]
 [4 5 6]], shape=(2, 3), dtype=int32)

Yapıcı bir yükseltir TypeError bir alanı değeri, belirtilen türüne dönüştürülür edilemezse:

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

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>)
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 varsayılan yazdırılabilir temsil yöntemi (ekler __repr__ sınıf adı ve her bir alan için değeri içerir):

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

eşitlik operatörleri

ExtensionType varsayılan eşitlik operatörleri (ekleyen __eq__ ve __ne__ aynı tip ve tüm alanları eşitse iki değer eşit düşünün). 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}")
a == a: True
a == b: False
a == a.values: False

Doğrulama yöntemi

ExtensionType bir ekler __validate__ alanları doğrulama denetimleri gerçekleştirmek için geçersiz kılınabilir yöntem. 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.

o Örneğin aşağıdaki günceller MaskedTensor doğrulamak için shape ler ve dtype onun alanların s:

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 geçersiz kılar __setattr__ ve __delattr__ o uzatma türü değerleri iletmenin sağlanması mutasyonu önlemek için yöntemler.

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ı karşılık gelen bir yer alır TypeSpec otomatik olarak oluşturulur ve depolanır sınıfı, <extension_type_name>.Spec .

Bu sınıf herhangi yuvalanmış tensörlerinin değerler dışında bir değerden tüm bilgileri yakalar. Özellikle, TypeSpec değeri için olan bir iç içe tensör, ExtensionType veya CompositeTensor değiştirilmesiyle oluşturulan 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 değerleri açıkça yapılabilir, ya da bir inşa edilebilir ExtensionType kullanarak değeri tf.type_spec_from_value :

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

TypeSpec ler statik bileşen ve dinamik bir bileşeni haline bölmek değerlerine TensorFlow tarafından kullanılır:

  • (Grafik inşaat zamanda sabittir,) Statik bileşen ile kodlanan tf.TypeSpec .
  • (Grafik her çalıştırıldığında değişebilir) dinamik bileşen listesi olarak kodlanan tf.Tensor s.

Örneğin, tf.function bir argüman daha önce görülmemiş olan her onun sarılmış fonksiyonu izini 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>}))

Daha fazla bilgi için, bkz tf.function Kılavuzu .

Uzantı Türlerini Özelleştirme

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

  • Varsayılan yazdırılabilir temsilini (geçersiz kıl __repr__ ).
  • Yöntemleri tanımlayın.
  • Sınıf yöntemlerini ve statik yöntemleri tanımlayın.
  • Özellikleri tanımlayın.
  • Varsayılan kurucuyu (geçersiz kıl __init__ ).
  • Varsayılan eşitlik operatörü (geçersiz kıl __eq__ ).
  • (Örneğin operatörler tanımlama __add__ ve __lt__ ).
  • 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, güncelleştirir MaskedTensor değerleri istekli modunda basılmıştır zaman daha okunabilir bir dizge gösterimini oluşturmak için sınıf.

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

yöntemleri tanımlama

Uzantı türleri, herhangi bir normal Python sınıfı gibi yöntemleri tanımlayabilir. Örneğin, MaskedTensor tipi bir tanımlayabiliriz with_default bir kopyası döndürdüğü yöntemi self maskeli değerlerle belirli bir yerine default değeri. Yöntem, isteğe bağlı olarak ek not edilebilir @tf.function dekoratör.

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

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

Uzatma türleri yöntemler kullanılarak tanımlayabilir @classmethod ve @staticmethod dekoratör. Örneğin, MaskedTensor bir fabrika yöntemi tanımlayabilir maskeleri, belirli bir değere sahip olan her eleman:

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

özellikleri tanımlama

Uzatma türleri kullanılarak özelliklerini tanımlayabilir @property sadece her normal Python sınıf gibi, dekoratör. Örneğin, MaskedTensor tipi tanımlayabilir dtype değerlerinin d_type için bir kısaltmadır özellik:

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

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

Uzantı türleri için varsayılan kurucuyu geçersiz kılabilirsiniz. Özel oluşturucular, bildirilen 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!
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))
Toy(name='ball', price=<tf.Tensor: shape=(), dtype=float32, numpy=4.0>)

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

Varsayılan geçersiz kılabilirsiniz __eq__ uzatma türleri için operatöre. Takip örneği günceller MaskedTensor eşitlik için karşılaştırırken maskeli unsurları göz ardı etmek.

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)

İ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, dize "Node" not eklemek için kullanılır children nedeniyle alanını Node tipi olmamıştır (tam) henüz tanımlanmış.

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

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, basit bir tanımlayan TensorGraph kullanımları üç bu sınıfı Tensor alanları düğümler arasındaki kenarlar, bir dizi kodlamak. Bu daha sonra bir ekleyen bir alt sınıfını tanımlar Tensor her bir düğüm için bir "özelliği değeri" kayıt alanı. 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)
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 en Özelleştirme TypeSpec

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

Özelleştirmek için TypeSpec sadece kendi iç içe sınıf adında tanımlamak, Spec ve ExtensionType otomatik inşa için temel olarak kullanacaktır TypeSpec . Sen özelleştirebilirsiniz Spec sınıfı tarafından:

  • 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 özelleştirir MaskedTensor.Spec daha kolay kullanmak hale getirmek için sınıf:

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

Uzatma türlerini uzmanlaşmak ya tarafından tanımlanan arayüz uzatmak anlamında, "tensör benzeri" olabilir tf.Tensor türü. Tensör benzeri uzantı türleri örnekleri arasında RaggedTensor , SparseTensor ve MaskedTensor . Tensör benzeri uzantı türleri uygulandığında Sevk dekoratörler TensorFlow operasyonları 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 imzası ile çağrılan bir Belirtilen TensorFlow operasyonu varsayılan davranışını geçersiz kılar. Örneğin, nasıl belirtmek için bu dekoratör kullanabilirsiniz tf.stack işlemek gerekir MaskedTensor değerleri:

@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 varsayılan uygulama geçersiz kılan tf.stack o listesiyle çağrıldığında MaskedTensor (beri değerlerle values argümanı ile açıklamalı 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]]>

İzin vermek için tf.stack karışık tanıtıcısı listelerine MaskedTensor ve Tensor değerler, sizin için tipi notunu geliştirebilirsiniz values parametre ve uygun fonksiyonun gövdesini güncelleyin:

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

Geçersiz kılınan olabilir API'leri listesi için, API belgelerine bakın tf.experimental.dispatch_for_api .

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

tf.experimental.dispatch_for_unary_elementwise_apis (gibi tüm tekli elementwise ops dekoratör geçersiz kılar varsayılan davranış tf.math.cos ilk argüman (tipik adlandırılmış değeri her) x ) tipi açıklama maçları x_type . Dekore edilmiş işlev iki argüman almalıdır:

  • api_func : tek bir parametre ve gerçekleştirir elementwise işlem (örneğin, alan bir fonksiyon tf.abs ).
  • x : elementwise işlemi ilk değişken.

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

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

Bir tek terimli elementwise işlemi çağrıldığında girdiğinde bu işlevi artık kullanılan olacaktır 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]>

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

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

@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], [_, _, _]]>

Geçersiz kılınan elementwise API'leri listesi için, API belgelerine bakın tf.experimental.dispatch_for_unary_elementwise_apis ve tf.experimental.dispatch_for_binary_elementwise_apis .

Toplu Uzantı Türleri

Bir ExtensionType tek bir örnek değerlerinin bir toplu temsil etmek için kullanılabilir eğer batchable olup. Tipik haliyle, bu tüm iç içe toplu boyutları ekleyerek gerçekleştirilir Tensor s. Aşağıdaki TensorFlow API'leri, herhangi bir uzantı türü girdisinin toplu hale getirilebilmesini gerektirir:

Varsayılan olarak, BatchableExtensionType herhangi yuvalanmış harmanlanmasından tarafından toplu iş değerleri oluşturur Tensor , s CompositeTensor ler ve ExtensionType s. Bu sınıf için uygun değilse, o zaman kullanmanız gerekecektir tf.experimental.ExtensionTypeBatchEncoder bu varsayılan davranışı geçersiz kılmak için. Örneğin, bir toplu oluşturmak uygun olmaz tf.SparseTensor sadece bireysel seyrek tensörlerle yığarak değerler values , indices ve dense_shape alanları - onlar uyumsuz biçimlere sahip olduğundan çoğu durumda, sen, bu tensörleri yığamaz ; Hatta eğer yapabilirsen ve sonuç geçerli olmaz SparseTensor .

BatchableExtensionType örneği: Ağ

Bir örnek olarak, basit bir düşünün Network çok iş her düğüm noktasında yapılacak Geriye ne izler yük dengeleme için kullanılan sınıfı ve ne kadar bant genişliği düğüm arasında hareket etmek mevcuttur:

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 batchable yapmak için taban türünü değiştirmek için BatchableExtensionType ve isteğe bağlı kesikli boyutları dahil etmek için her bir alanın şeklini ayarlamak. Şu örnek de ekler shape toplu şeklin keept parçaya alanını. Bu shape alan tarafından gerekli değildir tf.data.Dataset veya tf.map_fn , ancak gerektirdiği 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.]]]>

Daha sonra kullanabilirsiniz tf.data.Dataset ağların toplu yinelemenize:

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

Ve ayrıca kullanabilirsiniz map_fn her parti elemana bir işlev uygulamak için:

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

ExtensionTypes'ı destekleyen TensorFlow API'leri

@tf.fonksiyon

tf.function bir dekoratör olduğunu esasen sizin TensorFlow kod performansını artırabilirsiniz Python fonksiyonları için precomputes TensorFlow grafikler. Uzatma türü değerleri şeffaf kullanılabilir @tf.function -dekore fonksiyonları.

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

Açıkça belirtmek isterseniz input_signature için tf.function , o zaman uzatma türünün kullanarak bunu yapabilirsiniz 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)>)

somut fonksiyonlar

Beton fonksiyonlar tarafından inşa edilir bireysel takip grafikler saklanması tf.function . Uzatma türleri, somut işlevlerle şeffaf bir şekilde kullanılabilir.

cf = combine_pastry_features.get_concrete_function(pastry_spec)
cf(cookie)
<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]>
# 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 kontrol akışı ifadeleri tarafından da desteklenir (imza kullanılarak). Aşağıdaki örnekte, if deyim ve for ifadeleri otomatik dönüştürülür tf.cond ve tf.while_loop işlemleri, destek uzantı türleri.

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

Keras

tf.keras bina ve derin öğrenme modellerini eğitimi için TensorFlow en üst düzey API'sıdır. 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:

  • Bunlar toplulaştırılabilir olmalıdır (yukarıdaki "Toplu Uzantı Türleri" bölümüne bakın).
  • Bir alan veya özellik adında olmalıdır shape . shape[0] 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 örnek: Network

İlk Örneğin, düşünün Network yük düğüm arasında dengeleme için kullanılabilecek yukarıdaki "batchable ExtensionTypes" bölümünde tanımlanan sınıf,. 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)
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]]])

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

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 beslemek için ExtensionType bir model haline, bir kullanabilirsiniz tf.keras.layer.Input ile katmanı type_spec uzatma türünün için sette TypeSpec . Keras modeli süreç gruplar için kullanılacaksa, o zaman type_spec toplu boyut bulunması gerekir.

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.]]>
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 desteklemek için genişletilmiştir Keras . shape hesaplanan bir özelliği olarak tanımlanır values alan. Keras thatyou uzantısı türüne ve hem bu özelliği eklemek gerekir TypeSpec . MaskedTensor da tanımlar __name__ için gerekli olacaktır değişken SavedModel seri (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 (örneğin standart Keras tabakalar tarafından kullanıldığı için Dense bir tabaka), bu ağır basan bizi olan katmanları kullanmak sağlayacak MaskedTensor . Bu örneğin amaçları için, matmul maskeli tensörlerin (ürünün bunları içermez, yani) sıfır olarak maskelenmiş değerleri tedavi etmek 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)

Daha sonra kabul eden bir Keras modeli oluşturmak için MaskedTensor standart Keras katmanları kullanarak, giriş:

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)

Kayıtlı Model

Bir SavedModel ağırlıkları ve hesaplama her iki dahil olmak üzere, bir seri 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 süreç uzantı türlerini sürece uzatma türleri olduğunu modelleri, katmanları ve fonksiyonları kaydedebilirsiniz __name__ alanını. Bu ad, uzantı türünü kaydetmek için kullanılır, böylece model yüklendiğinde bulunabilir.

Örnek: bir Keras modelini kaydetme

Uzatma türlerini kullanmak Keras modelleri kullanılarak kaydedilmiş olabilir 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)>

Örnek: özel bir modeli kaydetme

SavedModel Ayrıca özel kaydetmek için kullanılabilir tf.Module süreci uzantı türleri olduğunu fonksiyonları ile alt sınıfları.

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

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

Eğer bir yüklerseniz SavedModel bir kullanır ExtensionType , ama bu ExtensionType (yani ithal edilmemiştir) mevcut değildir, o zaman bir uyarı görür ve TensorFlow bir "anonim uzantısı türü" nesnesini kullanarak geri düşecek. 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 hizmet veren (ve SavedModel "imzalar" Sözlüğün diğer tüketiciler) tüm giriş ve çıkışlar ham tansörler 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)
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 Eğer basit karmaşık girdi boru hatlarına, yeniden kullanılabilir parçaları oluşturmak için sağlayan bir API olduğunu. Çekirdek veri yapısıdır tf.data.Dataset her bir eleman, bir ya da daha fazla bileşenden oluştuğu elemanların bir sekans temsil eder.

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

Veri kümeleri kullanarak uzantı türü değerlerinden inşa edilebilir Dataset.from_tensors , Dataset.from_tensor_slices veya 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]>

Uzantı türleriyle Veri Kümelerini gruplama ve toplulaştırmayı kaldırma

Uzatma türleriyle Veri Setleri kullanarak batchand ve unbatched olabilir Dataset.batch adn 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]>