این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

طبقه بندی تصویر

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

این آموزش نحوه طبقه بندی تصاویر گل ها را نشان می دهد. این یک طبقه بندی کننده تصویر را با استفاده از یک مدل keras.Sequential ایجاد می کند. مدل keras.Sequential است و داده ها را با استفاده از preprocessing.image_dataset_from_directory بار می کند. شما با مفاهیم زیر تجربه عملی کسب خواهید کرد:

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

این آموزش از یک دوره کار اصلی یادگیری ماشین پیروی می کند:

  1. داده ها را بررسی و درک کنید
  2. یک خط لوله ورودی بسازید
  3. مدل را بسازید
  4. آموزش مدل
  5. مدل را تست کنید
  6. بهبود مدل و تکرار روند
pip install -q tf-nightly

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
 

داده را بارگیری و اکتشاف کنید

در این آموزش از مجموعه ای از حدود 3300 عکس گل استفاده شده است. مجموعه داده شامل 5 زیر دایرکتوری است ، هر کلاس:

 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)
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 4s 0us/step

پس از بارگیری ، اکنون باید یک کپی از مجموعه داده در دسترس داشته باشید. در کل 3،670 تصویر وجود دارد:

 image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)
 
3670

در اینجا چند گل رز آورده شده است:

 roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))
 

png

 PIL.Image.open(str(roses[1]))
 

png

و چند لاله:

 tulips = list(data_dir.glob('tulips/*'))
PIL.Image.open(str(tulips[0]))
 

png

 PIL.Image.open(str(tulips[1]))
 

png

با استفاده از پردازش keras.preup بارگیری کنید

بیایید با استفاده از ابزار مفید image_dataset_from_directory ، این تصاویر را از روی دیسک بارگذاری کنیم. این کار شما را از فهرست دایره تصاویر روی دیسک به tf.data.Dataset فقط در دو خط کد می برد. در صورت تمایل می توانید با مراجعه به آموزش تصاویر بار ، کد بارگیری داده های خود را از ابتدا نیز بنویسید.

ایجاد یک مجموعه داده

برخی از پارامترها را برای لودر تعریف کنید:

 batch_size = 32
img_height = 180
img_width = 180
 

این کار خوب است که هنگام تهیه مدل خود از یک تقسیم اعتبار استفاده کنید. از 80٪ تصاویر برای آموزش و 20٪ برای اعتبارسنجی استفاده خواهیم کرد.

 train_ds = tf.keras.preprocessing.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.preprocessing.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']

داده ها را تجسم کنید

در اینجا 9 تصویر اول از مجموعه داده های آموزش آورده شده است.

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

png

شما با انتقال آنها به 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 یک image_batch شکل است (32, 180, 180, 3) . این مجموعه ای از 32 تصویر به شکل 180x180x3 (آخرین بعد مربوط به کانال های رنگی RGB است). label_batch یک label_batch از شکل (32,) ، این برچسب های مربوط به 32 تصویر هستند.

برای تبدیل آنها به یک numpy.ndarray می توانید با .numpy() بر روی image_batch و labels_batch numpy.ndarray .

مجموعه داده برای عملکرد پیکربندی کنید

بیایید مطمئن شوید که از پیش تنظیم شده بافر استفاده می کنیم بنابراین می توانیم داده ها را از دیسک حاصل کنیم بدون اینکه I / O به انسداد تبدیل شود. این دو روش مهمی هستند که باید هنگام بارگیری داده ها از آنها استفاده کنید.

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

Dataset.prefetch() پردازش داده ها و اجرای مدل را در هنگام آموزش همپوشانی می کند.

خوانندگان علاقه مند می توانند اطلاعات بیشتری در مورد هر دو روش و همچنین نحوه ذخیره داده ها برای دیسک در راهنمای عملکرد داده ها کسب کنند .

 AUTOTUNE = tf.data.experimental.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
 

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

مقادیر کانال RGB در محدوده [0, 255] . این برای شبکه عصبی ایده آل نیست؛ به طور کلی باید به دنبال کوچک کردن مقادیر ورودی خود باشید. در اینجا ، ما با استفاده از یک لایه Rescaling مقادیر استاندارد را در [0, 1] قرار می دهیم.

 normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)
 

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

 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 pixels values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image)) 
 
0.0 1.0

یا می توانید لایه ای را در تعریف مدل خود وارد کنید ، که می تواند استقرار را ساده کند. ما در اینجا از رویکرد دوم استفاده خواهیم کرد.

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

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

 num_classes = 5

model = Sequential([
  layers.experimental.preprocessing.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)
])
 

مدل را کامپایل کنید

برای این آموزش، را انتخاب کنید optimizers.Adam بهینه ساز و losses.SparseCategoricalCrossentropy تابع از دست دادن. برای مشاهده آموزش و صحت اعتبار سنجی برای هر دوره آموزشی ، استدلال metrics را تصویب کنید.

 model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
 

خلاصه مدل

مشاهده تمام لایه های شبکه با استفاده از روش 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 (MaxPooling2 (None, 45, 45, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 45, 45, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 22, 22, 64)        0         
_________________________________________________________________
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 [==============================] - 4s 47ms/step - loss: 1.9328 - accuracy: 0.2896 - val_loss: 1.1022 - val_accuracy: 0.5245
Epoch 2/10
92/92 [==============================] - 1s 10ms/step - loss: 1.0441 - accuracy: 0.5761 - val_loss: 1.0057 - val_accuracy: 0.5913
Epoch 3/10
92/92 [==============================] - 1s 10ms/step - loss: 0.8640 - accuracy: 0.6763 - val_loss: 0.8951 - val_accuracy: 0.6499
Epoch 4/10
92/92 [==============================] - 1s 10ms/step - loss: 0.7106 - accuracy: 0.7472 - val_loss: 0.8992 - val_accuracy: 0.6621
Epoch 5/10
92/92 [==============================] - 1s 10ms/step - loss: 0.4817 - accuracy: 0.8285 - val_loss: 0.8997 - val_accuracy: 0.6662
Epoch 6/10
92/92 [==============================] - 1s 10ms/step - loss: 0.3131 - accuracy: 0.8903 - val_loss: 1.0014 - val_accuracy: 0.6567
Epoch 7/10
92/92 [==============================] - 1s 10ms/step - loss: 0.1782 - accuracy: 0.9436 - val_loss: 1.2140 - val_accuracy: 0.6431
Epoch 8/10
92/92 [==============================] - 1s 10ms/step - loss: 0.1024 - accuracy: 0.9703 - val_loss: 1.5144 - val_accuracy: 0.6240
Epoch 9/10
92/92 [==============================] - 1s 10ms/step - loss: 0.0736 - accuracy: 0.9815 - val_loss: 1.7651 - val_accuracy: 0.5926
Epoch 10/10
92/92 [==============================] - 1s 10ms/step - loss: 0.0761 - accuracy: 0.9775 - val_loss: 2.0429 - val_accuracy: 0.5967

نتایج آموزش را تجسم کنید

توطئه های از دست دادن و دقت در مجموعه های آموزش و اعتبار سنجی ایجاد کنید.

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

png

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

بیایید ببینیم چه اشتباهی رخ داده و سعی در افزایش عملکرد کلی مدل داریم.

بیش از حد

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

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

در فرایند آموزش روش های مختلفی برای مبارزه با اضافه بار وجود دارد. در این آموزش از تقویت داده استفاده کرده و Dropout را به مدل خود اضافه می کنید.

افزودن داده

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

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

 data_augmentation = keras.Sequential(
  [
    layers.experimental.preprocessing.RandomFlip("horizontal", 
                                                 input_shape=(img_height, 
                                                              img_width,
                                                              3)),
    layers.experimental.preprocessing.RandomRotation(0.1),
    layers.experimental.preprocessing.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")
 

png

برای تقویت یک مدل در یک لحظه از تقویت داده استفاده خواهیم کرد.

رها کردن

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

وقتی Dropout را روی یک لایه اعمال می کنید ، به طور تصادفی در مرحله آموزش تعدادی واحد خروجی از لایه خارج می شود. Dropout مقدار کسری را به عنوان مقدار ورودی خود ، در فرم هایی مانند 0.1 ، 0.2 ، 0.4 و غیره به دست می آورد. این به معنای کنار گذاشتن 10٪ ، 20٪ یا 40٪ از واحدهای خروجی به طور تصادفی از لایه کاربردی است.

بیایید با استفاده از layers.Dropout یک شبکه عصبی جدید ایجاد کنیم ، سپس آن را با استفاده از تصاویر تقویت شده آموزش دهید.

 model = Sequential([
  data_augmentation,
  layers.experimental.preprocessing.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 (MaxPooling2 (None, 90, 90, 16)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 90, 90, 32)        4640      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 45, 45, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 45, 45, 64)        18496     
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 22, 22, 64)        0         
_________________________________________________________________
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 20ms/step - loss: 1.4842 - accuracy: 0.3279 - val_loss: 1.0863 - val_accuracy: 0.5640
Epoch 2/15
92/92 [==============================] - 1s 12ms/step - loss: 1.1215 - accuracy: 0.5284 - val_loss: 1.0374 - val_accuracy: 0.6022
Epoch 3/15
92/92 [==============================] - 1s 12ms/step - loss: 0.9680 - accuracy: 0.6117 - val_loss: 0.9200 - val_accuracy: 0.6485
Epoch 4/15
92/92 [==============================] - 1s 12ms/step - loss: 0.8538 - accuracy: 0.6753 - val_loss: 0.9206 - val_accuracy: 0.6417
Epoch 5/15
92/92 [==============================] - 1s 12ms/step - loss: 0.7744 - accuracy: 0.6977 - val_loss: 0.8169 - val_accuracy: 0.6839
Epoch 6/15
92/92 [==============================] - 1s 13ms/step - loss: 0.7758 - accuracy: 0.7093 - val_loss: 0.7743 - val_accuracy: 0.6880
Epoch 7/15
92/92 [==============================] - 1s 13ms/step - loss: 0.6805 - accuracy: 0.7481 - val_loss: 0.8598 - val_accuracy: 0.6540
Epoch 8/15
92/92 [==============================] - 1s 13ms/step - loss: 0.7132 - accuracy: 0.7278 - val_loss: 0.7177 - val_accuracy: 0.7207
Epoch 9/15
92/92 [==============================] - 1s 13ms/step - loss: 0.6634 - accuracy: 0.7580 - val_loss: 0.7152 - val_accuracy: 0.7166
Epoch 10/15
92/92 [==============================] - 1s 13ms/step - loss: 0.6562 - accuracy: 0.7538 - val_loss: 0.7251 - val_accuracy: 0.7248
Epoch 11/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5798 - accuracy: 0.7840 - val_loss: 0.7016 - val_accuracy: 0.7357
Epoch 12/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5635 - accuracy: 0.7913 - val_loss: 0.7755 - val_accuracy: 0.7248
Epoch 13/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5361 - accuracy: 0.7982 - val_loss: 0.7575 - val_accuracy: 0.7153
Epoch 14/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5420 - accuracy: 0.8022 - val_loss: 0.7375 - val_accuracy: 0.7302
Epoch 15/15
92/92 [==============================] - 1s 12ms/step - loss: 0.5132 - accuracy: 0.8120 - val_loss: 0.7561 - val_accuracy: 0.7289

نتایج آموزش را تجسم کنید

پس از استفاده از افزودن داده ها و 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()
 

png

پیش بینی داده های جدید

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

 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 = keras.preprocessing.image.load_img(
    sunflower_path, target_size=(img_height, img_width)
)
img_array = keras.preprocessing.image.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
This image most likely belongs to sunflowers with a 89.39 percent confidence.