![]() | ![]() | ![]() | ![]() |
להכין
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 0x7fcf2e879978>, <tensorflow.python.keras.layers.core.Dense at 0x7fcfdad262b0>, <tensorflow.python.keras.layers.core.Dense at 0x7fcf2c237b70>]
ניתן גם ליצור מודל רציף באופן הדרגתי באמצעות שיטת 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.6612724 , 0.23639882, -0.17644602], [ 0.01855636, -0.7009475 , -0.05331248], [ 0.11539507, 0.03737205, -0.7473268 ], [ 0.45032406, 0.13835168, -0.1536408 ]], 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 0x7fcf2c24aac8>]
חלופה פשוטה היא פשוט להעביר טיעון 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()
ולהדפיס לעתים קרובות סיכומי מודלים. לדוגמה, זה מאפשר לך לפקח על אופן שבו ערימה של שכבות 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 _________________________________________________________________
מאוד פרקטי, נכון?
מה לעשות ברגע שיש לך מודל
לאחר שארכיטקטורת המודל שלך מוכנה, תרצה:
- אימן את המודל שלך, העריך אותו והפעל מסקנות. עיין במדריך שלנו להכשרה והערכה עם הלולאות המובנות
- שמור את המודל שלך בדיסק ושחזר אותו. עיין במדריך שלנו לסידור ושמירה .
- להאיץ את אימוני הדגמים על ידי מינוף מרובות GPUs. עיין במדריך שלנו לאימונים מרובי GPU והפצה .
מיצוי תכונות עם דגם רציף
לאחר שנבנה מודל רציף, הוא מתנהג כמו מודל 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(...)
אם אתה עושה למידה מעבירה, סביר להניח שתמצא את עצמך לעתים קרובות תוך שימוש בשני הדפוסים הללו.
זה בערך כל מה שאתה צריך לדעת על מודלים רצופים!
למידע נוסף על בניית מודלים בקרס, ראה: