تاریخ را ذخیره کنید! Google I / O 18-20 مه بازمی گردد اکنون ثبت نام کنید
این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

انتقال یادگیری و تنظیم دقیق

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub دانلود دفترچه یادداشت

برپایی

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

مقدمه

یادگیری انتقالی شامل استفاده از ویژگیهای آموخته شده روی یک مسئله و استفاده از آنها در یک مسئله مشابه جدید است. به عنوان مثال ، ویژگی های مدلی که شناسایی راکون را آموخته است ممکن است برای شروع یک مدل برای شناسایی تانوکیس مفید باشد.

انتقال یادگیری معمولاً برای کارهایی انجام می شود که داده های شما داده کمی برای آموزش یک مدل در مقیاس کامل از ابتدا داشته باشد.

متداول ترین تجسم یادگیری انتقالی در زمینه یادگیری عمیق ، گردش کار زیر است:

  1. لایه هایی را از یک مدل قبلا آموزش دیده بردارید.
  2. آنها را مسدود کنید تا از تخریب اطلاعات موجود در دوره های بعدی آموزشی جلوگیری شود.
  3. برخی از لایه های جدید و قابل آموزش را در بالای لایه های یخ زده اضافه کنید. آنها یاد خواهند گرفت که ویژگی های قدیمی را به مجموعه داده های جدید تبدیل به پیش بینی کنند.
  4. لایه های جدید را روی مجموعه داده خود آموزش دهید.

آخرین مرحله ، اختیاری ، تنظیم دقیق است که شامل خنک کردن کل مدلی است که در بالا (یا بخشی از آن) به دست آورده اید و آموزش مجدد آن بر روی داده های جدید با میزان یادگیری بسیار پایین است. این به طور بالقوه می تواند با انطباق تدریجی ویژگی های آموزش دیده با داده های جدید ، به پیشرفت های معنی داری دست یابد.

در ابتدا ، ما به طور کامل جزئیات API trainable Keras را مرور خواهیم کرد ، که اصلی ترین جریان یادگیری انتقال و تنظیم دقیق آن است.

سپس ، ما با گرفتن مدلی از پیش آموزش داده شده در مجموعه داده ImageNet ، و بازآموزی آن در مجموعه داده های طبقه بندی "گربه ها در مقابل سگها" Kaggle ، روند کار معمول را نشان خواهیم داد.

این مطلب از یادگیری عمیق با پایتون و پست وبلاگ 2016 "ساخت مدل های طبقه بندی تصویر قدرتمند با استفاده از داده های بسیار کم" اقتباس شده است.

انجماد لایه ها: درک ویژگی trainable

لایه ها و مدل ها دارای سه ویژگی وزن هستند:

  • weights لیستی از تمام متغیرهای وزن لایه است.
  • trainable_weights لیستی از مواردی است که قرار است به روز شود (از طریق گرادیان نزولی) تا حداقل ضرر را در حین آموزش کاهش دهد.
  • non_trainable_weights های غیر قابل آموزش لیستی از مواردی است که قصد آموزش ندارند. به طور معمول آنها توسط مدل در هنگام عبور به جلو به روز می شوند.

مثال: لایه Dense دارای 2 وزن قابل تمرین (هسته و تعصب) است

layer = keras.layers.Dense(3)
layer.build((None, 4))  # Create the weights

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 2
trainable_weights: 2
non_trainable_weights: 0

به طور کلی ، همه وزنه ها وزنی قابل تمرین هستند. تنها لایه داخلی که دارای وزنی BatchNormalization لایه BatchNormalization است. این از وزنه های غیرقابل آموزش برای اندازه گیری میانگین و واریانس ورودی های خود در طول آموزش استفاده می کند. برای یادگیری نحوه استفاده از وزنه های غیرقابل آموزش در لایه های سفارشی خود ، به راهنمای نوشتن لایه های جدید از ابتدا مراجعه کنید .

مثال: لایه BatchNormalization دارای 2 وزن قابل آموزش و 2 وزن غیر قابل آموزش است

layer = keras.layers.BatchNormalization()
layer.build((None, 4))  # Create the weights

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 4
trainable_weights: 2
non_trainable_weights: 2

لایه ها و مدل ها همچنین دارای ویژگی بولی trainable . مقدار آن قابل تغییر است. تنظیم layer.trainable به False حرکت می کند تمام وزن لایه را از تربیت شدنی به غیر تربیت شدنی به این حالت "انجماد" لایه گفته می شود: حالت لایه منجمد در حین آموزش به روز نمی شود (چه هنگام تمرین با fit() و چه هنگام آموزش با هر حلقه سفارشی که برای اعمال به روزرسانی های شیب دار به trainable_weights متکی باشد.

مثال: تنظیم trainable به False

layer = keras.layers.Dense(3)
layer.build((None, 4))  # Create the weights
layer.trainable = False  # Freeze the layer

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 2
trainable_weights: 0
non_trainable_weights: 2

وقتی وزنه ای قابل تمرین غیرقابل آموزش شود ، دیگر ارزش آن در حین آموزش به روز نمی شود.

# Make a model with 2 layers
layer1 = keras.layers.Dense(3, activation="relu")
layer2 = keras.layers.Dense(3, activation="sigmoid")
model = keras.Sequential([keras.Input(shape=(3,)), layer1, layer2])

# Freeze the first layer
layer1.trainable = False

# Keep a copy of the weights of layer1 for later reference
initial_layer1_weights_values = layer1.get_weights()

# Train the model
model.compile(optimizer="adam", loss="mse")
model.fit(np.random.random((2, 3)), np.random.random((2, 3)))

# Check that the weights of layer1 have not changed during training
final_layer1_weights_values = layer1.get_weights()
np.testing.assert_allclose(
    initial_layer1_weights_values[0], final_layer1_weights_values[0]
)
np.testing.assert_allclose(
    initial_layer1_weights_values[1], final_layer1_weights_values[1]
)
1/1 [==============================] - 1s 664ms/step - loss: 0.1025

ویژگی layer.trainable را با training آرگومان در layer.__call__() اشتباه نگیرید layer.__call__() (که کنترل می کند آیا لایه باید پاس رو به جلو را در حالت استنتاج یا حالت آموزش اجرا کند). برای اطلاعات بیشتر ، به س .الات متداول Keras مراجعه کنید.

تنظیم بازگشتی ویژگی trainable

اگر trainable = False روی یک مدل یا روی هر لایه ای که دارای زیر لایه باشد تنظیم کنید ، تمام لایه های کودکان نیز غیرقابل آموزش هستند.

مثال:

inner_model = keras.Sequential(
    [
        keras.Input(shape=(3,)),
        keras.layers.Dense(3, activation="relu"),
        keras.layers.Dense(3, activation="relu"),
    ]
)

model = keras.Sequential(
    [keras.Input(shape=(3,)), inner_model, keras.layers.Dense(3, activation="sigmoid"),]
)

model.trainable = False  # Freeze the outer model

assert inner_model.trainable == False  # All layers in `model` are now frozen
assert inner_model.layers[0].trainable == False  # `trainable` is propagated recursively

گردش کار یادگیری انتقال

این ما را به چگونگی پیاده سازی گردش کار یادگیری انتقال معمول در کراس هدایت می کند:

  1. یک مدل پایه را مثال بزنید و وزنه های از قبل آموزش دیده را در آن بارگیری کنید.
  2. با تنظیم قابلیت trainable = False تمام لایه ها را در مدل پایه مسدود کنید.
  3. در بالای خروجی یک (یا چند) لایه از مدل پایه ، یک مدل جدید ایجاد کنید.
  4. مدل جدید خود را بر روی مجموعه داده جدید خود آموزش دهید.

توجه داشته باشید که یک جریان کار جایگزین و سبک تر نیز می تواند این موارد باشد:

  1. یک مدل پایه را مثال بزنید و وزنه های از قبل آموزش دیده را در آن بارگیری کنید.
  2. مجموعه داده جدید خود را از طریق آن اجرا کرده و خروجی یک (یا چند) لایه از مدل پایه را ضبط کنید. به این عمل استخراج ویژگی گفته می شود .
  3. از آن خروجی به عنوان داده ورودی برای یک مدل کوچکتر و جدید استفاده کنید.

یک مزیت کلیدی در گردش کار دوم این است که شما فقط یک بار مدل پایه را بر روی داده های خود اجرا می کنید ، نه یک دوره در دوره آموزش. بنابراین بسیار سریعتر و ارزان تر است.

مسئله ای که در مورد گردش کار دوم وجود دارد این است که به شما اجازه نمی دهد داده های ورودی مدل جدید خود را در حین آموزش به صورت پویا تغییر دهید ، این مورد برای مثال در هنگام افزایش داده مورد نیاز است. یادگیری انتقال معمولاً برای کارهایی استفاده می شود که مجموعه داده جدید شما برای آموزش یک مدل در مقیاس کامل از ابتدا داده کمی داشته باشد و در چنین حالاتی ، افزایش داده بسیار مهم است. بنابراین در آنچه در زیر می آید ، روی اولین گردش کار تمرکز خواهیم کرد.

در اینجا اولین گردش کار در کراس به شرح زیر است:

ابتدا یک مدل پایه با وزنه های از قبل آموزش دیده نمونه بگیرید.

base_model = keras.applications.Xception(
    weights='imagenet',  # Load weights pre-trained on ImageNet.
    input_shape=(150, 150, 3),
    include_top=False)  # Do not include the ImageNet classifier at the top.

سپس ، مدل پایه را فریز کنید.

base_model.trainable = False

یک مدل جدید در بالا ایجاد کنید.

inputs = keras.Input(shape=(150, 150, 3))
# We make sure that the base_model is running in inference mode here,
# by passing `training=False`. This is important for fine-tuning, as you will
# learn in a few paragraphs.
x = base_model(inputs, training=False)
# Convert features of shape `base_model.output_shape[1:]` to vectors
x = keras.layers.GlobalAveragePooling2D()(x)
# A Dense classifier with a single unit (binary classification)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

مدل را بر روی داده های جدید آموزش دهید.

model.compile(optimizer=keras.optimizers.Adam(),
              loss=keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=[keras.metrics.BinaryAccuracy()])
model.fit(new_dataset, epochs=20, callbacks=..., validation_data=...)

تنظیم دقیق

هنگامی که مدل شما بر روی داده های جدید همگرایی کرد ، می توانید سعی کنید تمام یا بخشی از مدل پایه را خنک کرده و کل مدل را با سرعت یادگیری بسیار پایین ، از انتها به انتها آموزش دهید.

این آخرین مرحله اختیاری است که به طور بالقوه می تواند پیشرفت های افزایشی را برای شما ایجاد کند. همچنین می تواند به طور بالقوه باعث نصب سریع بیش از حد شود - این را بخاطر داشته باشید.

انجام این مرحله فقط پس از آموزش مدل با لایه های یخ زده برای همگرایی بسیار مهم است. اگر لایه های قابل آموزش اولیه را به طور تصادفی با لایه های قابل آموزش که دارای ویژگی های از قبل آموزش دیده اند مخلوط کنید ، لایه های اولیه به صورت تصادفی باعث به روزرسانی شیب بسیار بزرگ در حین آموزش می شوند ، که باعث از بین رفتن ویژگی های از قبل آموزش دیده شما می شود.

همچنین استفاده از میزان یادگیری بسیار پایین در این مرحله بسیار مهم است ، زیرا شما یک مدل بسیار بزرگتر از دور اول آموزش را روی مجموعه داده ای که معمولاً بسیار کوچک است آموزش می دهید. در نتیجه ، اگر به روزرسانی های سنگین وزن انجام دهید ، خیلی سریع در معرض خطر مجهز شدن بیش از حد قرار دارید. در اینجا ، شما فقط می خواهید وزن های آموزش دیده را به صورت افزایشی از نو تنظیم کنید.

این نحوه تنظیم دقیق کل مدل پایه است:

# Unfreeze the base model
base_model.trainable = True

# It's important to recompile your model after you make any changes
# to the `trainable` attribute of any inner layer, so that your changes
# are take into account
model.compile(optimizer=keras.optimizers.Adam(1e-5),  # Very low learning rate
              loss=keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=[keras.metrics.BinaryAccuracy()])

# Train end-to-end. Be careful to stop before you overfit!
model.fit(new_dataset, epochs=10, callbacks=..., validation_data=...)

یادداشت مهم در مورد compile() و trainable

فراخوانی compile() در مدل به معنای "مسدود کردن" رفتار آن مدل است. این بدان معنی است که مقادیر ویژگی trainable در زمان تدوین مدل باید در طول عمر آن مدل حفظ شود ، تا زمانی که دوباره compile فراخوانی شود. از این رو ، اگر مقدار trainable را تغییر دادید ، مطمئن شوید که compile() با compile() بر روی مدل خود تماس بگیرید تا تغییرات شما در نظر گرفته شود.

نکات مهم در مورد لایه BatchNormalization

بسیاری از مدل های تصویر حاوی لایه های BatchNormalization هستند. این لایه برای هر تعداد قابل تصور مورد خاصی است. در اینجا چند نکته وجود دارد که باید بخاطر بسپارید.

  • BatchNormalization شامل 2 وزن غیرقابل آموزش است که در حین آموزش به روز می شوند. اینها متغیرهایی هستند که میانگین و واریانس ورودی ها را ردیابی می کنند.
  • هنگامی که bn_layer.trainable = False تنظیم می کنید ، لایه BatchNormalization در حالت استنتاج اجرا می شود و میانگین و واریانس آن را به روز نمی کند. به طور کلی این مورد در مورد سایر لایه ها وجود ندارد ، زیرا حالت های آموزش وزن و استنباط / آموزش دو مفهوم متعامد هستند . اما این دو در مورد لایه BatchNormalization گره خورده اند.
  • هنگامی که مدلی را که شامل لایه های BatchNormalization برای تنظیم دقیق BatchNormalization می کنید ، باید با گذراندن training=False هنگام فراخوانی مدل پایه ، لایه های BatchNormalization در حالت استنتاج نگه دارید. در غیر این صورت ، به روزرسانی هایی که برای وزنه های غیرقابل تعلیم اعمال می شوند ، ناگهان آنچه را که مدل یاد گرفته است از بین می برند.

این الگو را به صورت عملی در انتهای این راهنما مشاهده خواهید کرد.

انتقال و تنظیم دقیق با یک حلقه آموزش سفارشی

اگر به جای fit() ، از حلقه آموزش سطح پایین خود استفاده می کنید ، روند کار اساساً ثابت می ماند. باید توجه داشته باشید که هنگام استفاده از به روزرسانی های شیب دار ، فقط model.trainable_weights را در نظر بگیرید:

# Create base model
base_model = keras.applications.Xception(
    weights='imagenet',
    input_shape=(150, 150, 3),
    include_top=False)
# Freeze base model
base_model.trainable = False

# Create new model on top.
inputs = keras.Input(shape=(150, 150, 3))
x = base_model(inputs, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
optimizer = keras.optimizers.Adam()

# Iterate over the batches of a dataset.
for inputs, targets in new_dataset:
    # Open a GradientTape.
    with tf.GradientTape() as tape:
        # Forward pass.
        predictions = model(inputs)
        # Compute the loss value for this batch.
        loss_value = loss_fn(targets, predictions)

    # Get gradients of loss wrt the *trainable* weights.
    gradients = tape.gradient(loss_value, model.trainable_weights)
    # Update the weights of the model.
    optimizer.apply_gradients(zip(gradients, model.trainable_weights))

به همین ترتیب برای تنظیم دقیق.

یک مثال از انتها به انتها: تنظیم دقیق یک مدل طبقه بندی تصویر در مجموعه داده گربه ها و سگ ها

برای تحکیم این مفاهیم ، بیایید شما را با یک مثال ملموس برای یادگیری انتقال پایان به انتها و تنظیم دقیق آن آشنا کنیم. ما مدل Xception را که قبلاً در ImageNet آموزش دیده است بارگیری می کنیم و از آن در مجموعه داده های طبقه بندی "گربه ها در مقابل سگها" Kaggle استفاده می کنیم.

دریافت داده ها

ابتدا ، بیایید مجموعه داده گربه ها و سگ ها را با استفاده از TFDS واکشی کنیم. اگر مجموعه داده خود را داشته باشید ، احتمالاً می خواهید از ابزار tf.keras.preprocessing.image_dataset_from_directory برای تولید اشیا dataset مشابه مجموعه داده با برچسب از مجموعه ای از تصاویر روی دیسک که در پوشه های خاص کلاس قرار دارند ، استفاده کنید.

انتقال کار هنگام کار با مجموعه داده های بسیار کوچک بسیار مفید است. برای کوچک نگه داشتن مجموعه داده خود ، از 40٪ از داده های اصلی آموزش (25000 تصویر) برای آموزش ، 10٪ برای اعتبار سنجی و 10٪ برای آزمایش استفاده خواهیم کرد.

import tensorflow_datasets as tfds

tfds.disable_progress_bar()

train_ds, validation_ds, test_ds = tfds.load(
    "cats_vs_dogs",
    # Reserve 10% for validation and 10% for test
    split=["train[:40%]", "train[40%:50%]", "train[50%:60%]"],
    as_supervised=True,  # Include labels
)

print("Number of training samples: %d" % tf.data.experimental.cardinality(train_ds))
print(
    "Number of validation samples: %d" % tf.data.experimental.cardinality(validation_ds)
)
print("Number of test samples: %d" % tf.data.experimental.cardinality(test_ds))
Number of training samples: 9305
Number of validation samples: 2326
Number of test samples: 2326

این 9 تصویر اول در مجموعه داده های آموزشی است - همانطور که می بینید ، اندازه همه آنها متفاوت است.

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for i, (image, label) in enumerate(train_ds.take(9)):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(image)
    plt.title(int(label))
    plt.axis("off")

png

همچنین می توانیم ببینیم که برچسب 1 "سگ" و برچسب 0 "گربه" است.

استاندارد سازی داده ها

تصاویر خام ما دارای اندازه های متنوعی هستند. علاوه بر این ، هر پیکسل از 3 مقدار عدد صحیح بین 0 تا 255 (مقادیر سطح RGB) تشکیل شده است. این مورد مناسبی برای تغذیه شبکه عصبی نیست. ما باید 2 کار انجام دهیم:

  • به اندازه تصویر ثابت استاندارد کنید. ما 150x150 را انتخاب می کنیم.
  • مقادیر پیکسل را بین 1 تا 1 Normalization این کار را با استفاده از یک لایه Normalization به عنوان بخشی از خود مدل انجام می دهیم.

به طور کلی ، تهیه مدل هایی که داده های خام را به عنوان ورودی در نظر می گیرند ، روش خوبی است ، در مقابل مدل هایی که داده های پیش پردازش شده قبلی را می گیرند. دلیل این امر این است که ، اگر مدل شما انتظار داده های پردازش شده را دارد ، هر زمان که مدل خود را برای استفاده از آن در مکان دیگری (در یک مرورگر وب ، در یک برنامه تلفن همراه) صادر می کنید ، باید دقیقاً همان خط تولید پیش پردازش را مجدداً پیاده سازی کنید. این خیلی سریع خیلی مشکل می شود. بنابراین ما باید کمترین میزان ممکن را برای پیش پردازش قبل از برخورد با مدل انجام دهیم.

در اینجا ، ما تغییر اندازه تصویر را در خط لوله داده انجام خواهیم داد (زیرا یک شبکه عصبی عمیق فقط می تواند دسته های مجاور داده را پردازش کند) و هنگام ایجاد مقیاس گذاری مقادیر ورودی را به عنوان بخشی از مدل انجام خواهیم داد.

اجازه دهید اندازه تصاویر را به 150x150 تغییر دهیم:

size = (150, 150)

train_ds = train_ds.map(lambda x, y: (tf.image.resize(x, size), y))
validation_ds = validation_ds.map(lambda x, y: (tf.image.resize(x, size), y))
test_ds = test_ds.map(lambda x, y: (tf.image.resize(x, size), y))

علاوه بر این ، بیایید داده ها را دسته ای کرده و برای بهینه سازی سرعت بارگذاری ، از حافظه پنهان و پیش تنظیم استفاده کنیم.

batch_size = 32

train_ds = train_ds.cache().batch(batch_size).prefetch(buffer_size=10)
validation_ds = validation_ds.cache().batch(batch_size).prefetch(buffer_size=10)
test_ds = test_ds.cache().batch(batch_size).prefetch(buffer_size=10)

با استفاده از افزایش داده تصادفی

وقتی مجموعه داده تصویری بزرگی ندارید ، روش خوبی است که با اعمال تحولات تصادفی و در عین حال واقع بینانه روی تصاویر آموزشی ، مانند ورق زدن افقی تصادفی یا چرخش های تصادفی کوچک ، تنوع نمونه را به طور مصنوعی معرفی کنید. این به شما کمک می کند تا مدل در معرض جنبه های مختلف داده های آموزش قرار گیرد در حالی که مجهز شدن بیش از حد به تجهیزات را کاهش می دهد.

from tensorflow import keras
from tensorflow.keras import layers

data_augmentation = keras.Sequential(
    [
        layers.experimental.preprocessing.RandomFlip("horizontal"),
        layers.experimental.preprocessing.RandomRotation(0.1),
    ]
)

بیایید تصور کنیم که اولین تصویر از دسته اول پس از تغییرات تصادفی مختلف به نظر می رسد:

import numpy as np

for images, labels in train_ds.take(1):
    plt.figure(figsize=(10, 10))
    first_image = images[0]
    for i in range(9):
        ax = plt.subplot(3, 3, i + 1)
        augmented_image = data_augmentation(
            tf.expand_dims(first_image, 0), training=True
        )
        plt.imshow(augmented_image[0].numpy().astype("int32"))
        plt.title(int(labels[0]))
        plt.axis("off")

png

یک مدل بسازید

حالا بیایید یک مدل بسازیم که از نقشه ای که قبلا توضیح دادیم پیروی کند.

توجه داشته باشید که:

  • ما یک لایه Normalization برای مقیاس گذاری مقادیر ورودی (ابتدا در محدوده [0, 255] ) به محدوده [-1, 1] .
  • ما یک لایه Dropout قبل از لایه طبقه بندی ، برای منظم سازی اضافه می کنیم.
  • ما اطمینان حاصل می کنیم که هنگام فراخوانی مدل پایه ، training=False ، بنابراین در حالت استنتاج اجرا می شود ، بنابراین حتی پس از باز کردن مدل پایه برای تنظیم دقیق ، آمار دسته ای به روز نمی شود.
base_model = keras.applications.Xception(
    weights="imagenet",  # Load weights pre-trained on ImageNet.
    input_shape=(150, 150, 3),
    include_top=False,
)  # Do not include the ImageNet classifier at the top.

# Freeze the base_model
base_model.trainable = False

# Create new model on top
inputs = keras.Input(shape=(150, 150, 3))
x = data_augmentation(inputs)  # Apply random data augmentation

# Pre-trained Xception weights requires that input be normalized
# from (0, 255) to a range (-1., +1.), the normalization layer
# does the following, outputs = (inputs - mean) / sqrt(var)
norm_layer = keras.layers.experimental.preprocessing.Normalization()
mean = np.array([127.5] * 3)
var = mean ** 2
# Scale inputs to [-1, +1]
x = norm_layer(x)
norm_layer.set_weights([mean, var])

# The base model contains batchnorm layers. We want to keep them in inference mode
# when we unfreeze the base model for fine-tuning, so we make sure that the
# base_model is running in inference mode here.
x = base_model(x, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
x = keras.layers.Dropout(0.2)(x)  # Regularize with dropout
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

model.summary()
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/xception/xception_weights_tf_dim_ordering_tf_kernels_notop.h5
83689472/83683744 [==============================] - 1s 0us/step
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         [(None, 150, 150, 3)]     0         
_________________________________________________________________
sequential_3 (Sequential)    (None, 150, 150, 3)       0         
_________________________________________________________________
normalization (Normalization (None, 150, 150, 3)       7         
_________________________________________________________________
xception (Functional)        (None, 5, 5, 2048)        20861480  
_________________________________________________________________
global_average_pooling2d (Gl (None, 2048)              0         
_________________________________________________________________
dropout (Dropout)            (None, 2048)              0         
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 2049      
=================================================================
Total params: 20,863,536
Trainable params: 2,049
Non-trainable params: 20,861,487
_________________________________________________________________

لایه بالایی را آموزش دهید

model.compile(
    optimizer=keras.optimizers.Adam(),
    loss=keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=[keras.metrics.BinaryAccuracy()],
)

epochs = 20
model.fit(train_ds, epochs=epochs, validation_data=validation_ds)
Epoch 1/20
291/291 [==============================] - 20s 49ms/step - loss: 0.2226 - binary_accuracy: 0.8972 - val_loss: 0.0805 - val_binary_accuracy: 0.9703
Epoch 2/20
291/291 [==============================] - 8s 29ms/step - loss: 0.1246 - binary_accuracy: 0.9464 - val_loss: 0.0757 - val_binary_accuracy: 0.9712
Epoch 3/20
291/291 [==============================] - 8s 29ms/step - loss: 0.1153 - binary_accuracy: 0.9480 - val_loss: 0.0724 - val_binary_accuracy: 0.9733
Epoch 4/20
291/291 [==============================] - 8s 29ms/step - loss: 0.1055 - binary_accuracy: 0.9575 - val_loss: 0.0753 - val_binary_accuracy: 0.9721
Epoch 5/20
291/291 [==============================] - 8s 28ms/step - loss: 0.1026 - binary_accuracy: 0.9589 - val_loss: 0.0750 - val_binary_accuracy: 0.9703
Epoch 6/20
291/291 [==============================] - 8s 28ms/step - loss: 0.1022 - binary_accuracy: 0.9587 - val_loss: 0.0723 - val_binary_accuracy: 0.9716
Epoch 7/20
291/291 [==============================] - 8s 28ms/step - loss: 0.1009 - binary_accuracy: 0.9570 - val_loss: 0.0731 - val_binary_accuracy: 0.9708
Epoch 8/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0947 - binary_accuracy: 0.9576 - val_loss: 0.0726 - val_binary_accuracy: 0.9716
Epoch 9/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0872 - binary_accuracy: 0.9624 - val_loss: 0.0720 - val_binary_accuracy: 0.9712
Epoch 10/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0892 - binary_accuracy: 0.9622 - val_loss: 0.0711 - val_binary_accuracy: 0.9716
Epoch 11/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0987 - binary_accuracy: 0.9608 - val_loss: 0.0752 - val_binary_accuracy: 0.9712
Epoch 12/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0962 - binary_accuracy: 0.9595 - val_loss: 0.0715 - val_binary_accuracy: 0.9738
Epoch 13/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0972 - binary_accuracy: 0.9606 - val_loss: 0.0700 - val_binary_accuracy: 0.9725
Epoch 14/20
291/291 [==============================] - 8s 28ms/step - loss: 0.1019 - binary_accuracy: 0.9568 - val_loss: 0.0779 - val_binary_accuracy: 0.9690
Epoch 15/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0929 - binary_accuracy: 0.9614 - val_loss: 0.0700 - val_binary_accuracy: 0.9729
Epoch 16/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0937 - binary_accuracy: 0.9610 - val_loss: 0.0698 - val_binary_accuracy: 0.9742
Epoch 17/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0945 - binary_accuracy: 0.9613 - val_loss: 0.0671 - val_binary_accuracy: 0.9759
Epoch 18/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0868 - binary_accuracy: 0.9612 - val_loss: 0.0692 - val_binary_accuracy: 0.9738
Epoch 19/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0871 - binary_accuracy: 0.9647 - val_loss: 0.0691 - val_binary_accuracy: 0.9746
Epoch 20/20
291/291 [==============================] - 8s 28ms/step - loss: 0.0922 - binary_accuracy: 0.9603 - val_loss: 0.0721 - val_binary_accuracy: 0.9738
<tensorflow.python.keras.callbacks.History at 0x7fb73f231860>

یک دور تنظیم دقیق از کل مدل را انجام دهید

در آخر ، بیایید مدل پایه را خنک کرده و کل مدل را با سرعت یادگیری پایین به انتها آموزش دهیم.

نکته مهم ، اگرچه مدل پایه قابل آموزش است ، اما از زمانی که ما training=False گذرانده ایم training=False هنگام تماس با آن هنگام ساختن مدل ، training=False ، آن را در حالت استنباط اجرا می کند. این بدان معنی است که لایه های نرمال دسته ای در داخل ، آمار دسته ای خود را به روز نمی کنند. اگر این کار را می کردند ، ویرانی هایی را که نمایندگان تاکنون آموخته اند خراب می کنند.

# Unfreeze the base_model. Note that it keeps running in inference mode
# since we passed `training=False` when calling it. This means that
# the batchnorm layers will not update their batch statistics.
# This prevents the batchnorm layers from undoing all the training
# we've done so far.
base_model.trainable = True
model.summary()

model.compile(
    optimizer=keras.optimizers.Adam(1e-5),  # Low learning rate
    loss=keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=[keras.metrics.BinaryAccuracy()],
)

epochs = 10
model.fit(train_ds, epochs=epochs, validation_data=validation_ds)
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         [(None, 150, 150, 3)]     0         
_________________________________________________________________
sequential_3 (Sequential)    (None, 150, 150, 3)       0         
_________________________________________________________________
normalization (Normalization (None, 150, 150, 3)       7         
_________________________________________________________________
xception (Functional)        (None, 5, 5, 2048)        20861480  
_________________________________________________________________
global_average_pooling2d (Gl (None, 2048)              0         
_________________________________________________________________
dropout (Dropout)            (None, 2048)              0         
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 2049      
=================================================================
Total params: 20,863,536
Trainable params: 20,809,001
Non-trainable params: 54,535
_________________________________________________________________
Epoch 1/10
291/291 [==============================] - 43s 133ms/step - loss: 0.0814 - binary_accuracy: 0.9677 - val_loss: 0.0527 - val_binary_accuracy: 0.9776
Epoch 2/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0544 - binary_accuracy: 0.9796 - val_loss: 0.0537 - val_binary_accuracy: 0.9776
Epoch 3/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0481 - binary_accuracy: 0.9822 - val_loss: 0.0471 - val_binary_accuracy: 0.9789
Epoch 4/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0324 - binary_accuracy: 0.9871 - val_loss: 0.0551 - val_binary_accuracy: 0.9807
Epoch 5/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0298 - binary_accuracy: 0.9899 - val_loss: 0.0447 - val_binary_accuracy: 0.9807
Epoch 6/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0262 - binary_accuracy: 0.9901 - val_loss: 0.0469 - val_binary_accuracy: 0.9824
Epoch 7/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0242 - binary_accuracy: 0.9918 - val_loss: 0.0539 - val_binary_accuracy: 0.9798
Epoch 8/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0153 - binary_accuracy: 0.9935 - val_loss: 0.0644 - val_binary_accuracy: 0.9794
Epoch 9/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0175 - binary_accuracy: 0.9934 - val_loss: 0.0496 - val_binary_accuracy: 0.9819
Epoch 10/10
291/291 [==============================] - 38s 129ms/step - loss: 0.0171 - binary_accuracy: 0.9936 - val_loss: 0.0496 - val_binary_accuracy: 0.9828
<tensorflow.python.keras.callbacks.History at 0x7fb74f74f940>

پس از 10 دوره ، تنظیم دقیق در اینجا پیشرفت خوبی به دست می آورد.