수색…


시작하기 : Python을 사용한 간단한 ANN

아래 코드는 MNIST 데이터 세트의 자필 자릿수를 분류하려고 시도합니다. 숫자는 다음과 같습니다.

MNIST

코드는이 숫자를 전처리하여 각 이미지를 0과 1의 2D 배열로 변환 한 다음이 데이터를 사용하여 최대 97 % 정확도 (50 에포크)의 신경 네트워크를 학습합니다.

"""
Deep Neural Net 

(Name: Classic Feedforward)

"""

import numpy as np
import pickle, json
import sklearn.datasets
import random
import time
import os


def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))

def sigmoid_prime(z):
    return sigmoid(z) * (1 - sigmoid(z))

def relU(z):
    return np.maximum(z, 0, z)
    
def relU_prime(z):
    return z * (z <= 0)
    
def tanh(z):
    return np.tanh(z)

def tanh_prime(z):
    return 1 - (tanh(z) ** 2)

def transform_target(y):
    t = np.zeros((10, 1))
    t[int(y)] = 1.0
    return t

"""--------------------------------------------------------------------------------"""

class NeuralNet:

    def __init__(self, layers, learning_rate=0.05, reg_lambda=0.01):
        self.num_layers = len(layers)
        self.layers = layers
        self.biases = [np.zeros((y, 1)) for y in layers[1:]]
        self.weights = [np.random.normal(loc=0.0, scale=0.1, size=(y, x)) for x, y in zip(layers[:-1], layers[1:])]
        self.learning_rate = learning_rate
        self.reg_lambda = reg_lambda
        self.nonlinearity = relU
        self.nonlinearity_prime = relU_prime

    def __feedforward(self, x):
        """ Returns softmax probabilities for the output layer """
        for w, b in zip(self.weights, self.biases):
            x = self.nonlinearity(np.dot(w, np.reshape(x, (len(x), 1))) + b)

        return np.exp(x) / np.sum(np.exp(x))

    def __backpropagation(self, x, y):
        """
        :param x: input
        :param y: target
        """
        weight_gradients = [np.zeros(w.shape) for w in self.weights]
        bias_gradients = [np.zeros(b.shape) for b in self.biases]

        # forward pass
        activation = x
        hidden_activations = [np.reshape(x, (len(x), 1))]
        z_list = []

        for w, b in zip(self.weights, self.biases):    
            z = np.dot(w, np.reshape(activation, (len(activation), 1))) + b
            z_list.append(z)
            activation = self.nonlinearity(z)
            hidden_activations.append(activation)

        t = hidden_activations[-1] 
        hidden_activations[-1] = np.exp(t) / np.sum(np.exp(t))

        # backward pass
        delta = (hidden_activations[-1] - y) * (z_list[-1] > 0)
        weight_gradients[-1] = np.dot(delta, hidden_activations[-2].T)
        bias_gradients[-1] = delta

        for l in range(2, self.num_layers):
            z = z_list[-l]
            delta = np.dot(self.weights[-l + 1].T, delta) * (z > 0)
            weight_gradients[-l] = np.dot(delta, hidden_activations[-l - 1].T)
            bias_gradients[-l] = delta

        return (weight_gradients, bias_gradients)

    def __update_params(self, weight_gradients, bias_gradients):
        for i in xrange(len(self.weights)):
            self.weights[i] += -self.learning_rate * weight_gradients[i]
            self.biases[i] += -self.learning_rate * bias_gradients[i]

    def train(self, training_data, validation_data=None, epochs=10):
        bias_gradients = None
        for i in xrange(epochs):
            random.shuffle(training_data)
            inputs = [data[0] for data in training_data]
            targets = [data[1] for data in training_data]

            for j in xrange(len(inputs)):
                (weight_gradients, bias_gradients) = self.__backpropagation(inputs[j], targets[j])
                self.__update_params(weight_gradients, bias_gradients)

            if validation_data: 
                random.shuffle(validation_data)
                inputs = [data[0] for data in validation_data]
                targets = [data[1] for data in validation_data]

                for j in xrange(len(inputs)):
                    (weight_gradients, bias_gradients) = self.__backpropagation(inputs[j], targets[j])
                    self.__update_params(weight_gradients, bias_gradients)

            print("{} epoch(s) done".format(i + 1))

        print("Training done.")

    def test(self, test_data):
        test_results = [(np.argmax(self.__feedforward(x[0])), np.argmax(x[1])) for x in test_data]
        return float(sum([int(x == y) for (x, y) in test_results])) / len(test_data) * 100

    def dump(self, file):
        pickle.dump(self, open(file, "wb"))

"""--------------------------------------------------------------------------------"""

if __name__ == "__main__":
    total = 5000
    training = int(total * 0.7)
    val = int(total * 0.15)
    test = int(total * 0.15)

    mnist = sklearn.datasets.fetch_mldata('MNIST original', data_home='./data')

    data = zip(mnist.data, mnist.target)
    random.shuffle(data)
    data = data[:total]
    data = [(x[0].astype(bool).astype(int), transform_target(x[1])) for x in data]

    train_data = data[:training]
    val_data = data[training:training+val]
    test_data = data[training+val:]

    print "Data fetched"

    NN = NeuralNet([784, 32, 10]) # defining an ANN with 1 input layer (size 784 = size of the image flattened), 1 hidden layer (size 32), and 1 output layer (size 10, unit at index i will predict the probability of the image being digit i, where 0 <= i <= 9)  

    NN.train(train_data, val_data, epochs=5)

    print "Network trained"

    print "Accuracy:", str(NN.test(test_data)) + "%"

이것은 자체 포함 된 코드 샘플이며 더 이상 수정하지 않고 실행할 수 있습니다. 파이썬 버전에 numpyscikit 설치해야합니다.

Backpropagation - 신경망의 핵심

역 전파의 목표는 신경망이 임의의 입력을 출력에 정확하게 매핑하는 방법을 학습 할 수 있도록 가중치를 최적화하는 것입니다.

각 레이어에는 고유 한 가중치 세트가 있으며이 가중치는 주어진 입력의 올바른 출력을 정확하게 예측할 수 있도록 조정해야합니다.

역 전파의 개요는 다음과 같습니다.

  1. 전달 전달 - 입력이 일부 출력으로 변환됩니다. 각 레이어에서 활성화는 입력과 가중치 사이의 내적을 계산 한 다음 그 결과를 바이어스와 합산합니다. 마지막으로이 값은 활성화 함수를 통해 전달되어 다음 계층의 입력이 될 해당 계층의 활성화를 가져옵니다.
  2. 마지막 레이어에서 출력은 해당 입력에 해당하는 실제 레이블과 비교되고 오류가 계산됩니다. 일반적으로 평균 제곱 오차입니다.
  3. 역방향 통과 - 2 단계에서 계산 된 오류가 내부 레이어로 전파되고 모든 레이어의 가중치가이 오류를 설명하기 위해 조정됩니다.

1. 가중치 초기화

가중치 초기화의 간단한 예는 다음과 같습니다.

layers = [784, 64, 10] 
weights = np.array([(np.random.randn(y, x) * np.sqrt(2.0 / (x + y))) for x, y in zip(layers[:-1], layers[1:])])
biases = np.array([np.zeros((y, 1)) for y in layers[1:]])
  • 숨겨진 레이어 1의 크기는 [64, 784]의 크기와 64의 바이어스입니다.

  • 출력 층은 크기 [10, 64]의 무게와 치수의 편향

위의 코드에서 가중치를 초기화 할 때 무슨 일이 일어나는지 궁금 할 것입니다. 이것은 Xavier 초기화 라 불리며 무작위로 체중 행렬을 초기화하는 것보다 더 나은 단계입니다. 예, 초기화가 중요합니다. 초기화를 기반으로 그라데이션 디센트 동안 더 나은 로컬 미니 마를 찾을 수 있습니다 (역 전파는 그라디언트 디센트의 영광 된 버전입니다).

2. 전달 통로

activation = x
hidden_activations = [np.reshape(x, (len(x), 1))]
z_list = []

for w, b in zip(self.weights, self.biases):    
    z = np.dot(w, np.reshape(activation, (len(activation), 1))) + b
    z_list.append(z)
    activation = relu(z)
    hidden_activations.append(activation)

t = hidden_activations[-1] 
hidden_activations[-1] = np.exp(t) / np.sum(np.exp(t))

이 코드는 위에서 설명한 변환을 수행합니다. hidden_activations[-1] 은 softmax 확률을 포함합니다. 모든 클래스의 예측. 합계는 1입니다. 숫자를 예측하는 경우 출력은 차원 10의 확률 벡터이며 합계는 1입니다.

3. 역방향 통과

weight_gradients = [np.zeros(w.shape) for w in self.weights]
bias_gradients = [np.zeros(b.shape) for b in self.biases]

delta = (hidden_activations[-1] - y) * (z_list[-1] > 0) # relu derivative
weight_gradients[-1] = np.dot(delta, hidden_activations[-2].T)
bias_gradients[-1] = delta

for l in range(2, self.num_layers):
    z = z_list[-l]
    delta = np.dot(self.weights[-l + 1].T, delta) * (z > 0) # relu derivative
    weight_gradients[-l] = np.dot(delta, hidden_activations[-l - 1].T)
    bias_gradients[-l] = delta

처음 두 줄은 그라디언트를 초기화합니다. 이러한 그라디언트가 계산되어 추후에 가중치 및 편차를 업데이트하는 데 사용됩니다.

다음 3 행은 목표에서 예측을 빼서 오류를 계산합니다. 오류는 다시 내부 레이어로 전달됩니다.

자, 조심스럽게 루프의 작동을 추적하십시오. 라인 2와 3은 layer[i] 에서 layer[i - 1] 에러를 변환합니다. 이해하기 위해 곱셈되는 행렬의 형태를 추적합니다.

4. 가중치 / 매개 변수 업데이트

for i in xrange(len(self.weights)):
    self.weights[i] += -self.learning_rate * weight_gradients[i]
    self.biases[i] += -self.learning_rate * bias_gradients[i] 

self.learning_rate 는 네트워크가 학습하는 속도를 지정합니다. 수렴하지 않을 수도 있으므로 너무 빨리 배울 필요가 없습니다. 좋은 미니 마를 찾는 데는 부드러운 후손이 선호됩니다. 일반적으로 0.010.1 사이의 비율은 양호한 것으로 간주됩니다.

활성화 함수

전송 기능이라고도하는 활성화 기능은 특정 방식으로 입력 노드를 출력 노드에 매핑하는 데 사용됩니다.

이들은 신경망 층의 출력에 비선형 성을 부여하는 데 사용됩니다.

일반적으로 사용되는 함수와 커브는 다음과 같습니다. 활성화 함수


시그 모이 드 함수

시그 모이 드는 출력이 [0, 1] 범위에있는 스쿼시 함수입니다.

여기에 이미지 설명을 입력하십시오.

numpy 로 미분과 함께 Sigmoid를 구현하는 코드는 다음과 같습니다.

def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))

def sigmoid_prime(z):
    return sigmoid(z) * (1 - sigmoid(z))

하이퍼 볼릭 탄젠트 함수 (tanh)

tanh와 sigmoid 함수의 기본적인 차이점은 tanh가 0에 집중되어 [-1, 1] 범위의 입력을 스쿼시하고 더 효율적으로 계산한다는 것입니다.

여기에 이미지 설명을 입력하십시오.

np.tanh 또는 math.tanh 함수를 사용하여 숨겨진 레이어의 활성화를 쉽게 계산할 수 있습니다.

ReLU 기능

정류 된 선형 단위는 단순히 max(0,x) 합니다. 그것은 신경망 단위의 활성화 기능에 대한 가장 일반적인 선택 중 하나입니다.

여기에 이미지 설명을 입력하십시오.

ReLUs는 Sigmoid / Hyperbolic Tangent 단위의 사라지는 그라디언트 문제를 해결 하므로 깊은 네트워크에서 효율적인 그라디언트 전파가 가능합니다.

ReLU라는 이름은 Nair와 Hinton의 논문 인 Rectified Linear Units Restricted Boltmann Machines에서 발췌 한 것입니다.

누출 ReLUs (LReLUs) 및 지수 선형 단위 (ELU)와 같은 몇 가지 변형이 있습니다.

바닐라 ReLU를 numpy 로 파생 된 코드와 함께 구현하는 코드는 다음과 같습니다.

def relU(z):
    return z * (z > 0)

def relU_prime(z):
    return z > 0

Softmax 기능

Softmax 회귀 (또는 다항 로지스틱 회귀)는 여러 클래스를 처리하려는 경우에 대한 회귀 회귀의 일반화입니다. 비 - 바이너리 분류를 적용하고자하는 신경망에 특히 유용합니다. 이 경우 간단한 로지스틱 회귀만으로는 충분하지 않습니다. 모든 레이블에서 확률 분포가 필요합니다. softmax가 우리에게 제공하는 것입니다.

Softmax는 다음 공식으로 계산됩니다.

공식

___________________________ 어디에서 적합합니까? _____________________________

Softmax 과에 softmax를 함수를 적용하여 벡터를 정상화하기 위해 numpy 사용 :

np.exp(x) / np.sum(np.exp(x))

여기서 x 는 ANN의 최종 계층에서의 활성화입니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow