machine-learning
तंत्रिका जाल
खोज…
आरंभ करना: पायथन के साथ एक सरल एएनएन
नीचे दी गई कोड सूची MNIST डेटासेट से हस्तलिखित अंकों को वर्गीकृत करने का प्रयास करती है। अंक इस तरह दिखते हैं:
कोड इन अंकों को पूर्ववर्ती करेगा, प्रत्येक छवि को 0s और 1s के 2 डी सरणी में परिवर्तित करेगा, और फिर 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
सीखा है।
बैकप्रोपैजेशन - द हार्ट ऑफ न्यूरल नेटवर्क्स
बैकप्रोपैजेशन का लक्ष्य वजन को अनुकूलित करना है ताकि तंत्रिका नेटवर्क सीख सके कि कैसे आउटपुट के लिए मनमाने ढंग से इनपुट को सही ढंग से मैप किया जाए।
प्रत्येक परत के वजन का अपना सेट होता है, और इन भारों को सही आउटपुट दिए गए इनपुट की सटीक भविष्यवाणी करने में सक्षम होना चाहिए।
बैक प्रचार का एक उच्च स्तरीय अवलोकन इस प्रकार है:
- फॉरवर्ड पास - इनपुट कुछ आउटपुट में तब्दील हो जाता है। प्रत्येक परत पर, सक्रियण की गणना इनपुट और भार के बीच एक डॉट उत्पाद के साथ की जाती है, इसके बाद परिणामी को पूर्वाग्रह के साथ जोड़ दिया जाता है। अंत में, यह मान एक सक्रियण फ़ंक्शन के माध्यम से पारित किया जाता है, ताकि उस परत की सक्रियता प्राप्त की जा सके जो अगली परत के लिए इनपुट बन जाएगा।
- अंतिम परत में, आउटपुट की तुलना उस इनपुट के अनुरूप वास्तविक लेबल से की जाती है, और त्रुटि की गणना की जाती है। आमतौर पर, यह औसत चुकता त्रुटि है।
- बैकवर्ड पास - चरण 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] और आयाम का पूर्वाग्रह
आप सोच रहे होंगे कि ऊपर दिए गए कोड में जब वजन शुरू हो रहा है तो क्या हो रहा है। इसे ज़ेवियर इनिशियलाइज़ेशन कहा जाता है, और यह आपके वेट मैट्रीज़ को बेतरतीब ढंग से इनिशियलाइज़ करने से बेहतर एक कदम है। हां, आरंभीकरण मायने रखता है। आपके आरंभ के आधार पर, आप ढाल वंश के दौरान एक बेहतर स्थानीय मिनीमा को खोजने में सक्षम हो सकते हैं (वापस प्रसार ग्रेडिएंट वंश का एक महिमा संस्करण है)।
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]
में सॉफ्टमैक्स प्रायिकताएं हैं - सभी वर्गों की भविष्यवाणियां, जिनमें से योग 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
पहली 2 लाइनें ग्रेडिएंट्स को इनिशियलाइज़ करती हैं। इन ग्रेडिएंट्स की गणना की जाती है और बाद में वेट और बायसेस को अपडेट करने के लिए उपयोग किया जाएगा।
अगली 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
के साथ इसके व्युत्पन्न के साथ numpy
को लागू करने के लिए कोड नीचे दिखाया गया है:
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
def sigmoid_prime(z):
return sigmoid(z) * (1 - sigmoid(z))
अतिशयोक्तिपूर्ण स्पर्शज्या समारोह (तन)
Tanh और sigmoid फ़ंक्शन के बीच मूल अंतर यह है कि tanh 0 केंद्रित है, सीमा में आदानों को स्खलित करता है [-1, 1] और गणना करने के लिए अधिक कुशल है।
छिपी हुई परत की सक्रियता की गणना करने के लिए आप आसानी से np.tanh
या math.tanh
फ़ंक्शन का उपयोग कर सकते हैं।
ReLU फ़ंक्शन
एक रेक्टिफाइड लीनियर यूनिट max(0,x)
। यह तंत्रिका नेटवर्क इकाइयों के सक्रियण कार्यों के लिए सबसे आम विकल्पों में से एक है।
ReLUs इस तरह से गहरे नेटवर्क में कुशल ढाल प्रसार के लिए अनुमति देता है, इस प्रकार सिग्मॉइड / हाइपरबोलिक स्पर्शरेखा इकाइयों की लुप्त होती ढाल समस्या को संबोधित करता है।
ReLU नाम नायर और हिंटन के पेपर से आता है, रेक्टीफाइड लाइनर यूनिट्स इम्प्रूव्ड रिस्ट्रिक्टेड बोल्ट्जमैन मशीनें ।
इसकी कुछ विविधताएँ हैं, उदाहरण के लिए, टपका हुआ ReLUs (LReLUs) और घातीय रैखिक इकाइयाँ (ELUL)।
के साथ अपने व्युत्पन्न के साथ वेनिला Relu लागू करने के लिए कोड numpy
नीचे दिखाया गया है:
def relU(z):
return z * (z > 0)
def relU_prime(z):
return z > 0
सॉफ्टमैक्स फंक्शन
सॉफ्टमैक्स रिग्रेशन (या मल्टिनोमियल लॉजिस्टिक रिग्रेशन) उस लॉजिस्टिक रिग्रेशन का एक सामान्यीकरण है जहां हम कई वर्गों को संभालना चाहते हैं। यह तंत्रिका नेटवर्क के लिए विशेष रूप से उपयोगी है जहां हम गैर-बाइनरी वर्गीकरण लागू करना चाहते हैं। इस मामले में, सरल लॉजिस्टिक प्रतिगमन पर्याप्त नहीं है। हमें सभी लेबलों में संभाव्यता वितरण की आवश्यकता होगी, जो कि सॉफ्टमैक्स हमें देता है।
सॉफ्टमैक्स की गणना निम्न सूत्र से की जाती है:
___________________________ इसमें कहां फिट बैठता है? _____________________________
एक वेक्टर को सामान्य करने के लिए इसे numpy
साथ numpy
फ़ंक्शन को लागू करने के लिए उपयोग करें:
np.exp(x) / np.sum(np.exp(x))
जहां x
, ANN की अंतिम परत से सक्रियता है।