Потери уменьшаются, но нейронная сеть показывает постоянный выход.

Вопрос или проблема

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

def forward_prop(x,w1,b1,w2,b2,w3,b3):
    Z1 = np.dot(w1,x.T) + b1
    A1 = sigmoid(Z1)
    Z2 = np.dot(w2,A1) + b2
    A2 = sigmoid(Z2)
    Z3 = np.dot(w3,A2) + b3
    A3 = sigmoid(Z3)
    cache = {'Z1':Z1,'A1':A1,'Z2':Z2, 'A2' : A2, 'Z3':Z3, 'A3':A3}
    return A3,cache

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_dir(x):
    return sigmoid(x) * (1 - sigmoid(x))
def prediction(x,W1,b1,W2,b2,W3,b3):
    A3,cache = forward_prop(x,W1,b1,W2,b2,W3,b3)
    return A3

def initialize_param(x,num_neuron_1 = 3,num_neuron_2 = 3,num_neuron_3 = 1):
    W1 = np.random.random((num_neuron_1,x.shape[1]))
    b1 = np.random.random((num_neuron_1,1))
    W2 = np.random.random((num_neuron_2, num_neuron_1))
    b2 = np.random.random((num_neuron_2,1))
    W3 = np.random.random((num_neuron_3,num_neuron_2))
    b3 = np.random.random((num_neuron_3,1))
    return W1,b1,W2,b2,W3,b3

def back_prop(cache,X,Y,W1,W2,W3):
    A1 = cache['A1']
    A2 = cache['A2']
    A3 = cache['A3']
    Z1 = cache['Z1']
    Z2 = cache['Z2']
    Z3 = cache['Z3']

    E3 = A3 - Y
    E2 = np.dot(W3.T,E3) * sigmoid_dir(Z2)
    E1 = np.dot(W2.T , E2) * sigmoid_dir(Z1)

    dW3 = np.dot(E3,A2.T) / X.shape[0]
    db3 = E3 / X.shape[0]
    dW2 = np.dot(E2,A1.T) / X.shape[0]
    db2 = E2 / X.shape[0]
    dW1 = np.dot(E1,X) / X.shape[0]
    db1 = E1 / X.shape[0]
    # print('dW1',dW1,'db1',db1,'dW2',dW2,'db2',db2,'dW3',dW3,'db3',db3 )
    return dW1,db1,dW2,db2,dW3,db3

def update_param(W1 , b1 , W2 , b2 , W3 , b3 , dW1,db1,dW2,db2,dW3,db3,lr = 0.01):
    W1 = W1 -  lr * dW1
    b1 = b1 -  lr * db1
    W2 = W2 -  lr * dW2
    b2 = b2 -  lr * db2
    W3 = W3 -  lr * dW3
    b3 = b3 -  lr * db3

    return W1,b1,W2,b2,W3,b3

def train(X,Y,epochs = 500000 ):
    W1,b1,W2,b2,W3,b3 = initialize_param(X)
    loss_values = []
    epoch_values = [] 
    X = X.to_numpy()
    X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)
    Y = Y.to_numpy()
    Y = Y.reshape(1, -1)
    for i in range(epochs):
        A3 , cache = forward_prop(X,W1,b1,W2,b2,W3,b3)
        dW1,db1,dW2,db2,dW3,db3 = back_prop(cache,X,Y,W1,W2,W3)
        W1,b1,W2,b2,W3,b3 = update_param(W1 , b1 , W2 , b2 , W3 , b3 , dW1,db1,dW2,db2,dW3,db3,lr = 0.00005)

        if i % 1000 == 0:
            loss = -np.mean(Y * np.log(A3) + (1 - Y) * np.log(1 - A3))
            loss_values.append(loss)
            epoch_values.append(i)
            print(f"Эпоха {i}, Потери: {loss}")
    plt.plot(epoch_values, loss_values)  # Построить график потерь по эпохам
    plt.xlabel('Эпохи')
    plt.ylabel('Потери')
    plt.title('Кривая потерь')
    plt.show()
    return W1,b1.mean(axis=1),W2,b2.mean(axis=1),W3,b3.mean(axis=1)

.

Ответ или решение

Причины, по которым выход нейронной сети остается постоянным, несмотря на снижение потерь

Логика и контекст

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

Фактор 1: Инициализация параметров

При инициализации весов и смещений можно столкнуться с проблемами, если они слишком малы или слишком велики. Ваша функция initialize_param использует np.random.random, что может привести к тому, что все начальные веса будут достаточно близки к нулю, но могут не быть достаточно разнообразными для того, чтобы моделировать более сложные функции. Попробуйте использовать более продвинутое распределение, например, инициализацию Хе или Глорота (в зависимости от активационной функции).

def initialize_param(x,num_neuron_1=3,num_neuron_2=3,num_neuron_3=1):
    W1 = np.random.randn(num_neuron_1, x.shape[1]) * np.sqrt(2. / x.shape[1])
    # Остальная часть кода остается прежней

Фактор 2: Линия активации

Вы используете сигмоидную функцию активации. Эта функция может приводить к проблемам с затухающими градиентами, в результате чего обновления весов становятся незначительными, особенно в глубоких сетях. Попробуйте заменить сигмоид на ReLU или Leaky ReLU:

def relu(x):
    return np.maximum(0, x)

Фактор 3: Скорость обучения

Скорость обучения, заданная в функции update_param, может быть слишком низкой, и, следовательно, изменения веса становятся незначительными. В результате сеть не может "узнать" закономерности в данных. Попробуйте увеличить значение lr:

def update_param(..., lr=0.01):  # Попробуйте 0.01 или 0.001

Фактор 4: Обработка данных

Ваша нормализация данных в функции train, где вы используете (X - np.mean(X, axis=0)) / np.std(X, axis=0), корректна, но убедитесь, что вы используете единообразные параметры нормализации как для обучения, так и для валидации. Некорректная нормализация может приводить к тому, что модель не сможет учитывать объем имеющихся данных.

Фактор 5: Комплексность модели

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

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...