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

Нейронная сеть всегда производит одинаковые/похожие результаты для любого входа

У меня проблема, когда я пытаюсь создать нейронную сеть для Tic-Tac-Toe. Однако, по какой-то причине, обучение нейронной сети приводит к тому, что она выдает почти одинаковый результат для любого заданного входа.

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

Чтобы убедиться, что проблема не только в моем выборе тренировочного набора (1218 состояний доски и ходов, генерируемых генетическим алгоритмом), я попытался обучить сеть воспроизводить XOR. Была использована функция логистической активации. Вместо того, чтобы использовать производную, я умножил ошибку на output*(1-output) как некоторые источники предположили, что это было эквивалентно использованию производной. Я могу поместить исходный текст на Haskell в HPaste, но это немного смущает. Сеть имеет 3 уровня: первый уровень имеет 2 входа и 4 выхода, второй имеет 4 входа и 1 выход, а третий имеет 1 выход. Увеличение до 4 нейронов во втором слое не помогло, равно как и увеличение до 8 выходов в первом слое.

Затем я вычислил ошибки, выходные данные сети, обновления смещения и обновления веса вручную, основываясь на http://hebb.mit.edu/courses/9.641/2002/lectures/lecture04.pdf, чтобы убедиться, что ошибки не было эти части кода (не было, но я, вероятно, сделаю это снова, чтобы убедиться). Поскольку я использую пакетное обучение, я не умножил на x в уравнении (4) там. Я добавляю изменение веса, хотя http://www.faqs.org/faqs/ai-faq/neural-nets/part2/section-2.html предлагает вместо этого вычесть это.

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

Input    |Target|Output (Batch)      |Output(Incremental)
[1.0,1.0]|[0.0] |[0.5003781562785173]|[0.5009731800870864]
[1.0,0.0]|[1.0] |[0.5003740346965251]|[0.5006347214672715]
[0.0,1.0]|[1.0] |[0.5003734471544522]|[0.500589332376345]
[0.0,0.0]|[0.0] |[0.5003674110937019]|[0.500095157458231]

Вычитание вместо сложения создает ту же проблему, за исключением того, что все равно 0,99 что-то вместо 0,50 что-то. 5000 эпох дает тот же результат, за исключением того, что сеть, прошедшая обучение в пакетном режиме, возвращает точно 0,5 для каждого случая. (Черт, даже 10 000 эпох не работали на периодическое обучение.)

Есть ли вообще что-нибудь, что могло бы вызвать такое поведение?

Кроме того, я посмотрел на промежуточные ошибки для инкрементного обучения, и хотя входы скрытых/входных слоев варьировались, ошибка для выходного нейрона всегда была + / -0.12. Для пакетного обучения ошибки увеличивались, но очень медленно, и все ошибки были чрезвычайно малы (x10 ^ -7). Разные начальные случайные веса и смещения также не имели значения.

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

РЕДАКТИРОВАТЬ: два слоя, входной слой с 2 входами на 8 выходов и выходной слой с 8 входами на 1 выход, дают почти одинаковые результаты: 0. 5+ / -0.2 (или около того) для каждой тренировки дело. Я также играю с PyBrain, чтобы увидеть, будет ли работать какая-либо структура сети там.

Изменить 2: я использую скорость обучения 0,1. Извините, что забыл об этом.

Редактировать 3: Pybrain "trainUntilConvergence" также не дает мне полностью обученную сеть, но это делает 20000 эпох с 16 нейронами в скрытом слое. 10000 эпох и 4 нейрона, не так много, но близко. Итак, в Haskell с входным слоем, имеющим 2 входа и 2 выхода, скрытым слоем с 2 входами и 8 выходами и выходным слоем с 8 входами и 1 выходом... У меня такая же проблема с 10000 эпохами. И с 20000 эпохами.

Редактировать 4: Я снова запустил сеть вручную на основе MIT PDF, приведенного выше, и значения совпадают, поэтому код должен быть правильным, если я не неправильно понял эти уравнения.

Часть моего исходного кода находится по адресу http://hpaste.org/42453/neural_network__not_working ; Я работаю над очисткой своего кода и помещаю его в Github (а не в частный Bitbucket) репозиторий.

Весь соответствующий исходный код теперь находится по адресу https://github.com/l33tnerd/hsann.

4b9b3361

Ответ 1

Я не тестировал его с проблемой XOR в вопросе, но для моего исходного набора данных, основанного на Tic-Tac-Toe, я считаю, что я получил сеть для обучения несколько (я побежал только 1000 эпох, что wasn 't достаточно): сеть быстрого распространения может выиграть/связать более половины своих игр; backpropagation может получить около 41%. Проблемы сводились к ошибкам внедрения (небольшие) и не понимали разницы между производной ошибки (которая является по весу) и ошибкой для каждого нейрона, которую я не получил в своих исследованиях. Ответ @darkcanuck о тренировке смещения, аналогичный весу, вероятно, помог бы, хотя я не реализовал его. Я также переписал свой код на Python, чтобы я мог более легко взломать его. Поэтому, хотя я не получил сеть для соответствия эффективности минимаксного алгоритма, я считаю, что мне удалось решить проблему.

Ответ 2

У меня были подобные проблемы, но я смог решить, изменив их:

  • Масштабируйте проблему до управляемого размера. Я сначала попробовал слишком много входов, со слишком большим количеством блоков скрытого уровня. Как только я уменьшил проблему, я мог видеть, работает ли решение проблемы меньшего размера. Это также работает, потому что, когда он уменьшался, время для вычисления весов значительно сокращается, поэтому я могу попробовать много разных вещей, не дожидаясь.
  • Убедитесь, что у вас достаточно скрытых блоков. Это была серьезная проблема для меня. У меня было около 900 входов, соединяющих ~ 10 единиц в скрытом слое. Это было слишком мало, чтобы быстро сходиться. Но также стал очень медленным, если я добавил дополнительные единицы. Масштабирование количества входов очень помогло.
  • Измените функцию активации и ее параметры. Сначала я использовал tanh. Я пробовал другие функции: сигмоид, нормированный сигмоид, гауссовый и т.д. Я также обнаружил, что изменение параметров функции, чтобы сделать функции более крутыми или более слабыми, повлияло на то, как быстро сеть сходится.
  • Измените параметры алгоритма обучения. Попробуйте разные курсы обучения (от 0,01 до 0,9). Также попробуйте разные параметры импульса, если ваш алго поддерживает его (от 0,1 до 0,9).

Надеюсь, это поможет тем, кто найдет эту тему в Google!

Ответ 3

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

Я работал над простой проблемой регрессии, но каждый раз, когда я обучал сеть, она сходилась к точке, где она давала мне одинаковые выходные данные (или иногда несколько разных выходных данных) для каждого входа. Я играл со скоростью обучения, количеством скрытых слоев/узлов, алгоритмом оптимизации и т.д., Но это не имело значения. Даже когда я посмотрел на смехотворно простой пример, пытаясь предсказать вывод (1d) двух разных входов (1d):

    import numpy as np
    import torch
    import torch.nn as nn
    import torch.nn.functional as F

    class net(nn.Module):
        def __init__(self, obs_size, hidden_size):
            super(net, self).__init__()
            self.fc = nn.Linear(obs_size, hidden_size)
            self.out = nn.Linear(hidden_size, 1)

        def forward(self, obs):
            h = F.relu(self.fc(obs))
            return self.out(h)

    inputs = np.array([[0.5],[0.9]])
    targets = torch.tensor([3.0, 2.0], dtype=torch.float32)

    network = net(1,5)
    optimizer = torch.optim.Adam(network.parameters(), lr=0.001)

    for i in range(10000):
        out = network(torch.tensor(inputs, dtype=torch.float32))
        loss = F.mse_loss(out, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        print("Loss: %f outputs: %f, %f"%(loss.data.numpy(), out.data.numpy()[0], out.data.numpy()[1]))

но все же всегда выводилось среднее значение выходов для обоих входов. Оказывается, причина в том, что размеры моих выходных данных и целей не были одинаковыми: целями был Размер [2], а выходными данными был Размер [2,1], и по какой-то причине PyTorch передавал выходные данные, чтобы иметь размер [2,2] в потере MSE, которая полностью все испортила. Однажды я изменился:

targets = torch.tensor([3.0, 2.0], dtype=torch.float32)

до

targets = torch.tensor([[3.0], [2.0]], dtype=torch.float32)

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

Ответ 4

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

Ответ 5

Трудно сказать, не видя образец кода, но это возможно для сети, потому что его количество скрытого neron.with incresing в количестве нерона и количестве скрытого слоя невозможно обучить сеть с небольшим набором учебные данные. Если можно создать сеть с меньшим слоем и неронами, нецелесообразно использовать большую сеть. Поэтому, возможно, ваша проблема будет решена с учетом этого.

Ответ 6

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

Fausett "Основы нейронных сетей" (стр .300) имеет пример XOR, использующий двоичные входы и сеть с 2 входами, 1 скрытый слой из 4 нейронов и один выходной нейрон. Весы произвольно инициализируются между +0,5 и -0,5. При скорости обучения 0,02 примерная сеть сходится примерно через 3000 эпох. Вы должны иметь возможность получить результат в том же самом шаге, если вы устраните проблемы смещения (и любые другие ошибки).

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

Ответ 7

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

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

Я использовал пакет Caret для R. Сначала я использовал гиперпараметр затухания = 0,01. Когда я посмотрел на диагностику, я увидел, что среднеквадратическое среднеквадратичное отклонение вычислялось для каждого сгиба (перекрестной проверки), но Rsquared всегда был NA. В этом случае все прогнозы выходили на одно и то же значение.

Как только я уменьшил затухание до гораздо более низкого значения (1E-5 и ниже), я получил ожидаемые результаты.

Надеюсь, это поможет.

Ответ 8

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

Ответ 9

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

Оказывается, у моего алгоритма обратного распространения была проблема. В одном месте я умножал на -1, где это не требовалось.

Может быть другая проблема, как эта. Вопрос в том, как это отладить?

Действия по отладке:

Step1 : Write the algorithm such that it can take variable number of input layers and variable number of input & output nodes.
Step2 : Reduce the hidden layers to 0. Reduce input to 2 nodes, output to 1 node.
Step3 : Now train for binary-OR-Operation.
Step4 : If it converges correctly, go to Step 8.
Step5 : If it does not converge, train it only for 1 training sample
Step6 : Print all the forward and prognostication variables (weights, node-outputs, deltas etc)
Step7 : Take pen&paper and calculate all the variables manually.
Step8 : Cross verify the values with algorithm.
Step9 : If you don't find any problem with 0 hidden layers. Increase hidden layer size to 1. Repeat step 5,6,7,8

Это звучит как большая работа, но это работает очень хорошо, ИМХО.

Ответ 10

У меня были схожие проблемы с алгоритмами машинного обучения, и когда я смотрел на код, я нашел случайные генераторы, которые не были действительно случайными. Если вы не используете новое случайное семя (например, время Unix, см. http://en.wikipedia.org/wiki/Unix_time), тогда можно получить точные результаты снова и снова.