مشاهده در TensorFlow.org | در Google Colab اجرا شود | مشاهده منبع در GitHub | دانلود دفترچه یادداشت |
این آموزش نحوه طبقه بندی تصاویر گل ها را نشان می دهد. با استفاده از مدل tf.keras.Sequential
یک طبقهبندی کننده تصویر ایجاد میکند و دادهها را با استفاده از tf.keras.utils.image_dataset_from_directory
. با مفاهیم زیر تجربه عملی کسب خواهید کرد:
- بارگذاری کارآمد یک مجموعه داده از روی دیسک.
- شناسایی بیش از حد برازش و به کارگیری تکنیکهایی برای کاهش آن، از جمله افزایش داده و حذف.
این آموزش یک گردش کار اصلی یادگیری ماشین را دنبال می کند:
- داده ها را بررسی و درک کنید
- یک خط لوله ورودی بسازید
- مدل را بسازید
- مدل را آموزش دهید
- مدل را تست کنید
- مدل را بهبود بخشید و روند را تکرار کنید
TensorFlow و کتابخانه های دیگر را وارد کنید
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
مجموعه داده را دانلود و کاوش کنید
این آموزش از مجموعه داده ای از حدود 3700 عکس گل استفاده می کند. مجموعه داده شامل پنج زیرمجموعه است، یکی در هر کلاس:
flower_photo/
daisy/
dandelion/
roses/
sunflowers/
tulips/
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
پس از دانلود، اکنون باید یک کپی از مجموعه داده در دسترس داشته باشید. در کل 3670 تصویر وجود دارد:
image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)
3670
در اینجا چند گل رز وجود دارد:
roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))
PIL.Image.open(str(roses[1]))
و چند گل لاله:
tulips = list(data_dir.glob('tulips/*'))
PIL.Image.open(str(tulips[0]))
PIL.Image.open(str(tulips[1]))
داده ها را با استفاده از ابزار Keras بارگیری کنید
بیایید این تصاویر را با استفاده از ابزار مفید tf.keras.utils.image_dataset_from_directory
از روی دیسک بارگذاری کنیم. این شما را از فهرستی از تصاویر روی دیسک به tf.data.Dataset
تنها در چند خط کد می برد. در صورت تمایل، می توانید با مراجعه به آموزش بارگیری و پیش پردازش تصاویر ، کد بارگذاری داده های خود را از ابتدا بنویسید.
یک مجموعه داده ایجاد کنید
چند پارامتر برای لودر تعریف کنید:
batch_size = 32
img_height = 180
img_width = 180
استفاده از تقسیم اعتبار در هنگام توسعه مدل خود تمرین خوبی است. بیایید 80٪ از تصاویر را برای آموزش و 20٪ برای اعتبار سنجی استفاده کنیم.
train_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
Found 3670 files belonging to 5 classes. Using 2936 files for training.
val_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
Found 3670 files belonging to 5 classes. Using 734 files for validation.
می توانید نام کلاس ها را در ویژگی class_names
در این مجموعه داده ها پیدا کنید. اینها به ترتیب حروف الفبا با نام دایرکتوری مطابقت دارند.
class_names = train_ds.class_names
print(class_names)
['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']
داده ها را تجسم کنید
در اینجا نه تصویر اول از مجموعه داده آموزشی آمده است:
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
شما یک مدل را با استفاده از این مجموعه داده ها با ارسال آنها به Model.fit
در یک لحظه آموزش خواهید داد. اگر دوست دارید، میتوانید به صورت دستی روی مجموعه داده تکرار کنید و دستهای از تصاویر را بازیابی کنید:
for image_batch, labels_batch in train_ds:
print(image_batch.shape)
print(labels_batch.shape)
break
(32, 180, 180, 3) (32,)
image_batch
تانسور شکل (32, 180, 180, 3)
است. این مجموعه ای از 32 تصویر به شکل 180x180x3
است (بعد آخر به کانال های رنگی RGB اشاره دارد). label_batch
یک تانسور شکل (32,)
است، اینها برچسب های مربوط به 32 تصویر هستند.
می توانید .numpy()
را در تانسورهای image_batch
و labels_batch
کنید تا آنها را به numpy.ndarray
تبدیل کنید.
مجموعه داده را برای عملکرد پیکربندی کنید
بیایید مطمئن شویم که از واکشی اولیه بافر استفاده می کنیم تا بتوانید بدون مسدود شدن ورودی/خروجی، داده ها را از دیسک به دست آورید. این دو روش مهم هستند که باید هنگام بارگیری داده ها از آنها استفاده کنید:
-
Dataset.cache
تصاویر را پس از بارگیری از دیسک در اولین دوره در حافظه نگه می دارد. این اطمینان حاصل می کند که مجموعه داده در حین آموزش مدل شما به یک گلوگاه تبدیل نمی شود. اگر مجموعه داده شما بیش از حد بزرگ است که نمی تواند در حافظه قرار بگیرد، می توانید از این روش برای ایجاد یک حافظه کش عملکردی روی دیسک نیز استفاده کنید. -
Dataset.prefetch
با پیش پردازش داده ها و اجرای مدل در حین آموزش همپوشانی دارد.
خوانندگان علاقه مند می توانند با راهنمای tf.data API اطلاعات بیشتری در مورد هر دو روش و همچنین نحوه کش کردن داده ها در دیسک در بخش Prefetching از عملکرد بهتر کسب کنند.
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
داده ها را استاندارد کنید
مقادیر کانال RGB در محدوده [0, 255]
است. این برای یک شبکه عصبی ایده آل نیست. به طور کلی باید به دنبال کوچک کردن مقادیر ورودی خود باشید.
در اینجا، با استفاده از tf.keras.layers.Rescaling
، مقادیر را در محدوده [0, 1]
استاندارد میکنید:
normalization_layer = layers.Rescaling(1./255)
دو روش برای استفاده از این لایه وجود دارد. با فراخوانی Dataset.map
می توانید آن را به مجموعه داده اعمال کنید:
normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixel values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image))
0.0 1.0
یا، می توانید لایه را در تعریف مدل خود قرار دهید، که می تواند استقرار را ساده کند. بیایید از رویکرد دوم در اینجا استفاده کنیم.
مدل را ایجاد کنید
مدل متوالی از سه بلوک کانولوشن ( tf.keras.layers.Conv2D
) با یک لایه تجمع حداکثر ( tf.keras.layers.MaxPooling2D
) در هر یک از آنها تشکیل شده است. یک لایه کاملاً متصل ( tf.keras.layers.Dense
) با 128 واحد در بالای آن وجود دارد که توسط یک تابع فعال سازی ReLU ( 'relu'
) فعال می شود. این مدل برای دقت بالا تنظیم نشده است - هدف این آموزش نشان دادن یک رویکرد استاندارد است.
num_classes = len(class_names)
model = Sequential([
layers.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes)
])
مدل را کامپایل کنید
برای این آموزش، تابع tf.keras.optimizers.Adam
و tf.keras.losses.SparseCategoricalCrossentropy
را انتخاب کنید. برای مشاهده دقت آموزش و اعتبارسنجی برای هر دوره آموزشی، آرگومان metrics
را به Model.compile
کنید.
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
خلاصه مدل
مشاهده تمام لایه های شبکه با استفاده از روش Model.summary
مدل:
model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= rescaling_1 (Rescaling) (None, 180, 180, 3) 0 conv2d (Conv2D) (None, 180, 180, 16) 448 max_pooling2d (MaxPooling2D (None, 90, 90, 16) 0 ) conv2d_1 (Conv2D) (None, 90, 90, 32) 4640 max_pooling2d_1 (MaxPooling (None, 45, 45, 32) 0 2D) conv2d_2 (Conv2D) (None, 45, 45, 64) 18496 max_pooling2d_2 (MaxPooling (None, 22, 22, 64) 0 2D) flatten (Flatten) (None, 30976) 0 dense (Dense) (None, 128) 3965056 dense_1 (Dense) (None, 5) 645 ================================================================= Total params: 3,989,285 Trainable params: 3,989,285 Non-trainable params: 0 _________________________________________________________________
مدل را آموزش دهید
epochs=10
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=epochs
)
Epoch 1/10 92/92 [==============================] - 3s 16ms/step - loss: 1.2769 - accuracy: 0.4489 - val_loss: 1.0457 - val_accuracy: 0.5804 Epoch 2/10 92/92 [==============================] - 1s 11ms/step - loss: 0.9386 - accuracy: 0.6328 - val_loss: 0.9665 - val_accuracy: 0.6158 Epoch 3/10 92/92 [==============================] - 1s 11ms/step - loss: 0.7390 - accuracy: 0.7200 - val_loss: 0.8768 - val_accuracy: 0.6540 Epoch 4/10 92/92 [==============================] - 1s 11ms/step - loss: 0.5649 - accuracy: 0.7963 - val_loss: 0.9258 - val_accuracy: 0.6540 Epoch 5/10 92/92 [==============================] - 1s 11ms/step - loss: 0.3662 - accuracy: 0.8733 - val_loss: 1.1734 - val_accuracy: 0.6267 Epoch 6/10 92/92 [==============================] - 1s 11ms/step - loss: 0.2169 - accuracy: 0.9343 - val_loss: 1.3728 - val_accuracy: 0.6499 Epoch 7/10 92/92 [==============================] - 1s 11ms/step - loss: 0.1191 - accuracy: 0.9629 - val_loss: 1.3791 - val_accuracy: 0.6471 Epoch 8/10 92/92 [==============================] - 1s 11ms/step - loss: 0.0497 - accuracy: 0.9871 - val_loss: 1.8002 - val_accuracy: 0.6390 Epoch 9/10 92/92 [==============================] - 1s 11ms/step - loss: 0.0372 - accuracy: 0.9922 - val_loss: 1.8545 - val_accuracy: 0.6390 Epoch 10/10 92/92 [==============================] - 1s 11ms/step - loss: 0.0715 - accuracy: 0.9813 - val_loss: 2.0656 - val_accuracy: 0.6049
نتایج آموزشی را تجسم کنید
نمودارهای از دست دادن و دقت را در مجموعه های آموزشی و اعتبار سنجی ایجاد کنید:
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
نمودارها نشان میدهند که دقت آموزش و صحت اعتبارسنجی با حاشیههای زیادی کاهش یافته است، و مدل تنها حدود 60 درصد دقت را در مجموعه اعتبارسنجی به دست آورده است.
بیایید بررسی کنیم که چه اشتباهی رخ داده است و سعی کنیم عملکرد کلی مدل را افزایش دهیم.
بیش از حد برازش
در نمودارهای بالا، دقت آموزش به صورت خطی در طول زمان افزایش مییابد، در حالی که دقت اعتبارسنجی در فرآیند آموزش حدود 60 درصد متوقف میشود. همچنین، تفاوت در دقت بین دقت آموزشی و اعتبارسنجی قابل توجه است - نشانه ای از برازش بیش از حد.
هنگامی که تعداد کمی از نمونه های آموزشی وجود دارد، مدل گاهی اوقات از نویزها یا جزئیات ناخواسته از نمونه های آموزشی یاد می گیرد - تا حدی که بر عملکرد مدل در نمونه های جدید تأثیر منفی می گذارد. این پدیده به نام overfitting شناخته می شود. این بدان معناست که تعمیم مدل بر روی یک مجموعه داده جدید با مشکل مواجه خواهد شد.
راه های متعددی برای مبارزه با بیش از حد تناسب در فرآیند تمرین وجود دارد. در این آموزش، از افزایش داده ها استفاده می کنید و Dropout را به مدل خود اضافه می کنید.
افزایش داده ها
Overfitting معمولا زمانی اتفاق می افتد که تعداد کمی از نمونه های آموزشی وجود داشته باشد. تقویت داده رویکرد تولید دادههای آموزشی اضافی از نمونههای موجود شما را با تقویت آنها با استفاده از تبدیلهای تصادفی که تصاویری با ظاهر باورپذیر به دست میدهد، اتخاذ میکند. این کمک می کند که مدل در معرض جنبه های بیشتری از داده ها قرار گیرد و بهتر تعمیم یابد.
با استفاده از لایههای پیشپردازش Keras زیر، تقویت دادهها را پیادهسازی خواهید کرد: tf.keras.layers.RandomFlip
، tf.keras.layers.RandomRotation
، و tf.keras.layers.RandomZoom
. اینها می توانند مانند لایه های دیگر در داخل مدل شما قرار داده شوند و روی GPU اجرا شوند.
data_augmentation = keras.Sequential(
[
layers.RandomFlip("horizontal",
input_shape=(img_height,
img_width,
3)),
layers.RandomRotation(0.1),
layers.RandomZoom(0.1),
]
)
بیایید با چندین بار اعمال تقویت داده ها در یک تصویر، چند مثال تقویت شده را تجسم کنیم:
plt.figure(figsize=(10, 10))
for images, _ in train_ds.take(1):
for i in range(9):
augmented_images = data_augmentation(images)
ax = plt.subplot(3, 3, i + 1)
plt.imshow(augmented_images[0].numpy().astype("uint8"))
plt.axis("off")
شما از تقویت داده ها برای آموزش یک مدل در یک لحظه استفاده خواهید کرد.
ترک تحصیل
یکی دیگر از تکنیکهای کاهش بیش از حد برازش، معرفی منظمسازی خروج از شبکه به شبکه است.
هنگامی که حذف را به یک لایه اعمال می کنید، به طور تصادفی (با تنظیم فعال سازی روی صفر) تعدادی از واحدهای خروجی از لایه در طول فرآیند آموزش حذف می شود. Dropout یک عدد کسری را به عنوان مقدار ورودی خود می گیرد، به شکل هایی مانند 0.1، 0.2، 0.4، و غیره. این به معنای حذف 10٪، 20٪ یا 40٪ از واحدهای خروجی به طور تصادفی از لایه اعمال شده است.
بیایید یک شبکه عصبی جدید با tf.keras.layers.Dropout
قبل از آموزش با استفاده از تصاویر تقویت شده ایجاد کنیم:
model = Sequential([
data_augmentation,
layers.Rescaling(1./255),
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Dropout(0.2),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes)
])
کامپایل و آموزش مدل
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.summary()
Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= sequential_1 (Sequential) (None, 180, 180, 3) 0 rescaling_2 (Rescaling) (None, 180, 180, 3) 0 conv2d_3 (Conv2D) (None, 180, 180, 16) 448 max_pooling2d_3 (MaxPooling (None, 90, 90, 16) 0 2D) conv2d_4 (Conv2D) (None, 90, 90, 32) 4640 max_pooling2d_4 (MaxPooling (None, 45, 45, 32) 0 2D) conv2d_5 (Conv2D) (None, 45, 45, 64) 18496 max_pooling2d_5 (MaxPooling (None, 22, 22, 64) 0 2D) dropout (Dropout) (None, 22, 22, 64) 0 flatten_1 (Flatten) (None, 30976) 0 dense_2 (Dense) (None, 128) 3965056 dense_3 (Dense) (None, 5) 645 ================================================================= Total params: 3,989,285 Trainable params: 3,989,285 Non-trainable params: 0 _________________________________________________________________
epochs = 15
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=epochs
)
Epoch 1/15 92/92 [==============================] - 2s 14ms/step - loss: 1.3840 - accuracy: 0.3999 - val_loss: 1.0967 - val_accuracy: 0.5518 Epoch 2/15 92/92 [==============================] - 1s 12ms/step - loss: 1.1152 - accuracy: 0.5395 - val_loss: 1.1123 - val_accuracy: 0.5545 Epoch 3/15 92/92 [==============================] - 1s 12ms/step - loss: 1.0049 - accuracy: 0.6052 - val_loss: 0.9544 - val_accuracy: 0.6253 Epoch 4/15 92/92 [==============================] - 1s 12ms/step - loss: 0.9452 - accuracy: 0.6257 - val_loss: 0.9681 - val_accuracy: 0.6213 Epoch 5/15 92/92 [==============================] - 1s 12ms/step - loss: 0.8804 - accuracy: 0.6591 - val_loss: 0.8450 - val_accuracy: 0.6798 Epoch 6/15 92/92 [==============================] - 1s 12ms/step - loss: 0.8001 - accuracy: 0.6945 - val_loss: 0.8715 - val_accuracy: 0.6594 Epoch 7/15 92/92 [==============================] - 1s 12ms/step - loss: 0.7736 - accuracy: 0.6965 - val_loss: 0.8059 - val_accuracy: 0.6935 Epoch 8/15 92/92 [==============================] - 1s 12ms/step - loss: 0.7477 - accuracy: 0.7078 - val_loss: 0.8292 - val_accuracy: 0.6812 Epoch 9/15 92/92 [==============================] - 1s 12ms/step - loss: 0.7053 - accuracy: 0.7251 - val_loss: 0.7743 - val_accuracy: 0.6989 Epoch 10/15 92/92 [==============================] - 1s 12ms/step - loss: 0.6884 - accuracy: 0.7340 - val_loss: 0.7867 - val_accuracy: 0.6907 Epoch 11/15 92/92 [==============================] - 1s 12ms/step - loss: 0.6536 - accuracy: 0.7469 - val_loss: 0.7732 - val_accuracy: 0.6785 Epoch 12/15 92/92 [==============================] - 1s 12ms/step - loss: 0.6456 - accuracy: 0.7500 - val_loss: 0.7801 - val_accuracy: 0.6907 Epoch 13/15 92/92 [==============================] - 1s 12ms/step - loss: 0.5941 - accuracy: 0.7735 - val_loss: 0.7185 - val_accuracy: 0.7330 Epoch 14/15 92/92 [==============================] - 1s 12ms/step - loss: 0.5824 - accuracy: 0.7735 - val_loss: 0.7282 - val_accuracy: 0.7357 Epoch 15/15 92/92 [==============================] - 1s 12ms/step - loss: 0.5771 - accuracy: 0.7851 - val_loss: 0.7308 - val_accuracy: 0.7343
نتایج آموزشی را تجسم کنید
پس از اعمال افزایش داده و tf.keras.layers.Dropout
، اضافه برازش کمتری نسبت به قبل وجود دارد، و دقت آموزش و اعتبارسنجی به هم تراز است:
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
پیش بینی بر روی داده های جدید
در نهایت، بیایید از مدل خود برای طبقهبندی تصویری استفاده کنیم که در مجموعههای آموزشی یا اعتبارسنجی گنجانده نشده است.
sunflower_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg"
sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url)
img = tf.keras.utils.load_img(
sunflower_path, target_size=(img_height, img_width)
)
img_array = tf.keras.utils.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch
predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[np.argmax(score)], 100 * np.max(score))
)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg 122880/117948 [===============================] - 0s 0us/step 131072/117948 [=================================] - 0s 0us/step This image most likely belongs to sunflowers with a 89.13 percent confidence.