النموذج المتسلسل

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

يثبت

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 عبر سمة layers :

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f8af834ccc0>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f8ba42a2080>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f8af4506240>]

يمكنك أيضًا إنشاء نموذج تسلسلي بشكل تدريجي عبر طريقة 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 ، تمامًا مثل أي طبقة أو نموذج في Keras. يُعد هذا مفيدًا لإضافة تعليق توضيحي على الرسوم البيانية للوحة 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"))

تحديد شكل الإدخال مقدمًا

بشكل عام ، تحتاج جميع الطبقات في Keras إلى معرفة شكل مدخلاتها حتى تتمكن من تكوين أوزانها. لذلك عندما تقوم بإنشاء طبقة مثل هذه ، في البداية ، ليس لها أي أوزان:

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.37242043,  0.8652495 ,  0.27929688],
        [-0.1227327 ,  0.80179167,  0.4077394 ],
        [-0.05193728,  0.6267668 , -0.00613904],
        [ 0.57773185, -0.54531974,  0.8418772 ]], 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() لعرض محتوياته:

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 0x7f8af4520470>]

البديل البسيط هو تمرير وسيطة 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 طبقات MaxPooling2D و 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 وتعيين 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(...)

إذا قمت بنقل التعلم ، فمن المحتمل أن تجد نفسك تستخدم هذين النموذجين بشكل متكرر.

هذا كل ما تحتاج لمعرفته حول النماذج المتتابعة!

لمعرفة المزيد حول بناء النماذج في Keras ، راجع: