Это пятый день моего ноябрьского испытания обновлений.
датчик
Нейронная сеть может быть просто понята какискусственный нейронСформированная сеть, персептрон представляет собой искусственный нейрон, простая форма которого выглядит следующим образом:
Пример персептрона имеет три входа, на выходе число 0 или 1, каждое соединение будет иметь вес, если сумма параметров и весов больше определенного порога, введите 1, иначе выведите 0, формальное представление выглядит следующим образом:
Из формулы (1) можно узнать, что путем изменения порога и веса можно получить разные модели решений.
Приведенный выше пример представляет собой простой персептрон, более сложная сеть, состоящая из нескольких персептронов, выглядит следующим образом:
- Первый уровень персептронов: принятие трех простых решений на основе входных данных
- Персептрон второго уровня: Следующее суждение делается на основе результата суждения персептрона первого уровня.Персептрон второго уровня более сложен и абстрактен, чем решение, принятое первым слоем.
И так далее, чем больше слоев принимает персептрон, тем более абстрактные и сложные решения он принимает.
Модифицированная формула (1) представлена векторным скалярным произведением,Сейчас,будетиспользоватьзначит получить:
будетиспользовать(предвзятая) замена, это можно рассматривать какСделать персептрон многоконтейнерным выходом 1параметры (т.е.Чем больше значение, тем легче персептрону вывести 1).
Ядром алгоритма обучения нейронной сети является автоматическая корректировка весов и смещений искусственных нейронов в соответствии с целевой функцией без прямого ручного вмешательства, в чем искусственные нейроны принципиально отличаются от традиционных логических элементов.
сигмовидные нейроны
При обучении обычно надеются, что небольшие корректировки параметров, таких как веса или смещения, лишь незначительно изменят выходные результаты.Однако из формулы (2) видно, что искусственные нейроны, такие как персептроны, с трудом удовлетворяют этому требованию. параметры могут изменить вывод с 0 на 1 (поскольку персептрон имеет только два выходных значения), метод, называемыйсигмовидные нейроныискусственные нейроны, чтобы улучшить это.
Вводится в сигмовидные нейронысигмовидная функция,определяется как:
Выход сигмовидного нейрона становится:
сигмовидная функцияПримерная форма показана на следующем рисунке:
, функция близка к 1, когда ее значение велико, и близко к 0, когда ее значение мало.
Если сигмовидная функцияПреобразуется в ступенчатую функцию следующим образом:
Видно, что это на самом деле персептрон, т.Сигмовидный нейрон на самом деле является сглаженной версией персептрона., так что параметры тонкой настройки могут точно настроить выходные результаты.
выходное изменениеЭто может быть выражено как:
Архитектура нейронной сети
Инфраструктура нейронной сети выглядит так:
Крайний левый слой называется входным слоем, нейроны в нем называются входными нейронами, крайний правый слой — выходным слоем, где нейроны называются выходными нейронами, а слои в середине вместе называются скрытым слоем.
Классификация сети рукописных цифр
Распознавание рукописных цифр можно разделить на две задачи, одна состоит в том, чтобы разделить строку цифр на отдельные цифры, а другая — в классификации отдельных цифр для завершения распознавания.Здесь решается только вторая задача. Используйте трехслойную нейронную сеть, как показано ниже, чтобы распознать число:
- Входной слой: установите размер изображения рукописных цифр, вводимого сетью, как:пиксель, входной пиксель имеет оттенки серого, 0,0 означает белый, 1,0 означает черный, а среднее значение означает градиент серого, тогда входной слой должен содержатьнейроны.
- Скрытый слой: использоватьпредставляет количество нейронов в скрытом слое,является регулируемым параметром, на рисунке.
- Выходной слой: содержит 10 нейронов, из, какой нейрон активирован, указывает, какой класс назначен.
Параметры обучения алгоритма градиентного спуска
Набор обучающих данных является известнымНабор данных MNIST.
Вход в сеть есть, размерность 784, ожидаемый результат — 10-мерный вектор, то есть мы хотим. Например, для входа числа 6 ожидаемый результат сети равен.
Чтобы количественно определить цель обучения нейронной сети, определите целевую функцию:
представляет все веса в сети,представляет все смещения,представляет общее количество входных данных,означает, что при вводеКогда выходной вектор,представляет собой сумму всех входных данных,представляет собой модуль вектора, эта целевая функция задается методом, называемымсреднеквадратическая ошибка. Интуитивно понятно, что при вводеВыход сети,иЧем меньше разница, темЧем меньше значение , тем целью обучения является поиск подходящего,сделать.
Эта проблема превращается в решение,когда:
мы можем использоватьГрадиентный спускДля решения этой задачи минимизации принцип метода градиентного спуска очень прост, то есть каждый раз значения двух параметров перемещаются в отрицательном направлении значения функции до тех пор, пока не будет достигнута крайняя точка.
использоватьпредставлять функциюВектор градиента:
Как видно из предыдущей статьи,Это может быть выражено как:
Проблема заключается в том, как выбратьсделатьдолжен быть отрицательным. Введите скорость обучения,сделать:
так какявляется небольшим положительным числом, поэтому мы получаем:
, поэтому можно получить постоянное отрицательное значение, и регулируяЗначение регулирует скорость градиентного спуска. На рисунке ниже показано геометрическое представление метода градиентного спуска.
Подводя итог, получается метод выбора изменения двух параметров:
Повторяйте вышеуказанные шаги несколько раз, пока не будет найдено минимальное значение функции.
Стохастический градиентный спуск
Обратите внимание, что процесс обучения вышеуказанного метода на самом деле очень трудоемкий, а целевая функция упоминалась ранее.,сделать,получить, в расчете необходимоВычислите его значение градиентаЗатем производится усреднение, что делает вычисления очень тяжелыми и замедляет обучение.
Поэтому для решения проблемы ускорения скорости обучения вводится алгоритм стохастического градиентного спуска.Основная идея состоит в том, чтобы случайным образом выбирать мелкомасштабные выборки для расчета, значение градиента всех выборок оценивается по значению градиента, рассчитанному по малой выборке.
Выберите небольшой пакет данных (мини-пакет), содержащий количество образцов как,существуетДостаточно большой, чтобы получить:
В методе градиентного спуска пакет мини-пакетов данных повторно выбирается для обучения на каждой итерации до тех пор, пока не будут израсходованы все выборки обучающего набора, что называется завершением эпохи обучения, а затем перезапускается новая эпоха.
Код
Построить нейронную сеть
import numpy as np
import random
# sigmoid函数
def sigmoid(z):
return 1.0/(1.0+np.exp(-z))
def sigmoid_prime(z):
# sigmoid函数的导数
return sigmoid(z)*(1-sigmoid(z))
# 定义网络类
# net = Network([2, 3, 1])
# 创建一个第一层2个神经元 第二层 3个神经元 第三层 1个神经元的网络
class Network:
def __init__(self,sizes):
# 获得网络的层数
self.num_layers=len(sizes)
self.sizes = sizes
# 随机初始化偏置和权重
# 第⼀层神经元是⼀个输⼊层不设置偏置,因此从1开始
# np.random.randn randn函数返回一个或一组样本,具有标准正态分布
# np.random.randn(y,1)返回y行1列的数据
self.biases=[np.random.randn(y,1)for y in sizes[1:]]
# zip函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
self.weights = [np.random.randn(y,x)
for x,y in list(zip(sizes[:-1],sizes[1:]))]
# feedforward方法,对于网络给定输入a返回对应输出
def feedforward(self,a):
for b,w in list(zip(self.biases,self.weights)):
#np.dot 矩阵乘法
a = sigmoid(np.dot(w,a)+b)
return a
# 随机梯度下降算法
def SGD(self,training_data,epochs,mini_batch_size,eta,test_data=None):
if test_data:n_test=len(test_data)
# training_data 为一个(x,y)的列表,x表示训练的输入样本的特征,y表示对应期望输出(标签)
# n为训练集样本数
n = len(training_data)
# epochs和mini_batch_size表示迭代期数量,和采样时的⼩批量数据的⼤⼩
for j in range(epochs):
# 随机打乱训练数据
random.shuffle(training_data)
# 从训练集中取k到k+mini_batch_size范围的数据作为mini_batches中的数据
mini_batches=[
training_data[k:k+mini_batch_size]
# range(0,n,mini_batch_size)
# k的取值范围从0开始到n,步长为nimi_batch_size
for k in range(0,n,mini_batch_size)
]
# eta 学习速率
for mini_batch in mini_batches:
# update_mini_batch 对于每⼀个 mini_batch计算⼀次梯度下降
self.update_mini_batch(mini_batch, eta)
# 若设置了test_data则每次迭代测试后评估一次网络,有助于追踪进度但会延缓执行速度
if test_data:
print ("Epoch {0}: {1} / {2}".format(j, self.evaluate(test_data), n_test))
else:
print("Epoch {0} complete".format(j))
# 对每个mini_batch使用反向传播梯度下降方法更新网络中的权重和偏置
def update_mini_batch(self, mini_batch, eta):
# np.zeros返回来一个给定形状和类型的用0填充的数组
# .shape可以快速读取矩阵的形状
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
for x,y in mini_batch:
# self.backprop 反向传播算法,⼀种快速计算代价函数的梯度的⽅法
delta_nabla_b,delta_nabla_w=self.backprop(x,y)
# 计算两个参数的梯度向量
nabla_b = [nb + dnb for nb, dnb in list(zip(nabla_b, delta_nabla_b))]
nabla_w = [nw + dnw for nw, dnw in list(zip(nabla_w, delta_nabla_w))]
# 更新两个参数的值
self.weights = [w - (eta / len(mini_batch)) * nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b - (eta / len(mini_batch)) * nb
for b, nb in zip(self.biases, nabla_b)]
# 反向传播算法
# 返回一个元祖,nabla_b, nabla_w表示损失函数C_x的梯度
def backprop(self,x,y):
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
# feedforward
activation = x
activations = [x] #存储所有激活值的列表,一层层
zs = [] # 存储所有z向量的列表,一层层
for b, w in list(zip(self.biases, self.weights)):
z = np.dot(w, activation) + b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)
# backward pass
delta = self.cost_derivative(activations[-1], y) * sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
for l in range(2, self.num_layers):
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l + 1].transpose(), delta) * sp
nabla_b[-l] = delta
nabla_w[-l] = np.dot(delta, activations[-l - 1].transpose())
return nabla_b, nabla_w
def evaluate(self, test_data):
"""Return the number of test inputs for which the neural
network outputs the correct result. Note that the neural
network's output is assumed to be the index of whichever
neuron in the final layer has the highest activation."""
test_results = [(np.argmax(self.feedforward(x)), y)
for (x, y) in test_data]
return sum(int(x == y) for (x, y) in test_results)
def cost_derivative(self, output_activations, y):
"""Return the vector of partial derivatives \partial C_x /
\partial a for the output activations."""
return output_activations - y
Прочитайте набор данных и преобразуйте его в соответствующий формат.
import pickle
import gzip
import numpy as np
# load_data返回MNIST数据为一个元祖包括training data、validation data和 test data
# training data为一个包含两个实体的元祖,第一个实体包含实际训练图像。一个numpy ndarray包含50000个实体
# 每个实体依次是一个包含784个值的numpy ndarray,也就是说一个MNIST图片为28X28=784个像素
# 第二个实体是一个包含50000个实体的numpy ndarray,这些实体的取值范围为0-9的实数表示第一个实体所属分类
# validation data和test data是一样的,每个包含10000张图片
def load_data():
# Gzip模块为GNU zip文件提供了一个类文件的接口,它使用zlib来压缩和解压缩数据文件,读写gzip文件
f = gzip.open('mnist.pkl.gz', 'rb')
# pickle.load 从f中读取一个字符串,并将它重构为原来的python对象
training_data, validation_data, test_data = pickle.load(f,encoding='bytes')
f.close()
return training_data, validation_data, test_data
# load_data_wrapper返回一个元祖包含(training_data, validation_data, test_data),将数据格式转化为更易于我们构建网络使用的格式
# training data为一个列表包含50000个二元组:(x,y),x为一个784维的numpy.ndarray,为输入图片
# y为一个10维的numpy.ndarray表示x对应的分类
# validation data和test data 为一个列表包含10000个二元组:(x,y)
def load_data_wrapper():
tr_d, va_d, te_d = load_data()
# np.reshape 在不改变数据内容的情况下,改变一个数组的格式 x为需要处理的数据,改变为(784,1),784行1列
training_inputs = [np.reshape(x, (784, 1)) for x in tr_d[0]]
training_results = [vectorized_result(y) for y in tr_d[1]]
training_data = list(zip(training_inputs, training_results))
validation_inputs = [np.reshape(x, (784, 1)) for x in va_d[0]]
validation_data = list(zip(validation_inputs, va_d[1]))
test_inputs = [np.reshape(x, (784, 1)) for x in te_d[0]]
test_data = list(zip(test_inputs, te_d[1]))
return training_data, validation_data, test_data
#返回一个10维的单位向量,在第j位设置1.0,其他为0,用来表示网络的分类(0-9)
def vectorized_result(j):
e = np.zeros((10, 1))
e[j] = 1.0
return e
контрольная работа
import handwrite
import mnist_loader
training_data, validation_data, test_data = mnist_loader.load_data_wrapper()
net = handwrite.Network([784, 30, 10])
net.SGD(training_data, 30, 10, 3.0, test_data=test_data)
Результаты теста
Epoch 0: 8917 / 10000
Epoch 1: 9193 / 10000
Epoch 2: 9305 / 10000
Epoch 3: 9301 / 10000
Epoch 4: 9338 / 10000
Epoch 5: 9366 / 10000
Epoch 6: 9356 / 10000
Epoch 7: 9425 / 10000
Epoch 8: 9405 / 10000
Epoch 9: 9415 / 10000
Epoch 10: 9402 / 10000
Epoch 11: 9448 / 10000
Epoch 12: 9437 / 10000
Epoch 13: 9426 / 10000
Epoch 14: 9466 / 10000
Epoch 15: 9414 / 10000
Epoch 16: 9439 / 10000
Epoch 17: 9432 / 10000
Epoch 18: 9473 / 10000
Epoch 19: 9462 / 10000
Epoch 20: 9456 / 10000
Epoch 21: 9471 / 10000
Epoch 22: 9485 / 10000
Epoch 23: 9460 / 10000
Epoch 24: 9472 / 10000
Epoch 25: 9492 / 10000
Epoch 26: 9492 / 10000
Epoch 27: 9475 / 10000
Epoch 28: 9508 / 10000
Epoch 29: 9470 / 10000
Видно, что точность окончательных результатов испытаний близка к 95%.