Keras+Tensorflow не обучается распознавать метку для пустого изображения

Вопрос или проблема

У меня есть модель Keras, и я хочу сделать с ней крутые визуализации. Это сеть для распознавания объектов.

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

Поэтому я написал следующий код:

# загрузка модели
model = load_model('model.h5')

# создание входного изображения как переменной
w = tf.Variable(tf.zeros([1,224,224,3]))

# создание потока данных с переменной на входе
pred = model.call(inputs=w)

# создание желаемого распределения выходных данных
desired = np.zeros((1000))
desired[928] = 1.0

err = tf.reduce_mean(tf.subtract(pred,desired))
lr = tf.placeholder(dtype=tf.float32, shape=None)

# создание оптимизатора, который может влиять только на первоначальную входную переменную, которую я создал
optimizer = tf.train.AdamOptimizer(learning_rate=0.0001).minimize(err, var_list=[w])

# обучение сети
for i in range(0,100):
    _,cost = sess.run([optimizer,err])
    print(cost)

Я думал, что код будет работать хорошо, но стоимость просто не меняется. Она остается на месте, как будто полностью не подвергается воздействию.

Попробуйте явно установить переменную как обучаемую, установив Trainable=True. Также после создания сети проверьте, находится ли переменная в списке обучаемых https://www.tensorflow.org/api_docs/python/tf/trainable_variables

Ошибка проста: когда вы вводите пустое изображение. Предположим, черное изображение, как вы сделали с tf.zeros, результат будет полон нулей, поэтому когда вы умножите свои веса на 0, полученное скалярное произведение будет 0.

Поскольку формула выглядит как sum(weights * conv), а так как conv заполнено нулями, скалярное произведение будет 0.

Затем мы добавим смещение: каждое значение в результирующем изображении будет активацией смещения, и будет оставаться тем же самым значением везде. Независимо от того, какое входное значение вы дадите и какие веса будут в первом слое, его градиент будет 0 и, следовательно, не изменится. Не имеет значения, какое входное изображение вы дадите, результирующее изображение будет заполнено 0 со значениями смещения, и конечный вывод будет тем же самым. Таким образом, оно не будет ничему учиться.

Ответ или решение

Ваша задача заключается в том, чтобы использовать пустое изображение в качестве переменной и обучить нейронную сеть генерировать определенную категорию объектов (в данном случае – мороженое). Однако, как вы уже заметили, ваша модель не обучается, потому что входные данные (пустое изображение) оказываются неэффективными для передачи информации в сеть.

Основная проблема

Когда вы используете tf.zeros для создания входного изображения, в результате вы получаете тензор, заполненный нулями. При прогонке через первую свертку нейронной сети, результат будет равен нулю, так как:

[ \text{output} = \text{sum(weights} \times \text{conv}) + \text{bias} ]

Поскольку все значения в conv равны нулю, произведение будет равно нулю. В таком случае на выходе мы получим только смещение (bias), что приводит к тому, что градиенты для веса будут равны нулю, и сеть не сможет обучаться.

Как можно решить проблему

Чтобы ваша модель могла учиться, вы можете использовать несколько подходов:

  1. Инициализация случайного изображения: Вместо того, чтобы начинать с нуля, создайте случайное изображение. Например, используйте tf.random.uniform для генерации случайных значений в нужной области:
w = tf.Variable(tf.random.uniform([1, 224, 224, 3]))
  1. Использование предобученного изображения: Вместо пустого изображения можете воспользоваться случайным предобученным изображением, соответствующим задаче, чтобы улучшить обучение.

  2. Добавление шума: Если не желаете использовать предобученные изображения, попробуйте добавить небольшой уровень шума к вашему пустому изображению, чтобы получить разнообразные градиенты.

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

Пример исправленного кода

Вот пример вашего кода с исправлениями:

# Загрузка модели
model = load_model('model.h5')

# Создаем случайное изображение в качестве переменной
w = tf.Variable(tf.random.uniform([1, 224, 224, 3], minval=0, maxval=255))

# Создаем граф потока с переменной на входе
pred = model.call(inputs=w)

# Создаем распределение желаемых выходов
desired = np.zeros((1000))
desired[928] = 1.0

# Функция потерь
err = tf.reduce_mean(tf.subtract(pred, desired))
lr = tf.placeholder(dtype=tf.float32, shape=None)

# Создаем оптимизатор
optimizer = tf.train.AdamOptimizer(learning_rate=0.0001).minimize(err, var_list=[w])

# Обучаем сеть
for i in range(100):
    _, cost = sess.run([optimizer, err])
    print(cost)

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

Оцените материал
Добавить комментарий

Капча загружается...