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

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

يثبت

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

متى تستخدم النموذج المتسلسل

A 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)))

A متسلسل نموذج غير مناسب في الحالات التالية:

  • يحتوي نموذجك على مدخلات متعددة أو مخرجات متعددة
  • تحتوي أي طبقة من طبقاتك على مدخلات متعددة أو مخرجات متعددة
  • ما عليك القيام به لمشاركة الطبقة
  • تريد طبولوجيا غير خطية (على سبيل المثال ، اتصال متبقي ، نموذج متعدد الفروع)

إنشاء نموذج تسلسلي

يمكنك إنشاء نموذج تسلسلي عن طريق تمرير قائمة الطبقات إلى المُنشئ المتسلسل:

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

طبقات يمكن الوصول إليها من خلال layers السمة:

model.layers
[<keras.layers.core.Dense at 0x7fdc784478d0>,
 <keras.layers.core.Dense at 0x7fdbbc3c4650>,
 <keras.layers.core.Dense at 0x7fdbbc3c4a10>]

يمكنك أيضا إنشاء نموذج متسلسل تدريجيا من خلال 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.5319189 , -0.8767905 , -0.63919735],
        [-0.6276014 ,  0.1689707 , -0.57695866],
        [ 0.6710613 ,  0.5354214 , -0.00893992],
        [ 0.15670097, -0.15280598,  0.8865864 ]], 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
[<keras.layers.core.Dense at 0x7fdbbc37c390>]

وثمة بديل بسيط هو مجرد تمرير 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
_________________________________________________________________

النماذج التي تم إنشاؤها باستخدام شكل إدخال محدد مسبقًا مثل هذا لها دائمًا أوزان (حتى قبل رؤية أي بيانات) ولها دائمًا شكل إخراج محدد.

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

A التصحيح العمل المشترك: add() + summary()

عند بناء هيكل متتابعة جديدة، فإنه من المفيد أن كومة تدريجيا طبقات مع add() ، وكثيرا ما طباعة ملخصات نموذج. على سبيل المثال، وهذا يتيح لك لمراقبة كيف كومة من 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 ومجموعة 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 ، راجع: