Часть 1
Вступление:
Я думаю, что слишком многие инженеры по машинному обучению сразу начинают применять модели машинного обучения с такими библиотеками, как Keras и Tensorflow, не понимая, что такое машинное обучение. Хорошее упражнение для этого - вернуться и попытаться создать алгоритм машинного обучения с нуля. Я решил пойти на один уровень глубже, пытаясь воссоздать функции, которые предоставляет Keras, с нуля.
Задача:
Целью этой программы было создание гибкого пользовательского интерфейса для создания нейронных сетей. Для простоты программа будет включать только самый простой тип слоя.
Концепция:
Структура моей программы была очень похожа на сборочную линию. Каждая часть программы действовала как рабочий на сборочной линии. Продукт будет передаваться из каждой части кода в центральный процессор, который выполняет все вычисления и отправляет обратно соответствующую информацию. Наилучший способ дать каждой программе эти атрибуты «сборочной линии» - это представить всю модель как класс, а каждый тип слоя - как подкласс.
Проходим код:
Шаг 1 | Предпосылки:
import numpy from matplotlib import pyplot as plt def sigmoid(x): return 1/(1+np.exp(-x)) def sigmoid_p(x): return sigmoid(x)*(1 -sigmoid(x)) def relu(x): return np.maximum(x, 0) def relu_p(x): return np.heaviside(x, 0) def tanh(x): return np.tanh(x) def tanh_p(x): return 1.0 - np.tanh(x)**2 def deriv_func(z,function): if function == sigmoid: return sigmoid_p(z) elif function == relu: return relu_p(z) elif function == tanh: return tanh_p(z)
Я импортировал Numpy для управления матрицей и Matplotlib для построения графика потерь с течением времени. Функции активации описаны ниже. Существует также другая функция, которая принимает значение и функцию активации в качестве входных данных и возвращает производное значение.
Шаг 2 | Создайте класс основной нейронной сети:
class NeuralNetwork: def __init__(self): self.layers = [] self.weights = [] self.loss = [] def add(self,layer_function): self.layers.append(layer_function) def initialize_weights(self): for layer in self.layers: index = self.layers.index(layer) weights = layer.initialize_weights(self.layers,index) self.weights.append(weights) def propagate(self,X): As,Zs = [],[] input_data = X for layer in self.layers: a,z = layer.propagate(input_data) As.append(a) Zs.append(z) input_data = a return As,Zs
Это класс, в котором определены все остальные классы и функции. Это работник, который работает со всеми продуктами другого работника и возвращает соответствующую информацию. Следовательно, он имеет доступ ко всем переменным, содержащимся во вложенных классах.
Шаг 3 | Создайте класс Perceptron:
class Perceptron: def __init__(self,nodes,input_shape= None,activation = None): self.nodes = nodes self.input_shape = input_shape self.activation = activation def initialize_weights(self,layers,index): if self.input_shape: self.weights = np.random.randn(self.input_shape[-1],self.nodes) else: self.weights = np.random.randn(layers[index-1].weights.shape[-1],self.nodes) return self.weights def propagate(self,input_data): z = np.dot(input_data,self.weights) if self.activation: a = self.activation(z) else: a = z return a,z def network_train(self,gradient): self.weights += gradient
Персептрон действует как мини-нейронная сеть в более крупной сети. Функция поезда очень проста, так как не требуется никаких внешних производных.
Шаг 4 | Определить обучение:
def train(self,X,y,iterations): loss = [] for i in range(iterations): As,Zs = self.propagate(X) loss.append(np.square(sum(y - As[-1]))) As.insert(0,X) g_wm = [0] * len(self.layers) for i in range(len(g_wm)): pre_req = (y-As[-1])*2 a_1 = As[-(i+2)] z_index = -1 w_index = -1 if i == 0: range_value = 1 else: range_value = 2*i for j in range(range_value): if j% 2 == 0: pre_req = pre_req * sigmoid_p(Zs[z_index]) z_index -= 1 else: pre_req = np.dot(pre_req,self.weights[w_index].T) w_index -= 1 gradient = np.dot(a_1.T,pre_req) g_wm[-(i+1)] = gradient for i in range(len(self.layers)): self.layers[i].network_train(g_wm[i]) return loss
Созданная мною обучающая функция может быть не самой лаконичной, но она надежна, так что сеть может сохранять свою гибкость.
Полный исходный код:
import numpy from matplotlib import pyplot as plt def sigmoid(x): return 1/(1+np.exp(-x)) def sigmoid_p(x): return sigmoid(x)*(1 -sigmoid(x)) def relu(x): return np.maximum(x, 0) def relu_p(x): return np.heaviside(x, 0) def tanh(x): return np.tanh(x) def tanh_p(x): return 1.0 - np.tanh(x)**2 def deriv_func(z,function): if function == sigmoid: return sigmoid_p(z) elif function == relu: return relu_p(z) elif function == tanh: return tanh_p(z) class NeuralNetwork: def __init__(self): self.layers = [] self.weights = [] self.loss = [] def add(self,layer_function): self.layers.append(layer_function) def initialize_weights(self): for layer in self.layers: index = self.layers.index(layer) weights = layer.initialize_weights(self.layers,index) self.weights.append(weights) def propagate(self,X): As,Zs = [],[] input_data = X for layer in self.layers: a,z = layer.propagate(input_data) As.append(a) Zs.append(z) input_data = a return As,Zs def train(self,X,y,iterations): loss = [] for i in range(iterations): As,Zs = self.propagate(X) loss.append(np.square(sum(y - As[-1]))) As.insert(0,X) g_wm = [0] * len(self.layers) for i in range(len(g_wm)): pre_req = (y-As[-1])*2 a_1 = As[-(i+2)] z_index = -1 w_index = -1 if i == 0: range_value = 1 else: range_value = 2*i for j in range(range_value): if j% 2 == 0: pre_req = pre_req * sigmoid_p(Zs[z_index]) z_index -= 1 else: pre_req = np.dot(pre_req,self.weights[w_index].T) w_index -= 1 gradient = np.dot(a_1.T,pre_req) g_wm[-(i+1)] = gradient for i in range(len(self.layers)): self.layers[i].network_train(g_wm[i]) return loss class Perceptron: def __init__(self,nodes,input_shape= None,activation = None): self.nodes = nodes self.input_shape = input_shape self.activation = activation def initialize_weights(self,layers,index): if self.input_shape: self.weights = np.random.randn(self.input_shape[-1],self.nodes) else: self.weights = np.random.randn(layers[index-1].weights.shape[-1],self.nodes) return self.weights def propagate(self,input_data): z = np.dot(input_data,self.weights) if self.activation: a = self.activation(z) else: a = z return a,z def network_train(self,gradient): self.weights += gradient model = NeuralNetwork() Perceptron = model.Perceptron X = np.array([[0,1,1],[1,1,0],[1,0,1]]) y = np.array([[0],[1],[1]]) model.add(Perceptron(5,input_shape = (None,3),activation = sigmoid)) model.add(Perceptron(10,activation = sigmoid)) model.add(Perceptron(10,activation = sigmoid)) model.add(Perceptron(1,activation = sigmoid)) model.initialize_weights() loss = model.train(X,y,1000) plt.plot(loss)
Надеюсь, вы кое-что узнали из этой статьи! Не стесняйтесь использовать этот код, чтобы углубить свое понимание машинного обучения!