از شبکه های عصبی کانولوشن (CNN) با تصاویر پیچیده استفاده کنید

1. قبل از شروع

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

پیش نیازها

اگر قبلاً با TensorFlow کانولوشن ساخته نشده‌اید، ممکن است بخواهید Build convolutions را کامل کنید و کد ادغام را انجام دهید ، جایی که ما کانولوشن‌ها و ادغام را معرفی می‌کنیم، و شبکه‌های عصبی کانولوشن (CNN) را برای تقویت بینایی رایانه ایجاد می‌کنیم، جایی که در مورد چگونگی ساخت رایانه بحث می‌کنیم. در تشخیص تصاویر کارآمدتر است.

چیزی که یاد خواهید گرفت

  • نحوه آموزش کامپیوترها برای تشخیص ویژگی های تصویری که در آن سوژه واضح نیست

چیزی که خواهی ساخت

  • یک شبکه عصبی کانولوشن که می تواند بین تصاویر اسب ها و عکس های انسان تمایز قائل شود

آنچه شما نیاز دارید

می‌توانید کد بقیه کدهای در حال اجرا در Colab را پیدا کنید.

همچنین به نصب TensorFlow و کتابخانه هایی که در codelab قبلی نصب کرده اید نیاز دارید.

2. شروع به کار: داده ها را بدست آورید

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

ابتدا داده ها را دانلود کنید:

!wget --no-check-certificate https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip  -O /tmp/horse-or-human.zip

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

import os
import zipfile
 
local_zip = '/tmp/horse-or-human.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/horse-or-human')
zip_ref.close()

محتویات فایل زیپ در دایرکتوری پایه /tmp/horse-or-human استخراج می‌شود که حاوی دایرکتوری‌های اسب و انسان است.

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

3. از ImageGenerator برای برچسب زدن و آماده سازی داده ها استفاده کنید

شما صراحتاً به تصاویر برچسب اسب یا انسان نمی زنید.

بعداً چیزی به نام ImageDataGenerator را خواهید دید که در حال استفاده است. تصاویر را از زیر شاخه ها می خواند و به طور خودکار آنها را از نام آن زیر شاخه برچسب گذاری می کند. به عنوان مثال، شما یک دایرکتوری آموزشی دارید که شامل دایرکتوری اسب ها و دایرکتوری انسان است. ImageDataGenerator تصاویر را به طور مناسب برای شما برچسب گذاری می کند و یک مرحله کدگذاری را کاهش می دهد.

هر یک از آن دایرکتوری ها را تعریف کنید.

# Directory with our training horse pictures
train_horse_dir = os.path.join('/tmp/horse-or-human/horses')
 
# Directory with our training human pictures
train_human_dir = os.path.join('/tmp/horse-or-human/humans')

اکنون، ببینید که نام فایل ها در فهرست راهنمای آموزش اسب ها و انسان ها چگونه است:

train_horse_names = os.listdir(train_horse_dir)
print(train_horse_names[:10])
train_human_names = os.listdir(train_human_dir)
print(train_human_names[:10])

تعداد کل تصاویر اسب و انسان را در فهرست ها بیابید:

print('total training horse images:', len(os.listdir(train_horse_dir)))
print('total training human images:', len(os.listdir(train_human_dir)))

4. داده ها را کاوش کنید

به چند عکس نگاهی بیندازید تا درک بهتری از ظاهر آنها پیدا کنید.

ابتدا پارامترهای matplot را پیکربندی کنید:

%matplotlib inline
 
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
 
# Parameters for our graph; we'll output images in a 4x4 configuration
nrows = 4
ncols = 4
 
# Index for iterating over images
pic_index = 0

اکنون، دسته ای از هشت عکس اسب و هشت عکس انسان را نمایش دهید. می‌توانید سلول را دوباره اجرا کنید تا هر بار یک دسته جدید ببینید.

# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)
 
pic_index += 8
next_horse_pix = [os.path.join(train_horse_dir, fname) 
                for fname in train_horse_names[pic_index-8:pic_index]]
next_human_pix = [os.path.join(train_human_dir, fname) 
                for fname in train_human_names[pic_index-8:pic_index]]
 
for i, img_path in enumerate(next_horse_pix+next_human_pix):
  # Set up subplot; subplot indices start at 1
  sp = plt.subplot(nrows, ncols, i + 1)
  sp.axis('Off') # Don't show axes (or gridlines)
 
  img = mpimg.imread(img_path)
  plt.imshow(img)
 
plt.show()
 

در اینجا چند نمونه تصویر وجود دارد که اسب ها و انسان ها را در حالت ها و جهت گیری های مختلف نشان می دهد:

6b6ebbc6e694ccd2.png

5. مدل را تعریف کنید

شروع به تعریف مدل کنید.

با وارد کردن TensorFlow شروع کنید:

import tensorflow as tf

سپس، لایه های کانولوشن را اضافه کنید و نتیجه نهایی را صاف کنید تا به لایه های متراکم متصل شود. در نهایت، لایه های متراکم متصل را اضافه کنید.

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

model = tf.keras.models.Sequential([
    # Note the input shape is the desired size of the image 300x300 with 3 bytes color
    # This is the first convolution
    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    # The second convolution
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The third convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fourth convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fifth convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'),
    # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
    tf.keras.layers.Dense(1, activation='sigmoid')
])

فراخوانی متد model.summary() خلاصه ای از شبکه را چاپ می کند.

model.summary()

در اینجا می توانید نتایج را مشاهده کنید:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 298, 298, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 149, 149, 16)      0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 147, 147, 32)      4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 73, 73, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 71, 71, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 35, 35, 64)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 33, 33, 64)        36928     
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 16, 16, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 14, 14, 64)        36928     
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
flatten (Flatten)            (None, 3136)              0         
_________________________________________________________________
dense (Dense)                (None, 512)               1606144   
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 513       
=================================================================
Total params: 1,704,097
Trainable params: 1,704,097
Non-trainable params: 0

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

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

سپس مشخصات مربوط به آموزش مدل را پیکربندی کنید. مدل خود را با از دست دادن binary_crossentropy آموزش دهید زیرا این یک مشکل طبقه بندی باینری است و فعال سازی نهایی شما یک سیگموئید است. (برای تجدید معیارهای ضرر، به نزول به ML مراجعه کنید.) از بهینه ساز rmsprop با نرخ یادگیری 0.001 استفاده کنید. در طول آموزش، دقت طبقه بندی را کنترل کنید.

from tensorflow.keras.optimizers import RMSprop
 
model.compile(loss='binary_crossentropy',
              optimizer=RMSprop(lr=0.001),
              metrics=['acc'])

7. مدل را از ژنراتورها آموزش دهید

مولدهای داده را راه اندازی کنید که تصاویر را در پوشه های منبع شما می خوانند، آنها را به تانسورهای float32 تبدیل می کنند و آنها را (با برچسب هایشان) به شبکه شما تغذیه می کنند.

شما یک مولد برای تصاویر آموزشی و یکی برای تصاویر اعتبار سنجی خواهید داشت. ژنراتورهای شما دسته‌هایی از تصاویر با اندازه 300x300 و برچسب‌های آن‌ها (باینری) را تولید می‌کنند.

همانطور که قبلاً می دانید، داده هایی که وارد شبکه های عصبی می شوند معمولاً باید به نحوی نرمال شوند تا بتوانند پردازش آنها توسط شبکه را بیشتر کنند. (غیر معمول است که پیکسل های خام را به یک CNN تغذیه کنید.) در مورد شما، تصاویر خود را با نرمال کردن مقادیر پیکسل در محدوده [0، 1] از قبل پردازش می کنید (در ابتدا همه مقادیر در محدوده [0، 255] هستند. ).

در Keras، این کار را می توان از طریق کلاس keras.preprocessing.image.ImageDataGenerator با استفاده از پارامتر rescale انجام داد. آن کلاس ImageDataGenerator به شما اجازه می دهد تا از طریق .flow (داده ها، برچسب ها) یا .flow_from_directory (دایرکتوری) مولدهای دسته های تصویر تقویت شده (و برچسب های آنها) را نمونه سازی کنید. سپس آن مولدها را می‌توان با روش‌های مدل Keras که مولدهای داده را به عنوان ورودی می‌پذیرد، استفاده کرد: fit_generator ، evaluate_generator و predict_generator .

from tensorflow.keras.preprocessing.image import ImageDataGenerator
 
# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale=1./255)
 
# Flow training images in batches of 128 using train_datagen generator
train_generator = train_datagen.flow_from_directory(
        '/tmp/horse-or-human/',  # This is the source directory for training images
        target_size=(300, 300),  # All images will be resized to 150x150
        batch_size=128,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')

8. آموزش را انجام دهید

برای 15 دوره قطار. (ممکن است چند دقیقه اجرا شود.)

history = model.fit(
      train_generator,
      steps_per_epoch=8,  
      epochs=15,
      verbose=1)

به مقادیر در هر دوره توجه کنید.

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

Epoch 1/15
9/9 [==============================] - 9s 1s/step - loss: 0.8662 - acc: 0.5151
Epoch 2/15
9/9 [==============================] - 8s 927ms/step - loss: 0.7212 - acc: 0.5969
Epoch 3/15
9/9 [==============================] - 8s 921ms/step - loss: 0.6612 - acc: 0.6592
Epoch 4/15
9/9 [==============================] - 8s 925ms/step - loss: 0.3135 - acc: 0.8481
Epoch 5/15
9/9 [==============================] - 8s 919ms/step - loss: 0.4640 - acc: 0.8530
Epoch 6/15
9/9 [==============================] - 8s 896ms/step - loss: 0.2306 - acc: 0.9231
Epoch 7/15
9/9 [==============================] - 8s 915ms/step - loss: 0.1464 - acc: 0.9396
Epoch 8/15
9/9 [==============================] - 8s 935ms/step - loss: 0.2663 - acc: 0.8919
Epoch 9/15
9/9 [==============================] - 8s 883ms/step - loss: 0.0772 - acc: 0.9698
Epoch 10/15
9/9 [==============================] - 9s 951ms/step - loss: 0.0403 - acc: 0.9805
Epoch 11/15
9/9 [==============================] - 8s 891ms/step - loss: 0.2618 - acc: 0.9075
Epoch 12/15
9/9 [==============================] - 8s 902ms/step - loss: 0.0434 - acc: 0.9873
Epoch 13/15
9/9 [==============================] - 8s 904ms/step - loss: 0.0187 - acc: 0.9932
Epoch 14/15
9/9 [==============================] - 9s 951ms/step - loss: 0.0974 - acc: 0.9649
Epoch 15/15
9/9 [==============================] - 8s 877ms/step - loss: 0.2859 - acc: 0.9338

9. مدل را تست کنید

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

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

این به دلیل چیزی به نام overfitting است، به این معنی که شبکه عصبی با داده های بسیار محدودی آموزش داده می شود (فقط تقریباً 500 تصویر از هر کلاس وجود دارد). بنابراین در تشخیص تصاویری که شبیه تصاویر موجود در مجموعه آموزشی هستند، بسیار خوب است، اما در تصاویری که در مجموعه آموزشی نیستند، می‌تواند بسیار شکست بخورد.

این نقطه داده ای است که ثابت می کند هر چه داده های بیشتری را آموزش دهید، شبکه نهایی شما بهتر خواهد بود!

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

import numpy as np
from google.colab import files
from keras.preprocessing import image
 
uploaded = files.upload()
 
for fn in uploaded.keys():
 
  # predicting images
  path = '/content/' + fn
  img = image.load_img(path, target_size=(300, 300))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)
 
  images = np.vstack([x])
  classes = model.predict(images, batch_size=10)
  print(classes[0])
  if classes[0]>0.5:
    print(fn + " is a human")
  else:
    print(fn + " is a horse")

به عنوان مثال، بگویید که می خواهید با این تصویر تست کنید:

9e07a57ff3be7a82.jpeg

در اینجا چیزی است که colab تولید می کند:

77b678e70b00862a.png

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

تصویر زیر نیز به درستی طبقه بندی می کند:

c9213173d9f3d83c.jpeg

f2844da737a1a2f2.png

برخی از تصاویر خود را امتحان کنید و کاوش کنید!

10. بازنمایی های میانی را تجسم کنید

برای اینکه بفهمید CNN شما چه نوع ویژگی هایی را یاد گرفته است، یک کار سرگرم کننده این است که تجسم کنید که چگونه یک ورودی هنگام عبور از CNN تغییر می کند.

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

import numpy as np
import random
from tensorflow.keras.preprocessing.image import img_to_array, load_img
 
# Let's define a new Model that will take an image as input, and will output
# intermediate representations for all layers in the previous model after
# the first.
successive_outputs = [layer.output for layer in model.layers[1:]]
#visualization_model = Model(img_input, successive_outputs)
visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)
# Let's prepare a random input image from the training set.
horse_img_files = [os.path.join(train_horse_dir, f) for f in train_horse_names]
human_img_files = [os.path.join(train_human_dir, f) for f in train_human_names]
img_path = random.choice(horse_img_files + human_img_files)
 
img = load_img(img_path, target_size=(300, 300))  # this is a PIL image
x = img_to_array(img)  # Numpy array with shape (150, 150, 3)
x = x.reshape((1,) + x.shape)  # Numpy array with shape (1, 150, 150, 3)
 
# Rescale by 1/255
x /= 255
 
# Let's run our image through our network, thus obtaining all
# intermediate representations for this image.
successive_feature_maps = visualization_model.predict(x)
 
# These are the names of the layers, so can have them as part of our plot
layer_names = [layer.name for layer in model.layers]
 
# Now let's display our representations
for layer_name, feature_map in zip(layer_names, successive_feature_maps):
  if len(feature_map.shape) == 4:
    # Just do this for the conv / maxpool layers, not the fully-connected layers
    n_features = feature_map.shape[-1]  # number of features in feature map
    # The feature map has shape (1, size, size, n_features)
    size = feature_map.shape[1]
    # We will tile our images in this matrix
    display_grid = np.zeros((size, size * n_features))
    for i in range(n_features):
      # Postprocess the feature to make it visually palatable
      x = feature_map[0, :, :, i]
      x -= x.mean()
      if x.std()>0:
        x /= x.std()
      x *= 64
      x += 128
      x = np.clip(x, 0, 255).astype('uint8')
      # We'll tile each filter into this big horizontal grid
      display_grid[:, i * size : (i + 1) * size] = x
    # Display the grid
    scale = 20. / n_features
    plt.figure(figsize=(scale * n_features, scale))
    plt.title(layer_name)
    plt.grid(False)
    plt.imshow(display_grid, aspect='auto', cmap='viridis')

در اینجا نمونه ای از نتایج است:

e078d1bc9662c93f.png

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

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

11. تبریک می گویم

شما یاد گرفته اید که از CNN برای بهبود تصاویر پیچیده استفاده کنید. برای یادگیری نحوه تقویت بیشتر مدل‌های بینایی رایانه خود، به استفاده از شبکه‌های عصبی کانولوشنال (CNN) با مجموعه داده‌های بزرگ برای جلوگیری از برازش بیش از حد اقدام کنید.