Создание нейросети со скрытым слоем

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

def non_linear(x):
    return 1/(1+exp(-x))
train_inp=array([[1,0,0,1],[1,1,1,1],[0,1,1,1],[1,0,1,1]])
train_out=array([[0,1,1,0]]).T
#hidden=array([[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]])
random.seed(1)
layer_1_weights= 2 * random.random((4,4)) -1 #Массив 4x4 между 4 входными нейронами, и 4-мя промежуточными
layer_2_weights= 2 * random.random((4,1)) -1 #Массив 4x1 между 4 промежуточными нейронами и 1 выходным
for iter in range(5000):#Кол-во повторений для обучения
    output_1_layer=non_linear(dot(train_inp,layer_1_weights)) #Результат работы входных нейронов, по совместительству 2-ой слой
    output_2_layer=non_linear(dot(output_1_layer,layer_2_weights)) #Результат работы нейронов скрытого слоя, по совместительству выходной нейрон
    layer_2_weights += dot(output_1_layer.T,(train_out-output_2_layer)*output_2_layer*(1-output_2_layer))
    layer_1_weights += dot(train_inp.T,(layer_2_weights-output_1_layer)*output_1_layer*(1-output_1_layer))
print(non_linear(dot(array([0,0,0,1]),layer_2_weights)))

Ответы (2 шт):

Автор решения: Константин
from numpy import dot, exp, array, random
def non_linear(x):
    return 1/(1+exp(-x))
train_inp=array([[1,0,0,1],[1,1,1,1],[0,1,1,1],[1,0,1,1]])
train_out=array([[0],[1],[1],[0]]) # Здесь должно столько же кейсов сколько и в train
l_r=0.07
#hidden=array([[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]])
#random.seed(1) Зерно обязательно убрать так как данные могут быть линейно-неразделимыми(надо 'ловить' результат)
# матрицы в моем стиле
layer_1_weights= 2 * random.random((4,4)) -1 #Массив 4x4 между 4 входными нейронами, и 4-мя промежуточными
layer_2_weights= 2 * random.random((1,4)) -1 
for iter in range(5000):#Кол-во повторений для обучения
    e=0
    for single_array_ind in range(len(train_inp)):
      output_1_layer=non_linear(dot(layer_1_weights,train_inp[single_array_ind].T)) #Результат работы входных нейронов, по совместительству 2-ой слой
      output_2_layer=non_linear(dot(layer_2_weights, output_1_layer)) #Результат работы нейронов скрытого слоя, по совместительству выходной нейрон
      # через 'матричные' ошибки так будут называться
      layer_2_errors=((train_out[single_array_ind].T-output_2_layer)*output_2_layer*(1-output_2_layer))
      layer_1_errors=dot((layer_2_errors).T, # ошибки нейронов последнего слоя
      layer_2_weights)
      layer_2_weights+=l_r * layer_1_errors * output_1_layer.T  
      errors=dot(layer_1_errors,layer_1_weights)
      layer_1_weights+=l_r * errors * train_inp[single_array_ind]
      e = (layer_2_errors * layer_2_errors) / 2

    print("error:",e)   

error: [0.01015946]
error: [0.01015946]
error: [0.01015945]
error: [0.01015945]
error: [0.01015944]
error: [0.01015944]
error: [0.01015943]
error: [0.01015942]
error: [0.01015942]
error: [0.01015941]
error: [0.01015941]
error: [0.0101594]
error: [0.0101594]
error: [0.01015939]
error: [0.01015938]
error: [0.01015938]
error: [0.01015937]
error: [0.01015937]
error: [0.01015936]
error: [0.01015936]
error: [0.01015935]
error: [0.01015934]
error: [0.01015934]
error: [0.01015933]
error: [0.01015933]
error: [0.01015932]
error: [0.01015932]
error: [0.01015931]
error: [0.0101593]
error: [0.0101593]
error: [0.01015929]
error: [0.01015929]
error: [0.01015928]
error: [0.01015928]
error: [0.01015927]
error: [0.01015926]
error: [0.01015926]
error: [0.01015925]
error: [0.01015925]
error: [0.01015924]
error: [0.01015924]
error: [0.01015923]
error: [0.01015922]
error: [0.01015922]
error: [0.01015921]
error: [0.01015921]
error: [0.0101592]
error: [0.0101592]
error: [0.01015919]
error: [0.01015918]
error: [0.01015918]
error: [0.01015917]
error: [0.01015917]
error: [0.01015916]
error: [0.01015916]
error: [0.01015915]
error: [0.01015914]
error: [0.01015914]
error: [0.01015913]
error: [0.01015913]
error: [0.01015912]
error: [0.01015912]
error: [0.01015911]
error: [0.0101591]
error: [0.0101591]
error: [0.01015909]
error: [0.01015909]
error: [0.01015908]
error: [0.01015908]
error: [0.01015907]
error: [0.01015907]
error: [0.01015906]
error: [0.01015905]
error: [0.01015905]
error: [0.01015904]
error: [0.01015904]
error: [0.01015903]
error: [0.01015903]
error: [0.01015902]
error: [0.01015901]
error: [0.01015901]
error: [0.010159]
error: [0.010159]
error: [0.01015899]
error: [0.01015899]
error: [0.01015898]
error: [0.01015898]
error: [0.01015897]
error: [0.01015896]
error: [0.01015896]
error: [0.01015895]
error: [0.01015895]
error: [0.01015894]
error: [0.01015894]
error: [0.01015893]
error: [0.01015892]
error: [0.01015892]
error: [0.01015891]
error: [0.01015891]
error: [0.0101589]
error: [0.0101589]
error: [0.01015889]
error: [0.01015889]
error: [0.01015888]
error: [0.01015887]
error: [0.01015887]
error: [0.01015886]
error: [0.01015886]
error: [0.01015885]
error: [0.01015885]
error: [0.01015884]
error: [0.01015883]
error: [0.01015883]
error: [0.01015882]
error: [0.01015882]
error: [0.01015881]
error: [0.01015881]
error: [0.0101588]
error: [0.0101588]
error: [0.01015879]
error: [0.01015878]
error: [0.01015878]
error: [0.01015877]
error: [0.01015877]
error: [0.01015876]
error: [0.01015876]
error: [0.01015875]
error: [0.01015875]
error: [0.01015874]
error: [0.01015873]
error: [0.01015873]
error: [0.01015872]
error: [0.01015872]
error: [0.01015871]
error: [0.01015871]
error: [0.0101587]
error: [0.0101587]
error: [0.01015869]
error: [0.01015868]
error: [0.01015868]
error: [0.01015867]
error: [0.01015867]
error: [0.01015866]
error: [0.01015866]
error: [0.01015865]
error: [0.01015865]
error: [0.01015864]
error: [0.01015863]
error: [0.01015863]
error: [0.01015862]
error: [0.01015862]
error: [0.01015861]
error: [0.01015861]
error: [0.0101586]
error: [0.0101586]
error: [0.01015859]
error: [0.01015858]
error: [0.01015858]
error: [0.01015857]
error: [0.01015857]
error: [0.01015856]
error: [0.01015856]
error: [0.01015855]
error: [0.01015855]
error: [0.01015854]
error: [0.01015853]
error: [0.01015853]
error: [0.01015852]
error: [0.01015852]
error: [0.01015851]
error: [0.01015851]
error: [0.0101585]

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

→ Ссылка
Автор решения: Константин

Очень важно строить график,понять ошибка уменьшается или увеличивается,когда писал на cyberforum статьи,там справедливо требовали график,некоторые не верят что нейросеть действительно работает или работает правильно, я тоже долго сомневался, пробовал без рандомной инициализации(только одни и те же числа),но понял что для нелинейно-разделемых данных нужны рэндомы(опыты с keras),но они же создают сложности,важно контролировать через графики,при одном распределении можно сразу 'уменьшаться',при другом система сперва неправильный 'курc' берет(там как говорят может быть застревание в локальных минимумах и другое).Доработанный код:

from numpy import dot, exp, array, random
import matplotlib.pyplot as plt
import logging


def plot_gr(_file:str,errors:list,epochs:list,name_gr:str,logger:logging.Logger)->None:
    fig:plt.Figure=None
    ax:plt.Axes=None
    fig, ax=plt.subplots()
    plt.text(0.1, 1.1, name_gr)
    ax.plot(epochs, errors,
    label="learning",   
    )
    # plt.plot(errors,label="errors")
    # plt.plot(history.history['acc'],label="Доля верных ответов на обучающем наборе")
    # if 'val_acc' in history.history: # Если работаем с val_acc
    #     plt.plot(history.history['val_acc'],label='Доля верных ответов на проверочном наборе')
    plt.xlabel('Эпоха обучения')
    plt.ylabel('loss')
    ax.legend()
    plt.savefig(_file)
    print("Graphic saved")
    # logger.info("Graphic saved")
    plt.show()

def non_linear(x):
    return 1/(1+exp(-x))
train_inp=array([[1,0,0,1],[1,1,1,1],[0,1,1,1],[1,0,1,1]])
train_out=array([[0],[1],[1],[0]]) # Здесь должно столько же кейсов сколько и в train
l_r=0.07
#hidden=array([[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]])
#random.seed(1) Зерно обязательно убрать так как данные могут быть линейно-неразделимыми(надо 'ловить' результат)
# матрицы в моем стиле
layer_1_weights= 2 * random.random((4,4)) -1 #Массив 4x4 между 4 входными нейронами, и 4-мя промежуточными
layer_2_weights= 2 * random.random((1,4)) -1
epochs=10
errors_y=[0]*epochs
epochs_x=[0]*epochs 
for ep in range(epochs):#Кол-во повторений для обучения
    e=0
    for single_array_ind in range(len(train_inp)):
      output_1_layer=non_linear(dot(layer_1_weights,train_inp[single_array_ind].T)) #Результат работы входных нейронов, по совместительству 2-ой слой
      output_2_layer=non_linear(dot(layer_2_weights, output_1_layer)) #Результат работы нейронов скрытого слоя, по совместительству выходной нейрон
      # через 'матричные' ошибки так будут называться
      layer_2_errors=((train_out[single_array_ind].T-output_2_layer)*output_2_layer*(1-output_2_layer))
      layer_1_errors=dot((layer_2_errors).T, # ошибки нейронов последнего слоя
      layer_2_weights)
      layer_2_weights+=l_r * layer_1_errors * output_1_layer.T  
      errors=dot(layer_1_errors,layer_1_weights)
      layer_1_weights+=l_r * errors * train_inp[single_array_ind]
      e = (layer_2_errors * layer_2_errors) / 2

    errors_y[ep]=e[0]
    epochs_x[ep]=ep

    print("error:",e)
print(f"{errors_y}")
print(f'{epochs_x}')
plot_gr('gr.png',errors_y,epochs_x,"test",None)    

learning1learnin2

→ Ссылка