Подтвердить что ты не робот

Нейронная сеть всегда предсказывает тот же класс

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

Здесь мой метод извлечения функции:

def extract(file):
    # Resize and subtract mean pixel
    img = cv2.resize(cv2.imread(file), (224, 224)).astype(np.float32)
    img[:, :, 0] -= 103.939
    img[:, :, 1] -= 116.779
    img[:, :, 2] -= 123.68
    # Normalize features
    img = (img.flatten() - np.mean(img)) / np.std(img)

    return np.array([img])

Здесь моя программа спуска градиента:

def fit(x, y, t1, t2):
    """Training routine"""
    ils = x.shape[1] if len(x.shape) > 1 else 1
    labels = len(set(y))

    if t1 is None or t2 is None:
        t1 = randweights(ils, 10)
        t2 = randweights(10, labels)

    params = np.concatenate([t1.reshape(-1), t2.reshape(-1)])
    res = grad(params, ils, 10, labels, x, y)
    params -= 0.1 * res

    return unpack(params, ils, 10, labels)

Вот мои передовые и обратные (градиентные) распространения:

def forward(x, theta1, theta2):
    """Forward propagation"""

    m = x.shape[0]

    # Forward prop
    a1 = np.vstack((np.ones([1, m]), x.T))
    z2 = np.dot(theta1, a1)

    a2 = np.vstack((np.ones([1, m]), sigmoid(z2)))
    a3 = sigmoid(np.dot(theta2, a2))

    return (a1, a2, a3, z2, m)

def grad(params, ils, hls, labels, x, Y, lmbda=0.01):
    """Compute gradient for hypothesis Theta"""

    theta1, theta2 = unpack(params, ils, hls, labels)

    a1, a2, a3, z2, m = forward(x, theta1, theta2)
    d3 = a3 - Y.T
    print('Current error: {}'.format(np.mean(np.abs(d3))))

    d2 = np.dot(theta2.T, d3) * (np.vstack([np.ones([1, m]), sigmoid_prime(z2)]))
    d3 = d3.T
    d2 = d2[1:, :].T

    t1_grad = np.dot(d2.T, a1.T)
    t2_grad = np.dot(d3.T, a2.T)

    theta1[0] = np.zeros([1, theta1.shape[1]])
    theta2[0] = np.zeros([1, theta2.shape[1]])

    t1_grad = t1_grad + (lmbda / m) * theta1
    t2_grad = t2_grad + (lmbda / m) * theta2

    return np.concatenate([t1_grad.reshape(-1), t2_grad.reshape(-1)])

И здесь моя функция предсказания:

def predict(theta1, theta2, x):
    """Predict output using learned weights"""
    m = x.shape[0]

    h1 = sigmoid(np.hstack((np.ones([m, 1]), x)).dot(theta1.T))
    h2 = sigmoid(np.hstack((np.ones([m, 1]), h1)).dot(theta2.T))

    return h2.argmax(axis=1)

Я вижу, что частота ошибок постепенно уменьшается с каждой итерацией, обычно сходясь где-то около 1.26e-05.

Что я пробовал до сих пор:

  • PCA
  • Различные наборы данных (Iris из sklearn и рукописные числа из курса Coursera ML, достигающие примерно 95% точности для обоих). Однако оба из них были обработаны в пакете, поэтому я могу предположить, что моя общая реализация верна, но что-то не так с тем, как я извлекаю функции, или как я тренирую классификатор.
  • Пробовал SGDClassifier sklearn, и он не работал намного лучше, давая мне 50% точности. Так что-то не так с функциями, то?

Edit: Средний вывод h2 выглядит следующим образом:

[0.5004899   0.45264441]
[0.50048522  0.47439413]
[0.50049019  0.46557124]
[0.50049261  0.45297816]

Итак, очень похожие сигмоидные выходы для всех примеров проверки.

4b9b3361

Ответ 1

После полутора недель исследований, я думаю, я понимаю, в чем проблема. В самом коде нет ничего плохого. Единственные две проблемы, которые препятствуют успешной классификации моей реализации, - это изучение времени и правильный выбор параметров скорости обучения/регуляризации.

У меня была процедура обучения, работающая для некоторого тома, и она уже нажимает 75% -ную точность, хотя для улучшения есть еще много места.

Ответ 2

  Моя сеть всегда предсказывает один и тот же класс. В чем проблема?

У меня было это пару раз. Хотя в настоящее время я слишком ленив, чтобы просмотреть ваш код, я думаю, что могу дать некоторые общие советы, которые также могут помочь другим, у которых есть тот же симптом, но, возможно, другие проблемы, лежащие в основе.

Отладка нейронных сетей

Подгонка наборов данных одного предмета

Для каждого класса в сети, который должен быть в состоянии предсказать, попробуйте следующее:

  1. Создайте набор данных только из одной точки данных класса I.
  2. Подгоните сеть к этому набору данных.
  3. Учится ли сеть предсказывать "класс i"?

Если это не работает, существует четыре возможных источника ошибок:

  1. Алгоритм обучения багги: попробуйте меньшую модель, напечатайте множество значений, которые рассчитываются между ними, и посмотрите, соответствуют ли они вашим ожиданиям.
    1. Деление на 0: добавление небольшого числа к знаменателю
    2. Логарифм 0/отрицательное число: как деление на 0
  2. Данные. Возможно, ваши данные имеют неправильный тип. Например, может потребоваться, чтобы ваши данные имели тип float32, но на самом деле были целыми числами.
  3. Модель. Также возможно, что вы только что создали модель, которая не может предсказать, что вы хотите. Это должно быть обнаружено, когда вы попробуете более простые модели.
  4. Инициализация/оптимизация: в зависимости от модели ваша инициализация и алгоритм оптимизации могут играть решающую роль. Для начинающих, которые используют стандартный стохастический градиентный спуск, я бы сказал, что в основном важно инициализировать веса случайным образом (каждый вес имеет свое значение). - см. также: этот вопрос/ответ

Кривая обучения

Подробнее см. sklearn.

Learning Curve showing the training error / test error curves to approach each other

Идея состоит в том, чтобы начать с крошечного обучающего набора данных (вероятно, только одного элемента). Тогда модель должна быть в состоянии соответствовать данным идеально. Если это работает, вы делаете немного больший набор данных. В какой-то момент ваша ошибка тренировки должна немного увеличиться вверх Это показывает способность ваших моделей моделировать данные.

Анализ данных

Проверьте, как часто появляются другие классы. Если один класс доминирует над другими (например, один класс составляет 99,9% данных), это проблема. Ищите методы "обнаружения выбросов".

Более

  • Скорость обучения: если ваша сеть не улучшается и становится немного лучше случайного, попробуйте уменьшить скорость обучения. Для компьютерного зрения часто используется/работает скорость обучения 0.001. Это также важно, если вы используете Адама в качестве оптимизатора.
  • Предварительная обработка: убедитесь, что вы используете одну и ту же предварительную обработку для обучения и тестирования. Вы можете увидеть различия в путанице (см. этот вопрос)

Распространенные ошибки

Это вдохновлено Reddit:

  • Вы забыли применить предварительную обработку
  • Умирающий ReLU
  • Слишком маленькая/слишком большая скорость обучения
  • Неправильная функция активации в последнем слое:
    • Ваши цели не в сумме один? → Не используйте softmax
    • Отдельные элементы ваших целей отрицательны → Не используйте Softmax, ReLU, Sigmoid. tanh может быть вариантом
  • Слишком глубокая сеть: вы не можете тренироваться. Сначала попробуйте более простую нейронную сеть.
  • Значительно несбалансированные данные: вы можете заглянуть в imbalanced-learn

Ответ 3

Просто если кто-нибудь еще столкнется с этой проблемой. Мой был с архитектурой deeplearning4j Lenet (CNN), он давал окончательный вывод последней обучающей папки для каждого теста.   Я смог решить ее с помощью increasing my batchsize и shuffling the training data, поэтому каждая партия содержала как минимум образец из более чем одной папки. Мой класс данных имел размер пакета 1, который был действительно dangerous.

Редактировать: Хотя еще одна вещь, которую я недавно наблюдал, это ограниченные наборы тренировочных выборок на класс, несмотря на большую dataset. например обучение neural-network распознавать human faces, но иметь максимум максимум 2 различных лиц для 1 person среднего значения, в то время как набор данных состоит из, скажем, 10000 persons, таким образом, всего dataset составляет 20 000 faces. Лучше dataset будет 1000 другим faces для 10 000 persons  таким образом, dataset из 10 000 000 faces в общей сложности. Это относительно необходимо, если вы хотите избежать наложения данных на один класс, чтобы ваш network мог легко обобщать и давать более точные прогнозы.

Ответ 4

То же самое случилось со мной. У меня был несбалансированный набор данных (около 66% -33% выборки между классами 0 и 1 соответственно), и сеть всегда выводила 0.0 для всех выборок после первой итерации.

Моя проблема была просто слишком высокой скоростью обучения. Переключение на 1e-05 решило проблему.

В общем, я предлагаю распечатать перед обновлением параметров:

  • ваш чистый выход (для одной партии)
  • соответствующий ярлык (для той же партии)
  • значение потерь (в одной партии) либо по выборке, либо по совокупности.

И затем проверьте те же три пункта после обновления параметра. В следующем пакете вы должны увидеть постепенное изменение чистой продукции. Когда моя скорость обучения была слишком высокой, уже во второй итерации чистый выходной сигнал соответствовал бы либо всем 1.0, либо всем 0.0 для всех образцов в партии.