Базовая нейронная сеть, слишком высокий вес - PullRequest
2 голосов
/ 24 марта 2019

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

Я использую Python 3.7 с numpy и scipy. Я попытался изменить тренировочный набор, новый экземпляр и случайное начальное число

import numpy as np
from scipy.special import expit as ex

rand.seed(10)
training_set=[[0,1,0],[1,0,1],[0,0,0],[1,1,1]] #The training sets and their outputs
training_outputs=[0,1,0,1]
weightlst=[rand.uniform(-1,1),rand.uniform(-1,1),rand.uniform(-1,1)]  #Weights are randomly set with a value between -1 and 1

print('Random weights\n'+str(weightlst))

def calcout(inputs,weights):    #Calculate the expected output with given inputs and weights
    output=0.5

    for i in range(len(inputs)):
        output=output+(inputs[i]*weights[i])
    #print('\nmy output is ' + str(ex(output)))
    return ex(output)                 #Return the output on a sigmoid curve between 0 and 1

def adj(expected_output,training_output,weights,inputs):   #Adjust the weights based on the expected output, true (training) output and the weights
    adjweights=[]
    error=expected_output-training_output

    for i in weights:
        adjweights.append(i+(error*(expected_output*(1-expected_output))))
    return adjweights

                                                       #Train the network, adjusting weights each time
training_iterations=10000
for k in range(training_iterations):
    for l in range(len(training_set)):

        expected=calcout(training_set[l],weightlst)
        weightlst=adj(expected,training_outputs[l],weightlst,training_set[l])

new_instance=[1,0,0]           #Calculate and return the expected output of a new instance

print('Adjusted weights\n'+str(weightlst))
print('\nExpected output of new instance = ' + str(calcout(new_instance,weightlst)))

Ожидаемый результат будет 0, или что-то очень близкое к нему, но независимо от того, что я установил new_instance, выход все еще

Random weights
[-0.7312715117751976, 0.6948674738744653, 0.5275492379532281]
Adjusted weights
[1999.6135460307303, 2001.03968501638, 2000.8723667804588]

Expected output of new instance = 1.0

Что не так с моим кодом?

1 Ответ

4 голосов
/ 24 марта 2019

Ошибки :

  • Нет смещения, используемого в нейроне
  • error = training_output-Ожидаемый_output (не наоборот) для градиента приличного
  • Правило обновления веса i-го веса w_i = w_i + learning_rate * delta_w_i, (delta_w_i - градиент потерь по отношению к w_i)
  • Для квадрата потерь delta_w_i = error*sample[i] (i-е значение входной выборки вектора)
  • Поскольку у вас есть только один нейрон (один скрытый слой или размер 1), ваша модель может изучать только линейно разделимые данные (это только линейный классификатор).Примерами линейно разделяемых данных являются данные, сгенерированные такими функциями, как логические AND, OR.Обратите внимание, что логическое значение XOR не является линейно разделяемым.

Код с исправленными ошибками

import numpy as np
from scipy.special import expit as ex

rand.seed(10)
training_set=[[0,1,0],[1,0,1],[0,0,0],[1,1,1]] #The training sets and their outputs
training_outputs=[1,1,0,1] # Boolean OR of input vector
#training_outputs=[0,0,,1] # Boolean AND of input vector

weightlst=[rand.uniform(-1,1),rand.uniform(-1,1),rand.uniform(-1,1)]  #Weights are randomly set with a value between -1 and 1
bias = rand.uniform(-1,1)

print('Random weights\n'+str(weightlst))

def calcout(inputs,weights, bias):    #Calculate the expected output with given inputs and weights
    output=bias
    for i in range(len(inputs)):
        output=output+(inputs[i]*weights[i])
    #print('\nmy output is ' + str(ex(output)))
    return ex(output)                 #Return the output on a sigmoid curve between 0 and 1

def adj(expected_output,training_output,weights,bias,inputs):   #Adjust the weights based on the expected output, true (training) output and the weights
    adjweights=[]
    error=training_output-expected_output
    lr = 0.1
    for j, i in enumerate(weights):
        adjweights.append(i+error*inputs[j]*lr)
    adjbias = bias+error*lr
    return adjweights, adjbias

#Train the network, adjusting weights each time
training_iterations=10000
for k in range(training_iterations):
    for l in range(len(training_set)):
        expected=calcout(training_set[l],weightlst, bias)
        weightlst, bias =adj(expected,training_outputs[l],weightlst,bias,training_set[l])

new_instance=[1,0,0]           #Calculate and return the expected output of a new instance

print('Adjusted weights\n'+str(weightlst))
print('\nExpected output of new instance = ' + str(calcout(new_instance,weightlst, bias)))

Вывод:

Random weights
[0.142805189379827, -0.14222189064977075, 0.15618260226894076]
Adjusted weights
[6.196759842119063, 11.71208191137411, 6.210137255008176]
Expected output of new instance = 0.6655563851223694

Как видно на входе [1,0,0], модель предсказала вероятность 0.66, которая является классом 1 (с 0,66> 0,5).Это правильно, так как выходной класс - ИЛИ входного вектора.

Примечание:

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

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