경계 상자 회귀-실패한 모험

Jan 19 2021

신경망의 많은 문제를 해결했지만 이미지 작업은 거의하지 않습니다. 경계 상자 회귀 네트워크를 만드는 데 약 18 시간이 걸렸지 만 계속해서 완전히 실패합니다. 일부 손실 함수를 사용하면 훈련 및 검증 중에 80 %의 정확도를 요구하지만 (둘 다에 대해 정말 큰 손실이 있음) 예측을 테스트하면 주어진 방향으로 1 ~ 2 픽셀 만 이동하고 데이터를 완전히 무시하는 것처럼 보이는 경계 상자가 나타납니다. 이제 IoU 손실의 한 형태를 구현했지만 IoU가 0에 고정되어 있음을 발견했습니다. 이것은 훈련 후 출력을 기반으로하는 것이 분명합니다. :). 누군가가 이것을 살펴보고 다음에 진행하는 방법에 대한 조언을 해주 었으면합니다.

내가 가진 것

저는 200x100x3 이미지의 40000 개의 예를 각각 하나의 문자가 무작위로 배치 된 상태로 생성하고 있습니다. 동시에 각 훈련 샘플에 대한 Ground Truth 경계 상자를 생성하고 있습니다. 이 모든 것이 작동하고 데이터가 올바른지 철저히 검증했습니다.

내가하는 일

그런 다음 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). 손실이 여러 시대에 걸쳐 0으로 고정 되었기 때문에 종이를 기반으로이 변경을 수행했습니다.

(손실 기능 :)

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)

모든 포인터를 환영합니다! 그 동안 나는 그것이 전혀 도움이되는지 확인하기 위해 중심점 손실 기능을 구현하고 있습니다.

답변

DavidHoelzer Jan 21 2021 at 07:35

결국,이 문제는 대체로 국소 최소값으로 떨어지는 경사 하강 법의 문제로 밝혀졌습니다.

사후를 읽는 사람들의 경우 해결하기 어려운 ML 문제 중 하나는 가중치, 편향 및 커널 (CNN에서)에 대해 합리적인 초기 값을 직관적으로 선택할 수 없다는 것입니다. 결과적으로 일반적으로 무작위로 초기화 할 수 있습니다. 이것은 몇 가지 도전을 제시 할 수 있습니다.

가장 큰 문제 중 하나는 임의의 시작점에서 시작할 때 다른 사람에게 실험을 완전히 복제하는 방법을 알리기 어렵다는 것입니다. 학습 된 모델에서 저장된 매개 변수를 제공 할 수 있기 때문에 이것은 결국 그다지 중요하지 않습니다. 그러나 이것은 사실상 완벽하게 괜찮은 "나쁜"것처럼 보이는 네트워크로 이어질 수도 있습니다.

이 경우에는 균일 한 이니셜 라이저 (위 코드에는 없음)를 사용하여 CNN을 초기화하는 데 많은 시간을 보냈습니다. 유전 검색 도구를 통해 네트워크를 더 잘 개선 할 수 있도록 때때로 임의의 시드 또는 다른 기능을 사용하여 초기 값을 생성합니다.

다양한 네트워크 반복 및이 특정 데이터와 결합 된 균일 한 이니셜 라이저는 절대적으로 비정상적인 훈련 성능과 비 수렴으로 이어집니다.

위와 같이 임의의 초기화와 한두 번의 조정으로 네트워크를 실행했을 때 잘 수렴되었습니다. 일부 훈련 반복은 경계 상자의 측면 중 하나를 가장자리에 고정하고 일부는 수렴하지 않지만 테스트 세트의 경계 상자에 대해 96-98 % 정확도 범위에있는 여러 훈련을 성공적으로 수행했습니다. 20000이므로 모든 것이 잘됩니다!