Что такое нейронная сеть?

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

Давайте рассмотрим, как работает нейронная сеть.

Считайте, что каждый узел представляет собой отдельную модель линейной регрессии с входными данными (X), весами (w), смещением (b) и выходными данными (Z). Формула должна выглядеть следующим образом:

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

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

Вот одна из функций стоимости:

Здесь 1/m масштабирует результаты потерь, yi представляет фактический выход, а log(yhat) представляет прогнозируемый выход. Самое интересное в этой функции потерь — это отрицательный знак в начале, она просто компенсирует логарифмический отрицательный выход как log (близко к 0) дает отрицательное значение.

Обратное распространение

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

Давайте посмотрим, как он рассчитывает градиенты

Градиентный спуск

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

Производная функции потерь по (w,b) и вычисление градиентов для оптимизации потерь. Здесь J — функция потерь, а градиент w представляет направление в пространстве. Целью здесь является достижение глобальных минимумов.

Обновить градиенты

Здесь альфа — скорость обучения, w — старый вес, а dl/dw — потеря производной по весу. Для нового смещения мы сделали то же самое.

Давайте реализуем эти идеи в коде

Инициализировать параметр для каждого уровня сети. У вас есть возможность инициализировать вес в различных типах распределения, например: равномерном, случайном нормальном распределении или любом другом распределении, если хотите. Здесь я использую numpy randn, который по сути генерирует стандартное нормальное распределение.

def initialize_parameters(self):
        np.random.seed(42)
 
        for l in range(1, len(self.layers_size)):
            self.parameters["W" + str(l)] = np.random.randn(self.layers_size[l], self.layers_size[l - 1]) / np.sqrt(
                self.layers_size[l - 1])
            self.parameters["b" + str(l)] = np.zeros((self.layers_size[l], 1))

Прямое распространение

def forward(self, X):
        dict = {}
 
        A = X.T
        for l in range(self.L - 1):
            Z = self.parameters["W" + str(l + 1)].dot(A) + self.parameters["b" + str(l + 1)]
            A = self.sigmoid(Z)
            dict["A" + str(l + 1)] = A
            dict["W" + str(l + 1)] = self.parameters["W" + str(l + 1)]
            dict["Z" + str(l + 1)] = Z
 
        Z = self.parameters["W" + str(self.L)].dot(A) + self.parameters["b" + str(self.L)]
        A = self.softmax(Z)
        dict["A" + str(self.L)] = A
        dict["W" + str(self.L)] = self.parameters["W" + str(self.L)]
        dict["Z" + str(self.L)] = Z
 
        return A, dict

Обратное распространение

def backward(self, X, Y, dict):
 
        derivatives = {}
 
        dict["A0"] = X.T
 
        A = store["A" + str(self.L)]
        dZ = A - Y.T
 
        dW = dZ.dot(dict["A" + str(self.L - 1)].T) / self.batch
        db = np.sum(dZ, axis=1, keepdims=True) / self.batch
        dAPrev = dict["W" + str(self.L)].T.dot(dZ)
 
        derivatives["dW" + str(self.L)] = dW
        derivatives["db" + str(self.L)] = db
 
        for l in range(self.L - 1, 0, -1):
            dZ = dAPrev * self.sigmoid_derivative(dict["Z" + str(l)])
            dW = 1. / self.batch * dZ.dot(dict["A" + str(l - 1)].T)
            db = 1. / self.batch * np.sum(dZ, axis=1, keepdims=True)
            if l > 1:
                dAPrev = dict["W" + str(l)].T.dot(dZ)
 
            derivatives["dW" + str(l)] = dW
            derivatives["db" + str(l)] = db
 
        return derivatives

Обновить градиенты с помощью мини-пакета

Мини-пакет — это фиксированное количество обучающих примеров, меньшее, чем фактический набор данных. Таким образом, на каждой итерации мы обучаем сеть на разных группах выборок, пока не будут использованы все выборки набора данных. У вас есть возможность выбирать размер пакета. Теоретически разумно выбрать любую степень по основанию 2.

def fit(self, X, Y, learning_rate=1, n_iterations=10,batch=32):
        np.random.seed(1)
        self.batch = batch
        for loop in range(n_iterations):

            mini_batches = self.create_mini_batches(X, Y, self.batch)
            loss = 0
            acc = 0
            for mini_batch in mini_batches:
                X_mini, y_mini = mini_batch
                A, store = self.forward(X_mini)
                loss += -1*np.mean(y_mini * np.log(A.T+ 1e-8))# CCE cost function A.T is updated weight 
                derivatives = self.backward(X_mini, y_mini, store)
     
                for l in range(1, self.L + 1):
                    self.parameters["W" + str(l)] = self.parameters["W" + str(l)] - learning_rate * derivatives[
                        "dW" + str(l)]
                    self.parameters["b" + str(l)] = self.parameters["b" + str(l)] - learning_rate * derivatives[
                        "db" + str(l)]

                acc += self.predict(X_mini, y_mini)

            
            self.costs.append(loss)
            print("Epoch",loop+1,"\steps ",len(mini_batches),"Train loss: ", "{:.4f}".format(loss/len(mini_batches)),
                                                "Train acc:", "{:.4f}".format(acc/len(mini_batches)))

Запустите и посмотрите результат

    train_x , test_x , train_y , test_y = load_mnist()
    
    layers_dims = [10, 10]
    
    ann = ANN(layers_dims,train_x.shape[1])
    ann.fit(train_x, train_y, learning_rate=.1, n_iterations=100,batch=64)

Я показываю вам только последние несколько шагов вывода обучающей модели, поскольку она имеет большое количество итераций.

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

Проверка работоспособности с помощью одного изображения прогноз

Как вы можете видеть, наша модель работает довольно хорошо: ее точность при тестировании составляет 92,3%, а точность поезда — 95,45%. Есть много возможностей для обновления этой модели и повышения точности. Дайте мне знать ваш подход к повышению производительности.

Спасибо, что прочитали. Вот полный код

Ссылки

MIT Deep Learning 6.S191MIT Deep Learning 6.S191http://introtodeeplearning.com



https://en.wikipedia.org/wiki/Backpropagation