Menggunakan jaringan neural konvolusional (CNN) dengan gambar yang kompleks

1. Sebelum memulai

Dalam codelab ini, Anda akan menggunakan konvolusi untuk mengklasifikasikan gambar kuda dan manusia. Anda akan menggunakan TensorFlow di lab ini untuk membuat CNN yang dilatih untuk mengenali gambar kuda dan manusia, serta mengklasifikasikannya.

Prasyarat

Jika Anda belum pernah membangun konvolusi dengan TensorFlow sebelumnya, Anda mungkin ingin menyelesaikan codelab Bangun konvolusi dan melakukan penggabungan, di mana kami memperkenalkan konvolusi dan penggabungan, dan Membuat jaringan neural konvolusional (CNN) untuk meningkatkan visi komputer, tempat kami membahas cara membuat komputer lebih efisien dalam mengenali gambar.

Yang akan Anda pelajari

  • Cara melatih komputer untuk mengenali fitur dalam gambar yang subjeknya tidak jelas

Yang akan Anda build

  • Jaringan neural konvolusional yang dapat membedakan antara gambar kuda dan gambar manusia

Yang Anda butuhkan

Anda dapat menemukan kode untuk codelab lainnya yang berjalan di Colab.

Anda juga perlu menginstal TensorFlow, dan library yang Anda instal di codelab sebelumnya.

2. Memulai: Mendapatkan data

Anda akan melakukannya dengan membuat pengklasifikasi kuda atau manusia yang akan memberi tahu Anda apakah gambar yang diberikan berisi kuda atau manusia, tempat jaringan dilatih untuk mengenali fitur yang menentukan fitur mana. Anda harus melakukan beberapa pemrosesan data sebelum dapat melakukan pelatihan.

Pertama, download data:

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

Kode Python berikut akan menggunakan library OS untuk menggunakan library sistem operasi, sehingga memberi Anda akses ke sistem file dan library file zip, sehingga Anda dapat mengekstrak data.

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

Isi file zip diekstrak ke direktori dasar /tmp/horse-or-human, yang berisi kuda dan subdirektori manusia.

Singkatnya, set pelatihan adalah data yang digunakan untuk memberi tahu model jaringan neural bahwa &quot adalah inilah tampilan kuda dan seperti inilah tampilan manusia."

3. Menggunakan ImageGenerator untuk memberi label dan menyiapkan data

Anda tidak memberi label gambar secara eksplisit sebagai kuda atau manusia.

Kemudian, Anda akan melihat sesuatu yang disebut ImageDataGenerator sedang digunakan. Alat ini membaca gambar dari subdirektori dan memberi label secara otomatis dari nama subdirektori tersebut. Misalnya, Anda memiliki direktori pelatihan yang berisi direktori kuda dan direktori manusia. ImageDataGenerator akan memberi label pada gambar dengan tepat untuk Anda, sehingga mengurangi langkah coding.

Tentukan setiap direktori tersebut.

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

Sekarang, lihat tampilan nama filenya di direktori pelatihan kuda dan manusia:

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

Temukan jumlah total gambar kuda dan manusia di direktori:

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

4. Menjelajahi data

Lihat beberapa gambar untuk lebih memahami tampilannya.

Pertama, konfigurasikan parameter 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

Sekarang, tampilkan batch yang berisi delapan gambar kuda dan delapan gambar manusia. Anda dapat menjalankan kembali sel untuk melihat batch baru setiap kali.

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

Berikut beberapa contoh gambar yang menampilkan kuda dan manusia dalam berbagai pose dan orientasi:

6b6ebbc6e694ccd2.png

5. Menentukan model

Mulai tentukan model.

Mulai dengan mengimpor TensorFlow:

import tensorflow as tf

Kemudian, tambahkan lapisan konvolusional dan meratakan hasil akhir untuk diberikan ke lapisan yang terhubung dengan rapat. Terakhir, tambahkan lapisan yang terhubung dengan padat.

Perhatikan bahwa karena Anda menghadapi masalah klasifikasi dua kelas (masalah klasifikasi biner), Anda akan mengakhiri jaringan dengan aktivasi sigmoid sehingga output jaringan Anda akan menjadi skalar tunggal antara 0 dan 1, yang mengenkode kemungkinan bahwa gambar saat ini adalah kelas 1 (bukan kelas 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')
])

Panggilan metode model.summary() akan mencetak ringkasan jaringan.

model.summary()

Anda dapat melihat hasilnya di sini:

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

Kolom output output menunjukkan perkembangan ukuran peta fitur di setiap lapisan berturut-turut. Lapisan konvolusi mengurangi ukuran peta fitur sedikit karena padding dan setiap lapisan penggabungan mengurangi separuh dimensi.

6. Mengompilasi model

Selanjutnya, konfigurasikan spesifikasi untuk pelatihan model. Latih model Anda dengan kehilangan binary_crossentropy karena merupakan masalah klasifikasi biner dan aktivasi akhir Anda adalah sigmoid. (Untuk mengingat kembali tentang metrik kerugian, lihat Menuju ke dalam ML.) Gunakan pengoptimal rmsprop dengan kecepatan pembelajaran 0,001. Selama pelatihan, pantau akurasi klasifikasi.

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

7. Melatih model dari generator

Siapkan generator data yang membaca gambar dalam folder sumber Anda, konversikan menjadi tensor float32, dan beri makan (dengan labelnya) ke jaringan Anda.

Anda akan memiliki satu generator untuk gambar pelatihan dan satu generator untuk gambar validasi. Generator Anda akan menghasilkan kumpulan gambar berukuran 300x300 dan labelnya (biner).

Seperti yang mungkin sudah Anda ketahui, data yang masuk ke jaringan neural biasanya harus dinormalkan dengan cara tertentu agar lebih mudah diproses oleh jaringan. (Tidak umum untuk memasukkan piksel mentah ke CNN.) Dalam kasus Anda, Anda akan melakukan praproses gambar Anda dengan menormalkan nilai piksel yang berada dalam rentang [0, 1] (awalnya semua nilai berada dalam rentang [0, 255]).

Di Keras, hal tersebut dapat dilakukan melalui class keras.preprocessing.image.ImageDataGenerator menggunakan parameter rescale. Class ImageDataGenerator tersebut memungkinkan Anda membuat instance generator batch gambar yang ditingkatkan (dan labelnya) melalui .flow(data, label) atau .flow_from_directory(directory). Generator tersebut kemudian dapat digunakan dengan metode model Keras yang menerima generator data sebagai input: fit_generator, evaluate_generator dan 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 Lakukan pelatihan

Kereta untuk 15 iterasi pelatihan. (Mungkin perlu waktu beberapa menit untuk dijalankan.)

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

Perhatikan nilai per iterasi pelatihan.

Kerugian dan Akurasi adalah indikasi yang bagus tentang progres pelatihan. Ia menebak klasifikasi data pelatihan, lalu mengukurnya dengan label umum, menghitung hasilnya. Akurasi adalah bagian dari tebakan yang benar.

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. Menguji model

Sekarang, jalankan prediksi menggunakan model. Kode akan memungkinkan Anda memilih satu atau beberapa file dari sistem file. Kemudian, model akan mengupload dan menjalankan model melalui model, yang memberikan indikasi apakah objek adalah kuda atau manusia.

Anda dapat mendownload gambar dari internet ke sistem file untuk mencobanya. Perhatikan bahwa Anda mungkin melihat jaringan membuat banyak kesalahan, meskipun faktanya akurasi pelatihan di atas 99%.

Hal ini disebabkan oleh sesuatu yang disebut overfit, yang berarti jaringan neural dilatih dengan data yang sangat terbatas (hanya ada sekitar 500 gambar dari setiap class). Jadi sangat bagus dalam mengenali gambar yang mirip dengan yang ada di set pelatihan, tetapi hal itu bisa gagal banyak pada gambar yang tidak ada di set pelatihan.

Itu adalah poin data yang membuktikan bahwa semakin banyak data yang Anda latih, semakin baik jaringan akhir Anda!

Ada banyak teknik yang dapat digunakan untuk membuat pelatihan Anda menjadi lebih baik, meskipun datanya terbatas, termasuk hal yang disebut augmentasi gambar, tetapi hal itu berada di luar cakupan codelab ini.

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

Misalnya, katakan Anda ingin menguji dengan gambar ini:

9e07a57ff3be7a82.jpeg

Berikut adalah hal yang dihasilkan oleh lab:

77b678e70b00862a.png

Meskipun dibuat sebagai kartun, grafis tersebut tetap diklasifikasikan dengan benar.

Gambar berikut juga terklasifikasi dengan benar:

c9213173d9f3d83c.jpeg

f2844da737a1a2f2.png

Coba beberapa gambar milik Anda dan jelajahi!

10. Memvisualisasikan representasi perantara

Untuk mengetahui jenis fitur yang telah dipelajari CNN Anda, hal menyenangkan yang dapat dilakukan adalah memvisualisasikan bagaimana input diubah saat melewati CNN.

Pilih gambar acak dari set pelatihan, lalu buat gambar dengan setiap baris adalah output dari lapisan dan setiap gambar dalam baris adalah filter tertentu dalam peta fitur output tersebut. Jalankan kembali sel tersebut untuk menghasilkan representasi perantara untuk berbagai gambar pelatihan.

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

Berikut adalah contoh hasil:

e078d1bc9662c93f.png

Seperti yang dapat dilihat, Anda mulai dari piksel mentah gambar ke representasi yang semakin abstrak dan ringkas. Representasi downstream mulai menyoroti apa yang diperhatikan jaringan, dan mereka menunjukkan lebih sedikit dan lebih sedikit fitur yang "diaktifkan." Sebagian besar parameter disetel ke nol. Itu disebut ketersebaran. Ketersebaran representasi adalah fitur utama dari deep learning.

Representasi tersebut membawa lebih sedikit informasi tentang piksel asli gambar, tetapi semakin banyak informasi yang disempurnakan tentang class gambar. Anda dapat menganggap CNN (atau jaringan dalam yang umum) sebagai pipeline distilasi informasi.

11. Selamat

Anda telah belajar menggunakan CNN untuk menyempurnakan gambar yang kompleks. Untuk mempelajari cara meningkatkan model computer vision Anda lebih lanjut, lanjutkan ke Menggunakan jaringan neural konvolusional (CNN) dengan set data besar untuk menghindari overfit.