当前位置: 首页 > 科技观察

Python中的多层感知器神经网络

时间:2023-03-12 14:03:04 科技观察

除非你能学到一些东西,否则不要重新发明轮子。强大的库已经存在,例如:TensorFlow、PyTorch、Keras等。我将介绍在Python中创建多层感知器(MLP)神经网络的基础知识。感知器是神经网络的基本构建块。感知器的输入函数是权重、偏差和输入数据的线性组合。具体来说:in_j=weightinput+bias。(in_j=权重输入+偏差)。在每个感知器上,我们可以指定一个激活函数g。激活函数是一种确保感知器“触发”或仅在达到特定输入水平后激活的数学方法。常见的非线性激活函数是sigmoid、softmax、整流线性单元(ReLU)或简单的tanH。激活函数有很多选项,但在本文中我们只涉及sigmoid和softmax。图1:感知器对于监督学习,我们随后将输入数据通过一系列隐藏层转发到输出层。这称为前向传播。在输出层,我们能够输出预测y。根据我们的预测y,我们可以计算误差|y*-y|并通过神经网络向后传播错误。这称为反向传播。通过随机梯度下降(SGD)过程,更新隐藏层中每个感知器的权重和偏差。图2:神经网络的基本结构现在我们已经介绍了基础知识,让我们来实现一个神经网络。我们神经网络的目标是对MNIST数据库中的手写数字进行分类。我将使用NumPy库进行基本矩阵计算。在我们的问题中,MNIST数据由[748,1]矩阵中的8位颜色通道表示。本质上,我们有一个从[0,1,....255]开始的[748,1]数字矩阵,其中0是白色,255是黑色。生成的MNIST手写数字数据库包含60,000个用于训练目的的手写示例和10,000个用于测试目的的示例。在对60,000个示例进行了30个epoch的训练后,我在测试数据集上运行了经过训练的神经网络,并获得了93.2%的准确率。它甚至可以通过调整超参数进一步优化。它是如何工作的?本文分为5个部分。这些部分是:激活函数权重初始化偏置初始化训练算法进行预测1.激活函数Sigmoid是由等式1/(1+exp(-x))定义的激活函数,将在隐藏层感知器中使用。Softmax是一种激活函数,当我们想要对输入进行分类时,通常在输出层使用它。在我们的例子中,我们想将一个数字分成10个桶[0,1,2,...,9]之一。它计算矩阵中每个条目的概率;概率总和为1。概率最高的条目将对应于其预测,即0,1,...,9。Softmax定义为exp(x)/sum(exp(x))。图3:激活函数的实现2.权重初始化对于我们的每个隐藏层,我们都需要初始化权重矩阵。有几种不同的方法可以做到这一点,这里是4.零初始化-初始化所有权重=0。随机初始化-权重是用随机数初始化的,而不是完全随机的。我们通常使用来自标准正态分布(均值0和方差1)的随机数。XavierInitialization-使用来自具有设定方差的正态分布的随机数初始化权重。我们将根据前一层的大小设置方差。如上所述,进入感知器的边与权重矩阵相乘。关键是矩阵的大小取决于当前层和之前层的大小。具体来说,权重矩阵的大小为[currentLayerSize,previousLayerSize]。如上所述,进入感知器的边与权重矩阵相乘。关键是矩阵的大小取决于当前层和之前层的大小。具体来说,权重矩阵的大小为[currentLayerSize,previousLayerSize]。假设我们有一个包含100个节点的隐藏层。我们的输入层大小为[748,1],我们想要的输出层大小为[10,1]。输入层和第一个隐藏层之间的权重矩阵的大小是[100,748]。隐藏层之间的每个权重矩阵的大小为[100,100]。最后,最终隐藏层和输出层之间的权重矩阵的大小为[10,100]。出于教育目的,我们将坚持使用单个隐藏层;在最终模型中,我们将使用多层。Figure4:Weightinitializationimplementation3.biasinitialization和weightinitialization一样,biasmatrix的大小取决于layersize,尤其是currentlayersize。初始化偏差的一种方法是将偏差设置为零。对于我们的实现,我们需要为每个隐藏层和输出层提供一个偏差。基于每个隐藏层100个节点,偏置矩阵的大小为[100,1],而输出层的大小为[10,1]。图5:偏差初始化的实现4.训练算法如前所述,训练基于随机梯度下降(SGD)的概念。在SGD中,我们一次只考虑一个训练点。在我们的示例中,我们将在输出层上使用softmax激活。损失将使用“交叉熵损失”公式计算。对于SGD,我们需要使用softmax来计算交叉熵损失的导数。也就是说,该导数减少为y-y,即预测y减去预期y。图6:softmax激活及其导数的交叉熵损失我们还需要编写sigmoid激活函数的导数。在图7中,我定义了sigmoid函数及其导数图7:Sigmoid函数(顶部)及其导数(底部)通常,神经网络将允许用户指定多个“超参数”。在我们的实现中,我们将专注于允许用户指定epoch、批量大小、学习率和动量。还有其他优化技术!学习率(LR):学习率是一个参数,用户通过该参数指定网络允许我们学习和更新其参数的速度。选择一个好的学习率是一门艺术。如果LR太高,我们可能永远不会收敛到可接受的良好训练误差。如果LR太低,我们可能会浪费大量的计算时间。epoch:一个epoch是对整个训练集的迭代。为了确保我们不会过度拟合早期样本中的数据,我们在每个纪元后对数据进行洗牌。Batchsize:通过Epoc2h的每次迭代,我们都会对训练数据进行批处理。对于批次中的每个训练点,我们将收集梯度并在批次完成后更新权重/偏差。动量:这是一个参数,我们将通过收集过去梯度的移动平均值并允许朝该方向移动来加速学习。在大多数情况下,这将导致更快的收敛。典型值范围从0.5到0.9。下面,我写了一些通用的伪代码来模拟反向传播学习算法的概况。为了可读性,计算输出和将训练数据分成批次等任务已写为注释。我们现在将展示伪代码的实现。5.做出预测我们现在只遗漏了这个实现的一个关键方面。预测算法。我们已经完成了编写反向传播算法的大部分工作。我们只需要使用相同的前向传递代码来进行预测。输出层的softmax激活函数将计算大小为[10,1]的矩阵中每个条目的概率。我们的目标是对从0到9的数字进行分类。因此,aj2矩阵的索引将对应于预测。概率最大的索引将由np.argmax()选择并作为我们的预测。结论就是这样!我们完成了。我们已经用Python编写了神经网络的实现。但是我们如何选择最佳参数呢?我们可以使用算法的一般知识来选择有意义的超参数。我们需要选择泛化但不会过度拟合数据的超参数。我们可以调整动量、学习率、时期数、批量大小和隐藏节点数来实现我们的目标。更进一步,我们可以编写更多算法来为我们做这件事!遗传算法是一种人工智能算法,可用于选择最佳参数。遗传算法的思想是创建一组具有不同参数的后代,并让它们产生依赖于参数的测试误差。我们可以传播和变异具有最佳超参数的神经网络,以找到性能更好的参数。花费大量时间后,我们将能够了解很多关于超参数的情况,并找到新的最优超参数值。我们可以做其他事情来减少测试错误吗?是的,我们可以缩放输入数据。与许多算法一样,较大的数字会对算法的结果产生重大影响。在我们的示例中,数字的范围是[0到255]。如果我们缩放数字使它们的范围从[0到1],则可以减少这种偏差。