Bounding Box Regression - การผจญภัยในความล้มเหลว
ฉันได้แก้ปัญหาหลายอย่างเกี่ยวกับโครงข่ายประสาทเทียม แต่ไม่ค่อยได้ผลกับภาพ ฉันมีเวลาประมาณ 18 ชั่วโมงในการสร้างเครือข่ายการถดถอยกล่องล้อมรอบและมันยังคงล้มเหลวอย่างเต็มที่ ด้วยฟังก์ชั่นการสูญเสียบางอย่างจะเรียกร้องความแม่นยำ 80% ในระหว่างการฝึกอบรมและการตรวจสอบความถูกต้อง (โดยมีการสูญเสียครั้งใหญ่อย่างแท้จริงสำหรับทั้งสองอย่าง) แต่การทดสอบการคาดคะเนแสดงให้เห็นกรอบที่มีการเคลื่อนย้ายพิกเซลเพียงหนึ่งหรือสองพิกเซลในทิศทางใดก็ได้และดูเหมือนว่าจะไม่สนใจข้อมูลโดยสิ้นเชิง ตอนนี้ฉันใช้รูปแบบของการสูญเสีย IoU แล้ว แต่พบว่า IoU ถูกตรึงไว้ที่ศูนย์ ... ซึ่งเห็นได้ชัดว่าเป็นจริงตามผลลัพธ์หลังการฝึกอบรม :). ฉันต้องการให้ใครสักคนมาดูเรื่องนี้และให้คำแนะนำเกี่ยวกับวิธีดำเนินการต่อไป
สิ่งที่ฉันมี
ฉันกำลังสร้างตัวอย่าง 40000 ภาพขนาด 200x100x3 โดยมีตัวอักษรตัวเดียววางแบบสุ่มในแต่ละภาพ ในขณะเดียวกันฉันก็กำลังสร้างกรอบความจริงพื้นฐานสำหรับแต่ละตัวอย่างการฝึกอบรม ฉันได้ตรวจสอบอย่างละเอียดแล้วว่าทั้งหมดนี้ใช้งานได้และข้อมูลถูกต้อง
สิ่งที่ฉันทำกับมัน
จากนั้นฉันก็เปลี่ยนภาพขนาด 200x100x3 เป็นสีเทาเพื่อสร้างภาพขนาด 200x100x1 จากนั้นภาพจะถูกทำให้เป็นมาตรฐานและกล่องขอบเขตจะถูกปรับขนาดให้อยู่ระหว่าง 0 ถึง 1 ในรูปแบบที่เรียบง่ายสิ่งนี้จะเกิดขึ้น:
x_train_normalized = (x_data - 127.5) / 127.5
y_train_scaled = boxes[:TRAIN]/[WIDTH,HEIGHT,WIDTH,HEIGHT]
ฉันได้รับข้อมูลนี้อย่างรอบคอบแม้กระทั่งการสร้างภาพและกรอบขอบเขตใหม่จากข้อมูลนั้น นี่ใช้งานได้แน่นอน
การฝึกอบรม
ในการฝึกอบรมหลังจากพยายามmse
และอื่น ๆ อีกมากมายซึ่งทั้งหมดนี้ล้มเหลวไม่ดีเท่ากันฉันได้ใช้ฟังก์ชันการสูญเสีย IOU ที่กำหนดเองอย่างง่าย -ln(IoU)
มันจริงผลตอบแทน ฉันทำการเปลี่ยนแปลงนี้โดยอ้างอิงจากกระดาษเนื่องจากการสูญเสีย (แปลก ๆ ?) ถูกตรึงไว้ที่ศูนย์ในหลายยุค
(ฟังก์ชั่นการสูญเสีย :)
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
เครือข่าย
สิ่งนี้ได้ผ่านการทำซ้ำหลายครั้ง อย่างที่ฉันพูดไปฉันได้แก้ไขปัญหาอื่น ๆ เกี่ยวกับ NN แล้ว ... นี่เป็นปัญหาแรกที่ทำให้ฉันติดอยู่อย่างสมบูรณ์ ณ จุดนี้เครือข่ายถูกปลดออกอย่างมาก แต่ยังคงล้มเหลวในการฝึกอบรมทั้งหมด:
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)
ยินดีต้อนรับคำแนะนำทั้งหมด! ในระหว่างนี้ฉันกำลังใช้ฟังก์ชันการสูญเสียจุดศูนย์กลางเพื่อดูว่าช่วยได้หรือไม่
คำตอบ
ในท้ายที่สุดปัญหานี้ส่วนใหญ่เป็นเรื่องของการไล่ระดับสีที่ตกลงไปใน minima ในท้องถิ่น
สำหรับผู้ที่อ่านเพื่อลูกหลานปัญหาอย่างหนึ่งใน ML ที่แก้ไขได้ยากคือเราไม่สามารถเลือกค่าเริ่มต้นที่สมเหตุสมผลสำหรับน้ำหนักอคติและเมล็ด (ใน CNN) ได้โดยสังหรณ์ใจ ด้วยเหตุนี้เราจึงอนุญาตให้เริ่มต้นแบบสุ่ม สิ่งนี้สามารถนำเสนอความท้าทายบางอย่าง
ความท้าทายที่ยิ่งใหญ่ที่สุดอย่างหนึ่งคือเมื่อคุณเริ่มจากจุดเริ่มต้นแบบสุ่มเป็นการยากที่จะบอกใครบางคนว่าจะทำซ้ำการทดสอบของคุณได้อย่างไร สิ่งนี้ไม่สำคัญมากในตอนท้ายเนื่องจากคุณสามารถระบุพารามิเตอร์ที่บันทึกไว้จากโมเดลที่ได้รับการฝึกอบรมของคุณ อย่างไรก็ตามสิ่งนี้ยังสามารถนำไปสู่เครือข่ายที่ดูเหมือนจะ "ไม่ดี" ซึ่งในความเป็นจริงแล้วดีอย่างสมบูรณ์แบบ
ในกรณีนี้ฉันใช้เวลาส่วนใหญ่ในการเริ่มต้น CNN ด้วยตัวเริ่มต้นที่เหมือนกัน (ไม่มีอยู่ในโค้ดด้านบน) บางครั้งฉันจะใช้เมล็ดพันธุ์แบบสุ่มหรือฟังก์ชันอื่น ๆ เพื่อสร้างค่าเริ่มต้นเพื่อให้ฉันสามารถปรับปรุงเครือข่ายได้ดีขึ้นผ่านเครื่องมือค้นหาทางพันธุกรรม
ดูเหมือนว่าตัวเริ่มต้นที่เหมือนกันจะรวมกับการทำซ้ำเครือข่ายต่างๆและข้อมูลเฉพาะนี้นำไปสู่ประสิทธิภาพการฝึกอบรมที่รุนแรงและไม่เกิดการบรรจบกัน
เมื่อฉันรันเครือข่ายดังกล่าวข้างต้นด้วยการเริ่มต้นแบบสุ่มและการปรับแต่งหนึ่งหรือสองครั้งมันก็มาบรรจบกันได้ดี การฝึกซ้ำบางอย่างจะตรึงด้านใดด้านหนึ่งของกรอบขอบเขตที่ขอบบางอันจะไม่มาบรรจบกัน แต่ฉันสามารถฝึกหลาย ๆ อันที่อยู่ในช่วงความแม่นยำ 96-98% สำหรับกล่องขอบเขตในชุดทดสอบของฉันได้สำเร็จ 20000 ทุกอย่างเรียบร้อยดี!