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

Что случилось с моей реализацией Neural Networks?

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

import sklearn
import numpy as np
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
from sklearn import neural_network
from sklearn import cross_validation

myList=[]
myList2=[]
w=[]

dataset=np.loadtxt("data", delimiter=",")
X=dataset[:, 0:6]
Y=dataset[:,6]
clf=sklearn.neural_network.MLPClassifier(hidden_layer_sizes=(2,3),activation='tanh')

# split the data between training and testing
X_train, X_test, Y_train, Y_test = cross_validation.train_test_split(X, Y, test_size=0.25, random_state=33)

# begin with few training datas
X_eff=X_train[0:int(len(X_train)/150), : ]
Y_eff=Y_train[0:int(len(Y_train)/150)]

k=int(len(X_train)/150)-1


for m in range (140) :


    print (m)

    w.append(k)

    # train the model and store the training error
    A=clf.fit(X_eff,Y_eff)
    myList.append(1-A.score(X_eff,Y_eff))

      # compute the testing error
    myList2.append(1-A.score(X_test,Y_test))

    # add some more training datas
    X_eff=np.vstack((X_eff,X_train[k+1:k+101,:]))
    Y_eff=np.hstack((Y_eff,Y_train[k+1:k+101]))
    k=k+100

plt.figure(figsize=(8, 8))
plt.subplots_adjust()
plt.title("Erreur d'entrainement et de test")
plt.plot(w,myList,label="training error")
plt.plot(w,myList2,label="test error")
plt.legend()
plt.show()

Тем не менее, я получаю очень странный результат, когда колебания колеблются, ошибка обучения очень близка к ошибке тестирования, которая не выглядит нормальной. Где ошибка? Я не могу понять, почему так много взлетов и падений, и почему ошибка обучения не увеличивается, как и следовало ожидать. Любая помощь будет оценена!

EDIT: набор данных, который я использую, https://archive.ics.uci.edu/ml/datasets/Chess+%28King-Rook+vs.+King%29, где я избавился от классов, имеющих менее 1000 экземпляров. Я вручную перекодировал данные переполнения.

4b9b3361

Ответ 1

Я думаю, что причина, по которой вы видите такую ​​кривую, состоит в том, что измеряемая метрика производительности отличается от показателя производительности, который вы оптимизируете.

Показатель оптимизации

Нейронная сеть минимизирует функцию потерь, а в случае активации tanh я предполагаю, что вы используете модифицированную версию потери кросс-энтропии. Если вы планируете потратить время на потерю, вы увидите более монотонно убывающую функцию ошибки, как вы ожидаете. (На самом деле не монотонно, потому что нейронные сети не выпуклые, но это не так.)

Показатель производительности

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

Совмещение

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

Есть несколько способов исправить это.

  • Постройте потерю вместо точности. Это фактически не устраняет вашу проблему, если вам действительно нужен график точности, но это даст вам гораздо более плавные кривые.
  • Участвуйте в среднем за несколько прогонов. Сохраните графики точности более 20 независимых прогонов вашего алгоритма (как в сети 20 раз), затем сравните их вместе и запишите. Это значительно уменьшит дисперсию.

TL; DR

Не ожидайте, что график точности всегда будет плавным и монотонно убывающим, это не будет.


После редактирования вопроса:

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

Информация по величине

Набор данных определяет ранг и файл (ряд и столбец) нескольких шахматных фигур. Они вводятся как целое число от 1 до 6. Однако 2 действительно 1 лучше, чем 1? Действительно ли 6 действительно лучше 2? Я не думаю, что это имеет место с точки зрения шахматной позиции.

Представьте, что я создаю классификатор, который берет деньги в качестве входных данных. Есть ли какая-то информация, изображаемая величиной моих ценностей? Да, $1 сильно отличается от $100; и мы можем сказать, что существует связь, основанная на величине.

Для шахматной игры строка 1 означает нечто отличное от строки 8? Совсем нет, на самом деле эти измерения симметричны! Использование блока смещения в вашей сети может помочь объяснить симметрию путем "масштабирования" ваших входов эффективно с [-3, 4], который теперь центрирован (ish) около 0.

Решение

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

Ответ 2

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

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

Кроме того, имейте в виду, что вам нужно использовать много учебных и тестовых данных, чтобы получить более или менее "гладкую" кривую или даже репрезентативную кривую; если вы используете только несколько (возможно, несколько сотен) точек данных, полученные метрики на самом деле не будут очень точными, так как они содержат много стохастических вещей. Чтобы решить эту ошибку, вы не должны каждый раз тренировать сеть с одинаковыми примерами, а скорее изменять заказы своих данных обучения и, возможно, разделить ее на разных mini партии. Я очень уверен, что вы можете решить или даже уменьшить свою проблему, пытаясь понять эти аспекты и реализовать их.

В зависимости от вашей проблемы вы должны изменить функцию активации на что-то другое, чем функция tanh. Выполняя классификацию, может также быть полезен OneHotEncoder (если ваши данные еще не были одним горячим кодированием); рама sklearn предлагает реализацию этого.

Ответ 3

Рандомизировать набор тренировок и повторить

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

Это даст что-то вроде этого (не проверено):

n_samples_array = np.arange(100,len(X_train),100)
N_repeat = 10

for n_samples in n_samples_array:
    print(n_samples)

    # repeat the fit several times and take the mean
    myList_tmp, myList2_tmp = [],[]
    for repeat in range(0,N_repeat):
        # Randomly pick samples
        selection = np.random.choice(range(0,len(X_train)),n_samples,repeat=False)

        # train the model and store the training error
        A=clf.fit(X_train[selection],Y_train[selection])
        myList_tmp.append(1-A.score(X_train[selection],Y_train[selection]))

          # compute the testing error
        myList2_tmp.append(1-A.score(X_test,Y_test))

    myList.append(np.mean(myList_tmp))
    myList2.append(np.mean(myList2_tmp))

Теплый старт

Когда вы используете функцию fit, вы начинаете оптимизацию с нуля. Если вы хотите улучшить оптимизацию при добавлении нескольких образцов в одну и ту же предварительно подготовленную сеть, вы можете использовать опцию warm_start=True

В соответствии с документация:

warm_start: bool, необязательный, по умолчанию False

Если установлено значение "Истина", повторно используйте решение предыдущего вызова, чтобы оно соответствовало как инициализация, иначе просто удалите предыдущее решение.