Введение данных: в ex4data1 есть 5000 обучающих примеров. где каждый обучающий экземпляр представляет собой изображение в градациях серого размером 20 на 20 пикселей. Каждый пиксель представлен числом с плавающей запятой, представляющим интенсивность оттенков серого в этом месте. Эта сетка размером 20x20 пикселей «развёрнута» в 400-мерный вектор. Каждый из этих обучающих примеров становится одной строкой в матрице данных X. В результате получается матрица X размером 5000×400, где каждая строка является обучающим примером изображения рукописной цифры.
Набор данных находится в собственном формате MATLAB, поэтому для его загрузки в Python нам нужно использовать библиотеку SciPy.
1. Алгоритм прямого распространения
1.1 Отображение данных
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from scipy.io import loadmat
# 加载数据
data = loadmat('ex4data1.mat')
X, y = data['X'], data['y']
X.shape,y.shape
Визуализируйте данные:
def plot_100figs():
"""
画100幅图
"""
# 随机100个索引,不重复
sample_list = np.random.choice(np.arange(X.shape[0]), 100, replace=False)
# 从数据中取出这100个值
sample_data = X[sample_list, :]
# 画图, sharex,sharey:子图共享x轴,y轴, ax_array:一个10*10的矩阵
fig, ax_array = plt.subplots(nrows=10, ncols=10, sharex=True, sharey=True, figsize=(8, 8))
# 画子图
for r in range(10):
for c in range(10):
ax_array[r, c].matshow(sample_data[10 * r + c, :].reshape((20, 20)).T,
cmap=matplotlib.cm.binary)
# 去掉刻度线
plt.xticks([])
plt.yticks([])
plt.show()
1.2 Горячее кодирование
Чтобы обучить нейронную сеть, нам нужно перекодировать метки в векторы, содержащие только 0 или 1. Нейронные сети по существу состоят из множества одноузловых логистических регрессий (бинарная классификация).
Поскольку числа, взятые из исходного целевого значения, равны 1-10, а индекс каждой строки в новой метке равен 0-9, необходимоcols = y[row] - 1сделать его соответствующим.
1.3 Развертывание параметров
Чтобы использовать функцию оптимизации, такую как «scipy.optimize.minimize», нам нужно «развернуть» все элементы и поместить их в длинный вектор.
Две суммы суммируют потери логистической регрессии для каждой единицы в выходном слое, теперь мы имееми.
Без учета размерностей m и K уравнение, и, наконец, просуммируйте полученные двумерные массивы и разделите на m.
def cost(theta, X, y):
X = np.matrix(X)
y = np.matrix(y)
# 前馈运算获取hθ(x)
_,_,_,_,h = feed_forward(theta, X, y)
# 计算
# np.multiply是对应位置相乘
first = np.multiply(-y, np.log(h))
second = np.multiply((1 - y), np.log(1 - h))
front = np.sum(first - second) / (len(X))
return front
Результат: 0,2876291651613189
Уведомлениеnp.multiply()и@Разница в том, что первое — это умножение соответствующих позиций, а второе — умножение матриц.
Регулярная функция потерьИгнорировать при регуляризациииПервый столбец смещения не нуждается в оптимизации.
Очевидно, что первая половина согласуется с обычной функцией потерь, просто добавьте обычный член.
def regular_cost(theta, X, y, lambd):
front = cost(theta, X, y)
# 函数后半部分,忽略θ(1)和θ(2)的第一列
# 恢复θ
theta1, theta2 = deserialize(theta)
last = lambd / (2 * len(X)) * (np.sum(np.power(theta1[:, 1:], 2)) + np.sum(np.power(theta2[:, 1:], 2)))
return front + last
Результат: 0,38376985909092365
2. Алгоритм обратного распространения
Целью использования алгоритма обратного распространения по-прежнему является нахождение функции потерьПроизводная от , которая затем используется при оптимизации алгоритма градиентного спуска. Для получения информации о градиентном спуске для алгоритмов линейной регрессии и логистической регрессии см. мою предыдущую статью:Упражнение по машинному обучению 2. Реализация логистической регрессии в Python.
2.1 Сигмовидный градиент (градиентная сигмовидная функция, то есть производная от сигмовидной функции)
Указывает, какой слой вычисляется в данный момент,Он представляет количество рассчитанных в данный момент выборок,Представляет количество узлов в этом слое, которые вычисляются в данный момент.
Иллюстрация модели:
Псевдокод может быть выражен как:
1. Набор данных:
2. Настройки
3.for-loop:
Математическая формула включала:
Код говорит:
Регуляризация в настоящее время не рассматривается, т.е.,
вЕго не нужно решать, потому что потери не нужно учитывать при вводе сигнала. ударение сноваnp.multiply()и@Разница в том, что первое — это умножение соответствующих позиций, а второе — умножение матриц.
Возвращаемое значение является расширеннымценность, то естьпроизводное значение .
2.3 Регулярный алгоритм BP
В этот момент вводятся гиперпараметры.
Код:
Очевидно, что при j=0 вычисляется первый узел (член смещения) слоя., регуляризация не требуется. Когда j>=1, первая половина такая же, как и в обычном алгоритме bp, просто добавьте обычный член. В реализации кода метод установки первого столбца θ на ноль используется для достижения вышеуказанной цели.
Первый столбец параметра Θ является смещением и не нуждается в оптимизации.
Инициализация всех весов нулем сделает нейронную сеть бесполезной (этот подход работает в логистической регрессии). Потому что при расчете алгоритма обратного распространения веса на всех узлах будут обновляться до одинакового значения. Точно так же, если мы изначально установим для всех параметров ненулевое число, результат будет таким же. Это также известно как параметрическая симметрия.
Чтобы нарушить симметрию, нам нужно инициализировать переменные случайным образом.
Аналогично предыдущей функции рисования 100 графиков.
В вашей обучающей сети вы должны обнаружить, что скрытые единицы примерно соответствуют детекторам, которые ищут штрихи и другие шаблоны во входных данных.
def plot_hidden(final_theta):
"""
将隐层画出来
"""
# 获取theta1
theta1, _ = deserialize(final_theta) # (25, 401)
# 去掉偏置列
theta1 = theta1[:, 1:]
# 画图, sharex,sharey:子图共享x轴,y轴, ax_array:一个5*5的矩阵
fig, ax_array = plt.subplots(nrows=5, ncols=5, sharex=True, sharey=True, figsize=(8, 8))
# 画子图
for r in range(5):
for c in range(5):
ax_array[r, c].matshow(theta1[5 * r + c, :].reshape((20, 20)).T,
cmap=matplotlib.cm.binary)
# 去掉刻度线
plt.xticks([])
plt.yticks([])
plt.show()