Bu codelab hakkında
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:
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:
Colab'ın sundukları:
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:
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:
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.