Hồi quy hộp giới hạn - Một cuộc phiêu lưu trong thất bại
Tôi đã giải quyết nhiều vấn đề với mạng nơ-ron, nhưng hiếm khi làm việc với hình ảnh. Tôi có khoảng 18 giờ để tạo một mạng hồi quy hộp giới hạn và nó tiếp tục hoàn toàn thất bại. Với một số hàm mất mát, nó sẽ yêu cầu độ chính xác 80% trong quá trình đào tạo và xác thực (với sự mất mát thực sự lớn trên cả hai) nhưng việc kiểm tra các dự đoán cho thấy một hộp giới hạn chỉ di chuyển một hoặc hai pixel theo bất kỳ hướng nào và dường như hoàn toàn bỏ qua dữ liệu. Bây giờ tôi đã triển khai một dạng mất IoU, nhưng thấy rằng IoU được ghim ở mức 0 ... điều này rõ ràng là đúng dựa trên kết quả đầu ra sau khi đào tạo. :). Tôi muốn ai đó xem qua vấn đề này và cho tôi một số lời khuyên về cách tiếp tục.
Tôi có gì
Tôi đang tạo 40000 ví dụ về hình ảnh 200x100x3 với một chữ cái duy nhất được đặt ngẫu nhiên trong mỗi hình ảnh. Đồng thời, tôi đang tạo các hộp giới hạn sự thật cơ bản cho mỗi mẫu đào tạo. Tôi đã xác nhận kỹ lưỡng rằng tất cả điều này hoạt động và dữ liệu là chính xác.
Những gì tôi làm với nó
Sau đó, tôi chuyển đổi hình ảnh 200x100x3 xuống thang độ xám để tạo ra hình ảnh 200x100x1. Sau đó, các hình ảnh được chuẩn hóa và các hộp giới hạn được chia tỷ lệ để rơi vào khoảng từ 0 đến 1. Ở dạng đơn giản, điều này xảy ra:
x_train_normalized = (x_data - 127.5) / 127.5
y_train_scaled = boxes[:TRAIN]/[WIDTH,HEIGHT,WIDTH,HEIGHT]
Tôi đã xem qua dữ liệu này một cách cẩn thận, thậm chí còn tạo lại hình ảnh và các hộp giới hạn từ nó. Điều này chắc chắn đang hoạt động.
Đào tạo
Để huấn luyện, sau khi thử mse
và nhiều người khác, tất cả đều thất bại nặng nề như nhau, tôi đã triển khai một chức năng mất IOU tùy chỉnh đơn giản. Nó thực sự trở lại -ln(IoU)
. Tôi thực hiện thay đổi này dựa trên một bài báo vì khoản lỗ (kỳ lạ là?) Được ghim ở mức 0 trong nhiều kỷ nguyên.
(Mất chức năng:)
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
Mạng lưới
Điều này đã được trải qua rất nhiều lần lặp lại. Như tôi đã nói, tôi đã giải quyết nhiều vấn đề khác với NN ... Đây là vấn đề đầu tiên khiến tôi hoàn toàn bế tắc. Tại thời điểm này, mạng đã bị xóa đáng kể nhưng vẫn tiếp tục không đào tạo được:
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)
Tất cả các gợi ý đều được chào đón! Trong thời gian chờ đợi, tôi đang triển khai chức năng mất điểm trung tâm để xem liệu điều đó có giúp ích được gì không.
Trả lời
Cuối cùng, vấn đề này phần lớn là vấn đề của sự giảm dần gradient rơi vào cực tiểu cục bộ.
Đối với những người đọc cho hậu thế, một trong những vấn đề khó giải quyết trong ML là chúng ta không thể chọn trực quan các giá trị ban đầu hợp lý cho trọng số, độ lệch và hạt nhân (trong CNN). Do đó, chúng tôi thường cho phép chúng khởi tạo ngẫu nhiên. Điều này có thể đưa ra một số thách thức.
Một trong những thách thức lớn nhất là khi bạn bắt đầu từ một điểm xuất phát ngẫu nhiên, rất khó để nói cho ai đó biết cách tái tạo hoàn toàn các thử nghiệm của bạn. Cuối cùng thì điều này cũng không quá quan trọng vì bạn có thể cung cấp cho họ các thông số đã lưu từ mô hình được đào tạo của bạn. Tuy nhiên, điều này cũng có thể dẫn đến các mạng có vẻ "xấu" mà trên thực tế là hoàn toàn tốt.
Trong trường hợp này, tôi đã dành nhiều thời gian để khởi tạo CNN bằng một bộ khởi tạo thống nhất (không có trong đoạn mã trên). Đôi khi tôi sẽ sử dụng một hạt giống ngẫu nhiên hoặc một số chức năng khác để tạo ra các giá trị ban đầu để tôi có thể cải thiện mạng tốt hơn thông qua các công cụ tìm kiếm di truyền.
Có vẻ như các bộ khởi tạo thống nhất kết hợp với các lần lặp lại mạng khác nhau và dữ liệu cụ thể này dẫn đến hiệu suất đào tạo hoàn toàn không ổn định và không hội tụ.
Khi tôi chạy mạng như trên với các lần khởi tạo ngẫu nhiên và một hoặc hai lần chỉnh sửa, nó đã hội tụ tốt. Một số lần lặp lại đào tạo sẽ ghim một trong các cạnh của hộp giới hạn ở cạnh, một số sẽ không bao giờ hội tụ, nhưng tôi đã cố gắng đào tạo thành công một số trong phạm vi chính xác 96-98% cho các hộp giới hạn trong bộ thử nghiệm của tôi 20000, vậy là tất cả đều ổn!