Мой однослойный персептрон сходится в наборе данных OR, но не в наборе данных AND - PullRequest
0 голосов
/ 20 мая 2018

Я строю свою первую однослойную сеть персептрона и обучаю ее имитировать поведение простейших логических элементов (И и ИЛИ) с двумя входами.

Сеть состоит из двух входовузлы и уклон.Используется алгоритм обучения дельта-правила для однослойного персептрона с функцией tanh в качестве функции активации.

При обучении на наборе данных AND сеть должна давать ответ, близкий к 1 при вводе данных(1, 1) и 0 для любого другого входа, такого как (0, 1), (1, 0) или (1, 1).Когда он обучен набору данных OR, он должен возвращать ответ, близкий к 1, если дан любой ввод, отличный от (0, 0).

Однако он демонстрирует поведение, которое я не мог понять.Он хорошо сходится (т. Е. Частота ошибок довольно низкая - 0.01 или меньше), когда я обучил его на наборе данных OR:

$ python nn.py
[0 0]: (actual result = [[0.00051257]]). (expected result from training set=0, error rate=[[-0.00051257]])
[0 1]: (actual result = [[0.98865851]]). (expected result from training set=1, error rate=[[0.01134149]])
[1 0]: (actual result = [[0.98865222]]). (expected result from training set=1, error rate=[[0.01134778]])
[1 1]: (actual result = [[0.99993485]]). (expected result from training set=1, error rate=[[6.51512784e-05]])

Однако, он не очень хорошо сходится на наборе данных AND:

$ python nn.py
[0 0]: (actual result = [[-0.28911014]]). (expected result from training set=0, error rate=[[0.28911014]])
[0 1]: (actual result = [[0.23984154]]). (expected result from training set=0, error rate=[[-0.23984154]])
[1 0]: (actual result = [[0.28911014]]). (expected result from training set=0, error rate=[[-0.28911014]])
[1 1]: (actual result = [[0.68570095]]). (expected result from training set=1, error rate=[[0.31429905]])

Я пытался настроить epoch для различных чисел между 500 - 10000 безрезультатно.И от eta до любого значения от 0.1 до 1.0.

Глядя на график конвергенции ниже, вы увидите, как нейронная сеть значительно лучше сходится для набора данных OR, чем набор данных AND, как показановечно «прореживающимся» оранжевым сюжетом.enter image description here

Я думал, что вентили OR и AND противоположны друг другу, и если сеть работает на одном, то это определенно должно работать на другом.Что мне здесь не хватает?

Здесь я приложил исходный код nn.py.

ПРИМЕЧАНИЕ. Когда вы посмотрите, вы увидите, что я инициализировал матрицу весов для1 вместо некоторых случайных значений.Это просто потому, что я хочу, чтобы какой-то детерминизм помог мне решить проблему.Насколько я понимаю, это не должно влиять на правильность алгоритма (хотя это может замедлить его сходимость). Вес теперь правильно инициализирован для некоторых случайных значений, следуя предложению @Dennis Soemers.Проблема все еще существует.

import numpy as np

def tanh(x):
    return (1.0 - np.exp(-2*x))/(1.0 + np.exp(-2*x))

def tanh_derivative(x):
    return (1 + tanh(x))*(1 - tanh(x))

# AND dataset
training_set = [
    (np.array([0, 0]), 0),
    (np.array([0, 1]), 0),
    (np.array([1, 0]), 0),
    (np.array([1, 1]), 1)
]

# # OR dataset
# training_set = [
#     (np.array([0, 0]), 0),
#     (np.array([0, 1]), 1),
#     (np.array([1, 0]), 1),
#     (np.array([1, 1]), 1)
# ]

weight = np.random.rand(3, 1)

# fit
eta = 0.2
epoch = 5000
for i in range(0, len(training_set)*epoch):
    input_, expected_output = training_set[np.random.randint(0, len(training_set))]
    input_with_bias = np.concatenate((input_, np.ones(1))).reshape(3, 1)
    sum_weights_of_input = np.dot(input_with_bias.T, weight)
    actual_output = tanh(sum_weights_of_input)
    error = expected_output - actual_output
    delta = np.multiply(eta, np.multiply(error, np.multiply(input_with_bias, tanh_derivative(sum_weights_of_input))))
    weight = weight + delta

# print
for input_, expected_output in training_set:
    input_with_bias = np.concatenate((input_, np.ones(1))).reshape(3, 1)
    actual_output = tanh(np.dot(input_with_bias.T, weight))
    error = expected_output - actual_output
    print("{}: (actual result = {}). (expected result from training set={}, error rate={})".format(input_, actual_output, expected_output, error))

1 Ответ

0 голосов
/ 20 мая 2018

Помимо примечания о случайной инициализации весов (которое вы уже рассмотрели сейчас, переместило эту точку в конец ответа), важно отметить, что вы используете tanh в качестве активации, но ожидаете результатовблизко к 0 или 1.tanh гораздо больше подходит для случаев, когда вы ожидаете вывод в [-1, 1], а не [0, 1].

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

enter image description here

Пусть w0 обозначает вес для смещения (всегда 1), и w1 и w2 веса для первого и второго входов x1 и x2 соответственно.Наш вывод всегда будет y = tanh(w0 + w1 x1 + w2 x2).

Давайте сначала рассмотрим случай, когда x1 = x2 = 0, где мы хотим, чтобы вывод был приблизительно 0.Другими словами, мы хотим иметь tanh(w0 + 0 + 0) ~= 0.Если вы посмотрите на изображение, это возможно только в том случае, если вес нашего смещения w0 сам по себе также приблизительно равен 0.

Теперь рассмотрим случаи, когда x1 = 1 или x2 = 1 и другиеввод 1.Опять же, желаемый результат равен 0, и из вышесказанного мы уже знаем, что у нас должно быть w0 ~= 0.Итак, теперь мы знаем, что хотим, чтобы следующие две вещи были приблизительно верными:

  • tanh(w1 x1) = 0
  • tanh(w2 x2) = 0

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

Примечание: Ваша сеть по-прежнему способна успешно «решить» проблему AND, если вы принимаете чуть менее строгое понятие «решение».Обратите внимание, что с результатами, которые вы получаете, он может четко разделить разные случаи.Он не обеспечивает чистые выходы, очень близкие к 0 или 1, как вам нужно, но вы можете легко придумать порог (например, 0.5) и сказать «каждый выход ниже этого порога рассматривается как 0, каждый выход над ним обрабатывается как 1 ".

Если вы хотите, чтобы выходы были ближе к точным 0 и 1, вы могли бы вместо этого использовать сигмовидную функцию tanh.Он имеет очень похожую форму, но генерирует выходные данные только в [0, 1] (именно тот диапазон, который вам нужен), а не [-1, 1].


ПРИМЕЧАНИЕ.видите, что я инициализировал весовую матрицу 1 с вместо некоторых случайных значений.Это просто потому, что я хочу, чтобы какой-то детерминизм помог мне решить проблему.Насколько я понимаю, это не должно влиять на правильность алгоритма (хотя это может замедлить процесс сходимости)

Это действительно является (или, по крайней мере,) причиной вашей проблемы.Когда все веса имеют одинаковое начальное значение, вы получаете симметрии, которые больше не могут быть нарушены.Некоторые пары весов всегда будут иметь одинаковое начальное значение, один и тот же градиент, одну и ту же ошибку и будут обновляться абсолютно одинаково (это означает, что они остаются неизменными).Вы также можете увидеть это в ваших результатах и ​​ошибках;обратите внимание, что есть некоторые числа, которые почти идентичны (в случае проблемы AND, одно из которых точно является отрицательным для другого).

Вы захотите использовать случайные начальные веса, чтобы нарушить эти симметрии с самого начала.Если вам нужен детерминизм, вы можете просто сделать это, используя фиксированное начальное число для генератора случайных чисел, чтобы вы всегда получали одинаковые «случайные» начальные веса.

...