机器学习正在成为数据科学中最具革命性的技术之一,它允许我们发现特征之间的非线性关系,并使用它来预测新的样本。机器学习中最简单的体例之一是多层感知器。在本文中,我将讨论多层感知器背后的概念,并向您展示如何在不使用流行的“scikit-learn”库的情况下用Python构建自己的多层感知器。我觉得,在没有库的情况下从零开始构建多层感知器,可以让我们更深入地了解反向传播和前馈等想法是如何工作的。
感知器
在措置多层感知器之前,我们先看一下简单很多的单层感知器。感知机接收n个来自不合特征x的输入,并给定不合权重w,产生一个输出。如果输入大于0,这个输出被放入一个函数,如果输入小于0,返回1(基本上是Heavyside函数)。
当最终二进制输出与训练集输出进行比较时,学习就会产生。两者之间的差别乘以学习率和输入值,并作为校正加到权重上。这是感知器中唯一产生的“反向传播”。正如我们稍后将看到的,当我们转向MLP时,这种反向传播的想法变得更加复杂。感知器可以很是容易地实现到python中,特别是对numpy高度优化的矩阵运算。这是感知器的Python代码:
import numpy as np
class Perceptron(object):
def __init__(self, learn, itr):
"""
:param learn: learning rate
:type learn: float
:param itr: number of iterations
:type itr: integer
"""
self.learn = learn
self.itr = itr
def train(self, x, y):
"""
Train the weights with data set x for outputs y
:param x: training data features
:type x: array (matrix) of n-samples, n-features
:param y: training data outputs
:type y: array of n-samples
:return: weights (w) and errors for each iteration
"""
self.w = np.zeros(1 + x.shape[1])
self.error = []
for _ in range(self.itr):
errors = 0
for xi, target in zip(x, y):
update = self.learn*(target - self.predict(xi))
self.w[1:] += update*xi
self.w[0] += update
errors += int(update != 0)
self.error.append(errors)
return self
def predict(self, x):
"""
:param x: input vector of features
:type x: ndarray
:return: int 1 or -1
"""
self.output = np.dot(x, self.w[1:]) + self.w[0]
return np.where(self.output >= 0, 1, -1)
现在我们已经看过了感知器,我们可以深入了解MLP的工作原理。
多层感知器
顾名思义,MLP基本上是编织在一起的感知层的组合。它使用第一层的输出作为下一层的输入,直到最后在特定命量的层之后,它达到输出层。输入和输出层之间的层称为隐藏层。与感知器一样,MLP也具有可调剂的权重以训练系统。现在,这些权重在层之间的每个连接处以矩阵形式呈现。
多层感知器背后的概念及Python实现-1.jpg (43.35 KB, 下载次数: 0)
2018-9-9 17:31 上传
前馈
建立MLP的第一部分是开发前馈算法。前馈基本上是用于将输入转换为输出的过程。然而,它其实不像感知器那样简单,但现在需要迭代不合数量的层。使用矩阵运算,这在python中相对容易完成:
def feedforward(self, x):
"""
Predict the output given the inputs
:param x: input vector of features
:type x: ndarray
:return: All activation values and x values.
"""
self.z0 = np.dot(self.w0, x)
self.output1 = self.sigmoid(self.z0)
self.z1 = np.matmul(self.w1, self.output1)
self.output2 = self.sigmoid(self.z1)
self.z2 = np.matmul(self.w2, self.output2)
self.output3 = self.sigmoid(self.z2)
return self.z0, self.output1, self.z1, self.output2, self.z2, self.output3
反向传播
现在是讨论任何MLP最重要的方面的时候了,它是反向传播。为了理解反向传播,我们需要了解基本的微积分知识。
反向传播主要依赖于链式法例。我们想知道如何改变特定神经元中的权重会影响预界说的本钱函数。因为我们有一个从权值集合到本钱函数的函数,因此我们可以根据权重进行微分。问题是我们没有从权重到本钱函数的这个函数的明确解决方案,所以我们需要利用链规则“step-by-step”:
多层感知器背后的概念及Python实现-2.jpg (3.23 KB, 下载次数: 0)
2018-9-9 17:31 上传
链式法例导数的每一个成分都是已知的。因此,这大大简化了反向传播所需的本钱函数梯度的计算。现在梯度酿成:
多层感知器背后的概念及Python实现-3.jpg (5.78 KB, 下载次数: 0)
2018-9-9 17:31 上传
每个组件都是已知的。每个训练样本的权重转变成:
多层感知器背后的概念及Python实现-4.jpg (1.19 KB, 下载次数: 0)
2018-9-9 17:31 上传
其中η是学习率,一个超参数,可用于改变权重转变的速率。这通常设置为较小的值,直到完成超参数的进一步优化。现在我们已经掌握了反向传播的工作原理,我们可以用Python代码编写它。
for _ in range(self.itr):
for xi, target in zip(self.x, self.y):
self.feedforward(xi)
cost = target.T - self.output3
for i in range(self.w2.shape[0]):
self.w2+= -self.learn * cost.sum() * \ self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2)) * \ self.output2for i in range(self.w1.shape[0]):
for j in range(self.w1.shape[1]):
self.w1[i, j] += -self.learn * cost.sum() * \ self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2)) * self.w2* \
self.sigmoid(self.z1) * (1 - self.sigmoid(self.z1)) * \ self.output1[j]
for i in range(self.w0.shape[0]):
for j in range(self.w0.shape[1]):
self.w0[i, j] += -self.learn * cost.sum() * \ self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2)) * self.w2* \
self.sigmoid(self.z1) * (1 - self.sigmoid(self.z1)) * \ self.w1[i, j] * self.sigmoid(self.z0) * (1 - \ self.sigmoid(self.z0)) * xi[j]
正如您所知,在代码中编写反向传播最困难的部分是措置numpy数组中的各种索引。
结论
编写多层感知器程序很是有趣,但实际功能并未优化。预先存在的库,例如keras使用各种工具来优化他们的模型。因此,如果您想从头开始建立机器学习和神经网络模型,请将其作为编码实践的一种形式,并作为一种提高您对模型自己的理解的体例。
更多内容回复查看:
游客,如果您要查看本帖隐藏内容请回复