तिथि को रक्षित करें! Google I / O 18-20 मई को पंजीकृत करता है
इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • RandomCrop परत
  • RandomFlip परत
  • RandomTranslation परत
  • RandomRotation लेयर
  • RandomZoom परत
  • RandomHeight परत
  • RandomWidth परत

adapt() विधि

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

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

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

आप एक प्रीप्रोसेसिंग परत की स्थिति को adapt() विधि के माध्यम से प्रशिक्षण डेटा में उजागर करके सेट करते हैं:

001a88d20
Features mean: 0.00
Features std: 1.00

adapt() विधि या तो एक Numpy सरणी याtf.data.Dataset ऑब्जेक्ट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 परत को StringLookup शब्दावली के साथ StringLookup :

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: उन्हें इस तरह से मॉडल का हिस्सा बनाएं:

0 बी 363 डी 350

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

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

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

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

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

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

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

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

यदि आप शुरू में अपनी प्रीप्रोसेसिंग परतों को अपनी tf.data पाइपलाइन में tf.data हैं, तो आप एक 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() दौरान नहीं देखा गया 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() दौरान नहीं देखा गया 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)

टोकन सूचकांकों के अनुक्रम के रूप में पाठ को एन्कोड करना

यह है कि आप पाठ को 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 परत का उपयोग करना चाहिए (जो कि ऊपर दिए गए पाठ वर्गीकरण उदाहरण में हम करते हैं)।

मल्टी-हॉट एन्कोडिंग के साथ एनग्राम के घने मैट्रिक्स के रूप में टेक्स्ट को एन्कोड करना

यह है कि आपको पाठ को एक 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)

टीएफ-आईडीएफ भार के साथ एनग्राम के घने मैट्रिक्स के रूप में पाठ को एन्कोडिंग

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