Derin Öğrenme için Görüntü Verileri Çoğaltma

Görüntü veri çoğaltmanın ne olduğunu ve derin öğrenme projeleriniz için Keras’ı kullanarak nasıl yapılacağını görelim!

Derin öğrenmeyi kullanarak görüntü tanıma gerçekleştirmeyi daha önce denediyseniz, eğitim için iyi bir veri kümesinin önemini biliyorsunuzdur. Ancak, eğitim için yeterli görüntü bulmak her zaman kolay değildir ve modelinizin doğruluğu doğrudan eğitim verilerinin kalitesine bağlıdır.

Neyse ki, eğitim için kullandıkları görüntü veri kümesini desteklemek için kullanabileceğiniz teknikler vardır. Tekniklerden biri görüntü veri çoğaltma olarak adlandırılır. Bu yazıda, görüntü veri büyütmenin ne olduğunu, nasıl çalıştığını, derin öğrenmede neden yararlı olduğunu ve son olarak Keras kütüphanesini kullanarak görüntü veri büyütmenin nasıl gerçekleştirileceğini tartışacağım.

Görüntü Verisi Çoğaltma Nedir?

Görüntü verisi çoğaltmamevcut olanlardan yeni görüntüler oluşturan bir tekniktir. Bunu yapmak için, görüntünün parlaklığını ayarlamak, görüntüyü döndürmek veya görüntüdeki nesneyi yatay veya dikey olarak kaydırmak gibi bazı küçük değişiklikler yaparsınız.

Görüntü çoğaltma teknikleri, eğitim kümenizin boyutunu yapay olarak artırmanıza olanak tanıyarak eğitim için modelinize çok daha fazla veri sağlar. Bu, modelinizin eğitim verilerinizin yeni türevlerini tanıma yeteneğini geliştirerek modelinizin doğruluğunu artırmanıza olanak tanır.

Görüntü Verileri Çoğaltma Türleri

Görüntü çoğaltma birçok biçimde gelir, işte yaygın olanlardan bazıları – Dikey kaydırma, Yatay kaydırma, Dikey çevirme, Yatay çevirme, Döndürme, Parlaklık ayarı ve Yakınlaştırma / Uzaklaştırma.

Keras kullanarak Görüntü Çoğaltma

İlk önce Python ve Keras kullanarak çeşitli görüntü çoğaltma tekniklerini göstereceğim. Birlikte denemek istiyorsanız, aşağıdaki yazılım ve paketlerin yüklü olduğundan emin olun:

Anaconda ve TensorFlow yüklendikten sonra yeni bir Jupyter Notebook oluşturun.

Dikey Kaydırma

Göstermek istediğim ilk görüntü çoğaltma tekniği dikey kaymadırDikey kaydırma, görüntüyü rastgele dikey olarak yukarı veya aşağı kaydırır. Bu örnek için, Jupyter Notebook ile aynı klasörde bulunan 747.jpg adlı bir görüntü kullanacağım.

Görüntü kaynağı: https://commons.wikimedia.org/wiki/File:Qantas_Boeing_747-438ER_VH-OEI_at_LAX.jpg. Bu dosya Creative Commons Attribution-Share Alike 2.0 Generic lisansı ile lisanslanmıştır.

Aşağıdaki kod parçacığı, görüntüyü dikey olarak kaydırmak için Keras’taki sınıfı kullanır.ImageDataGenerator

Keras’ın sınıfı, gerçek zamanlı veri çoğaltma ile toplu görüntü verileri oluşturur.ImageDataGenerator

#---import the modules---
import numpy as np
import matplotlib.pyplot as pltfrom tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import ImageDataGenerator#---load the image---
image_filename = '747.jpg'
img = load_img(image_filename)#---convert the image to 3D array---
image_data = img_to_array(img)#---convert into a 4-D array of 1 element of 3D array representing
# the image---
images_data = np.expand_dims(image_data, axis=0)#---create image data augmentation generator---
datagen = ImageDataGenerator(width_shift_range=0.2)#---prepare the iterator; flow() takes in a 4D array and returns 
# an iterator containing a batch of images---
train_generator = datagen.flow(images_data, batch_size=1)rows = 5
columns = 4#---plot 5 rows and 4 columns---
fig, axes = plt.subplots(rows,columns)for r in range(rows):
    for c in range(columns):
        #---get the next image in the batch (one image since batch 
        # size is 1)---
        image_batch = train_generator.next()
        
        #---convert to unsigned integers for viewing---
        image = image_batch[0].astype('uint8')        #---show the image---
        axes[r,c].imshow(image)#---set the size of the figure---
fig.set_size_inches(15,10)

Yukarıdaki kod parçacığı aşağıdaki çıktıyı üretir:

Yukarıdaki çıktıdan da görebileceğiniz gibi, yöntemi nesneden her çağırdığınızda, biraz değiştirilmiş bir görüntü elde edersiniz. Yukarıdaki kod snippet’inde, yöntemi her çağırdığınızda orijinal görüntü yüksekliğine göre %20 oranında kaydırılan yeni bir resim döndürülür:
next()train_generatornext()

datagen = ImageDataGenerator(width_shift_range=0.2)

İlginçtir ki, () sınıfının bu sürümü için, parametrenin belirtilmesi, görüntüyü yatay olarak değil, dikey olarak kaydırır (bu, modülden daha eski olanın davranışıdır). Benzer şekilde, görüntünün yatay olarak kaydırılmasını istiyorsanız, parametreyi kullanmanız gerekir (bir sonraki bölüme bakın).ImageDataGeneratortensorflow.keras.preprocessing.
imagewidth_shift_rangeImageDataGeneratorkeras.preprocessing.
imageheight_shift_range

Yöntemin artırılmış bir görüntüyü istediğiniz kadar döndüreceğini unutmayın. Yukarıdaki kod snippet’inde, 20 kez adlandırdık (5 satır çarpı 4 sütun).next()

Yatay Kaydırma

Artık parametreyi kullanarak görüntüyü yatay olarak kaydırmayı deneyebilirsiniz:height_shift_range

datagen = ImageDataGenerator(height_shift_range=0.2)
train_generator = datagen.flow(images_data, batch_size=1)rows = 5
columns = 4fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)fig.set_size_inches(15,10)

Yukarıdaki kod parçacığı aşağıdaki çıktıyı üretir:

Yatay Çevirme

Bazen görüntüyü yatay olarak çevirmek mantıklıdır. Bir uçak söz konusu olduğunda, uçağın önü sola veya sağa bakıyor olabilir:

datagen = ImageDataGenerator(horizontal_flip=True)
train_generator = datagen.flow(images_data, batch_size=1)rows = 2
columns = 2fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):        
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)fig.set_size_inches(15,10)

Yukarıdaki kod snippet’i için, uçağın önü sola veya sağa baktığından dört görüntü oluşturmak yeterince iyidir:

Çevirme işleminin rastgele olduğunu unutmayın (bazen dört orijinal görüntünün tümünü alırsınız ve bazen yatay olarak çevrilmiş görüntüler alırsınız). Yukarıdaki dört görüntünün hepsinin aynı olması muhtemeldir. Bu durumda, bu kod bloğunu tekrar çalıştırmanız yeterlidir.

Dikey Çevirme

Yatay çevirme gibi, dikey çevirme de gerçekleştirebilirsiniz:

datagen = ImageDataGenerator(vertical_flip=True)
train_generator = datagen.flow(images_data, batch_size=1)
rows = 2
columns = 2
fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)
fig.set_size_inches(15,10)

Uçaklar söz konusu olduğunda, uçağımızı baş aşağı çevirmek çok mantıklı olmayabilir! Görüntü tanıma işlemi gerçekleştirmeye çalışıyorsanız, uçak görüntülerinizin dik olma ihtimali yüksektir ve bu nedenle modelinizi baş aşağı düzlemleri tanımak için eğitmek çok yaygın olmayabilir. Diğer durumlarda, dikey çevirme çok mantıklıdır.


Rotasyon

Döndürme, adından da anlaşılacağı gibi, görüntünüzü döndürür. Bu, uçak imajımız için çok yararlı olacaktır. Aşağıdaki kod parçacıkları görüntüyü rastgele 50 dereceye kadar döndürür:

datagen = ImageDataGenerator(rotation_range=50)
train_generator = datagen.flow(images_data)
rows = 5
columns = 4
fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)
fig.set_size_inches(15,10)

Rotasyonla, çıkış uçakları çeşitli konumlarda gösterir – kalkış ve iniş konumlarını simüle eder:


Parlaklık

Başka bir çoğaltma tekniği görüntünün parlaklığını ayarlamaktır. Aşağıdaki kod parçacığı parlaklık kaydırma değerleri aralığını ayarlar:

datagen = ImageDataGenerator(brightness_range=[0.15,2.0])
train_generator = datagen.flow(images_data, batch_size=1)rows = 5
columns = 4fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)fig.set_size_inches(15,10)

Çıktı, değişen parlaklıkta bir dizi görüntü içerir:

Yakınlaştırma

Ayrıca görüntüleri yakınlaştırabilir veya uzaklaştırabilirsiniz:

datagen = ImageDataGenerator(zoom_range=[5,0.5])
train_generator = datagen.flow(images_data, batch_size=1)rows = 5
columns = 4fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)fig.set_size_inches(15,10)

Çıktı, görüntüyü çeşitli yakınlaştırma oranlarında gösterir:

Görüntüleri yakınlaştırmanın görüntülerin en boy oranlarını değiştireceğini unutmayın.

Tüm güçlendirmeleri birleştirme

Tabii ki, şimdiye kadar tartıştığım tüm çeşitli çoğaltma teknikleri birleştirilebilir:

datagen = ImageDataGenerator(width_shift_range=0.2,
                             height_shift_range=0.2,
                             horizontal_flip=True,
                             rotation_range=50,
                             brightness_range=[0.15,2.0],
                             zoom_range=[5,0.5])train_generator = datagen.flow(images_data, batch_size=1)rows = 8
columns = 8fig, axes = plt.subplots(rows,columns)
for r in range(rows):
    for c in range(columns):
        image_batch = train_generator.next()
        image = image_batch[0].astype('uint8')
        axes[r,c].imshow(image)fig.set_size_inches(15,10)

Örneğimiz için bir anlam ifade etmediği için dikey çevirmeyi dışarıda bıraktığımı unutmayın.

Çıktı şimdi görüntüyü çeşitli çoğaltmaların uygulandığı şekilde gösterir:

Görüntü Sınıflarında ImageDataGenerator’ı Kullanma

Önceki bölümlerde, görüntü veri çoğaltmanın temelleri ve bunun tek bir görüntüye nasıl uygulanabileceği gösterildi. Derin öğrenmede, genellikle bir dizi görüntüyle uğraşırız. Şimdi görüntü büyütmenin bir dizi görüntüye nasıl uygulanabileceğini görelim. Çizimler için, Jupyter Notebook içeren klasörde, bir Fruits klasörünüz ve aşağıdaki alt klasörleriniz olduğunu varsayacağım:

Fruits
|__banana
|__banana1.jpg
|__banana2.jpg
|__banana3.jpg
|__ ...
|__durian
|__durian1.jpg
|__durian2.jpg
|__durian3.jpg
|__ ...
|__orange
|__orange1.jpg
|__orange2.jpg
|__orange3.jpg
|__ ...
|__strawberry
|__strawberry1.jpg
|__strawberry2.jpg
|__strawberry3.jpg
|__ ...

Her alt klasör bir dizi görüntü içerir. Örneğin, banana klasörü banana1.jpgbanana2.jpg vb. adlı bir dizi görüntü içerir. Alt klasörlerin adı, çeşitli görüntülerin etiketleri olarak işlev görür. Bu, banana klasörünün altındaki tüm dosyaların banana görüntüleri içerdiği anlamına gelir.

Diskten bir dizi görüntü yüklemek için, artık yöntem yerine örneğin yöntemini çağırırsınız (görüntüleri bellekten yüklemek için):flow_from_directory()ImageDataGeneratorflow()

train_datagen = ImageDataGenerator(
    horizontal_flip=True,
    vertical_flip=True,
    rotation_range=50,
)batch_size = 8train_generator = train_datagen.flow_from_directory(
    './Fruits',
    target_size=(224,224), 
    color_mode='rgb', 
    batch_size=batch_size, 
    class_mode='categorical', 
    shuffle=True)

Şimdi 8 olarak ayarladığımı gözlemleyin. Kısa süre içinde parti boyutunun kullanımını göreceksiniz.batch_size

Geri dönen yineleyiciyi kullanarak, çeşitli meyvelerin (banana, durian, orange ve strawberry) etiketlerini bulabilirim:

class_dictionary = train_generator.class_indices

#---create a dictionary of labels---
class_dictionary = { value:key for key,value in
    class_dictionary.items()}

#---convert the dictionary to a list---
class_list = [value for _,value in class_dictionary.items()]
print(class_list)

Aşağıdaki çıktıyı göreceksiniz:

Found 54 images belonging to 4 classes.
['banana', 'durian', 'orange', 'strawberry']

Toplamda, 4 klasörde toplam 54 görüntü var. Ayrıca, değişken meyvelerin listesini içerir.class_list

Şimdi sınıf tarafından oluşturulan artırılmış görüntüler kümesini yazdıracağım. Satırları keyfi olarak 10 olarak ayarlayacağım ve her satır için döndürülen görüntü grubunu yazdırmak istiyorum (bu örnekte 8’dir):ImageDataGenerator

rows = 10
fig, axes = plt.subplots(rows,batch_size)
for r in range(rows):    
    #---get the batch of augmented images---
    image_batch = train_generator.next()    
    #---get the number of images returned---
    images_count = image_batch[0].shape[0]
    
    for c in range(images_count):
        #---convert to unsigned integers for viewing---
        image = image_batch[0][c].astype('uint8')
        
        #---display the image---
        axes[r,c].imshow(image)
        #---display the label of the image---
        axes[r,c].title.set_text(
            class_list[np.argmax(image_batch[1][c])])
        #---hides the x and y-ticks---
        axes[r,c].set_xticks([])
        axes[r,c].set_yticks([])
fig.set_size_inches(15,18)

Şimdi 8 olarak ayarlandığından (ve artık 1 değil), yöntem her çağırdığınızda size sekiz artırılmış görüntüden oluşan bir grup döndürür. Döndürülen görüntü sayısı, yöntemde daha önce ayarladığınız görüntüye bağlıdır:batch_sizetrain_generator.next()batch_sizeflow_from_directory()

train_generator = train_datagen.flow_from_directory(
    './Fruits',
    target_size=(224,224), 
    color_mode='rgb', 
    batch_size=batch_size,        # batch_size = 8
    class_mode='categorical', 
    shuffle=True)

Değişkenin değeri (yöntem tarafından döndürülür) iki öğeden oluşan bir demettir:image_batchnext()

  • İlk öğe (), batch_size görüntülerden oluşan bir dizidir (4B dizi)image_batch[0]
  • İkinci öğe () görüntülerin etiketlerini içeririmage_batch[1]

Yukarıdaki kod parçacığı aşağıdaki çıktıyı üretir:

Yedinci satırda, resimsiz iki boş grafik olduğuna dikkat edin. Görüntü kümesinde toplam 54 görüntü olduğunu ve her parti 8 görüntü (satır başına) döndürdüğünden, ilk yedi satırın toplam 54 görüntü (8×6 + 6) görüntüleyeceğini unutmayın. Aşağıdaki şekil bunu açıkça ortaya koymaktadır:

Herhangi bir sayıya ayarlayabileceğinizi ve sınıfın sizin için yeni artırılmış görüntüler oluşturmaya devam edeceğini unutmayın.rowsImageDataGenerator

Transfer Learning kullanarak model oluşturma

Artık çoğaltma için diskten görüntü kümelerini yüklemek için nasıl kullanılacağını biliyorsunuz. Ama bunu eğitim için nasıl kullanıyorsunuz? Aşağıdaki kod parçacığı, aktarımlı öğrenmeyi kullanarak derin öğrenme modelinin nasıl oluşturulacağını gösterir.ImageDataGenerator

Transfer learning, bir görev için geliştirilen bir modelin ikinci bir görevdeki modelin başlangıç noktası olarak yeniden kullanıldığı bir makine öğrenimi yöntemidir. Transfer öğrenme, eğitime harcamanız gereken zamanı azaltır.

from tensorflow.keras.models import Model
from tensorflow.keras.applications import VGG16
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
#---number of fruits---
NO_CLASSES = max(train_generator.class_indices.values()) + 1
#---load the VGG16 model as the base model for training---
base_model = VGG16(include_top=False, input_shape=(224, 224, 3))
#---add our own layers---
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024,activation='relu')(x)       # add dense layers so
                                           # that the model can 
                                           # learn more complex 
                                           # functions and 
                                           # classify for better 
                                           # results.
x = Dense(1024,activation='relu')(x)       # dense layer 2
x = Dense(512,activation='relu')(x)        # dense layer 3
preds = Dense(NO_CLASSES,
              activation='softmax')(x)     # final layer with 
                                           # softmax activation
#---create a new model with the base model's original 
# input and the new model's output---
model = Model(inputs = base_model.input, outputs = preds)
#---don't train the first 19 layers - 0..18---
for layer in model.layers[:19]:
    layer.trainable=False
#---train the rest of the layers - 19 onwards---
for layer in model.layers[19:]:
    layer.trainable=True
        
#---compile the model---    
model.compile(optimizer='Adam',
          loss='categorical_crossentropy',
          metrics=['accuracy'])

Transfer öğrenmenin nasıl çalıştığını açıklamak bu yazının kapsamı dışındadır. Başka bir yazı için bırakacağım.

Oluşturulan görüntüleri eğitim için kullanma

Artırılmış görüntüleri eğitim için kullanmak üzere modelin yöntemine geçin:train_generatorfit()

#---train the model---
step_size_train = train_generator.n // train_generator.batch_size
model.fit(train_generator,
          steps_per_epoch=step_size_train,
          epochs=15)

Parametre temel olarak bir çağda kaç adım olduğu anlamına gelir – sahip olduğunuz görüntü sayısına ve daha önce tanımlanan toplu iş boyutuna bağlıdır. Bunu yüksek bir sayıya ayarlarsanız, tekrarlayan eğitim yapıyorsunuz demektir. Bu formüle göre ayarlamanız gerekir:steps_per_epoch

Görüntü sayısı / batch size

Örneğimizde, toplamda 54 görüntümüz var. Ve böylece her çağda, sınıf eğitim için 54 görüntünün tümünü dönüştürecektir. Her çağda model, görüntülerin farklı varyasyonlarını alacaktır. 15 döneminiz varsa, görüntülerin toplam 15×54 varyasyonları oluşturulacak ve eğitim modeline beslenecektir.ImageDataGenerator

Sınıf, modelinizin her dönemde görüntülerin yeni varyasyonlarını almasını sağlar. Ancak, yalnızca dönüştürülmüş görüntüleri döndürdüğünü ve sahip olduğunuz görüntü kümesine eklemediğini unutmayın.ImageDataGenerator

Özet

Umarım bu yazı size görüntü veri çoğaltmanın neyle ilgili olduğu ve derin öğrenme modellerinizin eğitiminde neden bunlara ihtiyaç duyduğunuz konusunda iyi bir fikir vermiştir. Özellikle, TensorFlow kütüphanesindeki Keras modülünü kullanarak gösterdim.

Kaynaklar:

Image Data Augmentation for Deep Learning | by Wei-Meng Lee | Towards Data Science