Чтобы начать работу и понять глубокое обучение, некоторые из этих концепций неизбежно потребуют от вас понимания, например:
- что такое персептрон
- что такое нейронная сеть
- Тензоры и операции
- дифференциал
- градиентный спуск
начать с проблемы
Прежде чем начать, я надеюсь, что вы немного разбираетесь в машинном обучении.Предпосылка решения проблем заключается в том, чтобы задавать вопросы.Мы задаем такой вопрос, правильноMNIST数据集
Проанализируйте, а затем шаг за шагом в процессе решения проблемы, чтобы прояснить задействованные концепции.
MNIST数据集
набор для обучения письму отMNIST
, я думаю, вы не незнакомы с ним. Это классический набор данных в области машинного обучения. Я чувствую, что любой учебник может использовать его в качестве примера, но это также доказывает классику этого набора данных. Вот краткое изложение введение:
- Учебный набор из 60 000 примеров и тестовый набор из 10 000 примеров.
- Изображения представлены матрицей 28 × 28, и каждое изображение представлено 784-мерным вектором.
- Картинки разделены на 10 категорий, соответствующих от 0 до 9, всего 10 арабских цифр.
Содержимое сжатого пакета следующее:
- train-images-idx3-ubyte.gz: training set images (9912422 bytes)
- train-labels-idx1-ubyte.gz: training set labels (28881 bytes)
- t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)
- t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)
Выше:
Код генерации изображения выглядит следующим образом:
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
def plot_digits(instances, images_per_row=10, **options):
size = 28
images_per_row = min(len(instances), images_per_row)
images = instances
n_rows = (len(instances) - 1) // images_per_row + 1
row_images = []
n_empty = n_rows * images_per_row - len(instances)
images.append(np.zeros((size, size * n_empty)))
for row in range(n_rows):
rimages = images[row * images_per_row : (row + 1) * images_per_row]
row_images.append(np.concatenate(rimages, axis=1))
image = np.concatenate(row_images, axis=0)
plt.imshow(image, cmap = matplotlib.cm.binary, **options)
plt.axis("off")
plt.figure(figsize=(9,9))
plot_digits(train_images[:100], images_per_row=10)
plt.show()
Но вам не нужно пробовать это в спешке, Далее мы можем шаг за шагом разобрать набор для обучения письму.
Посмотрите на эту строку кода:
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
MNIST数据集
пройти черезkeras.datasets
нагрузка, гдеtrain_images
иtrain_labels
Формируется обучающая выборка, а две другие являются тестовой выборкой:
- train_images.shape: (60000, 28, 28)
- train_labels.shape: (60000,)
Нам нужно сделать очень просто.Закинуть обучающую выборку в нейронную сеть.После обучения генерируется нужная модель нейронной сети,а затем модель предсказывает тестовую выборку.Нам нужно только судить,верны ли предсказанные числа или не может
Прежде чем создавать нейронную сеть с помощью кода, позвольте мне кратко представить, что такое нейронная сеть, начнем с персептрона.
датчик
Персептрон — это искусственная нейронная сеть, состоящая из двух слоев нейронов, предложенная Фрэнком Розенблаттом, ее появление произвело в свое время сенсацию, ведь персептрон был первой нейронной сетью, способной обучаться
Персептрон работает следующим образом:
Три переменные слева представляют соответственно три различных двоичных входа, а выход представляет собой двоичный выход.Для множества входных данных некоторые входные данные могут быть действительными, а некоторые могут быть недействительными.Под влиянием такого количества входных данных, как судить вывод вывод? Розенблатт вводит веса, чтобы представить важность соответствующего входа.
В этот момент выход может быть выражен как:
Формула в правой части выше представляет собой ступенчатую функцию, которая представляет собой функцию активации, действующую как Sigmoid и Relu, и тогда мы можем сами реализовать персептрон:
import numpy as np
class Perceptron:
"""
代码实现 Frank Rosenblatt 提出的感知器的与非门,加深对感知器的理解
blog: https://www.howie6879.cn/post/33/
"""
def __init__(self, act_func, input_nums=2):
"""
实例化一些基本参数
:param act_func: 激活函数
"""
# 激活函数
self.act_func = act_func
# 权重 已经确定只会有两个二进制输入
self.w = np.zeros(input_nums)
# 偏置项
self.b = 0.0
def fit(self, input_vectors, labels, learn_nums=10, rate=0.1):
"""
训练出合适的 w 和 b
:param input_vectors: 样本训练数据集
:param labels: 标记值
:param learn_nums: 学习多少次
:param rate: 学习率
"""
for i in range(learn_nums):
for index, input_vector in enumerate(input_vectors):
label = labels[index]
output = self.predict(input_vector)
delta = label - output
self.w += input_vector * rate * delta
self.b += rate * delta
print("此时感知器权重为{0},偏置项为{1}".format(self.w, self.b))
return self
def predict(self, input_vector):
if isinstance(input_vector, list):
input_vector = np.array(input_vector)
return self.act_func(sum(self.w * input_vector) + self.b)
def f(z):
"""
激活函数
:param z: (w1*x1+w2*x2+...+wj*xj) + b
:return: 1 or 0
"""
return 1 if z > 0 else 0
def get_and_gate_training_data():
'''
AND 训练数据集
'''
input_vectors = np.array([[1, 1], [1, 0], [0, 1], [0, 0]])
labels = np.array([1, 0, 0, 0])
return input_vectors, labels
if __name__ == '__main__':
"""
输出如下:
此时感知器权重为[ 0.1 0.2],偏置项为-0.2 与门
1 and 1 = 1
1 and 0 = 0
0 and 1 = 0
0 and 0 = 0
"""
# 获取样本数据
and_input_vectors, and_labels = get_and_gate_training_data()
# 实例化感知器模型
p = Perceptron(f)
# 开始学习 AND
p_and = p.fit(and_input_vectors, and_labels)
# 开始预测 AND
print('1 and 1 = %d' % p_and.predict([1, 1]))
print('1 and 0 = %d' % p_and.predict([1, 0]))
print('0 and 1 = %d' % p_and.predict([0, 1]))
print('0 and 0 = %d' % p_and.predict([0, 0]))
сигмовидные нейроны
Нейроны и перцептроны по сути одинаковые, разница между ними в том, что функция активации разная, например функция перехода изменена на сигмовидную функцию
Нейронная сеть может регулировать веса и смещения искусственных нейронов посредством изучения выборок, чтобы сделать выходные результаты более точными, так как же разработать такой алгоритм для нейронной сети?
Взяв в качестве примера распознавание цифр, предположим, что сеть неправильно классифицирует изображение 9 как 8, мы можем внести небольшие изменения в веса и смещения, чтобы получить нужный нам результат, 9, то есть обучение. Для персептрона мы знаем, что возвращаемый результат равен 0 или 1. Очень вероятно, что такая ситуация произойдет.Мы, наконец, классифицируем цель, например, классифицируя изображение 9 как 8, и корректируем его обратно к исходному правильному классификация, но порог в это время и систематическая ошибка вызовут неправильную оценку других выборок, такая корректировка не является хорошим решением
Итак, нам нужен сигмовидный нейрон, потому что сигмовидный нейрон возвращает любое действительное число между [0, 1], так что небольшие изменения весов и смещений вызовут лишь небольшие изменения на выходе. Выход можно выразить как σ(w⋅x +b), а σ — сигмовидная функция.В сигмовидной функции S относится к сигмовидной функции, которая определяется следующим образом:
Нейронные сети
На самом деле нейронная сеть представляет собой множество нейронов, соединенных по определенным правилам.Нейронная сеть состоит из следующих компонентов:
- Входной слой: принимаем передаваемые данные, здесь должно быть 784 нейрона
- Скрытые слои: выявление особенностей
- Веса между слоями: учитываются автоматически
- Каждый скрытый слой будет иметь тщательно разработанную функцию активации, такую как Sigmoid, функция активации Relu.
- выходной слой, 10 выходов
- Выход предыдущего слоя используется как вход следующего слоя, и информация всегда распространяется вперед и никогда не возвращается обратно: нейронная сеть с прямой связью.
- Существуют циклы, в которых возможны циклы обратной связи: рекуррентные нейронные сети.
поступающие из входного слоя手写字训练集
, а затем передать данные обучающего набора вперед через скрытый слой, и, наконец, выходной слой выведет 10 значений вероятности, сумма которых равна 1. Теперь мы можем посмотреть наKeras
Код:
Первым шагом является предварительная обработка данных.Мы знаем, что исходная форма данных(60000, 28, 28)
, диапазон значений[0, 255]
, который теперь изменен на[0, 1]
:
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
Затем категорически закодируйте метки:
from keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
Второй шаг, напишите модель:
from keras import models
from keras import layers
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax')
network.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])
network.fit(train_images, train_labels, epochs=5, batch_size=128)
Скрытый слой, функция активации выбранаrelu
, выходной слой используетsoftmax
Возвращает массив из 10 значений вероятности, сумма которых равна 1.
При обучении показывается два числа: одно — потери сети на обучающих данныхloss
, другой - точность сети на обучающих данныхacc
Очень просто, мы строим и обучаем нейронную сеть, всего несколько строк кода, причина, по которой она написана так коротко, заключается в том, чтоkeras
Интерфейсный пакет проще в использовании, но нам все равно нужно изучить теоретические знания внутри.
Представление данных для нейронных сетей
TensorFlow
внутриTensor
Это означает тензор, Данные, хранящиеся в многомерном массиве Numpy в приведенном выше примере, являются тензором: тензор — это контейнер данных, матрица — двумерный тензор, а тензор — это обобщение матрицы на любой размерности. Размерность тензора называется осью
скаляр
Тензор, содержащий число, называется скаляром (0D-тензором) следующим образом:
x = np.array(12)
print(x, x.ndim)
# 12, 0
Число осей тензора также называют рангом
вектор
Массив чисел называется вектором (одномерным тензором) следующим образом:
x = np.array([12, 3, 6, 14, 7])
print(x, x.ndim)
# [12 3 6 14 7] 1
матрица
Массив векторов называется матрицей (двумерным тензором) следующим образом:
x = np.array([[5, 78, 2, 34, 0], [6, 79, 3, 35, 1], [7, 80, 4, 36, 2]])
print(x, x.ndim)
# [[ 5 78 2 34 0]
# [ 6 79 3 35 1]
# [ 7 80 4 36 2]] 2
Трехмерные тензоры против многомерных тензоров
Объединение нескольких матриц в новый массив представляет собой трехмерный тензор, как показано ниже:
x = np.array([[[5, 78, 2, 34, 0], [6, 79, 3, 35, 1]], [[5, 78, 2, 34, 0], [6, 79, 3, 35, 1]], [[5, 78, 2, 34, 0], [6, 79, 3, 35, 1]]])
print(x, x.ndim)
# (array([[[ 5, 78, 2, 34, 0],
# [ 6, 79, 3, 35, 1]],
#
# [[ 5, 78, 2, 34, 0],
# [ 6, 79, 3, 35, 1]],
#
# [[ 5, 78, 2, 34, 0],
# [ 6, 79, 3, 35, 1]]]), 3)
Объединение нескольких трехмерных тензоров в массив создает четырехмерный тензор.
ключевой атрибут
Тензоры определяются следующими тремя ключевыми свойствами:
- Количество осей: три оси для трехмерных тензоров, две оси для матриц
- Форма: это целочисленный кортеж, например, предыдущая матрица (3, 5), вектор (5,) и трехмерный тензор (3, 2, 5)
- тип данных
Тензор в работе в Numpy
ранее загруженныйtrain_images
за:
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
например, выбор фрагмента10~100
номера:
train_images[10:100].shape
# (90, 28, 28)
Концепция пакетной обработки данных
Модели глубокого обучения случайным образом разбивают набор данных на мини-пакеты для обработки, например:
batch = train_images[:128]
batch.shape
# (128, 28, 28)
тензоры реальных данных
Вот посмотрите на форму данных в реальном мире:
- Векторные данные: двумерные тензоры (образцы, признаки)
- Данные временных рядов или данные последовательности: трехмерные тензоры (выборки, временные интервалы, признаки)
- изображение: тензор 4D (образцы, высота, ширина, каналы) или (образцы, каналы, высота, ширина)
- видео: тензор 5D (образцы, кадры, высота, ширина, каналы) или (образцы, кадры, каналы, высота, ширина)
Тензорные операции
Расчеты, подобные компьютерным программам, могут быть преобразованы в двоичные вычисления, а вычисления глубокого обучения могут быть преобразованы в некоторые тензоры числовых данных.Тензорные операции(tensor operation)
Код скрытого слоя приведенной выше модели выглядит следующим образом:
keras.layers.Dense(512, activation='relu')
Этот слой можно понимать как функцию, которая вводит двумерный тензор и выводит двумерный тензор, точно так же, как функция вычисления, выводимая в последнем разделе персептрона выше:
output = relu(dot(W, input) + b)
Поэлементный расчет
И Relu, и операции сложения являются поэлементными операциями, такими как:
# 输入示例
input_x = np.array([[2], [3], [1]])
# 权重
W = np.array([[5, 6, 1], [7, 8, 1]])
# 计算输出 z
z = np.dot(W, input_x)
# 实现激活函数
def naive_relu(x):
assert len(x.shape) == 2
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i, j] = max(x[i, j], 0)
return x
# 激活函数对应的输出
output = naive_relu(z)
output
транслировать
В том разделе натяжения есть такой код:
output = relu(dot(W, input) + b)
dot(W, input)
является двумерным тензором,b
является вектором, что произойдет, если добавить два тензора разных форм?
Если нет двусмысленности, меньший тензор передается в соответствии с формой большего тензора:
input_x = np.array([[1], [3]])
# 权重
W = np.array([[5, 6], [7, 8]])
b = np.array([1])
# 计算输出 z
z = np.dot(W, input_x) + b
# array([[24],
# [32]])
Тензорное скалярное произведение
Операция скалярного произведения, также называемая тензорным произведением, например:
import numpy as np
# 输入示例
input_x = np.array([[2], [3], [1]])
# 权重
W = np.array([[5, 6, 1], [7, 8, 1]])
np.dot(W, input_x)
Скалярное произведение между двумя векторами является скаляром:
def naive_vector_dot(x, y):
assert len(x.shape) == 1
assert len(y.shape) == 1
assert x.shape[0] == y.shape[0]
z = 0.
for i in range(x.shape[0]):
z += x[i] * y[i]
return z
x = np.array([1,2])
y = np.array([1,2])
naive_vector_dot(x, y)
# 5.0
Скалярное произведение матрицы и вектора является вектором:
np.dot(W, [1, 2, 3])
# array([20, 26])
Тензорная деформация
При предварительной обработке данных перед:
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
В приведенном выше примере форма входных данных изменяется на (60000, 784). Деформация тензора относится к изменению строк и столбцов тензора для получения желаемой формы. Количество наборов данных до и после не изменяется. Часто встречаются специальные Тензорная деформация представляет собой транспозицию следующим образом:
x = np.zeros((300, 20))
x = np.transpose(x)
x.shape
# (20, 300)
Оптимизация градиента
Для каждого входа нейронная сеть преобразует входные данные с помощью следующей функции:
output = relu(dot(W, input_x) + b)
в:
- relu: функция активации
- W: тензор, представляющий вес, первый шаг может принимать небольшое случайное значение для случайной инициализации
- b: представляет собой тензор, представляющий смещение
Теперь нам нужен алгоритм, который позволит нам найти веса и смещения, такие что y = y (x) соответствует выборке входных данных x
вернуться к персептрону
Процесс обучения персептрона - это процесс, в котором веса и смещения постоянно настраиваются и обновляются.Смещения можно понимать как значение веса, вход которого равен 1, так как же обновляются веса?
Во-первых, представим понятие функции потерь, цитируя объяснение из книги «Статистические методы обучения» г-на Ли Ханга:
Задача обучения с супервизором состоит в том, чтобы выбрать в качестве решающей функции в пространстве гипотез модель F. Для данного входа X соответствующий выход Y задается f (x), а прогнозируемое значение f (x) этого выхода также равно согласуется с реальным значением y. Это может быть несовместимо с функцией потерь (функцией потерь) или функцией стоимости, измеряется степень ошибки прогнозирования, функция потерь представляет собой неотрицательную функцию реального значения F (x) и y, не забудьте L (Y, F (X))
Среди них средняя потеря модели f (X) о наборе обучающих данных называется: эмпирический риск, Вышеупомянутая корректировка веса предназначена для постоянной минимизации эмпирического риска и поиска лучшей модели f (X), мы не рассматриваем регуляризацию на данный момент, и целевая функция нашей оптимизации эмпирического риска:
Значение веса, соответствующее минимальной целевой функции, решается, что является соответствующим значением веса в нашем персептроне.Перед выводом мы должны понять две концепции:
- Что такое производная
- что такое градиент
Что такое производная
Предположим, что существует непрерывная гладкая функцияf(x) = y
, что такое функциональная непрерывность? Это означает, что небольшие изменения x могут привести только к небольшим изменениям y.
Предположим, что две точки на f(x)a,b
достаточно близко, тоa,b
могут быть аппроксимированы как линейная функция, где их наклон равенk
, то можно сказать, что наклон k равен f в точке bПроизводная
Таким образом, производная описывает, как изменяется f(x) при изменении x. Если вы хотите уменьшить значение f(x), просто переместите x на небольшой шаг в направлении, противоположном производной, и наоборот.
что такое градиент
Градиент является производной тензорной операции.Это обобщение понятия производной на производную многомерных функций.Он указывает на направление, в котором значение функции возрастает быстрее всего, а направление, в котором значение функции уменьшается быстрее всего, естественно противоположное направление градиента.
Стохастический градиентный спуск
Процесс получения выглядит следующим образом:
Этот раздел кода персептрона:
self.w += input_vector * rate * delta
Это соответствует правилам, полученным из приведенной выше формулы
Суммировать
Давайте посмотрим на весь код модели распознавания рукописных слов:
from keras import models
from keras import layers
from keras.utils import to_categorical
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))
network.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])
network.fit(train_images, train_labels, epochs=5, batch_size=128)
test_loss, test_acc = network.evaluate(test_images, test_labels)
print('test_acc:', test_acc)
- Входные данные сохраняются в
float32
форматированныйNumpy
В тензоре формы (60000, 784) и (10000, 784) - Структура нейронной сети: 1 входной слой, один скрытый слой и один выходной слой.
- categorical_crossentropy — функция потерь для моделей классификации.
- Каждая партия из 128 образцов, всего 5 итераций, всего обновлений (469 * 5) = 2345 раз
инструкция
Книги и статьи, которые повлияли на эту статью, благодаря их вкладу:
- [Статистические методы обучения] Глава 1
- Neural Networks and Deep LearningГлава Один
- Deep Learning with PythonГлава вторая
- hands_on_Ml_with_Sklearn_and_TF
- Вводная серия по глубокому обучению hanbt на основе нуля