דף זה תורגם על ידי Cloud Translation API.
Switch to English

המודל הרציף

צפה ב- TensorFlow.org הפעל בגוגל קולאב צפה במקור ב- GitHub הורד מחברת

להכין

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

מתי להשתמש במודל רציף

מודל Sequential מתאים לערימה רגילה של שכבות כאשר לכל שכבה יש בדיוק טנסור קלט אחד וטנסור פלט אחד .

באופן סכמטי, המודל Sequential הבא:

# Define Sequential model with 3 layers
model = keras.Sequential(
    [
        layers.Dense(2, activation="relu", name="layer1"),
        layers.Dense(3, activation="relu", name="layer2"),
        layers.Dense(4, name="layer3"),
    ]
)
# Call model on a test input
x = tf.ones((3, 3))
y = model(x)

שווה ערך לפונקציה זו:

# Create 3 layers
layer1 = layers.Dense(2, activation="relu", name="layer1")
layer2 = layers.Dense(3, activation="relu", name="layer2")
layer3 = layers.Dense(4, name="layer3")

# Call layers on a test input
x = tf.ones((3, 3))
y = layer3(layer2(layer1(x)))

מודל רציף אינו מתאים כאשר:

  • המודל שלך כולל מספר כניסות או יציאות מרובות
  • לכל אחת מהשכבות שלך יש מספר כניסות או יציאות מרובות
  • עליך לבצע שיתוף שכבות
  • אתה רוצה טופולוגיה לא ליניארית (למשל חיבור שיורי, מודל רב ענפי)

יצירת מודל רציף

באפשרותך ליצור מודל רציף על ידי העברת רשימת שכבות לבנאי הרצף:

model = keras.Sequential(
    [
        layers.Dense(2, activation="relu"),
        layers.Dense(3, activation="relu"),
        layers.Dense(4),
    ]
)

ניתן לגשת לשכבותיה באמצעות תכונת layers :

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f7d1d5c7898>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f7d2f6e0a20>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f7d16beb9b0>]

ניתן גם ליצור מודל רציף באופן הדרגתי באמצעות שיטת add() :

model = keras.Sequential()
model.add(layers.Dense(2, activation="relu"))
model.add(layers.Dense(3, activation="relu"))
model.add(layers.Dense(4))

שים לב שיש גם שיטת pop() מתאימה להסרת שכבות: מודל רציף מתנהג כמו רשימה של שכבות.

model.pop()
print(len(model.layers))  # 2
2

שים לב גם כי הבנאי הרצף מקבל טיעון name , בדיוק כמו כל שכבה או מודל בקרס. זה שימושי לביאור גרפים של TensorBoard עם שמות בעלי משמעות סמנטית.

model = keras.Sequential(name="my_sequential")
model.add(layers.Dense(2, activation="relu", name="layer1"))
model.add(layers.Dense(3, activation="relu", name="layer2"))
model.add(layers.Dense(4, name="layer3"))

ציון צורת הקלט מראש

באופן כללי, כל השכבות בקרס צריכות לדעת את צורת התשומות שלהן כדי להיות מסוגלות ליצור את המשקולות שלהן. אז כשאתה יוצר שכבה כזו, בהתחלה, אין לה משקלים:

layer = layers.Dense(3)
layer.weights  # Empty
[]

זה יוצר את המשקולות שלו בפעם הראשונה שהוא נקרא על קלט, מכיוון שצורת המשקולות תלויה בצורת התשומות:

# Call layer on a test input
x = tf.ones((1, 4))
y = layer(x)
layer.weights  # Now it has weights, of shape (4, 3) and (3,)
[<tf.Variable 'dense_6/kernel:0' shape=(4, 3) dtype=float32, numpy=
 array([[-0.06262648,  0.36915624, -0.27826005],
        [-0.6703571 , -0.03467071,  0.80370367],
        [-0.00725174,  0.19120002,  0.34244013],
        [-0.20762473, -0.31104177, -0.26624495]], dtype=float32)>,
 <tf.Variable 'dense_6/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

מטבע הדברים זה חל גם על מודלים רצופים. כאשר אתה מייצר מודל רציף ללא צורת קלט, הוא אינו "בנוי": אין לו משקולות ( model.weights מביאה לשגיאה המציינת בדיוק את זה). המשקולות נוצרים כאשר המודל רואה לראשונה נתוני קלט:

model = keras.Sequential(
    [
        layers.Dense(2, activation="relu"),
        layers.Dense(3, activation="relu"),
        layers.Dense(4),
    ]
)  # No weights at this stage!

# At this point, you can't do this:
# model.weights

# You also can't do this:
# model.summary()

# Call the model on a test input
x = tf.ones((1, 4))
y = model(x)
print("Number of weights after calling the model:", len(model.weights))  # 6
Number of weights after calling the model: 6

לאחר שמודל "נבנה", אתה יכול להתקשר לשיטת summary() שלו summary() כדי להציג את תוכנו:

model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_7 (Dense)              (1, 2)                    10        
_________________________________________________________________
dense_8 (Dense)              (1, 3)                    9         
_________________________________________________________________
dense_9 (Dense)              (1, 4)                    16        
=================================================================
Total params: 35
Trainable params: 35
Non-trainable params: 0
_________________________________________________________________

עם זאת, זה יכול להיות שימושי מאוד בבניית מודל רציף באופן הדרגתי כדי להיות מסוגל להציג את סיכום הדגם עד כה, כולל צורת הפלט הנוכחית. במקרה זה, עליך להתחיל את המודל שלך על ידי העברת אובייקט Input למודל שלך, כדי שהוא יידע את צורת הקלט שלו מההתחלה:

model = keras.Sequential()
model.add(keras.Input(shape=(4,)))
model.add(layers.Dense(2, activation="relu"))

model.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_10 (Dense)             (None, 2)                 10        
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________

שים לב שאובייקט Input אינו מוצג כחלק מ- model.layers , מכיוון שהוא אינו שכבה:

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f7d16b870f0>]

חלופה פשוטה היא פשוט להעביר טיעון input_shape לשכבה הראשונה שלך:

model = keras.Sequential()
model.add(layers.Dense(2, activation="relu", input_shape=(4,)))

model.summary()
Model: "sequential_5"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_11 (Dense)             (None, 2)                 10        
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________

לדוגמניות הבנויות עם צורת קלט מוגדרת מראש יש תמיד משקלים (עוד לפני שרואים נתונים כלשהם) ותמיד יש צורת פלט מוגדרת.

באופן כללי, מומלץ להשתמש בשיטה הטובה ביותר תמיד לציין את צורת הקלט של מודל רצף מראש אם אתה יודע מה זה.

זרימת עבודה נפוצה של איתור באגים: add() + summary()

בבניית ארכיטקטורה רציפה חדשה, כדאי לערום שכבות באופן הדרגתי עם add() ולהדפיס לעתים קרובות סיכומי מודלים. לדוגמה, זה מאפשר לך לפקח על כך Conv2D של שכבות MaxPooling2D ו- Conv2D MaxPooling2D המפה של תכונות התמונה:

model = keras.Sequential()
model.add(keras.Input(shape=(250, 250, 3)))  # 250x250 RGB images
model.add(layers.Conv2D(32, 5, strides=2, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))

# Can you guess what the current output shape is at this point? Probably not.
# Let's just print it:
model.summary()

# The answer was: (40, 40, 32), so we can keep downsampling...

model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(2))

# And now?
model.summary()

# Now that we have 4x4 feature maps, time to apply global max pooling.
model.add(layers.GlobalMaxPooling2D())

# Finally, we add a classification layer.
model.add(layers.Dense(10))
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 123, 123, 32)      2432      
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 121, 121, 32)      9248      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 40, 40, 32)        0         
=================================================================
Total params: 11,680
Trainable params: 11,680
Non-trainable params: 0
_________________________________________________________________
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 123, 123, 32)      2432      
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 121, 121, 32)      9248      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 40, 40, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 38, 38, 32)        9248      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 36, 36, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 10, 10, 32)        9248      
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 8, 8, 32)          9248      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 4, 4, 32)          0         
=================================================================
Total params: 48,672
Trainable params: 48,672
Non-trainable params: 0
_________________________________________________________________

מאוד פרקטי, נכון?

מה לעשות ברגע שיש לך מודל

לאחר שארכיטקטורת המודל שלך מוכנה, תרצה:

מיצוי תכונות עם דגם רציף

לאחר שנבנה מודל רציף, הוא מתנהג כמו מודל API פונקציונלי . המשמעות היא שלכל שכבה יש תכונת input output . ניתן להשתמש במאפיינים אלה כדי לעשות דברים מסודרים, כמו ליצור במהירות מודל שחולץ את התפוקות של כל שכבות הביניים במודל רציף:

initial_model = keras.Sequential(
    [
        keras.Input(shape=(250, 250, 3)),
        layers.Conv2D(32, 5, strides=2, activation="relu"),
        layers.Conv2D(32, 3, activation="relu"),
        layers.Conv2D(32, 3, activation="relu"),
    ]
)
feature_extractor = keras.Model(
    inputs=initial_model.inputs,
    outputs=[layer.output for layer in initial_model.layers],
)

# Call feature extractor on test input.
x = tf.ones((1, 250, 250, 3))
features = feature_extractor(x)

הנה דוגמה דומה המוציאה רק תכונות משכבה אחת:

initial_model = keras.Sequential(
    [
        keras.Input(shape=(250, 250, 3)),
        layers.Conv2D(32, 5, strides=2, activation="relu"),
        layers.Conv2D(32, 3, activation="relu", name="my_intermediate_layer"),
        layers.Conv2D(32, 3, activation="relu"),
    ]
)
feature_extractor = keras.Model(
    inputs=initial_model.inputs,
    outputs=initial_model.get_layer(name="my_intermediate_layer").output,
)
# Call feature extractor on test input.
x = tf.ones((1, 250, 250, 3))
features = feature_extractor(x)

העבר למידה באמצעות מודל רציף

למידת העברה מורכבת מהקפאת השכבות התחתונות במודל ואימון רק של השכבות העליונות. אם אתה לא מכיר את זה, הקפד לקרוא את המדריך שלנו להעברת למידה .

להלן שתי תכניות לימוד העברה נפוצות הכוללות מודלים רצופים.

ראשית, נניח שיש לך מודל רציף, ואתה רוצה להקפיא את כל השכבות למעט האחרונה. במקרה זה, אתה פשוט model.layers על פני model.layers layer.trainable = False בכל שכבה, למעט האחרונה. ככה:

model = keras.Sequential([
    keras.Input(shape=(784))
    layers.Dense(32, activation='relu'),
    layers.Dense(32, activation='relu'),
    layers.Dense(32, activation='relu'),
    layers.Dense(10),
])

# Presumably you would want to first load pre-trained weights.
model.load_weights(...)

# Freeze all layers except the last one.
for layer in model.layers[:-1]:
  layer.trainable = False

# Recompile and train (this will only update the weights of the last layer).
model.compile(...)
model.fit(...)

שרטוט נפוץ נוסף הוא להשתמש במודל רצף כדי לערום מודל שהוכשר מראש וכמה שכבות סיווג שזה עברו אתחול חדש. ככה:

# Load a convolutional base with pre-trained weights
base_model = keras.applications.Xception(
    weights='imagenet',
    include_top=False,
    pooling='avg')

# Freeze the base model
base_model.trainable = False

# Use a Sequential model to add a trainable classifier on top
model = keras.Sequential([
    base_model,
    layers.Dense(1000),
])

# Compile & train
model.compile(...)
model.fit(...)

אם אתה עושה למידה מעבירה, סביר להניח שתמצא את עצמך לעתים קרובות תוך שימוש בשני הדפוסים הללו.

זה בערך כל מה שאתה צריך לדעת על מודלים רצופים!

למידע נוסף על בניית מודלים בקרס, ראה: