Сбой в обучении нейронной сети 3dconv; потери сходятся на .6931

#python #tensorflow #machine-learning #neural-network #nibabel

#python #тензорный поток #машинное обучение #нейронная сеть #nibabel

Вопрос:

Я написал скрипт для обучения нейронной сети использованию файлов .nii в качестве входных данных, используя руководство из TensorFlow здесьhttps://www.tensorflow.org/tutorials/load_data/images. Я немного изменил ее для работы с файлами NiBabel и .nii, но она по-прежнему соответствует той же базовой структуре. Однако я столкнулся с проблемой, когда моя потеря сходится к 0.6931, что, как я полагаю, связано с тем, что модель начинает угадывать одно и то же независимо от ввода, формы изображения или размера пакета. Таким образом, я считаю, что модель не обучается. Кто-нибудь может определить какие-либо фатальные недостатки в моем коде; Я уже устал:

  • Обратные вызовы с изменением LR
  • Изменение данных, их очистка и реорганизация
  • Изменение пропорций количества каждого класса
  • Использование различных оптимизаторов и функций потерь
  • Использование простой плотной модели, но, похоже, это не работает, поскольку она даже не хочет начинать обучение
  • Использование повторяющегося набора данных, а также фиксированного размера (хотя мне неясно, какая разница)
 # Gets the label of the image, the label determines how tensorflow will classify the image
def get_label(file_path):
    # Convert the path to a list of path components
    parts = tf.strings.split(file_path, os.path.sep)
    # The fourth last is the class-directory
    return float(parts[-4] == "class1")


# Reads the data from a .nii file and returns a NumPy ndarray that is compatible with tensorflow
def decode_img(img):
    img = nib.load(img.numpy().decode('utf-8'))
    # convert the compressed string to a NumPy ndarray
    data = img.get_fdata()
    # Resize img
    data = np.resize(data, imgshape)
    # Normalize
    max = np.amax(data)
    min = np.amin(data)
    data = ((data-min)/(max-min))
    return data


# Processes a path to return a image data and label pair
def process_path(file_path):
    # Gets the files label
    label = get_label(file_path)
    img = decode_img(file_path)
    return img, label
  

Я использую эти функции для обработки своих данных и сопоставления их с наборами данных моих файлов списка для обработки моих данных.

 def configure_for_performance(ds):
    #ds = ds.cache(filename='cachefile')
    ds = ds.cache()
    ds = ds.shuffle(buffer_size=1000)
    ds = ds.repeat()
    ds = ds.batch(BATCH_SIZE)
    ds = ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
    return ds
  

Я извлек это непосредственно из руководства по TensorFlow.

 # Create a sequential network
model = tf.keras.Sequential([
    tf.keras.layers.Convolution3D(
        4, 4, padding='same', data_format="channels_last", input_shape=imgshape, activation='tanh'),
    tf.keras.layers.MaxPooling3D(padding='same'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Convolution3D(4, 4, padding='same', activation='tanh'),
    tf.keras.layers.MaxPooling3D(padding='same'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Convolution3D(4, 4, padding='same', activation='tanh'),
    tf.keras.layers.MaxPooling3D(padding='same'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Convolution3D(4, 4, padding='same', activation='tanh'),
    tf.keras.layers.MaxPooling3D(padding='same'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(2048, activation='tanh'),
    tf.keras.layers.Dense(1024, activation='tanh'),
    tf.keras.layers.Dense(512, activation='tanh'),
    tf.keras.layers.Dense(256, activation='tanh'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.summary()
model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=500,
    steps_per_epoch=BATCH_SIZE,
    validation_steps=BATCH_SIZE
)
  

Это моя модель, я использую 3dconv аналогично тому, как 2dconv используется в обычной классификации изображений.

Любой совет был бы оценен!

Комментарии:

1. Можете ли вы добавить журналы обучения, которые генерируются после запуска model.fit()?

Ответ №1:

Ваш код для извлечения изображений выглядит хорошо, однако я не могу проверить его на себе, потому что я не уверен, как хранятся ваши данные. Также тот факт, что ваша модель начнет обучение, указывает на то, что ошибки, вероятно, здесь нет. Если вы хотите убедиться, что вы можете использовать matplotlib для отображения изображений, чтобы убедиться, что они правильно загружены.

Я бы начал с того, что сделал вашу модель настолько простой, насколько это возможно, и все еще работает, проверьте, сходится ли она по-прежнему к 0.6931 или какому-либо другому числу. Затем попробуйте использовать другую функцию активации, т.Е. relu. Другим подходом может быть использование некоторой пакетной нормализации. Моя теория заключается в том, что у вас очень большие или маленькие значения, входящие в вашу функцию tanh, это приводит к тому, что результат каждый раз приближается к 0 или 1. Это также предотвращает дальнейшее обучение, поскольку существует очень маленький градиент для обучения. Переход на relu может обойти эту проблему для больших значений, но, возможно, не для маленьких. Использование пакетной нормализации приведет к удалению ваших значений от конечных точек, где вывод tanh равен только 0 или 1.

График Tanh

Ответ №2:

Если вы последовательно сходитесь к точно такой же потере, то, по моему опыту, есть только одно объяснение — вы неправильно закодировали загрузчик данных. Происходит то, что изображение и метка не совпадают. Он пытается изучить чистую случайность. В таком сценарии он просто сделает лучшее, что может, то есть выведет «средний» правильный ответ. Я подозреваю, что значение 0.69 исходит из ваших меток данных, например, у вас 69% класса 1 и 31% класса 0.