оригинал:Deep Learning From Scratch II: Perceptrons - deep ideas
Перевод: Сунь Имэн
- Глава 1: Вычислительные графики
- Глава 2: Персептроны
- Глава 3: Стандарты обучения
- Глава 4: Градиентный спуск и обратное распространение
- Глава 5: Многослойные персептроны
- Глава 6: TensorFlow
Персептроны
захватывающий пример
感知机
Это небольшая форма нейронной сети, являющаяся базовым блоком более сложных структур.
Прежде чем углубляться в детали, давайте взглянем на этот захватывающий пример. Предположим, у нас есть набор данных из ста точек на плоскости, половина из которых — красные, а другая половина — синие.
Нажмите, чтобы запустить код и наблюдать за распределением баллов.
import numpy as np
import matplotlib.pyplot as plt[/amalthea_pre_exercise_code]
[amalthea_sample_code]
# 创建一些集中于 (-2, -2) 的红点
red_points = np.random.randn(50, 2) - 2*np.ones((50, 2))
# 创建一些集中于 (2, 2) 的蓝点
blue_points = np.random.randn(50, 2) + 2*np.ones((50, 2))
# 把红点和蓝点都在图上画出来
plt.scatter(red_points[:,0], red_points[:,1], color='red')
plt.scatter(blue_points[:,0], blue_points[:,1], color='blue')
Как показано на рисунке, красные точки сосредоточены в, а синие точки фокусируются на. Глядя на данные, как вы думаете, есть ли способ определить, красная точка или синяя?
если вы спроситеКакого она цвета, синий вы ответите сразу, даже если этой точки нет в приведенных выше данных, мы все равно можем судить о ее цвете по области (синей) в которой она находится.
Но есть ли более общий способ сделать вывод, что синий цвет более вероятен? Очевидно, мы можем провести линию на графике выше, идеально делит пространство на красную и синюю зоны.
# 创建一些集中于 (-2, -2) 的红点
red_points = np.random.randn(50, 2) - 2*np.ones((50, 2))
# 创建一些集中于 (2, 2) 的蓝点
blue_points = np.random.randn(50, 2) + 2*np.ones((50, 2))
# 把红点和蓝点都在图上画出来
plt.scatter(red_points[:,0], red_points[:,1], color='red')
plt.scatter(blue_points[:,0], blue_points[:,1], color='blue')[/amalthea_pre_exercise_code]
[amalthea_sample_code]
# 画一条线 y = -x
x_axis = np.linspace(-4, 4, 100)
y_axis = -x_axis
plt.plot(x_axis, y_axis)
мы можем использовать权向量
и偏置
неявно представлять линию, точку на линиивстречает.
Подставьте данные в приведенном выше примере, чтобы получить , . следовательноравный.
Таким образом, эту строку можно выразить так:
Ну, а теперь, чтобы судить, красное оно или синее, просто оцените, находится оно выше или ниже линии: поставьте точкузаменять, по знаку результата, если он положительный,Чуть выше линии, минус чуть ниже.
Как пункт выше:
, поэтому точка находится над линией, поэтому она синяя.
Определение персептрона
Часто分类器
(classifier
) функция: { }, вы можете сопоставить точку с категорией (всего категорий C).
и один二元分类器
То есть всего есть две категории ()из分类器
.
Что мы используем, чтобы судить о красной точке и синей точке感知机
, это二元分类器
,ви偏置
:
это,будетОн разделен на два пространства, каждое из которых соответствует категории.
Примерами красных и синих точек являются двумерные (размер), в двумерном случае пространство разделено по линии. способствоватьВ случае размерности деление плоскости всегда происходит вдольразмерная гиперплоскость.
От классификации категорий к расчету вероятностей
В практических приложениях мы не только хотим знать, к какому классу, скорее всего, относится точка, мы также задаемся вопросом, какова вероятность того, что точка принадлежит к определенному классу.
Прежде чем судить о красном и синем, подставим данные точки x, если получимЧем выше значение, тем дальше эта точка должна быть от разделительной линии, и тем больше мы уверены, что она синяя.
но когда мы получаемПри значении , мы не можем сказать, велико оно или нет. Затем, чтобы преобразовать это значение в вероятность, мы можем сжать значения, чтобы они были распределены между 0 и 1.
Это можно сделать сsigmoid
Функция σ реализует:
в
Посмотримsigmoid
Реализация функции:
import matplotlib.pyplot as plt
import numpy as np
# 创建从 -5 到 5 的间隔,步长 0.01
a = np.arange(-5, 5, 0.01)
# 计算对应的 sigmoid 函数的值
s = 1 / (1 + np.exp(-a))
# 画出结果
plt.plot(a, s)
plt.grid(True)
plt.show()
Как показано, когда, то есть когда точка лежит на разделительной линии,sigmoid
Вероятность того, что функция получит это значение, соответствует 0,5. По мере приближения асимптоты к 1Чем больше значение , тем ближе асимптота к 0, темтем меньше значение.
Оправдать наши ожидания.
Теперь давайте определимsigmoid
функциональныйOperation
,этоOperation
Мы будем использовать позже:
class Operation:
"""Represents a graph node that performs a computation.
An `Operation` is a node in a `Graph` that takes zero or
more objects as input, and produces zero or more objects
as output.
"""
def __init__(self, input_nodes=[]):
"""Construct Operation
"""
self.input_nodes = input_nodes
# Initialize list of consumers (i.e. nodes that receive this operation's output as input)
self.consumers = []
# Append this operation to the list of consumers of all input nodes
for input_node in input_nodes:
input_node.consumers.append(self)
# Append this operation to the list of operations in the currently active default graph
_default_graph.operations.append(self)
def compute(self):
"""Computes the output of this operation.
"" Must be implemented by the particular operation.
"""
pass
class Graph:
"""Represents a computational graph
"""
def __init__(self):
"""Construct Graph"""
self.operations = []
self.placeholders = []
self.variables = []
def as_default(self):
global _default_graph
_default_graph = self
class placeholder:
"""Represents a placeholder node that has to be provided with a value
when computing the output of a computational graph
"""
def __init__(self):
"""Construct placeholder
"""
self.consumers = []
# Append this placeholder to the list of placeholders in the currently active default graph
_default_graph.placeholders.append(self)
class Variable:
"""Represents a variable (i.e. an intrinsic, changeable parameter of a computational graph).
"""
def __init__(self, initial_value=None):
"""Construct Variable
Args:
initial_value: The initial value of this variable
"""
self.value = initial_value
self.consumers = []
# Append this variable to the list of variables in the currently active default graph
_default_graph.variables.append(self)
class add(Operation):
"""Returns x + y element-wise.
"""
def __init__(self, x, y):
"""Construct add
Args:
x: First summand node
y: Second summand node
"""
super().__init__([x, y])
def compute(self, x_value, y_value):
"""Compute the output of the add operation
Args:
x_value: First summand value
y_value: Second summand value
"""
return x_value + y_value
class matmul(Operation):
"""Multiplies matrix a by matrix b, producing a * b.
"""
def __init__(self, a, b):
"""Construct matmul
Args:
a: First matrix
b: Second matrix
"""
super().__init__([a, b])
def compute(self, a_value, b_value):
"""Compute the output of the matmul operation
Args:
a_value: First matrix value
b_value: Second matrix value
"""
return a_value.dot(b_value)
class Session:
"""Represents a particular execution of a computational graph.
"""
def run(self, operation, feed_dict={}):
"""Computes the output of an operation
Args:
operation: The operation whose output we'd like to compute.
feed_dict: A dictionary that maps placeholders to values for this session
"""
# Perform a post-order traversal of the graph to bring the nodes into the right order
nodes_postorder = traverse_postorder(operation)
# Iterate all nodes to determine their value
for node in nodes_postorder:
if type(node) == placeholder:
# Set the node value to the placeholder value from feed_dict
node.output = feed_dict[node]
elif type(node) == Variable:
# Set the node value to the variable's value attribute
node.output = node.value
else: # Operation
# Get the input values for this operation from node_values
node.inputs = [input_node.output for input_node in node.input_nodes]
# Compute the output of this operation
node.output = node.compute(*node.inputs)
# Convert lists to numpy arrays
if type(node.output) == list:
node.output = np.array(node.output)
# Return the requested node value
return operation.output
def traverse_postorder(operation):
"""Performs a post-order traversal, returning a list of nodes
in the order in which they have to be computed
Args:
operation: The operation to start traversal at
"""
nodes_postorder = []
def recurse(node):
if isinstance(node, Operation):
for input_node in node.input_nodes:
recurse(input_node)
nodes_postorder.append(node)
recurse(operation)
return nodes_postorder
[/amalthea_pre_exercise_code]
[amalthea_sample_code]
class sigmoid(Operation):
"""返回元素 x 的 sigmoid 结果。
"""
def __init__(self, a):
"""构造 sigmoid
参数列表:
a: 输入节点
"""
super().__init__([a])
def compute(self, a_value):
"""计算本 sigmoid operation 的输出
参数列表:
a_value: 输入值
"""
return 1 / (1 + np.exp(-a_value))
def reTrue():
return True
reTrue()
1. Приведите пример
Теперь мы можем сделать Python感知机
, чтобы решить предыдущую красно-синюю проблему. использовать это снова感知机
считатьэто вероятность синей точки
# 创建一个新 graph
Graph().as_default()
x = placeholder()
w = Variable([1, 1])
b = Variable(0)
p = sigmoid( add(matmul(w, x), b) )
session = Session()
print(session.run(p, {
x: [3, 2]
}))
Мультиклассовый персептрон
До сих пор мы использовали только感知机
сделал бинарный分类器
, используется для расчета вероятности того, что точка принадлежит к определенной категории (всего две категории), то, естественно, вероятность принадлежности к другому классу равна.
Но часто на практике количество категорий будет больше двух. Например, при классификации изображений может быть много категорий для вывода (например, собаки, стулья, люди, дома и т. д.).
Поэтому мы будем感知机
Расширьте его, чтобы поддерживать возможность экспорта нескольких категорий.
мы по-прежнему берем константукак количество категорий. Но больше не используйте предыдущее двоичное время权向量
, но ввести权矩阵
.
权矩阵
Каждый столбец содержит отдельный线性分类器
веса в , по одному для каждой категории分类器
.
В двоичном формате мы должны вычислитьизскалярное произведение, и теперь мы хотим вычислить. рассчитатьвозвращеноВектор , его члены можно рассматривать как权矩阵
Результат скалярного произведения разных столбцов.
Затем мы конвертируем векторплюс偏置向量
. векторТовар соответствует категории.
Это создаетВектор , каждый элемент этого вектора представляет, что точка принадлежит к определенной категории (всегокатегории) возможность.
Процесс может показаться сложным, но на самом деле это умножение матриц является просто параллельнымкаждая из категорий, выполняет свои соответствующие线性分类器
Вот и все, у каждого из них есть своя разделительная линия, и эту разделительную линию можно еще определить по заданному вектору весов и偏置
Неявное представление, но здесь权向量
Зависит от权矩阵
Столбцы предоставляются, в то время как偏置
являетсяЭлементы вектора.
1. Softmax
оригинальный感知机
Сгенерируйте один скаляр, черезsigmoid
, мы сжимаем этот скаляр, чтобы получить вероятность, распределенную между 0 и 1.
Продвижение в несколько категорий感知机
, который генерирует вектор. Точно так жеЧем больше значение терма, тем больше мы уверены, что входная точка принадлежит первомукатегории.
Следовательно, мы также хотим преобразовать векторПреобразованный в вектор вероятности, каждый элемент вектора представляет вероятность того, что входное значение принадлежит каждой категории, каждый элемент вектора распределен между 0 и 1, а сумма всех элементов равна 1.
Для этого обычно используютsoftmax
функция.Softmax
Функция на самом делеsigmoid
Обобщение в случае многоклассового вывода:
[math] ? \sigma(a)_i = \frac{e^{a_i}}{\sum_{j=1}^C e^{a_j}} ? [/math]
class softmax(Operation):
"""返回 a 的 softmax 函数结果.
"""
def __init__(self, a):
"""构造 softmax
参数列表:
a: 输入节点
"""
super().__init__([a])
def compute(self, a_value):
"""计算 softmax operation 的输出值
参数列表:
a_value: 输入值
"""
return np.exp(a_value) / np.sum(np.exp(a_value), axis=1)[:, None]
2. Пакетный расчет
Мы можем передать сразу несколько значений в виде матрицы. То есть, раньше мы могли проходить только по одной точке за раз, теперь мы можем проходить по матрице за раз, каждая строка матрицы содержит точку (всегострока, содержащаяКусокизмерение).
Мы называем эту матрицу пакетом.
В этом случае мы вычисляемвместо. рассчитатьвернетматрица, каждая строка матрицы содержит.
Давайте добавим еще одну строку в каждую строку偏置向量
(В настоящее времяЯвляетсявектор строки).
Таким образом, весь процесс вычисляет функцию,в. здесь计算图
следующее:
3. Пример
Давайте обобщим предыдущий красно-синий пример для поддержки пакетных вычислений и многоклассового вывода.
# 创建一个新 graph
Graph().as_default()
X = placeholder()
# 为两种输出类别创建一个权矩阵:
# 蓝色的权向量是 (1, 1) ,红色是 (-1, -1)
W = Variable([
[1, -1],
[1, -1]
])
b = Variable([0, 0])
p = softmax( add(matmul(X, W), b) )
# 创建一个 Session,针对我们的蓝色/红色点运行 perceptron
session = Session()
output_probabilities = session.run(p, {
X: np.concatenate((blue_points, red_points))
})
# 打印前 10 行, 也就是前 10 个点的概率
print(output_probabilities[:10])
Поскольку все первые 10 точек в наборе данных окрашены в синий цвет, вывод персептрона, скорее всего, будет синим (левый столбец), а не красным.
Если у вас есть какие-либо вопросы, не стесняйтесь задавать их в разделе комментариев к оригинальному сообщению.