Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Реалізація Зворотного Поширення Помилки | Нейронна Мережа з Нуля
Вступ до нейронних мереж

bookРеалізація Зворотного Поширення Помилки

Загальний підхід

Під час прямого поширення кожен шар ll отримує виходи з попереднього шару, al1a^{l-1}, як вхідні дані та обчислює власні виходи. Тому метод forward() класу Layer приймає вектор попередніх виходів як єдиний параметр, тоді як решта необхідної інформації зберігається всередині класу.

Під час зворотного поширення кожен шар ll потребує лише dalda^l для обчислення відповідних градієнтів і повернення dal1da^{l-1}, тому метод backward() приймає вектор dalda^l як параметр. Вся інша необхідна інформація вже зберігається в класі Layer.

Похідні функцій активації

Оскільки для зворотного поширення потрібні похідні функцій активації, такі функції активації, як ReLU та sigmoid, слід реалізовувати у вигляді класів, а не окремих функцій. Така структура дозволяє чітко визначити обидва компоненти:

  1. Сама функція активації — реалізується за допомогою методу __call__(), тому її можна застосовувати безпосередньо в класі Layer через self.activation(z);
  2. Її похідна — реалізується через метод derivative(), що забезпечує ефективне обчислення під час зворотного поширення за допомогою self.activation.derivative(z).

Представлення функцій активації як об'єктів спрощує їх передачу різним шарам і динамічне застосування під час як прямого, так і зворотного поширення.

ReLu

Похідна функції активації ReLU виглядає наступним чином, де ziz_i — елемент вектора преактивацій zz:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Сигмоїда

Похідна сигмоїдної функції активації має вигляд:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Для обох функцій активації операція застосовується до всього вектора zz, а також до його похідної. NumPy автоматично виконує обчислення елементно, тобто кожен елемент вектора обробляється окремо.

Наприклад, якщо вектор zz містить три елементи, похідна обчислюється так:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'\left( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} \right) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

Метод backward()

Метод backward() відповідає за обчислення градієнтів за допомогою наступних формул:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} та zlz^l зберігаються як атрибути inputs та outputs відповідно у класі Layer. Функція активації ff зберігається як атрибут activation.

Після обчислення всіх необхідних градієнтів можна оновити ваги та зміщення, оскільки вони більше не потрібні для подальших обчислень:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Отже, learning_rate (α\alpha) є ще одним параметром цього методу.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Примітка

Оператор * виконує покомпонентне множення, тоді як функція np.dot() виконує скалярний добуток у NumPy. Атрибут .T транспонує масив.

question mark

Яке з наведеного найкраще описує роль методу backward() у класі Layer під час зворотного поширення помилки?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 8

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Suggested prompts:

Can you explain how the backward() method uses the stored attributes in the Layer class?

What is the purpose of the derivative() method in the activation function classes?

Could you provide an example of how forward and backward propagation work together in a simple neural network?

Awesome!

Completion rate improved to 4

bookРеалізація Зворотного Поширення Помилки

Свайпніть щоб показати меню

Загальний підхід

Під час прямого поширення кожен шар ll отримує виходи з попереднього шару, al1a^{l-1}, як вхідні дані та обчислює власні виходи. Тому метод forward() класу Layer приймає вектор попередніх виходів як єдиний параметр, тоді як решта необхідної інформації зберігається всередині класу.

Під час зворотного поширення кожен шар ll потребує лише dalda^l для обчислення відповідних градієнтів і повернення dal1da^{l-1}, тому метод backward() приймає вектор dalda^l як параметр. Вся інша необхідна інформація вже зберігається в класі Layer.

Похідні функцій активації

Оскільки для зворотного поширення потрібні похідні функцій активації, такі функції активації, як ReLU та sigmoid, слід реалізовувати у вигляді класів, а не окремих функцій. Така структура дозволяє чітко визначити обидва компоненти:

  1. Сама функція активації — реалізується за допомогою методу __call__(), тому її можна застосовувати безпосередньо в класі Layer через self.activation(z);
  2. Її похідна — реалізується через метод derivative(), що забезпечує ефективне обчислення під час зворотного поширення за допомогою self.activation.derivative(z).

Представлення функцій активації як об'єктів спрощує їх передачу різним шарам і динамічне застосування під час як прямого, так і зворотного поширення.

ReLu

Похідна функції активації ReLU виглядає наступним чином, де ziz_i — елемент вектора преактивацій zz:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Сигмоїда

Похідна сигмоїдної функції активації має вигляд:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Для обох функцій активації операція застосовується до всього вектора zz, а також до його похідної. NumPy автоматично виконує обчислення елементно, тобто кожен елемент вектора обробляється окремо.

Наприклад, якщо вектор zz містить три елементи, похідна обчислюється так:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'\left( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} \right) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

Метод backward()

Метод backward() відповідає за обчислення градієнтів за допомогою наступних формул:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} та zlz^l зберігаються як атрибути inputs та outputs відповідно у класі Layer. Функція активації ff зберігається як атрибут activation.

Після обчислення всіх необхідних градієнтів можна оновити ваги та зміщення, оскільки вони більше не потрібні для подальших обчислень:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Отже, learning_rate (α\alpha) є ще одним параметром цього методу.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Примітка

Оператор * виконує покомпонентне множення, тоді як функція np.dot() виконує скалярний добуток у NumPy. Атрибут .T транспонує масив.

question mark

Яке з наведеного найкраще описує роль методу backward() у класі Layer під час зворотного поширення помилки?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 8
some-alt