Karmaşık resimler içeren kıvrımlı nöral ağlar (CNN'ler) kullanma

1. Başlamadan önce

Bu codelab'de, atların ve insanların resimlerini sınıflandırmak için evrimler kullanacaksınız. Atların ve insanların resimlerini tanımak ve sınıflandırmak için eğitilmiş bir CNN oluşturmak için bu laboratuvarda TensorFlow'u kullanacaksınız.

Ön koşullar

Daha önce TensorFlow ile herhangi bir evrim oluşturmadıysanız, evrimleri ve havuzları bir araya getirdiğimiz dönüştürme ve havuz oluşturma codelab'ini ve görüntüleri tanımak amacıyla bilgisayarları nasıl daha verimli hale getirebileceğimizi ele aldığımız evrişimli nöral ağlar (CNN'ler) oluşturur.

Neler öğreneceksiniz?

  • Bilgisayarları, öznenin net olmadığı bir görüntüdeki özellikleri tanıyacak şekilde eğitme

Geliştireceğiniz uygulama

  • At resimleri ile insan resimleri arasında ayrım yapabilen kıvrımlı bir nöral ağ

Gerekenler

Colab'da çalışan codelab'in geri kalanının kodunu bulabilirsiniz.

Ayrıca TensorFlow'un ve önceki codelab'de yüklediğiniz kitaplıkların bulunması gerekir.

2. Başlarken: Verileri edinme

Bunu, belirli bir resmin at mı yoksa insan mı içerdiğini bildiren bir at veya insan sınıflandırıcı geliştirerek yapabilirsiniz. Bu durumda, ağ, hangisinin hangisi olduğunu belirleyen özellikleri tanımak için eğitilir. Eğitimden önce verilerin bir kısmını işlemeniz gerekecek.

Öncelikle verileri indirin:

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

Aşağıdaki Python kodu, işletim sistemi kitaplığını kullanarak işletim sistemi kitaplığını kullanarak dosya sistemi ve zip dosyası kitaplığına erişmenizi sağlar. Böylece verilerin sıkıştırmasını açabilirsiniz.

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

Zip dosyasının içeriği, atlar ve insan alt dizinlerinin bulunduğu /tmp/horse-or-human temel dizinine çıkarılır.

Kısaca eğitim kümesi, nöral nöral modele bu şekilde bir atın nasıl göründüğünü ve insanın böyle göründüğünü bildirmek için kullanılan verilerdir.

3. Verileri etiketlemek ve hazırlamak için ImageGenerator uygulamasını kullanın

Resimleri at veya insan olarak açıkça etiketlemezsiniz.

Daha sonra, ImageDataGenerator adlı öğenin kullanıldığını görürsünüz. Alt dizinlerdeki resimleri okur ve alt dizinlerin adından otomatik olarak etiketler. Örneğin, bir at dizini ve bir insan dizini içeren bir eğitim dizininiz vardır. ImageDataGenerator, resimleri sizin için uygun şekilde etiketler ve kodlama adımını azaltır.

Bu dizinlerin her birini tanımlayın.

# 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')

Şimdi dosya adlarının atlar ve insanlar eğitim dizinlerinde nasıl göründüğüne bakın:

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

Dizinlerdeki toplam at ve insan görüntüsü sayısını bulun:

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

4. Verileri keşfedin

Nasıl olduklarını daha iyi anlamak için birkaç resme göz atın.

Önce matplot parametrelerini yapılandırın:

%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

Şimdi, sekiz at resmi ve sekiz insan resmi sergileyin. Her seferinde yeni bir grup görmek için hücreyi yeniden çalıştırabilirsiniz.

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

Burada, farklı duruşlarda ve yönlerde atları ve insanları gösteren bazı örnek resimler verilmiştir:

6b6ebbc6e694ccd2.png

5. Modeli tanımlayın

Modeli tanımlamaya başlayın.

TensorFlow'u içe aktararak başlayın:

import tensorflow as tf

Ardından, evrişim katmanları ekleyin ve yoğun sonuçları yoğunlaşan katmanlara aktarmak için nihai sonucu birleştirin. Son olarak, yoğun şekilde bağlı katmanları ekleyin.

İki sınıflı sınıflandırma sorunu (ikili sınıflandırma sorunu) ile karşılaştığınız için ağınızı sigmoid etkinleştirmesi ile sonlandıracağınızı unutmayın. Böylece ağınızın sonucu, 0 ile 1 arasında (ör. 0. sınıf) değil, 1. sınıf olma olasılığını kodlar.

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() yöntemi çağrısı, ağın bir özetini yazdırır.

model.summary()

Sonuçları burada görebilirsiniz:

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

Çıkış şekli sütunu, özellik haritanızın boyutunun her bir sonraki katmanda nasıl değiştiğini gösterir. Evrişim katmanları, dolgu nedeniyle özellik eşlemelerinin boyutunu biraz küçültür ve her havuzlama katmanı, boyutları yarıya indirir.

6. Modeli derleme

Ardından, model eğitimi için spesifikasyonları yapılandırın. Modelinizi bir ikili sınıflandırma sorunu ve son etkinleştirmenizin bir sigmoid olması nedeniyle binary_crossentropy kaybıyla eğitin. (Kayıp metrikleri hakkında bilgi edinmek için Makine öğrenimine geçme başlıklı makaleyi inceleyin.) 0,001 öğrenme hızına sahip rmsprop optimize ediciyi kullanın. Eğitim sırasında sınıflandırma doğruluğunu izleyin.

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

7. Modeli jeneratörlerden eğitme

Kaynak klasörlerinizdeki resimleri okuyan, bunları float32 tensörüne dönüştüren ve (etiketleriyle) ağınıza besleyen veri oluşturucular oluşturun.

Eğitim görüntüleri ve doğrulama resimleri için birer oluşturucunuz vardır. Jeneratörleriniz, 300x300 boyutunda gruplar ve bunların etiketleri (ikili) oluşturur.

Bildiğiniz gibi, nöral ağlara giden veriler genellikle ağ tarafından işlenmesini daha uygun hale getirmek üzere normalleştirilmelidir. (İşlenmemiş pikselleri bir CNN'e aktarmak yaygın değildir.) Bu durumda, piksel değerlerini [0, 1] aralığında olacak şekilde normalleştirerek resimlerinizi önceden işleyebilirsiniz (aslında tüm değerler [0, 255] aralığındadır).

Bu, Keras'ta yeniden ölçeklendirme parametresi kullanılarak keras.preprocessing.image.ImageDataGenerator sınıfı aracılığıyla yapılabilir. Bu ImageDataGenerator sınıfı, .flow (data, labels) veya .flow_from_directory(directory) aracılığıyla, artırılmış resim grupları(ve etiketleri) oluşturma araçlarının örneğini oluşturmanıza olanak tanır. Daha sonra bu Jeneratörler, veri oluşturucuları giriş olarak kabul eden Keras model yöntemleriyle kullanılabilir: fit_generator, evaluate_generator ve 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. Eğitimi yapın

15 dönem için eğit. (Bu işlem birkaç dakika sürebilir.)

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

Dönem başına değerleri not edin.

Kayıp ve Doğruluk, eğitimin ilerleme durumunun mükemmel bir göstergesidir. Eğitim verilerinin sınıflandırılması konusunda bir tahminde bulunuyor ve daha sonra, bilinen etikete göre ölçümü yaparak sonucu hesaplıyor. Doğruluk, doğru tahminlerin parçasıdır.

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. Modeli test edin

Şimdi modeli kullanarak gerçekte bir tahmin çalıştırın. Bu kod, dosya sisteminizden bir veya daha fazla dosya seçmenize olanak sağlar. Daha sonra, bu nesneleri yükleyecek ve modelden geçerek, nesnenin bir insan veya insan olduğuna dair bir gösterge sağlayacaktır.

Resimleri denemek için internetteki dosyaları dosya sisteminize indirebilirsiniz. Eğitim doğruluğunun %99'un üzerinde olmasına rağmen ağın birçok hata yaptığını görebilirsiniz.

Bu durum, aşırıya sığdırma adı verilen bir olaydan kaynaklanır. Bu, nöral ağın çok sınırlı verilerle eğitildiği anlamına gelir (her sınıf için yalnızca yaklaşık 500 resim vardır). Bu nedenle, eğitim grubunda yer alan resimlere benzeyen görüntüleri tanımak çok iyidir, ancak eğitim kümesinde yer almayan resimlerde çok başarısız olabilir.

Bu, ne kadar çok veri üzerinde eğitim yaparsanız nihai ağınızın o kadar iyi olacağını kanıtlayan bir veri noktasıdır.

Resim geliştirme adı verilen veriler de dahil olmak üzere sınırlı verilere rağmen eğitiminizi daha iyi hale getirmek için kullanılabilen birçok teknik vardır. Ancak bu teknik, codelab'in kapsamı dışındadır.

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

Örneğin, bu resimle test etmek istediğinizi düşünelim:

9e07a57ff3be7a82.jpeg

Colab'ın sundukları:

77b678e70b00862a.png

Karikatür olmasına rağmen çizgi doğru şekilde sınıflandırılıyor.

Aşağıdaki resim de doğru şekilde sınıflandırılmaktadır:

c9213173d9f3d83c.jpeg

f2844da737a1a2f2.png

Kendi resimlerinizi deneyin ve keşfedin.

10. Orta düzey temsilleri görselleştirin

CNN'nin öğrendiği özelliklere dair fikir edinmek için CNN'de geçen bir girişin nasıl dönüştürüldüğünü görselleştirmek eğlencelidir.

Eğitim kümesinden rastgele bir resim seçin, ardından her satırın bir katmanın sonucu olduğu ve satırdaki her bir resmin o çıkış özelliği eşlemesindeki belirli bir filtre olduğu bir sayı oluşturun. Çeşitli eğitim görüntüleri için ara temsiller oluşturmak için bu hücreyi yeniden çalıştırın.

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

Aşağıda örnek sonuçlar verilmiştir:

e078d1bc9662c93f.png

Gördüğünüz gibi, resimlerin ham piksellerinden giderek daha soyut ve kompakt temsillere doğru ilerliyorsunuz. Yayına ait akışlar, ağın nelere dikkat ettiğini vurgulamaya başlar ve "azaltılan" özelliklerin sayısını giderek azaltır. Çoğu sıfıra ayarlanır. Buna uygunsuzluk denir. Temsil eksikliği, derin öğrenimin temel bir özelliğidir.

Bu gösterimler, resmin orijinal pikselleri hakkında giderek daha az bilgi içerir, ancak resmin sınıfı hakkında giderek daha hassas bilgiler içerir. CNN'i (veya genel olarak derin ağı) bilgi rafinasyonu hattı olarak düşünebilirsiniz.

11. Tebrikler

Karmaşık resimleri geliştirmek için CNN'ler kullanmayı öğrendiniz. Bilgisayar görüşü modellerinizi nasıl daha da geliştireceğinizi öğrenmek için Fazla sığınmamak için büyük veri kümeleriyle evrişimli nöral ağlar (CNN'ler) kullanma bölümüne geçin.