प्रीप्रोसेसिंग परतों के साथ काम करना

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

केरस प्रीप्रोसेसिंग परतें

केरस प्रीप्रोसेसिंग लेयर्स एपीआई डेवलपर्स को केरस-देशी इनपुट प्रोसेसिंग पाइपलाइन बनाने की अनुमति देता है। इन इनपुट प्रोसेसिंग पाइपलाइनों का उपयोग गैर-केरस वर्कफ़्लोज़ में स्वतंत्र प्रीप्रोसेसिंग कोड के रूप में किया जा सकता है, जो सीधे केरस मॉडल के साथ संयुक्त होता है, और केरस सेव्डमॉडल के हिस्से के रूप में निर्यात किया जाता है।

केरस प्रीप्रोसेसिंग परतों के साथ, आप ऐसे मॉडल बना और निर्यात कर सकते हैं जो वास्तव में एंड-टू-एंड हैं: ऐसे मॉडल जो कच्ची छवियों या कच्चे संरचित डेटा को इनपुट के रूप में स्वीकार करते हैं; ऐसे मॉडल जो फीचर नॉर्मलाइजेशन या फीचर वैल्यू इंडेक्सिंग को अपने दम पर हैंडल करते हैं।

उपलब्ध प्रीप्रोसेसिंग परतें

कोर प्रीप्रोसेसिंग परतें

  • TextVectorization परत: एक एन्कोड प्रतिनिधित्व है कि एक द्वारा पढ़ा जा सकता में कच्चे तार बदल जाता है Embedding परत या Dense परत।
  • Normalization परत: प्रदर्शन सुविधा के लिहाज से इनपुट सुविधाओं के सामान्य।

संरचित डेटा प्रीप्रोसेसिंग परतें

ये परतें संरचित डेटा एन्कोडिंग और फीचर इंजीनियरिंग के लिए हैं।

  • CategoryEncoding , एक गर्म बहु गर्म, या TF-आईडीएफ घने अभ्यावेदन में स्पष्ट सुविधाओं पूर्णांक बदल जाता है: परत।
  • Hashing परत: प्रदर्शन स्पष्ट सुविधा हैशिंग, जिसे "हैशिंग चाल" के रूप में जाना जाता है।
  • Discretization परत: स्पष्ट सुविधाओं पूर्णांक में निरंतर संख्यात्मक सुविधाओं बदल जाता है।
  • StringLookup परत: पूर्णांकों सूचकांकों में स्ट्रिंग स्पष्ट मूल्यों बदल जाता है।
  • IntegerLookup परत: बदल जाता है पूर्णांक सूचकांक में स्पष्ट मूल्यों पूर्णांक।
  • CategoryCrossing परत: सह-घटना सुविधाओं में स्पष्ट सुविधाओं को जोड़ती है। उदाहरण के लिए यदि आपके पास "ए" और "बी" फीचर मान हैं, तो यह संयोजन सुविधा प्रदान कर सकता है "ए और बी एक ही समय में मौजूद हैं"।

छवि प्रीप्रोसेसिंग परतें

ये परतें एक छवि मॉडल के इनपुट को मानकीकृत करने के लिए हैं।

  • Resizing परत: एक लक्ष्य आकार के लिए छवियों का एक बैच आकार बदलता है।
  • Rescaling परत: rescales और ऑफसेट छवि का एक बैच के मूल्यों (जैसे में आदानों से जाना [0, 255] में आदानों की रेंज [0, 1] रेंज।
  • CenterCrop परत: छवियों का एक बैच का एक केंद्र फसल देता है।

छवि डेटा वृद्धि परतें

ये परतें छवियों के एक बैच में यादृच्छिक संवर्द्धन परिवर्तन लागू करती हैं। वे प्रशिक्षण के दौरान ही सक्रिय रहते हैं।

  • RandomCrop परत
  • RandomFlip परत
  • RandomTranslation परत
  • RandomRotation परत
  • RandomZoom परत
  • RandomHeight परत
  • RandomWidth परत

adapt() विधि

कुछ प्रीप्रोसेसिंग परतों में एक आंतरिक स्थिति होती है जिसे प्रशिक्षण डेटा के नमूने के आधार पर गणना की जानी चाहिए। स्टेटफुल प्रीप्रोसेसिंग लेयर्स की सूची है:

  • TextVectorization : स्ट्रिंग टोकन और पूर्णांक सूचकांक के बीच एक मैपिंग रखती है
  • Normalization : सुविधाओं के माध्य और मानक विचलन रखती है
  • StringLookup और IntegerLookup : इनपुट मानों और उत्पादन सूचकांक के बीच एक मैपिंग पकड़ो।
  • CategoryEncoding : इनपुट मानों के एक सूचकांक आयोजित करता है।
  • Discretization : मूल्य बाल्टी सीमाओं के बारे में जानकारी रखती है।

महत्वपूर्ण बात, इन परतों गैर trainable रहे हैं। उनका राज्य प्रशिक्षण के दौरान निर्धारित नहीं है; यह एक कदम "अनुकूलन" कहा जाता है प्रशिक्षण से पहले स्थापित होना चाहिये।

आप प्रशिक्षण डेटा के संपर्क में लाने से एक preprocessing परत की स्थिति निर्धारित करते हैं, के माध्यम से adapt() विधि:

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers.experimental import preprocessing

data = np.array([[0.1, 0.2, 0.3], [0.8, 0.9, 1.0], [1.5, 1.6, 1.7],])
layer = preprocessing.Normalization()
layer.adapt(data)
normalized_data = layer(data)

print("Features mean: %.2f" % (normalized_data.numpy().mean()))
print("Features std: %.2f" % (normalized_data.numpy().std()))
Features mean: 0.00
Features std: 1.00

adapt() विधि या तो एक Numpy सरणी या एक लेता है tf.data.Dataset वस्तु। के मामले में StringLookup और TextVectorization , आप भी स्ट्रिंग की एक सूची पारित कर सकते हैं:

data = [
    "ξεῖν᾽, ἦ τοι μὲν ὄνειροι ἀμήχανοι ἀκριτόμυθοι",
    "γίγνοντ᾽, οὐδέ τι πάντα τελείεται ἀνθρώποισι.",
    "δοιαὶ γάρ τε πύλαι ἀμενηνῶν εἰσὶν ὀνείρων:",
    "αἱ μὲν γὰρ κεράεσσι τετεύχαται, αἱ δ᾽ ἐλέφαντι:",
    "τῶν οἳ μέν κ᾽ ἔλθωσι διὰ πριστοῦ ἐλέφαντος,",
    "οἵ ῥ᾽ ἐλεφαίρονται, ἔπε᾽ ἀκράαντα φέροντες:",
    "οἱ δὲ διὰ ξεστῶν κεράων ἔλθωσι θύραζε,",
    "οἵ ῥ᾽ ἔτυμα κραίνουσι, βροτῶν ὅτε κέν τις ἴδηται.",
]
layer = preprocessing.TextVectorization()
layer.adapt(data)
vectorized_text = layer(data)
print(vectorized_text)
tf.Tensor(
[[37 12 25  5  9 20 21  0  0]
 [51 34 27 33 29 18  0  0  0]
 [49 52 30 31 19 46 10  0  0]
 [ 7  5 50 43 28  7 47 17  0]
 [24 35 39 40  3  6 32 16  0]
 [ 4  2 15 14 22 23  0  0  0]
 [36 48  6 38 42  3 45  0  0]
 [ 4  2 13 41 53  8 44 26 11]], shape=(8, 9), dtype=int64)

इसके अलावा, अनुकूलनीय परतें हमेशा कंस्ट्रक्टर तर्कों या वेट असाइनमेंट के माध्यम से सीधे राज्य को सेट करने के विकल्प को उजागर करती हैं। इरादा राज्य मूल्यों परत निर्माण समय में जाना जाता है, या के बाहर गणना कर रहे हैं, तो adapt() कॉल, वे परत के आंतरिक गणना पर निर्भर रहे बिना स्थापित किया जा सकता। उदाहरण के लिए, यदि के लिए बाहरी शब्दावली फ़ाइलों TextVectorization , StringLookup , या IntegerLookup परतों पहले से ही मौजूद है, उन सीधे देखने तालिका में परत के निर्माता तर्क में शब्दावली फाइल करने के लिए एक रास्ता पारित करके लोड किया जा सकता।

यहाँ एक उदाहरण है, जहां हम एक दृष्टांत है StringLookup precomputed शब्दावली के साथ परत:

vocab = ["a", "b", "c", "d"]
data = tf.constant([["a", "c", "d"], ["d", "z", "b"]])
layer = preprocessing.StringLookup(vocabulary=vocab)
vectorized_data = layer(data)
print(vectorized_data)
tf.Tensor(
[[2 4 5]
 [5 1 3]], shape=(2, 3), dtype=int64)

मॉडल से पहले या मॉडल के अंदर प्रीप्रोसेसिंग डेटा

प्रीप्रोसेसिंग परतों का उपयोग करने के दो तरीके हैं:

विकल्प 1: मॉडल, इस तरह की उन्हें हिस्सा बनाएं:

inputs = keras.Input(shape=input_shape)
x = preprocessing_layer(inputs)
outputs = rest_of_the_model(x)
model = keras.Model(inputs, outputs)

इस विकल्प के साथ, प्रीप्रोसेसिंग डिवाइस पर होगी, बाकी मॉडल निष्पादन के साथ समकालिक रूप से, जिसका अर्थ है कि यह GPU त्वरण से लाभान्वित होगा। आप तो GPU पर हैं प्रशिक्षण, इस के लिए सबसे अच्छा विकल्प है Normalization परत, और सभी छवि preprocessing और डेटा वृद्धि परतों के लिए।

विकल्प 2: अपने पर लागू tf.data.Dataset एक डाटासेट प्राप्त करने के लिए इतनी के रूप में, कि preprocessed डेटा, इस तरह की पैदावार बैचों:

dataset = dataset.map(
  lambda x, y: (preprocessing_layer(x), y))

इस विकल्प के साथ, आपका प्रीप्रोसेसिंग सीपीयू पर एसिंक्रोनस रूप से होगा, और मॉडल में जाने से पहले बफ़र किया जाएगा।

इस के लिए सबसे अच्छा विकल्प है TextVectorization , और सभी संरचित डेटा परतों preprocessing। यह एक अच्छा विकल्प भी हो सकता है यदि आप सीपीयू पर प्रशिक्षण ले रहे हैं और आप छवि प्रीप्रोसेसिंग परतों का उपयोग करते हैं।

अनुमान के समय मॉडल के अंदर प्रीप्रोसेसिंग करने के लाभ

यहां तक ​​कि अगर आप विकल्प 2 के साथ जाते हैं, तो आप बाद में एक अनुमान-केवल एंड-टू-एंड मॉडल निर्यात करना चाह सकते हैं जिसमें प्रीप्रोसेसिंग परतें शामिल होंगी। ऐसा करने के लिए महत्वपूर्ण लाभ यह है कि यह अपने मॉडल पोर्टेबल बनाता है और इसे कम करने में मदद करता है तिरछा सेवारत / प्रशिक्षण

जब सभी डेटा प्रीप्रोसेसिंग मॉडल का हिस्सा होता है, तो अन्य लोग इस बात से अवगत हुए बिना आपके मॉडल को लोड और उपयोग कर सकते हैं कि प्रत्येक सुविधा के एन्कोडेड और सामान्यीकृत होने की उम्मीद कैसे की जाती है। आपका अनुमान मॉडल कच्ची छवियों या कच्चे संरचित डेटा को संसाधित करने में सक्षम होगा, और मॉडल के उपयोगकर्ताओं को विवरण के बारे में जागरूक होने की आवश्यकता नहीं होगी, उदाहरण के लिए पाठ के लिए उपयोग की जाने वाली टोकन योजना, श्रेणीबद्ध सुविधाओं के लिए उपयोग की जाने वाली अनुक्रमण योजना, चाहे छवि पिक्सेल मान करने के लिए सामान्यीकृत कर रहे हैं [-1, +1] या करने के लिए [0, 1] , आदि यह विशेष रूप से शक्तिशाली है अगर आप इस तरह के TensorFlow.js के रूप में, एक और क्रम में अपने मॉडल को निर्यात कर रहे हैं: यदि आप अपने पूर्व प्रसंस्करण reimplement नहीं होगा जावास्क्रिप्ट में पाइपलाइन।

आरंभ में आप अपने में अपने preprocessing परतों डाल दिया tf.data पाइपलाइन, आप एक अनुमान मॉडल है कि संकुल पूर्व प्रसंस्करण निर्यात कर सकते हैं। बस एक नए मॉडल को इंस्टेंट करें जो आपकी प्रीप्रोसेसिंग परतों और आपके प्रशिक्षण मॉडल को जंजीर से बांधे:

inputs = keras.Input(shape=input_shape)
x = preprocessing_layer(inputs)
outputs = training_model(x)
inference_model = keras.Model(inputs, outputs)

त्वरित व्यंजन

छवि डेटा वृद्धि (डिवाइस पर)

ध्यान दें कि छवि डेटा वृद्धि परतों केवल सक्रिय प्रशिक्षण के दौरान (करने के लिए इसी तरह कर रहे हैं Dropout परत)।

from tensorflow import keras
from tensorflow.keras import layers

# Create a data augmentation stage with horizontal flipping, rotations, zooms
data_augmentation = keras.Sequential(
    [
        preprocessing.RandomFlip("horizontal"),
        preprocessing.RandomRotation(0.1),
        preprocessing.RandomZoom(0.1),
    ]
)

# Create a model that includes the augmentation stage
input_shape = (32, 32, 3)
classes = 10
inputs = keras.Input(shape=input_shape)
# Augment images
x = data_augmentation(inputs)
# Rescale image values to [0, 1]
x = preprocessing.Rescaling(1.0 / 255)(x)
# Add the rest of the model
outputs = keras.applications.ResNet50(
    weights=None, input_shape=input_shape, classes=classes
)(x)
model = keras.Model(inputs, outputs)

आप उदाहरण में कार्रवाई में एक समान सेटअप देख सकते हैं खरोंच से छवि वर्गीकरण

संख्यात्मक विशेषताओं का सामान्यीकरण

# Load some data
(x_train, y_train), _ = keras.datasets.cifar10.load_data()
x_train = x_train.reshape((len(x_train), -1))
input_shape = x_train.shape[1:]
classes = 10

# Create a Normalization layer and set its internal state using the training data
normalizer = preprocessing.Normalization()
normalizer.adapt(x_train)

# Create a model that include the normalization layer
inputs = keras.Input(shape=input_shape)
x = normalizer(inputs)
outputs = layers.Dense(classes, activation="softmax")(x)
model = keras.Model(inputs, outputs)

# Train the model
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")
model.fit(x_train, y_train)
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 11s 0us/step
1563/1563 [==============================] - 3s 1ms/step - loss: 2.1776
<tensorflow.python.keras.callbacks.History at 0x7f58c5f44208>

एक-हॉट एन्कोडिंग के माध्यम से एन्कोडिंग स्ट्रिंग श्रेणीबद्ध विशेषताएं

# Define some toy data
data = tf.constant(["a", "b", "c", "b", "c", "a"])

# Use StringLookup to build an index of the feature values
indexer = preprocessing.StringLookup()
indexer.adapt(data)

# Use CategoryEncoding to encode the integer indices to a one-hot vector
encoder = preprocessing.CategoryEncoding(output_mode="binary")
encoder.adapt(indexer(data))

# Convert new test data (which includes unknown feature values)
test_data = tf.constant(["a", "b", "c", "d", "e", ""])
encoded_data = encoder(indexer(test_data))
print(encoded_data)
tf.Tensor(
[[0. 0. 0. 0. 1.]
 [0. 0. 0. 1. 0.]
 [0. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [1. 0. 0. 0. 0.]], shape=(6, 5), dtype=float32)

ध्यान दें कि सूचकांक 0 मान (जो आप रिक्त स्ट्रिंग के रूप में निर्दिष्ट करना चाहिए लापता के लिए आरक्षित है "" ), और सूचकांक 1 आउट-ऑफ-शब्दावली मूल्यों के लिए आरक्षित है (मानों के दौरान नहीं देखा गया adapt() )। आप का उपयोग करके यह कॉन्फ़िगर कर सकते हैं mask_token और oov_token के निर्माता तर्क StringLookup

आप देख सकते हैं StringLookup और CategoryEncoding उदाहरण में कार्रवाई में परतों खरोंच से संरचित डेटा वर्गीकरण

एक-हॉट एन्कोडिंग के माध्यम से पूर्णांक श्रेणीबद्ध सुविधाओं को एन्कोड करना

# Define some toy data
data = tf.constant([10, 20, 20, 10, 30, 0])

# Use IntegerLookup to build an index of the feature values
indexer = preprocessing.IntegerLookup()
indexer.adapt(data)

# Use CategoryEncoding to encode the integer indices to a one-hot vector
encoder = preprocessing.CategoryEncoding(output_mode="binary")
encoder.adapt(indexer(data))

# Convert new test data (which includes unknown feature values)
test_data = tf.constant([10, 10, 20, 50, 60, 0])
encoded_data = encoder(indexer(test_data))
print(encoded_data)
tf.Tensor(
[[0. 0. 0. 1. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [1. 0. 0. 0. 0.]], shape=(6, 5), dtype=float32)

ध्यान दें कि सूचकांक 0 मान अनुपलब्ध के लिए आरक्षित है (जो आप मान 0 के रूप में निर्दिष्ट करना चाहिए), और सूचकांक 1 आउट-ऑफ-शब्दावली मूल्यों के लिए आरक्षित है (मानों के दौरान नहीं देखा गया adapt() )। आप का उपयोग करके यह कॉन्फ़िगर कर सकते हैं mask_value और oov_value के निर्माता तर्क IntegerLookup

आप देख सकते हैं IntegerLookup और CategoryEncoding उदाहरण में कार्रवाई में परतों खरोंच से संरचित डेटा वर्गीकरण

हैशिंग ट्रिक को एक पूर्णांक श्रेणीबद्ध विशेषता पर लागू करना

यदि आपके पास एक स्पष्ट विशेषता है जो कई अलग-अलग मान (10e3 या उच्चतर के क्रम पर) ले सकती है, जहां प्रत्येक मान डेटा में केवल कुछ ही बार दिखाई देता है, तो यह इंडेक्स के लिए अव्यवहारिक और अप्रभावी हो जाता है और एक-हॉट फीचर मानों को एन्कोड करता है। इसके बजाय, "हैशिंग ट्रिक" लागू करना एक अच्छा विचार हो सकता है: हैश मानों को निश्चित आकार के वेक्टर में। यह सुविधा स्थान के आकार को प्रबंधनीय रखता है, और स्पष्ट अनुक्रमण की आवश्यकता को दूर करता है।

# Sample data: 10,000 random integers with values between 0 and 100,000
data = np.random.randint(0, 100000, size=(10000, 1))

# Use the Hashing layer to hash the values to the range [0, 64]
hasher = preprocessing.Hashing(num_bins=64, salt=1337)

# Use the CategoryEncoding layer to one-hot encode the hashed values
encoder = preprocessing.CategoryEncoding(max_tokens=64, output_mode="binary")
encoded_data = encoder(hasher(data))
print(encoded_data.shape)
(10000, 64)

टोकन इंडेक्स के अनुक्रम के रूप में एन्कोडिंग टेक्स्ट

यह आप कैसे preprocess चाहिए पाठ एक को पास करने की है Embedding परत।

# Define some text data to adapt the layer
data = tf.constant(
    [
        "The Brain is wider than the Sky",
        "For put them side by side",
        "The one the other will contain",
        "With ease and You beside",
    ]
)
# Instantiate TextVectorization with "int" output_mode
text_vectorizer = preprocessing.TextVectorization(output_mode="int")
# Index the vocabulary via `adapt()`
text_vectorizer.adapt(data)

# You can retrieve the vocabulary we indexed via get_vocabulary()
vocab = text_vectorizer.get_vocabulary()
print("Vocabulary:", vocab)

# Create an Embedding + LSTM model
inputs = keras.Input(shape=(1,), dtype="string")
x = text_vectorizer(inputs)
x = layers.Embedding(input_dim=len(vocab), output_dim=64)(x)
outputs = layers.LSTM(1)(x)
model = keras.Model(inputs, outputs)

# Call the model on test data (which includes unknown tokens)
test_data = tf.constant(["The Brain is deeper than the sea"])
test_output = model(test_data)
Vocabulary: ['', '[UNK]', 'the', 'side', 'you', 'with', 'will', 'wider', 'them', 'than', 'sky', 'put', 'other', 'one', 'is', 'for', 'ease', 'contain', 'by', 'brain', 'beside', 'and']

आप देख सकते हैं TextVectorization कार्रवाई में परत, एक के साथ संयुक्त Embedding मोड, उदाहरण में खरोंच से पाठ वर्गीकरण

ध्यान दें कि जब इस तरह के एक मॉडल के प्रशिक्षण, सर्वश्रेष्ठ प्रदर्शन के लिए, आप का उपयोग करना चाहिए TextVectorization परत इनपुट पाइपलाइन के हिस्से के रूप में (जो है क्या हम ऊपर पाठ वर्गीकरण के उदाहरण में करते हैं)।

बहु-गर्म एन्कोडिंग के साथ एनग्राम के घने मैट्रिक्स के रूप में एन्कोडिंग पाठ

यह आप कैसे preprocess चाहिए पाठ एक को पास करने की है Dense परत।

# Define some text data to adapt the layer
data = tf.constant(
    [
        "The Brain is wider than the Sky",
        "For put them side by side",
        "The one the other will contain",
        "With ease and You beside",
    ]
)
# Instantiate TextVectorization with "binary" output_mode (multi-hot)
# and ngrams=2 (index all bigrams)
text_vectorizer = preprocessing.TextVectorization(output_mode="binary", ngrams=2)
# Index the bigrams via `adapt()`
text_vectorizer.adapt(data)

print(
    "Encoded text:\n",
    text_vectorizer(["The Brain is deeper than the sea"]).numpy(),
    "\n",
)

# Create a Dense model
inputs = keras.Input(shape=(1,), dtype="string")
x = text_vectorizer(inputs)
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

# Call the model on test data (which includes unknown tokens)
test_data = tf.constant(["The Brain is deeper than the sea"])
test_output = model(test_data)

print("Model output:", test_output)
Encoded text:
 [[1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 0. 0. 0. 0. 0.

  0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0. 0.]] 

Model output: tf.Tensor([[0.6381588]], shape=(1, 1), dtype=float32)

TF-IDF भारोत्तोलन के साथ ngrams के घने मैट्रिक्स के रूप में एन्कोडिंग पाठ

यह यह एक करने के लिए पारित करने से पहले पाठ preprocessing का एक वैकल्पिक तरीका है Dense परत।

# Define some text data to adapt the layer
data = tf.constant(
    [
        "The Brain is wider than the Sky",
        "For put them side by side",
        "The one the other will contain",
        "With ease and You beside",
    ]
)
# Instantiate TextVectorization with "tf-idf" output_mode
# (multi-hot with TF-IDF weighting) and ngrams=2 (index all bigrams)
text_vectorizer = preprocessing.TextVectorization(output_mode="tf-idf", ngrams=2)
# Index the bigrams and learn the TF-IDF weights via `adapt()`
text_vectorizer.adapt(data)

print(
    "Encoded text:\n",
    text_vectorizer(["The Brain is deeper than the sea"]).numpy(),
    "\n",
)

# Create a Dense model
inputs = keras.Input(shape=(1,), dtype="string")
x = text_vectorizer(inputs)
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

# Call the model on test data (which includes unknown tokens)
test_data = tf.constant(["The Brain is deeper than the sea"])
test_output = model(test_data)
print("Model output:", test_output)
Encoded text:
 [[8.04719   1.6945957 0.        0.        0.        0.        0.

  0.        0.        0.        0.        0.        0.        0.
  0.        0.        1.0986123 1.0986123 1.0986123 0.        0.
  0.        0.        0.        0.        0.        0.        0.
  1.0986123 0.        0.        0.        0.        0.        0.
  0.        1.0986123 1.0986123 0.        0.        0.       ]] 

Model output: tf.Tensor([[-1.2379041]], shape=(1, 1), dtype=float32)