Почему моя нейронная сеть всегда дает мне одни и те же прогнозы? - PullRequest
0 голосов
/ 08 июня 2019

Я пытаюсь создать последовательную нейронную сеть, в которой на выходе будет 12 неисключительных вероятностей (вероятность A, вероятность B, вероятность C, ...). Моя сеть, кажется, запоминает наиболее распространенный вывод и всегда предсказывает это для каждого входа. Все мои выходные значения всегда равны «1» или «0», между ними нет ничего, и всегда одно и то же значение в одной и той же позиции (подробности ниже).

Я далеко не эксперт по ML, поэтому возможно, что решение очень простое.

Я пытался использовать пакеты разных размеров (от 8 до 128) и много разных функций потерь, но ни одна из них не помогла.

Как я создал модель с помощью Keras:

model = Sequential()
model.add( Dense( 150, input_dim=9600, activation='relu') )
model.add( LeakyReLU(alpha=.01) )
model.add( Dense( 50, activation='relu') )
model.add( LeakyReLU(alpha=.01) )
model.add( Dense( 12, activation='sigmoid') )

metrics_to_output=[ 'accuracy' ]
# I've tried many loss functions, not just mean_squared_error
model.compile( loss='mean_squared_error', optimizer='adam', metrics=metrics_to_output )

Это может не относиться к делу, но именно так я готовлю данные и обучаю модель. Я также пытался использовать train_on_batch:

def generate_data_from_files( file1, file2 ):
    input = numpy.load( file1, allow_pickle=True )
    output = numpy.load( file2, allow_pickle=True )

    # The file only has 2 values, and I generate 12 probabilities derived from those 2 values
    transformed_output = output.copy()
    new_shape = ( output.shape[ 0 ], 12 )
    transformed_output.resize( new_shape )

    for x in range( 0, len( output ) ):
        #First 6 probabilities model the value of output[ x ][ 0 ]
        transformed_output[ x ][ 0 ] = 1 if output[ x ][ 0 ] <= -5.0 else 0
        transformed_output[ x ][ 1 ] = 1 if output[ x ][ 0 ] <= -3.0 else 0
        transformed_output[ x ][ 2 ] = 1 if output[ x ][ 0 ] <= -1.0 else 0
        transformed_output[ x ][ 3 ] = 1 if output[ x ][ 0 ] >= 1.0 else 0
        transformed_output[ x ][ 4 ] = 1 if output[ x ][ 0 ] >= 3.0 else 0
        transformed_output[ x ][ 5 ] = 1 if output[ x ][ 0 ] >= 5.0 else 0
        #Second 6 probabilities model the value of output[ x ][ 1 ]
        transformed_output[ x ][ 6 ] = 1 if output[ x ][ 1 ] <= -5.0 else 0
        transformed_output[ x ][ 7 ] = 1 if output[ x ][ 1 ] <= -3.0 else 0
        transformed_output[ x ][ 8 ] = 1 if output[ x ][ 1 ] <= -1.0 else 0
        transformed_output[ x ][ 9 ] = 1 if output[ x ][ 1 ] >= 1.0 else 0
        transformed_output[ x ][ 10] = 1 if output[ x ][ 1 ] >= 3.0 else 0
        transformed_output[ x ][ 11] = 1 if output[ x ][ 1 ] >= 5.0 else 0
    return input, transformed_output


input, output = generate_data_from_file( file1, file2 )
model.fit( x=input, y=output, batch_size=8, epochs=1 )

Я ожидаю получить 12 значений в диапазоне от 0 до 1, каждое из которых моделирует вероятность. Однако, когда я использую сеть, чтобы делать прогнозы (даже на данных обучения), я всегда получаю один и тот же идентичный вывод:

0 1 1 0 0 0 0 0 0 0 0 0

Это разумное среднее предположение, потому что 2-е и 3-е логические значения обычно верны, а все остальное обычно ложно, но я никогда не вижу каких-либо отклонений от этого прогноза, даже в обучающих данных, где ожидаемый результат является чем-то другим. Иногда я вижу 0,999999 или 0,000001 вместо 0 или 1, но даже это редко.

Мой вывод: я настраиваю модель, чтобы всегда прогнозировать средний случай. Любая обратная связь или совет будет принята с благодарностью. Заранее спасибо!

Edit: Спасибо всем за совет. Прочитав больше об этом, я думаю, что происходит то, что мой выходной слой становится насыщенным. Я переключаюсь на использование softsign вместо сигмоида (и корректирую логику, ожидая, что -1 будет полом вместо 0), и, надеюсь, это поможет.

1 Ответ

0 голосов
/ 09 июня 2019

Вы используете функцию активации сигмоида для вашего выходного слоя.

model.add( Dense( 12, activation='sigmoid') )

Сигмоид выводит либо 0, либо 1. Я думаю, что вам нужна функция активации softmax, которая выводит значения от 0 до 1, и все (12) значения складываются до 1. Затем вы должны выполнить argmax для найдите самое высокое значение и примите это как свой прогноз.

Две другие вещи: почему вы используете две функции активации в ваших скрытых слоях? Используйте одно или другое, а не оба.

model.add( Dense( 50, activation='relu') )
model.add( LeakyReLU(alpha=.01) )

Среднеквадратическая ошибка используется для задач регрессии, на основании вашего описания это, похоже, проблема классификации.

...