Bounding Box Regression - Petualangan dalam Kegagalan

Jan 20 2021

Saya telah memecahkan banyak masalah dengan jaringan saraf, tetapi jarang bekerja dengan gambar. Saya memiliki sekitar 18 jam untuk membuat jaringan regresi kotak pembatas dan terus gagal total. Dengan beberapa fungsi kerugian, ini akan mengklaim akurasi 80% selama pelatihan dan validasi (dengan kerugian yang benar-benar besar pada keduanya) tetapi pengujian prediksi mengungkapkan kotak pembatas yang hanya bergerak satu atau dua piksel ke arah tertentu dan tampaknya mengabaikan data sepenuhnya. Saya sekarang telah menerapkan bentuk kehilangan IoU, tetapi menemukan bahwa IoU disematkan ke nol ... yang jelas benar berdasarkan keluaran setelah pelatihan. :). Saya ingin seseorang memeriksanya dan memberi saya beberapa saran tentang cara melanjutkan selanjutnya.

Apa yang saya punya

Saya membuat 40.000 contoh gambar 200x100x3 dengan satu huruf ditempatkan secara acak di setiap gambar. Secara bersamaan, saya membuat kotak pembatas kebenaran dasar untuk setiap sampel pelatihan. Saya telah sepenuhnya memvalidasi bahwa ini semua berfungsi dan datanya benar.

Apa yang Saya Lakukan Untuk Itu

Saya kemudian mengubah gambar 200x100x3 menjadi abu-abu untuk menghasilkan gambar 200x100x1. Gambar kemudian dinormalisasi dan kotak pembatas diskalakan antara 0 dan 1. Dalam bentuk yang disederhanakan, ini terjadi:

x_train_normalized = (x_data - 127.5) / 127.5
y_train_scaled = boxes[:TRAIN]/[WIDTH,HEIGHT,WIDTH,HEIGHT]

Saya telah melalui data ini dengan hati-hati, bahkan menyusun kembali gambar dan kotak pembatas darinya. Ini pasti berhasil.

Latihan

Untuk melatih, setelah mencoba msedan banyak lainnya, yang semuanya gagal sama-sama buruk, saya telah menerapkan fungsi kerugian IOU kustom sederhana. Ini benar-benar kembali -ln(IoU). Saya membuat perubahan ini berdasarkan kertas karena kerugiannya (anehnya?) Disematkan pada nol selama beberapa zaman.

(Fungsi kerugian :)

import tensorflow.keras.backend as kb
def iou_loss(y_actual,y_pred):
    b1 = y_actual
    b2 = y_pred
#    tf.print(b1)
#    tf.print(b2)
    zero = tf.convert_to_tensor(0.0, b1.dtype)
    b1_ymin, b1_xmin, b1_ymax, b1_xmax = tf.unstack(b1, 4, axis=-1)
    b2_ymin, b2_xmin, b2_ymax, b2_xmax = tf.unstack(b2, 4, axis=-1)
    b1_width = tf.maximum(zero, b1_xmax - b1_xmin)
    b1_height = tf.maximum(zero, b1_ymax - b1_ymin)
    b2_width = tf.maximum(zero, b2_xmax - b2_xmin)
    b2_height = tf.maximum(zero, b2_ymax - b2_ymin)
    b1_area = b1_width * b1_height
    b2_area = b2_width * b2_height

    intersect_ymin = tf.maximum(b1_ymin, b2_ymin)
    intersect_xmin = tf.maximum(b1_xmin, b2_xmin)
    intersect_ymax = tf.minimum(b1_ymax, b2_ymax)
    intersect_xmax = tf.minimum(b1_xmax, b2_xmax)
    intersect_width = tf.maximum(zero, intersect_xmax - intersect_xmin)
    intersect_height = tf.maximum(zero, intersect_ymax - intersect_ymin)
    intersect_area = intersect_width * intersect_height

    union_area = b1_area + b2_area - intersect_area
    iou = -1 * tf.math.log(tf.math.divide_no_nan(intersect_area, union_area))
    return iou

Jaringan

Ini telah melalui banyak sekali iterasi. Seperti yang saya katakan, saya telah memecahkan banyak masalah lain dengan NN ... Ini adalah masalah pertama yang membuat saya benar-benar macet. Pada titik ini, jaringan secara dramatis dipreteli tetapi terus gagal untuk berlatih sama sekali:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers

tf.keras.backend.set_floatx('float32') # Use Float32s for everything

input_shape = x_train_normalized.shape[-3:]
model = keras.Sequential()
model.add(layers.Conv2D(4, 16, activation = tf.keras.layers.LeakyReLU(alpha=0.2), input_shape=input_shape))
model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
model.add(layers.Dropout(0.2))
model.add(layers.Flatten())
model.add(layers.Dense(200, activation = tf.keras.layers.LeakyReLU(alpha=0.2)))
model.add(layers.Dense(64, activation=tf.keras.layers.LeakyReLU(alpha=0.2)))
model.add(layers.Dense(4, activation="sigmoid"))

model.compile(loss = iou_loss, optimizer = "adadelta", metrics=['accuracy'])
history = model.fit(x_train_normalized, y_train_scaled, epochs=8, batch_size=100, validation_split=0.4)

Semua petunjuk diterima! Sementara itu, saya menerapkan fungsi kehilangan titik pusat untuk melihat apakah itu membantu sama sekali.

Jawaban

DavidHoelzer Jan 21 2021 at 07:35

Pada akhirnya, masalah ini ternyata sebagian besar merupakan masalah penurunan gradien yang jatuh ke minimum lokal.

Bagi mereka yang membaca untuk anak cucu, salah satu masalah dalam ML yang sulit untuk diselesaikan adalah bahwa kita tidak dapat secara intuitif memilih nilai awal yang wajar untuk bobot, bias, dan kernel (di CNN). Akibatnya, kami biasanya mengizinkan mereka untuk menginisialisasi secara acak. Ini dapat menghadirkan beberapa tantangan.

Salah satu tantangan terbesar adalah ketika Anda memulai dari titik awal acak, sulit untuk memberi tahu seseorang cara mereplikasi eksperimen Anda sepenuhnya. Ini tidak terlalu penting pada akhirnya karena Anda dapat memberi mereka parameter yang disimpan dari model terlatih Anda. Namun, ini juga dapat menyebabkan jaringan yang tampak "buruk" yang sebenarnya baik-baik saja.

Dalam kasus ini, saya menghabiskan banyak waktu untuk menginisialisasi CNN dengan penginisialisasi seragam (tidak ada dalam kode di atas). Saya kadang-kadang akan menggunakan benih acak atau beberapa fungsi lain untuk menghasilkan nilai awal sehingga saya dapat meningkatkan jaringan dengan lebih baik melalui alat pencarian genetik.

Tampaknya penginisialisasi seragam dikombinasikan dengan berbagai iterasi jaringan dan data khusus ini mengarah pada kinerja pelatihan yang sangat buruk dan non-konvergensi.

Ketika saya menjalankan jaringan seperti di atas dengan inisialisasi acak dan satu atau dua tweak, itu menyatu dengan baik. Beberapa iterasi pelatihan akan menyematkan salah satu sisi kotak pembatas di tepi, beberapa tidak akan pernah menyatu, tetapi saya telah berhasil melatih beberapa yang berada dalam kisaran akurasi 96-98% untuk kotak pembatas di set pengujian saya 20000, jadi semuanya baik-baik saja!