machine-learning
신경망
수색…
시작하기 : Python을 사용한 간단한 ANN
아래 코드는 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)) + "%"
이것은 자체 포함 된 코드 샘플이며 더 이상 수정하지 않고 실행할 수 있습니다. 파이썬 버전에 numpy
와 scikit
설치해야합니다.
Backpropagation - 신경망의 핵심
역 전파의 목표는 신경망이 임의의 입력을 출력에 정확하게 매핑하는 방법을 학습 할 수 있도록 가중치를 최적화하는 것입니다.
각 레이어에는 고유 한 가중치 세트가 있으며이 가중치는 주어진 입력의 올바른 출력을 정확하게 예측할 수 있도록 조정해야합니다.
역 전파의 개요는 다음과 같습니다.
- 전달 전달 - 입력이 일부 출력으로 변환됩니다. 각 레이어에서 활성화는 입력과 가중치 사이의 내적을 계산 한 다음 그 결과를 바이어스와 합산합니다. 마지막으로이 값은 활성화 함수를 통해 전달되어 다음 계층의 입력이 될 해당 계층의 활성화를 가져옵니다.
- 마지막 레이어에서 출력은 해당 입력에 해당하는 실제 레이블과 비교되고 오류가 계산됩니다. 일반적으로 평균 제곱 오차입니다.
- 역방향 통과 - 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.01
과 0.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를 함수를 적용하여 벡터를 정상화하기 위해 numpy
사용 :
np.exp(x) / np.sum(np.exp(x))
여기서 x
는 ANN의 최종 계층에서의 활성화입니다.