इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

कार्यात्मक एपीआई

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

सेट अप

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

परिचय

केरस कार्यात्मक एपीआई मॉडल बनाने का एक तरीका है जो tf.keras.Sequential API से अधिक लचीला है। कार्यात्मक एपीआई गैर-रेखीय टोपोलॉजी, साझा परतों और यहां तक ​​कि कई इनपुट या आउटपुट के साथ मॉडल को संभाल सकता है।

मुख्य विचार यह है कि एक गहरा सीखने वाला मॉडल आमतौर पर परतों का एक निर्देशित चक्रीय ग्राफ (डीएजी) होता है। तो कार्यात्मक एपीआई परतों के रेखांकन बनाने का एक तरीका है।

निम्नलिखित मॉडल पर विचार करें:

(input: 784-dimensional vectors)
       ↧
[Dense (64 units, relu activation)]
       ↧
[Dense (64 units, relu activation)]
       ↧
[Dense (10 units, softmax activation)]
       ↧
(output: logits of a probability distribution over 10 classes)

यह तीन परतों वाला एक बुनियादी ग्राफ है। कार्यात्मक API का उपयोग करके इस मॉडल का निर्माण करने के लिए, इनपुट नोड बनाकर शुरू करें:

inputs = keras.Input(shape=(784,))

डेटा का आकार 784-आयामी वेक्टर के रूप में सेट किया गया है। बैच के आकार को हमेशा छोड़ा जाता है क्योंकि केवल प्रत्येक नमूने का आकार निर्दिष्ट किया जाता है।

यदि, उदाहरण के लिए, आपके पास (32, 32, 3) आकार के साथ एक छवि इनपुट है, तो आप उपयोग करेंगे:

# Just for demonstration purposes.
img_inputs = keras.Input(shape=(32, 32, 3))

जो inputs लौटाए जाते हैं dtype इनपुट डेटा के आकार और dtype के बारे में जानकारी होती है जिसे आप अपने मॉडल को खिलाते हैं। यहाँ आकार है:

inputs.shape
TensorShape([None, 784])

यहाँ dtype है:

inputs.dtype
tf.float32

आप इस inputs ऑब्जेक्ट पर एक परत कॉल करके परतों के ग्राफ में एक नया नोड बनाते हैं:

dense = layers.Dense(64, activation="relu")
x = dense(inputs)

"लेयर कॉल" एक्शन आपके द्वारा बनाई गई इस लेयर के लिए "इनपुट्स" से एक तीर खींचने जैसा है। आप इनपुट को dense परत में "पास" कर रहे हैं, और आपको आउटपुट के रूप में x मिलता है।

आइए परतों के ग्राफ में कुछ और परतें जोड़ते हैं:

x = layers.Dense(64, activation="relu")(x)
outputs = layers.Dense(10)(x)

इस बिंदु पर, आप परतों के ग्राफ़ में इसके इनपुट और आउटपुट को निर्दिष्ट करके एक Model बना सकते हैं:

model = keras.Model(inputs=inputs, outputs=outputs, name="mnist_model")

आइए देखें कि मॉडल सारांश कैसा दिखता है:

model.summary()
Model: "mnist_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 784)]             0         
_________________________________________________________________
dense (Dense)                (None, 64)                50240     
_________________________________________________________________
dense_1 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_2 (Dense)              (None, 10)                650       
=================================================================
Total params: 55,050
Trainable params: 55,050
Non-trainable params: 0
_________________________________________________________________

आप मॉडल को ग्राफ के रूप में भी प्लॉट कर सकते हैं:

keras.utils.plot_model(model, "my_first_model.png")

png

और, वैकल्पिक रूप से, प्लॉट किए गए ग्राफ़ में प्रत्येक परत के इनपुट और आउटपुट आकृतियों को प्रदर्शित करें:

keras.utils.plot_model(model, "my_first_model_with_shape_info.png", show_shapes=True)

png

यह आंकड़ा और कोड लगभग समान हैं। कोड संस्करण में, कनेक्शन तीर को कॉल ऑपरेशन द्वारा बदल दिया जाता है।

एक "परतों का ग्राफ" एक गहरी सीखने के मॉडल के लिए एक सहज मानसिक छवि है, और कार्यात्मक एपीआई मॉडल बनाने का एक तरीका है जो इसे बारीकी से प्रतिबिंबित करता है।

प्रशिक्षण, मूल्यांकन और अनुमान

Sequential मॉडल के लिए कार्यात्मक एपीआई का उपयोग करके बनाए गए मॉडल के लिए प्रशिक्षण, मूल्यांकन और अनुमान बिल्कुल उसी तरह से काम करते हैं।

यहां, MNIST छवि डेटा लोड करें, इसे वैक्टर में फिर से खोलें, मॉडल को डेटा पर फिट करें (सत्यापन विभाजन पर प्रदर्शन की निगरानी करते हुए), फिर परीक्षण डेटा पर मॉडल का मूल्यांकन करें:

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

x_train = x_train.reshape(60000, 784).astype("float32") / 255
x_test = x_test.reshape(10000, 784).astype("float32") / 255

model.compile(
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    optimizer=keras.optimizers.RMSprop(),
    metrics=["accuracy"],
)

history = model.fit(x_train, y_train, batch_size=64, epochs=2, validation_split=0.2)

test_scores = model.evaluate(x_test, y_test, verbose=2)
print("Test loss:", test_scores[0])
print("Test accuracy:", test_scores[1])
Epoch 1/2
750/750 [==============================] - 2s 2ms/step - loss: 0.3388 - accuracy: 0.9032 - val_loss: 0.1877 - val_accuracy: 0.9457
Epoch 2/2
750/750 [==============================] - 2s 2ms/step - loss: 0.1636 - accuracy: 0.9521 - val_loss: 0.1559 - val_accuracy: 0.9543
313/313 - 0s - loss: 0.1454 - accuracy: 0.9551
Test loss: 0.14535436034202576
Test accuracy: 0.9550999999046326

आगे पढ़ने के लिए, प्रशिक्षण और मूल्यांकन गाइड देखें।

सहेजें और क्रमबद्ध करें

मॉडल को सहेजना और क्रमबद्धता कार्यात्मक एपीआई का उपयोग करके बनाए गए मॉडल के लिए उसी तरह काम करते हैं जैसे वे Sequential मॉडल के लिए करते हैं। फंक्शनल मॉडल को बचाने का मानक तरीका है मॉडल model.save() save model.save() को कॉल करना। पूरे मॉडल को सिंगल फाइल के रूप में सेव करना। आप बाद में इस फ़ाइल से उसी मॉडल को फिर से बना सकते हैं, भले ही कोड जिसने मॉडल बनाया हो वह अब उपलब्ध नहीं है।

इस सहेजी गई फ़ाइल में शामिल हैं:

  • मॉडल वास्तुकला
  • मॉडल वजन मूल्य (जो प्रशिक्षण के दौरान सीखे गए थे)
  • मॉडल प्रशिक्षण विन्यास, यदि कोई हो ( compile करने के compile पारित)
  • आशावादी और इसकी स्थिति, यदि कोई हो (प्रशिक्षण को फिर से शुरू करने के लिए जहां आपने छोड़ दिया था)
model.save("path_to_my_model")
del model
# Recreate the exact same model purely from the file:
model = keras.models.load_model("path_to_my_model")
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: path_to_my_model/assets

विवरण के लिए, मॉडल क्रमांकन और बचत गाइड पढ़ें।

कई मॉडलों को परिभाषित करने के लिए परतों के समान ग्राफ का उपयोग करें

कार्यात्मक एपीआई में, उनके इनपुट और आउटपुट को परतों के ग्राफ में निर्दिष्ट करके मॉडल बनाए जाते हैं। इसका मतलब है कि परतों के एक एकल ग्राफ का उपयोग कई मॉडल बनाने के लिए किया जा सकता है।

नीचे दिए गए उदाहरण में, आप परतों के एक ही स्टैक का उपयोग दो मॉडलों को करने के लिए करते हैं: एक encoder मॉडल जो छवि इनपुट को 16-आयामी वैक्टर में बदल देता है, और प्रशिक्षण के लिए एक एंड-टू-एंड autoencoder मॉडल।

encoder_input = keras.Input(shape=(28, 28, 1), name="img")
x = layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.Conv2D(16, 3, activation="relu")(x)
encoder_output = layers.GlobalMaxPooling2D()(x)

encoder = keras.Model(encoder_input, encoder_output, name="encoder")
encoder.summary()

x = layers.Reshape((4, 4, 1))(encoder_output)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
x = layers.Conv2DTranspose(32, 3, activation="relu")(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation="relu")(x)

autoencoder = keras.Model(encoder_input, decoder_output, name="autoencoder")
autoencoder.summary()
Model: "encoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
img (InputLayer)             [(None, 28, 28, 1)]       0         
_________________________________________________________________
conv2d (Conv2D)              (None, 26, 26, 16)        160       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 24, 24, 32)        4640      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 8, 8, 32)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 6, 6, 32)          9248      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 4, 4, 16)          4624      
_________________________________________________________________
global_max_pooling2d (Global (None, 16)                0         
=================================================================
Total params: 18,672
Trainable params: 18,672
Non-trainable params: 0
_________________________________________________________________
Model: "autoencoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
img (InputLayer)             [(None, 28, 28, 1)]       0         
_________________________________________________________________
conv2d (Conv2D)              (None, 26, 26, 16)        160       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 24, 24, 32)        4640      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 8, 8, 32)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 6, 6, 32)          9248      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 4, 4, 16)          4624      
_________________________________________________________________
global_max_pooling2d (Global (None, 16)                0         
_________________________________________________________________
reshape (Reshape)            (None, 4, 4, 1)           0         
_________________________________________________________________
conv2d_transpose (Conv2DTran (None, 6, 6, 16)          160       
_________________________________________________________________
conv2d_transpose_1 (Conv2DTr (None, 8, 8, 32)          4640      
_________________________________________________________________
up_sampling2d (UpSampling2D) (None, 24, 24, 32)        0         
_________________________________________________________________
conv2d_transpose_2 (Conv2DTr (None, 26, 26, 16)        4624      
_________________________________________________________________
conv2d_transpose_3 (Conv2DTr (None, 28, 28, 1)         145       
=================================================================
Total params: 28,241
Trainable params: 28,241
Non-trainable params: 0
_________________________________________________________________

यहां, डिकोडिंग आर्किटेक्चर एन्कोडिंग आर्किटेक्चर के लिए सख्ती से सममित है, इसलिए आउटपुट आकार इनपुट आकार (28, 28, 1)

एक के पीछे Conv2D परत एक है Conv2DTranspose परत है, और एक के पीछे MaxPooling2D परत एक है UpSampling2D परत।

सभी मॉडल कॉल करने योग्य हैं, जैसे परतें

आप किसी भी मॉडल का इलाज कर सकते हैं जैसे कि वह एक Input पर या दूसरी परत के आउटपुट पर इसे लागू करके एक परत थी। एक मॉडल को कॉल करके आप केवल मॉडल की वास्तुकला का पुन: उपयोग नहीं कर रहे हैं, आप इसके वजन का पुन: उपयोग कर रहे हैं।

इसे एक्शन में देखने के लिए, यहां एक अलग-अलग टेकऑनकोडर उदाहरण है जो एक एनकोडर मॉडल, एक डिकोडर मॉडल बनाता है, और उन्हें दो कॉल में ऑटोकेनकोड मॉडल प्राप्त करने के लिए चेन लेता है:

2ccb66129
Model: "encoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
original_img (InputLayer)    [(None, 28, 28, 1)]       0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 26, 26, 16)        160       
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 24, 24, 32)        4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 8, 8, 32)          0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 6, 6, 32)          9248      
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 4, 4, 16)          4624      
_________________________________________________________________
global_max_pooling2d_1 (Glob (None, 16)                0         
=================================================================
Total params: 18,672
Trainable params: 18,672
Non-trainable params: 0
_________________________________________________________________
Model: "decoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
encoded_img (InputLayer)     [(None, 16)]              0         
_________________________________________________________________
reshape_1 (Reshape)          (None, 4, 4, 1)           0         
_________________________________________________________________
conv2d_transpose_4 (Conv2DTr (None, 6, 6, 16)          160       
_________________________________________________________________
conv2d_transpose_5 (Conv2DTr (None, 8, 8, 32)          4640      
_________________________________________________________________
up_sampling2d_1 (UpSampling2 (None, 24, 24, 32)        0         
_________________________________________________________________
conv2d_transpose_6 (Conv2DTr (None, 26, 26, 16)        4624      
_________________________________________________________________
conv2d_transpose_7 (Conv2DTr (None, 28, 28, 1)         145       
=================================================================
Total params: 9,569
Trainable params: 9,569
Non-trainable params: 0
_________________________________________________________________
Model: "autoencoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
img (InputLayer)             [(None, 28, 28, 1)]       0         
_________________________________________________________________
encoder (Functional)         (None, 16)                18672     
_________________________________________________________________
decoder (Functional)         (None, 28, 28, 1)         9569      
=================================================================
Total params: 28,241
Trainable params: 28,241
Non-trainable params: 0
_________________________________________________________________

जैसा कि आप देख सकते हैं, मॉडल को नेस्टेड किया जा सकता है: एक मॉडल में उप-मॉडल हो सकते हैं (चूंकि एक मॉडल एक परत की तरह है)। मॉडल घोंसले के लिए उपयोग आम तौर ensembling है। उदाहरण के लिए, यहां एक मॉडल में एक मॉडल को सेट करने का तरीका बताया गया है जो उनकी भविष्यवाणियों को औसत करता है:

def get_model():
    inputs = keras.Input(shape=(128,))
    outputs = layers.Dense(1)(inputs)
    return keras.Model(inputs, outputs)


model1 = get_model()
model2 = get_model()
model3 = get_model()

inputs = keras.Input(shape=(128,))
y1 = model1(inputs)
y2 = model2(inputs)
y3 = model3(inputs)
outputs = layers.average([y1, y2, y3])
ensemble_model = keras.Model(inputs=inputs, outputs=outputs)

जटिल ग्राफ टोपोलॉजी में हेरफेर करें

कई इनपुट और आउटपुट के साथ मॉडल

कार्यात्मक एपीआई कई इनपुट और आउटपुट में हेरफेर करना आसान बनाता है। इसे Sequential API से नियंत्रित नहीं किया जा सकता है।

उदाहरण के लिए, यदि आप प्राथमिकता के आधार पर ग्राहकों के टिकट जारी करने और उन्हें सही विभाग में भेजने के लिए एक प्रणाली का निर्माण कर रहे हैं, तो मॉडल में तीन इनपुट होंगे:

  • टिकट का शीर्षक (पाठ इनपुट),
  • टिकट का पाठ निकाय (पाठ इनपुट), और
  • उपयोगकर्ता द्वारा जोड़ा गया कोई भी टैग (श्रेणीबद्ध इनपुट)

इस मॉडल में दो आउटपुट होंगे:

  • 0 और 1 (स्केलर सिग्मॉइड आउटपुट) के बीच प्राथमिकता स्कोर, और
  • वह विभाग जिसे टिकट संभालना चाहिए (विभागों के सेट पर सॉफ्टमैक्स आउटपुट)।

आप कार्यात्मक API के साथ इस मॉडल को कुछ लाइनों में बना सकते हैं:

num_tags = 12  # Number of unique issue tags
num_words = 10000  # Size of vocabulary obtained when preprocessing text data
num_departments = 4  # Number of departments for predictions

title_input = keras.Input(
    shape=(None,), name="title"
)  # Variable-length sequence of ints
body_input = keras.Input(shape=(None,), name="body")  # Variable-length sequence of ints
tags_input = keras.Input(
    shape=(num_tags,), name="tags"
)  # Binary vectors of size `num_tags`

# Embed each word in the title into a 64-dimensional vector
title_features = layers.Embedding(num_words, 64)(title_input)
# Embed each word in the text into a 64-dimensional vector
body_features = layers.Embedding(num_words, 64)(body_input)

# Reduce sequence of embedded words in the title into a single 128-dimensional vector
title_features = layers.LSTM(128)(title_features)
# Reduce sequence of embedded words in the body into a single 32-dimensional vector
body_features = layers.LSTM(32)(body_features)

# Merge all available features into a single large vector via concatenation
x = layers.concatenate([title_features, body_features, tags_input])

# Stick a logistic regression for priority prediction on top of the features
priority_pred = layers.Dense(1, name="priority")(x)
# Stick a department classifier on top of the features
department_pred = layers.Dense(num_departments, name="department")(x)

# Instantiate an end-to-end model predicting both priority and department
model = keras.Model(
    inputs=[title_input, body_input, tags_input],
    outputs=[priority_pred, department_pred],
)

अब मॉडल की साजिश करें:

keras.utils.plot_model(model, "multi_input_and_output_model.png", show_shapes=True)

png

इस मॉडल को संकलित करते समय, आप प्रत्येक आउटपुट को अलग-अलग नुकसान दे सकते हैं। आप प्रत्येक नुकसान के लिए अलग-अलग भार भी असाइन कर सकते हैं - कुल प्रशिक्षण हानि में उनके योगदान को संशोधित करने के लिए।

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=[
        keras.losses.BinaryCrossentropy(from_logits=True),
        keras.losses.CategoricalCrossentropy(from_logits=True),
    ],
    loss_weights=[1.0, 0.2],
)

चूंकि आउटपुट लेयर्स के अलग-अलग नाम हैं, इसलिए आप इस तरह से नुकसान भी बता सकते हैं:

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss={
        "priority": keras.losses.BinaryCrossentropy(from_logits=True),
        "department": keras.losses.CategoricalCrossentropy(from_logits=True),
    },
    loss_weights=[1.0, 0.2],
)

इनपुट्स और टारगेट के NumPy सरणियों की सूची पास करके मॉडल को प्रशिक्षित करें:

2a77c3f83
Epoch 1/2
40/40 [==============================] - 0s 11ms/step - loss: 1.2819 - priority_loss: 0.7088 - department_loss: 2.8653
Epoch 2/2
40/40 [==============================] - 0s 10ms/step - loss: 1.2723 - priority_loss: 0.6992 - department_loss: 2.8655

<tensorflow.python.keras.callbacks.History at 0x7f57b19336d8>

जब एक साथ फिट बुला Dataset वस्तु, यह या तो जैसे सूचियों का एक टपल उपज चाहिए ([title_data, body_data, tags_data], [priority_targets, dept_targets]) या तरह शब्दकोशों की एक टपल ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets})

अधिक विस्तृत विवरण के लिए, प्रशिक्षण और मूल्यांकन मार्गदर्शिका देखें।

एक खिलौना ResNet मॉडल

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

इसके लिए एक सामान्य उपयोग मामला अवशिष्ट कनेक्शन है। इसे प्रदर्शित करने के लिए CIFAR10 के लिए एक खिलौना रेसनेट मॉडल का निर्माण करें:

inputs = keras.Input(shape=(32, 32, 3), name="img")
x = layers.Conv2D(32, 3, activation="relu")(inputs)
x = layers.Conv2D(64, 3, activation="relu")(x)
block_1_output = layers.MaxPooling2D(3)(x)

x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_1_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_2_output = layers.add([x, block_1_output])

x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_2_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_3_output = layers.add([x, block_2_output])

x = layers.Conv2D(64, 3, activation="relu")(block_3_output)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10)(x)

model = keras.Model(inputs, outputs, name="toy_resnet")
model.summary()
Model: "toy_resnet"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
img (InputLayer)                [(None, 32, 32, 3)]  0                                            
__________________________________________________________________________________________________
conv2d_8 (Conv2D)               (None, 30, 30, 32)   896         img[0][0]                        
__________________________________________________________________________________________________
conv2d_9 (Conv2D)               (None, 28, 28, 64)   18496       conv2d_8[0][0]                   
__________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D)  (None, 9, 9, 64)     0           conv2d_9[0][0]                   
__________________________________________________________________________________________________
conv2d_10 (Conv2D)              (None, 9, 9, 64)     36928       max_pooling2d_2[0][0]            
__________________________________________________________________________________________________
conv2d_11 (Conv2D)              (None, 9, 9, 64)     36928       conv2d_10[0][0]                  
__________________________________________________________________________________________________
add (Add)                       (None, 9, 9, 64)     0           conv2d_11[0][0]                  
                                                                 max_pooling2d_2[0][0]            
__________________________________________________________________________________________________
conv2d_12 (Conv2D)              (None, 9, 9, 64)     36928       add[0][0]                        
__________________________________________________________________________________________________
conv2d_13 (Conv2D)              (None, 9, 9, 64)     36928       conv2d_12[0][0]                  
__________________________________________________________________________________________________
add_1 (Add)                     (None, 9, 9, 64)     0           conv2d_13[0][0]                  
                                                                 add[0][0]                        
__________________________________________________________________________________________________
conv2d_14 (Conv2D)              (None, 7, 7, 64)     36928       add_1[0][0]                      
__________________________________________________________________________________________________
global_average_pooling2d (Globa (None, 64)           0           conv2d_14[0][0]                  
__________________________________________________________________________________________________
dense_6 (Dense)                 (None, 256)          16640       global_average_pooling2d[0][0]   
__________________________________________________________________________________________________
dropout (Dropout)               (None, 256)          0           dense_6[0][0]                    
__________________________________________________________________________________________________
dense_7 (Dense)                 (None, 10)           2570        dropout[0][0]                    
==================================================================================================
Total params: 223,242
Trainable params: 223,242
Non-trainable params: 0
__________________________________________________________________________________________________

मॉडल प्लॉट करें:

keras.utils.plot_model(model, "mini_resnet.png", show_shapes=True)

png

अब मॉडल को प्रशिक्षित करें:

(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()

x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)

model.compile(
    optimizer=keras.optimizers.RMSprop(1e-3),
    loss=keras.losses.CategoricalCrossentropy(from_logits=True),
    metrics=["acc"],
)
# We restrict the data to the first 1000 samples so as to limit execution time
# on Colab. Try to train on the entire dataset until convergence!
model.fit(x_train[:1000], y_train[:1000], batch_size=64, epochs=1, validation_split=0.2)
13/13 [==============================] - 0s 21ms/step - loss: 2.3574 - acc: 0.1037 - val_loss: 2.3011 - val_acc: 0.1000

<tensorflow.python.keras.callbacks.History at 0x7f57b026cf98>

परतों को साझा किया

कार्यात्मक एपीआई के लिए एक और अच्छा उपयोग ऐसे मॉडल हैं जो साझा परतों का उपयोग करते हैं । साझा परतें परत उदाहरण हैं जिनका एक ही मॉडल में कई बार पुन: उपयोग किया जाता है - वे उन विशेषताओं को सीखते हैं जो ग्राफ़-ऑफ-लेयर्स में कई पथों के अनुरूप हैं।

साझा परतों का उपयोग अक्सर समान रिक्त स्थान से इनपुट को एन्कोड करने के लिए किया जाता है (जैसे, पाठ के दो अलग-अलग टुकड़े जो समान शब्दावली की सुविधा देते हैं)। वे इन विभिन्न इनपुटों में जानकारी साझा करने में सक्षम होते हैं, और वे कम डेटा पर ऐसे मॉडल को प्रशिक्षित करना संभव बनाते हैं। यदि किसी दिए गए शब्द को इनपुट में से किसी एक में देखा जाता है, तो इससे उन सभी इनपुटों के प्रसंस्करण में लाभ होगा जो साझा परत से गुजरते हैं।

कार्यात्मक API में एक परत साझा करने के लिए, एक ही परत आवृत्ति को कई बार कॉल करें। उदाहरण के लिए, यहां दो अलग-अलग पाठ इनपुटों में एक Embedding परत साझा की गई है:

# Embedding for 1000 unique words mapped to 128-dimensional vectors
shared_embedding = layers.Embedding(1000, 128)

# Variable-length sequence of integers
text_input_a = keras.Input(shape=(None,), dtype="int32")

# Variable-length sequence of integers
text_input_b = keras.Input(shape=(None,), dtype="int32")

# Reuse the same layer to encode both inputs
encoded_input_a = shared_embedding(text_input_a)
encoded_input_b = shared_embedding(text_input_b)

परतों के ग्राफ में नोड्स निकालें और पुन: उपयोग करें

क्योंकि जिन परतों का आप हेरफेर कर रहे हैं, उनका ग्राफ एक स्थिर डेटा संरचना है, इसे एक्सेस और निरीक्षण किया जा सकता है। और यह है कि आप छवियों के रूप में कार्यात्मक मॉडल कैसे तैयार कर सकते हैं।

इसका मतलब यह भी है कि आप मध्यवर्ती परतों ("ग्राफ में" नोड्स) की सक्रियण तक पहुंच सकते हैं और उन्हें कहीं और फिर से उपयोग कर सकते हैं - जो सुविधा निष्कर्षण जैसी किसी चीज के लिए बहुत उपयोगी है।

आइए एक उदाहरण देखें। यह एक वीजीजी 19 मॉडल है जिसका वजन इमेजनेट पर दर्शाया गया है:

vgg19 = tf.keras.applications.VGG19()
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg19/vgg19_weights_tf_dim_ordering_tf_kernels.h5
574717952/574710816 [==============================] - 20s 0us/step

और ये मॉडल के मध्यवर्ती सक्रियण हैं, जो ग्राफ डेटा संरचना को क्वेरी करके प्राप्त किया गया है:

features_list = [layer.output for layer in vgg19.layers]

एक नया फीचर-निष्कर्षण मॉडल बनाने के लिए इन सुविधाओं का उपयोग करें जो मध्यवर्ती परत सक्रियण के मूल्यों को लौटाता है:

feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)

img = np.random.random((1, 224, 224, 3)).astype("float32")
extracted_features = feat_extraction_model(img)

यह अन्य चीजों के अलावा, न्यूरल स्टाइल ट्रांसफर जैसे कार्यों के लिए काम आता है।

कस्टम परतों का उपयोग करके एपीआई बढ़ाएँ

tf.keras में अंतर्निहित परतों की एक विस्तृत श्रृंखला शामिल है, उदाहरण के लिए:

  • Conv1D परतें: Conv1D , Conv2D , Conv3D , Conv2DTranspose
  • पूलिंग परतें: MaxPooling1D , MaxPooling2D 2 MaxPooling1D , MaxPooling2D MaxPooling3D , AveragePooling1D
  • RNN परतें: GRU , LSTM , ConvLSTM2D
  • BatchNormalization , Dropout , Embedding , आदि

लेकिन अगर आपको वह नहीं मिल रहा है जिसकी आपको आवश्यकता है, तो अपनी खुद की परतें बनाकर एपीआई का विस्तार करना आसान है। सभी Layer वर्ग को उपवर्गित करती हैं और कार्यान्वित करती हैं:

  • call विधि, जो परत द्वारा की गई गणना को निर्दिष्ट करती है।
  • build विधि, कि परत के वजन बनाता है (यह सिर्फ एक शैली सम्मेलन है क्योंकि आप __init__ , साथ ही में वजन बना सकते हैं)।

खरोंच से परतें बनाने के बारे में अधिक जानने के लिए, कस्टम परतें और मॉडल गाइड पढ़ें।

निम्नलिखित tf.keras.layers.Dense का एक बुनियादी कार्यान्वयन है:

class CustomDense(layers.Layer):
    def __init__(self, units=32):
        super(CustomDense, self).__init__()
        self.units = units

    def build(self, input_shape):
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        self.b = self.add_weight(
            shape=(self.units,), initializer="random_normal", trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b


inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)

model = keras.Model(inputs, outputs)

अपने कस्टम लेयर में क्रमांकन समर्थन के लिए, get_config विधि को परिभाषित करें जो लेयर इंस्टेंस के कंस्ट्रक्टर तर्कों को लौटाता है:

class CustomDense(layers.Layer):
    def __init__(self, units=32):
        super(CustomDense, self).__init__()
        self.units = units

    def build(self, input_shape):
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        self.b = self.add_weight(
            shape=(self.units,), initializer="random_normal", trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

    def get_config(self):
        return {"units": self.units}


inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)

model = keras.Model(inputs, outputs)
config = model.get_config()

new_model = keras.Model.from_config(config, custom_objects={"CustomDense": CustomDense})

वैकल्पिक रूप से, वर्ग विधि from_config(cls, config) कार्यान्वित करें from_config(cls, config) जिसका उपयोग तब किया जाता है जब एक लेयर इंस्टेंस को from_config(cls, config) लिए इसका विन्यास शब्दकोश दिया जाता है। from_config का डिफ़ॉल्ट कार्यान्वयन है:

def from_config(cls, config):
  return cls(**config)

कार्यात्मक एपीआई का उपयोग कब करें

क्या आपको एक नया मॉडल बनाने के लिए केरस कार्यात्मक एपीआई का उपयोग करना चाहिए, या सीधे Model वर्ग को सीधे उपवर्ग करना चाहिए? सामान्य तौर पर, कार्यात्मक एपीआई उच्च-स्तरीय, आसान और सुरक्षित होता है, और इसमें कई विशेषताएं होती हैं जो उपवर्ग मॉडल का समर्थन नहीं करती हैं।

हालांकि, मॉडल उप-वर्गिंग उन मॉडलों के निर्माण के दौरान अधिक लचीलापन प्रदान करता है जो आसानी से परतों के निर्देशित चक्रीय ग्राफ के रूप में व्यक्त नहीं होते हैं। उदाहरण के लिए, आप कार्यात्मक API के साथ ट्री-आरएनएन को लागू नहीं कर सकते हैं और सीधे Model को उप-वर्ग करना होगा।

कार्यात्मक एपीआई और मॉडल उपवर्ग के बीच के अंतर को गहराई से देखने के लिए, पढ़ें TensorFlow 2.0 में प्रतीकात्मक और इंपीरियल एपीआई क्या हैं?

कार्यात्मक एपीआई ताकत:

अनुक्रमिक मॉडल (जो डेटा संरचनाएं भी हैं) के लिए निम्नलिखित गुण भी सही हैं, लेकिन उप-वर्ग मॉडल (जो पायथन बाइटकोड हैं, डेटा संरचना नहीं) के लिए सही नहीं हैं।

कम क्रिया

कोई super(MyClass, self).__init__(...) , कोई def call(self, ...): आदि।

की तुलना करें:

inputs = keras.Input(shape=(32,))
x = layers.Dense(64, activation='relu')(inputs)
outputs = layers.Dense(10)(x)
mlp = keras.Model(inputs, outputs)

उपवर्गित संस्करण के साथ:

class MLP(keras.Model):

  def __init__(self, **kwargs):
    super(MLP, self).__init__(**kwargs)
    self.dense_1 = layers.Dense(64, activation='relu')
    self.dense_2 = layers.Dense(10)

  def call(self, inputs):
    x = self.dense_1(inputs)
    return self.dense_2(x)

# Instantiate the model.
mlp = MLP()
# Necessary to create the model's state.
# The model doesn't have a state until it's called at least once.
_ = mlp(tf.zeros((1, 32)))

इसके कनेक्टिविटी ग्राफ को परिभाषित करते हुए मॉडल सत्यापन

कार्यात्मक एपीआई में, इनपुट विनिर्देश (आकार और dtype) अग्रिम में बनाया गया है ( Input का उपयोग करके)। हर बार जब आप एक परत कहते हैं, तो परत यह जांचती है कि इसके लिए दिया गया विनिर्देश इसकी मान्यताओं से मेल खाता है या नहीं और यह एक उपयोगी त्रुटि संदेश को बढ़ाएगा या नहीं।

यह गारंटी देता है कि कार्यात्मक एपीआई के साथ आप जो भी मॉडल बना सकते हैं। सभी डिबगिंग - अभिसरण से संबंधित डिबगिंग के अलावा - मॉडल निर्माण के दौरान सांख्यिकीय रूप से होता है और निष्पादन समय पर नहीं। यह एक कंपाइलर में टाइपिंग चेकिंग के समान है।

एक कार्यात्मक मॉडल प्लॉट करने योग्य और निरीक्षण योग्य है

आप मॉडल को ग्राफ के रूप में प्लॉट कर सकते हैं, और आप इस ग्राफ में इंटरमीडिएट नोड्स तक आसानी से पहुंच सकते हैं। उदाहरण के लिए, मध्यवर्ती परतों की गतिविधियों को निकालने और पुन: उपयोग करने के लिए (जैसा कि पिछले उदाहरण में देखा गया है):

features_list = [layer.output for layer in vgg19.layers]
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)

एक कार्यात्मक मॉडल को क्रमबद्ध या क्लोन किया जा सकता है

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

उप- get_config() मॉडल को क्रमबद्ध करने के लिए, कार्यान्वयनकर्ता के लिए मॉडल स्तर पर get_config() और from_config() विधि निर्दिष्ट करना आवश्यक है।

कार्यात्मक एपीआई कमजोरी:

यह गतिशील आर्किटेक्चर का समर्थन नहीं करता है

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

मिक्स-एंड-मैच एपीआई शैलियों

कार्यात्मक एपीआई या मॉडल उपवर्ग के बीच चयन करना एक द्विआधारी निर्णय नहीं है जो आपको मॉडल की एक श्रेणी में प्रतिबंधित करता है। tf.keras API के सभी मॉडल एक-दूसरे के साथ बातचीत कर सकते हैं, चाहे वे Sequential मॉडल हों, tf.keras मॉडल हों, या tf.keras किए गए मॉडल जो स्क्रैच से लिखे गए हों।

आप हमेशा एक उप-मॉडल मॉडल या परत के हिस्से के रूप में एक कार्यात्मक मॉडल या Sequential मॉडल का उपयोग कर सकते हैं:

units = 32
timesteps = 10
input_dim = 5

# Define a Functional model
inputs = keras.Input((None, units))
x = layers.GlobalAveragePooling1D()(inputs)
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)


class CustomRNN(layers.Layer):
    def __init__(self):
        super(CustomRNN, self).__init__()
        self.units = units
        self.projection_1 = layers.Dense(units=units, activation="tanh")
        self.projection_2 = layers.Dense(units=units, activation="tanh")
        # Our previously-defined Functional model
        self.classifier = model

    def call(self, inputs):
        outputs = []
        state = tf.zeros(shape=(inputs.shape[0], self.units))
        for t in range(inputs.shape[1]):
            x = inputs[:, t, :]
            h = self.projection_1(x)
            y = h + self.projection_2(state)
            state = y
            outputs.append(y)
        features = tf.stack(outputs, axis=1)
        print(features.shape)
        return self.classifier(features)


rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, timesteps, input_dim)))
(1, 10, 32)

आप कार्यात्मक एपीआई में किसी भी उपवर्गित परत या मॉडल का उपयोग कर सकते हैं जब तक कि यह एक call विधि को लागू करता है जो निम्न पैटर्न में से एक है:

  • call(self, inputs, **kwargs) - जहां inputs एक टेंसर या नेस्टेड संरचना ऑफ़ टेंसर्स है (उदाहरण के लिए टेनर्स की एक सूची), और जहाँ **kwargs नॉन-टेनसर तर्क (गैर-इनपुट) हैं।
  • call(self, inputs, training=None, **kwargs) - जहां training एक बूलियन है जो यह दर्शाता है कि क्या परत को प्रशिक्षण मोड और इंजेक्शन मोड में व्यवहार करना चाहिए।
  • call(self, inputs, mask=None, **kwargs) - जहां mask एक बूलियन मास्क टेंसर है (उदाहरण के लिए, RNN के लिए उपयोगी)।
  • call(self, inputs, training=None, mask=None, **kwargs) - बेशक, आपके पास एक ही समय में मास्किंग और प्रशिक्षण-विशिष्ट व्यवहार दोनों हो सकते हैं।

इसके अतिरिक्त, यदि आप अपने कस्टम लेयर या मॉडल पर get_config पद्धति को लागू करते हैं, तो आपके द्वारा get_config गए कार्यात्मक मॉडल अभी भी धारावाहिक और क्लोन करने योग्य होंगे।

यहाँ एक कस्टम RNN का एक त्वरित उदाहरण है, जो स्क्रैच से लिखा गया है, एक कार्यात्मक मॉडल में उपयोग किया जा रहा है:

units = 32
timesteps = 10
input_dim = 5
batch_size = 16


class CustomRNN(layers.Layer):
    def __init__(self):
        super(CustomRNN, self).__init__()
        self.units = units
        self.projection_1 = layers.Dense(units=units, activation="tanh")
        self.projection_2 = layers.Dense(units=units, activation="tanh")
        self.classifier = layers.Dense(1)

    def call(self, inputs):
        outputs = []
        state = tf.zeros(shape=(inputs.shape[0], self.units))
        for t in range(inputs.shape[1]):
            x = inputs[:, t, :]
            h = self.projection_1(x)
            y = h + self.projection_2(state)
            state = y
            outputs.append(y)
        features = tf.stack(outputs, axis=1)
        return self.classifier(features)


# Note that you specify a static batch size for the inputs with the `batch_shape`
# arg, because the inner computation of `CustomRNN` requires a static batch size
# (when you create the `state` zeros tensor).
inputs = keras.Input(batch_shape=(batch_size, timesteps, input_dim))
x = layers.Conv1D(32, 3)(inputs)
outputs = CustomRNN()(x)

model = keras.Model(inputs, outputs)

rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, 10, 5)))