Faizan Shaikh作者张一豪校对黄继彦编辑李文婧翻译

数据科学家的必备读物:从零开始用Python构建循环神经网络(附代码)

本文带你快速浏览典型NN模型核心部分,并教你构建RNN解决相关问题。

引言

人类不会每听到一个句子就对语言进行重新理解。看到一篇文章时,我们会根据之前对这些词的理解来了解背景。我们将其定义为记忆力。

算法可以复制这种模式吗?神经网络(NN)是最先被想到的技术。但令人遗憾的是传统的神经网络还无法做到这一点。 举个例子,如果让传统的神经网络预测一个视频中接下来会发生什么,它很难有精确的结果。

这就是循环神经网络(RNN)发挥作用的地方。循环神经网络深度学习领域非常热门,因此,学习循环神经网络势在必行。循环神经网络在现实生活中的一些实际应用:     

  • 语音识别

  • 机器翻译

  • 音乐创作

  • 手写识别

  • 语法学习

在这篇文章中,我们首先对一个典型的循环神经网络模型的核心部分进行快速浏览。然后我们将设置问题陈述,最后我们将从零开始用Python构建一个循环神经网络模型解决这些问题陈述。

我们总是习惯用高级Python库编写循环神经网络。那为什么还要从零开始编码呢?我坚信从头学习是学习和真正理解一个概念的最佳方式。这就是我将在本教程中展示的内容。

本文假设读者已对循环神经网络有基本的了解。如果您需要快速复习或希望学习循环神经网络的基础知识,我建议您先阅读下面两篇文章:

  • 深度学习的基础知识

    https://www.analyticsvidhya.com/blog/2016/03/introduction-deep-learning-fundamentals-neural-networks/


  • 循环神经网络简介

    https://www.analyticsvidhya.com/blog/2017/12/introduction-to-recurrent-neural-networks/

目录

一、快速回顾:循环神经网络概念回顾

二、使用循环神经网络进行序列预测

三、使用Python构建循环神经网络模型

一、快速回顾:循环神经网络概念回顾

让我们快速回顾一下循环神经网络的核心概念。我们将以一家公司的股票的序列数据为例。一个简单的机器学习模型或人工神经网络可以根据一些特征预测股票价格,比如股票的数量,开盘价值等。除此之外,该股票在之前的几天和几个星期的表现也影响着股票价格。对交易者来说,这些历史数据实际上是进行预判的主要决定因素。

在传统的前馈神经网络中,所有测试用例都被认为是独立的。 在预测股价时,你能看出那不是一个合适的选择吗? 神经网络模型不会考虑之前的股票价格 – 这不是一个好想法!

面对时间敏感数据时,我们可以利用另一个概念 — 循环神经网络(RNN)

典型的循环神经网络如下所示:

这刚开始看起来可能很吓人。 但是如果我们展开来讲,事情就开始变得更简单:

现在,我们更容易想象出这些循环神经网络如何预测股票价格的走势。这有助于我们预测当天的价格。这里,有关时间t(h_t)的每个预测都需要依赖先前所有的预测和从它们那学习到的信息。相当直截了当吧?

循环神经网络可以在很大程度上帮助我们解决序列处理问题。 

文本是序列数据的另一个好例子。一旦给定文本之后,循环神经网络就可以预测出接下来将会出现的单词或短语,这可将是非常有用的资产。我们希望我们的循环神经网络可以写出莎士比亚的十四行诗!

现在,循环神经网络在涉及短或小的环境时非常棒。 但是为了能够构建一个故事并记住它,我们的循环神经网络模型应该能理解序列背后的背景,就像人脑一样。

二、使用循环神经网络进行序列预测

在本文中,我们将使用循环神经网络处理序列预测问题。对此最简单的例子之一是正弦波预测。序列包含可见趋势,使用启发式方式很容易解决。下面就是正弦波的样子:

我们首先从零开始设计一个循环神经网络解决这个问题。 我们的循环神经网络模型也应该得到很好地推广,以便我们可以将其应用于其他序列问题。    我们将像这样制定我们的问题:给定一个属于正弦波的50个数字的序列,预测系列中的第51个数字。 是时候打开你的Jupyter notebook(一个交互式笔记本,支持运行 40 多种编程语言)或你选择的IDE(Integrated Development Environment,是一种编程软件)!

三、使用Python编码循环神经网络

第0步:数据准备

在做任何其他事情之前,数据准备是任何数据科学项目中不可避免的第一步。我们的网络模型期望数据是什么样的? 它将输入长度为50的单个序列。所以输入数据的形状将是:

(number_of_records x length_of_sequence x types_of_sequences)

这里,types_of_sequence是1,因为我们只有一种类型的序列—正弦波。

另一方面,每次记录的输出只有一个值。那就是输入序列中的第51个值。 所以它的形状将是:

(number_of_records x types_of_sequences) #where types_of_sequences is 1

让我们深入研究这个代码。首先,导入必要的库:

%pylab inline

import math

创建像数据一样的正弦波,我们将使用Python数学库中的正弦函数:

sin_wave = np.array([math.sin(x) for x in np.arange(200)])

将刚刚生成的正弦波可视化:

plt.plot(sin_wave[:50])

我们现在将在下面的代码块中创建数据:

X = []

Y = []

seq_len = 50

num_records = len(sin_wave) - seq_len

for i in range(num_records - 50):

    X.append(sin_wave[i:i+seq_len])

    Y.append(sin_wave[i+seq_len])

   X = np.array(X)

X = np.expand_dims(X, axis=2)

Y = np.array(Y)

Y = np.expand_dims(Y, axis=1)

打印数据的形状:

X.shape, Y.shape

((100, 50, 1), (100, 1))

请注意,我们循环(num_records  -  50),是因为我们想要留出50条记录作为验证数据。现在我们可以创建这个验证数据:

X_val = []

Y_val = []

for i in range(num_records - 50, num_records):

    X_val.append(sin_wave[i:i+seq_len])

    Y_val.append(sin_wave[i+seq_len])

    X_val = np.array(X_val)

X_val = np.expand_dims(X_val, axis=2)

Y_val = np.array(Y_val)

Y_val = np.expand_dims(Y_val, axis=1)

第1步:为我们的循环神经网络模型创建架构

我们接来下的任务是将我们在循环神经网络模型中使用的所有必要变量和函数进行定义。我们的循环神经网络模型将接受输入序列,通过100个单位的隐藏层处理它,并产生单值输出:

learning_rate = 0.0001    

nepoch = 25               

T = 50                   # length of sequence

hidden_dim = 100         

output_dim = 1

bptt_truncate = 5

min_clip_value = -10

max_clip_value = 10

然后我们将定义网络的权重

U = np.random.uniform(0, 1, (hidden_dim, T))

W = np.random.uniform(0, 1, (hidden_dim, hidden_dim))

V = np.random.uniform(0, 1, (output_dim, hidden_dim))

其中:

  • U是输入和隐藏图层之间权重权重矩阵

  • V是隐藏层和输出层之间权重权重矩阵

  • W是循环神经网络层(隐藏层)中共享权重权重矩阵

最后,我们将定义在隐藏层中使用S型函数:

def sigmoid(x):

    return 1 / (1 + np.exp(-x))

第2步:训练模型

既然我们已经定义了模型,最后我们就可以继续训练我们的序列数据了。我们可以将训练过程细分为更小的步骤,即:

步骤2.1:检查训练数据是否丢失

    步骤2.1.1:前馈传递

    步骤2.1.2:计算误差

步骤2.2:检查验证数据是否丢失

    步骤2.2.1前馈传递

    步骤2.2.2:计算误差

步骤2.3:开始实际训练

    步骤2.3.1:正推法

    步骤2.3.2:反向传递误差

    步骤2.3.3:更新权重

我们需要重复这些步骤直到数据收敛。 如果模型开始过拟合,请停止! 或者只是预先定义epoch的数量。

  • 步骤2.1:检查训练数据是否丢失

我们将通过我们的循环神经网络模型进行正推法,并计算所有记录的预测的平方误差,以获得损失值。

for epoch in range(nepoch):

    # check loss on train

    loss = 0.0

       # do a forward pass to get prediction

    for i in range(Y.shape[0]):

        x, y = X[i], Y[i]                    # get input, output values of each record

        prev_s = np.zeros((hidden_dim, 1))   # here, prev-s is the value of the previous activation of hidden layer; which is initialized as all zeroes

        for t in range(T):

            new_input = np.zeros(x.shape)    # we then do a forward pass for every timestep in the sequence

            new_input[t] = x[t]              # for this, we define a single input for that timestep

            mulu = np.dot(U, new_input)

            mulw = np.dot(W, prev_s)

            add = mulw + mulu

            s = sigmoid(add)

            mulv = np.dot(V, s)

            prev_s = s

    # calculate error

        loss_per_record = (y - mulv)**2 / 2

        loss += loss_per_record

    loss = loss / float(y.shape[0])

  • 步骤2.2:检查验证数据是否丢失

我们将对计算验证数据的损失做同样的事情(在同一循环中):

     # check loss on val

    val_loss = 0.0

    for i in range(Y_val.shape[0]):

        x, y = X_val[i], Y_val[i]

        prev_s = np.zeros((hidden_dim, 1))

        for t in range(T):

            new_input = np.zeros(x.shape)

            new_input[t] = x[t]

            mulu = np.dot(U, new_input)

            mulw = np.dot(W, prev_s)

            add = mulw + mulu

            s = sigmoid(add)

            mulv = np.dot(V, s)

            prev_s = s

        loss_per_record = (y - mulv)**2 / 2

        val_loss += loss_per_record

    val_loss = val_loss / float(y.shape[0])


    print('Epoch: ', epoch + 1, ', Loss: ', loss, ', Val Loss: ', val_loss)

你应该会得到以下输出:

Epoch:  1 , Loss:  [[101185.61756671]] , Val Loss:  [[50591.0340148]]

...

...

  • 步骤2.3:开始实际训练

现在我们开始对网络进行实际训练。在这里,我们首先进行正推法计算误差,然后使用逆推法来计算梯度并更新它们。让我逐步向您展示这些内容,以便您可以直观地了解它的工作原理。

  • 步骤2.3.1:正推法

正推法步骤如下

  1. 我们首先将输入与输入和隐藏层之间的权重相乘;

  2. 在循环神经网络层中添加权重乘以此项,这是因为我们希望获取前一个时间步的内容;

  3. 通过sigmoid 激活函数将其与隐藏层和输出层之间的权重相乘;

  4. 在输出层,我们对数值进行线性激活,因此我们不会通过激活层传递数值;

  5. 在字典中保存当前图层的状态以及上一个时间步的状态。

这是执行正推法的代码(请注意,它是上述循环的继续):

     # train model

    for i in range(Y.shape[0]):

        x, y = X[i], Y[i]

           layers = []

        prev_s = np.zeros((hidden_dim, 1))

        dU = np.zeros(U.shape)

        dV = np.zeros(V.shape)

        dW = np.zeros(W.shape)

        dU_t = np.zeros(U.shape)

        dV_t = np.zeros(V.shape)

        dW_t = np.zeros(W.shape)

        dU_i = np.zeros(U.shape)

        dW_i = np.zeros(W.shape)

          # forward pass

          for t in range(T):

            new_input = np.zeros(x.shape)

            new_input[t] = x[t]

            mulu = np.dot(U, new_input)

            mulw = np.dot(W, prev_s)

            add = mulw + mulu

            s = sigmoid(add)

            mulv = np.dot(V, s)

            layers.append({'s':s, 'prev_s':prev_s})

            prev_s = s

  • 步骤2.3.2:反向传播误差

在前向传播步骤之后,我们计算每一层的梯度,并反向传播误差。 我们将使用截断反向传播时间(TBPTT),而不是vanilla backprop(反向传播的非直观效应的一个例子)。这可能听起来很复杂但实际上非常直接。

BPTT与backprop的核心差异在于,循环神经网络层中的所有时间步骤,都进行了反向传播步骤。 因此,如果我们的序列长度为50,我们将反向传播当前时间步之前的所有时间步长。

如果你猜对了,那么BPTT在计算上看起来非常昂贵。 因此,我们不是反向传播所有先前的时间步,而是反向传播直到x时间步以节省计算能力。考虑这在概念上类似于随机梯度下降,我们包括一批数据点而不是所有数据点。

以下是反向传播误差的代码:

         # derivative of pred

        dmulv = (mulv - y)

         # backward pass

        for t in range(T):

            dV_t = np.dot(dmulv, np.transpose(layers[t]['s']))

            dsv = np.dot(np.transpose(V), dmulv)

             ds = dsv

            dadd = add * (1 - add) * ds

            dmulw = dadd * np.ones_like(mulw)

            dprev_s = np.dot(np.transpose(W), dmulw)

            for i in range(t-1, max(-1, t-bptt_truncate-1), -1):

                ds = dsv + dprev_s

                dadd = add * (1 - add) * ds

                dmulw = dadd * np.ones_like(mulw)

                dmulu = dadd * np.ones_like(mulu)

                dW_i = np.dot(W, layers[t]['prev_s'])

                dprev_s = np.dot(np.transpose(W), dmulw)

                new_input = np.zeros(x.shape)

                new_input[t] = x[t]

                dU_i = np.dot(U, new_input)

                dx = np.dot(np.transpose(U), dmulu)

                dU_t += dU_i

                dW_t += dW_i

               dV += dV_t

               dU += dU_t

   dW += dW_t

  • 步骤2.3.3:更新权重

最后,我们使用计算的权重梯度更新权重。 有一件事我们必须记住,如果不对它们进行检查,梯度往往会爆炸。这是训练神经网络的一个基本问题,称为梯度爆炸问题。 所以我们必须将它们夹在一个范围内,这样它们就不会增长得太快。 我们可以这样做:

            if dU.max() > max_clip_value:

                dU[dU > max_clip_value] = max_clip_value

            if dV.max() > max_clip_value:

                dV[dV > max_clip_value] = max_clip_value

            if dW.max() > max_clip_value:

                dW[dW > max_clip_value] = max_clip_value

               if dU.min() < min_clip_value:

                dU[dU < min_clip_value] = min_clip_value

            if dV.min() < min_clip_value:

                dV[dV < min_clip_value] = min_clip_value

            if dW.min() < min_clip_value:

                dW[dW < min_clip_value] = min_clip_value

               # update

        U -= learning_rate * dU

        V -= learning_rate * dV

        W -= learning_rate * dW

在训练上述模型时,我们得到了这个输出:

Epoch:  1 , Loss:  [[101185.61756671]] , Val Loss:  [[50591.0340148]]

Epoch:  2 , Loss:  [[61205.46869629]] , Val Loss:  [[30601.34535365]]

Epoch:  3 , Loss:  [[31225.3198258]] , Val Loss:  [[15611.65669247]]

Epoch:  4 , Loss:  [[11245.17049551]] , Val Loss:  [[5621.96780111]]

Epoch:  5 , Loss:  [[1264.5157739]] , Val Loss:  [[632.02563908]]

Epoch:  6 , Loss:  [[20.15654115]] , Val Loss:  [[10.05477285]]

Epoch:  7 , Loss:  [[17.13622839]] , Val Loss:  [[8.55190426]]

Epoch:  8 , Loss:  [[17.38870495]] , Val Loss:  [[8.68196484]]

Epoch:  9 , Loss:  [[17.181681]] , Val Loss:  [[8.57837827]]

Epoch:  10 , Loss:  [[17.31275313]] , Val Loss:  [[8.64199652]]

Epoch:  11 , Loss:  [[17.12960034]] , Val Loss:  [[8.54768294]]

Epoch:  12 , Loss:  [[17.09020065]] , Val Loss:  [[8.52993502]]

Epoch:  13 , Loss:  [[17.17370113]] , Val Loss:  [[8.57517454]]

Epoch:  14 , Loss:  [[17.04906914]] , Val Loss:  [[8.50658127]]

Epoch:  15 , Loss:  [[16.96420184]] , Val Loss:  [[8.46794248]]

Epoch:  16 , Loss:  [[17.017519]] , Val Loss:  [[8.49241316]]

Epoch:  17 , Loss:  [[16.94199493]] , Val Loss:  [[8.45748739]]

Epoch:  18 , Loss:  [[16.99796892]] , Val Loss:  [[8.48242177]]

Epoch:  19 , Loss:  [[17.24817035]] , Val Loss:  [[8.6126231]]

Epoch:  20 , Loss:  [[17.00844599]] , Val Loss:  [[8.48682234]]

Epoch:  21 , Loss:  [[17.03943262]] , Val Loss:  [[8.50437328]]

Epoch:  22 , Loss:  [[17.01417255]] , Val Loss:  [[8.49409597]]

Epoch:  23 , Loss:  [[17.20918888]] , Val Loss:  [[8.5854792]]

Epoch:  24 , Loss:  [[16.92068017]] , Val Loss:  [[8.44794633]]

Epoch:  25 , Loss:  [[16.76856238]] , Val Loss:  [[8.37295808]]

看起来不错!是时候进行预测并绘制它们以获得我们设计的视觉感受。

第3步:获得预测

我们将通过训练的权重利用正推法获得预测:

preds = []

for i in range(Y.shape[0]):

    x, y = X[i], Y[i]

    prev_s = np.zeros((hidden_dim, 1))

    # Forward pass

    for t in range(T):

        mulu = np.dot(U, x)

        mulw = np.dot(W, prev_s)

        add = mulw + mulu

        s = sigmoid(add)

        mulv = np.dot(V, s)

        prev_s = s

    preds.append(mulv)

  preds = np.array(preds)

将这些预测与实际值一起绘制:

plt.plot(preds[:, 0, 0], 'g')

plt.plot(Y[:, 0], 'r')

plt.show()

这是有关培训数据的。 我们怎么知道我们的模型是不是过拟合? 这就是我们之前创建的验证集发挥作用的时候:

preds = []

for i in range(Y_val.shape[0]):

    x, y = X_val[i], Y_val[i]

    prev_s = np.zeros((hidden_dim, 1))

    # For each time step...

    for t in range(T):

        mulu = np.dot(U, x)

        mulw = np.dot(W, prev_s)

        add = mulw + mulu

        s = sigmoid(add)

        mulv = np.dot(V, s)

        prev_s = s

    preds.append(mulv)

  preds = np.array(preds)

plt.plot(preds[:, 0, 0], 'g')

plt.plot(Y_val[:, 0], 'r')

plt.show()

不错。 预测看起来令人印象深刻。 验证数据的均方根误差分数也是可以接受的:

from sklearn.metrics import mean_squared_error

math.sqrt(mean_squared_error(Y_val[:, 0] * max_val, preds[:, 0, 0] * max_val))

0.127191931509431

总结

在处理序列数据时,我没有足够强调循环神经网络多么有用。 我恳请大家学习并将其应用于数据集。 尝试去解决NLP问题,看看是否可以找到解决方案。 如果您有任何疑问,可以随时通过以下评论部分与我联系。

在本文中,我们学习了如何使用numpy库从零开始创建循环神经网络模型。 您也可以使用像Keras或Caffe这样的高级库,但了解您正在实施的概念至关重要。

请在下面分享您对本文的想法,问题和反馈。 快乐学习!

您还可以在Analytics Vidhya的Android APP上阅读这篇文章。

原文标题:

Build a Recurrent Neural Network from Scratch in Python – An Essential Read for Data Scientists

原文链接:https://www.analyticsvidhya.com/blog/2019/01/fundamentals-deep-learning-recurrent-neural-networks-scratch-python/

THU数据派
THU数据派

THU数据派"基于清华,放眼世界",以扎实的理工功底闯荡“数据江湖”。发布全球大数据资讯,定期组织线下活动,分享前沿产业动态。了解清华大数据,敬请关注姐妹号“数据派THU”。

入门循环神经网络Python
4
相关数据
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

激活函数技术

在 计算网络中, 一个节点的激活函数定义了该节点在给定的输入或输入的集合下的输出。标准的计算机芯片电路可以看作是根据输入得到"开"(1)或"关"(0)输出的数字网络激活函数。这与神经网络中的线性感知机的行为类似。 一种函数(例如 ReLU 或 S 型函数),用于对上一层的所有输入求加权和,然后生成一个输出值(通常为非线性值),并将其传递给下一层。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

数据科学技术

数据科学,又称资料科学,是一门利用数据学习知识的学科,其目标是通过从数据中提取出有价值的部分来生产数据产品。它结合了诸多领域中的理论和技术,包括应用数学、统计、模式识别、机器学习、数据可视化、数据仓库以及高性能计算。数据科学通过运用各种相关的数据来帮助非专业人士理解问题。

收敛技术

在数学,计算机科学和逻辑学中,收敛指的是不同的变换序列在有限的时间内达到一个结论(变换终止),并且得出的结论是独立于达到它的路径(他们是融合的)。 通俗来说,收敛通常是指在训练期间达到的一种状态,即经过一定次数的迭代之后,训练损失和验证损失在每次迭代中的变化都非常小或根本没有变化。也就是说,如果采用当前数据进行额外的训练将无法改进模型,模型即达到收敛状态。在深度学习中,损失值有时会在最终下降之前的多次迭代中保持不变或几乎保持不变,暂时形成收敛的假象。

验证集技术

验证数据集是用于调整分类器超参数(即模型结构)的一组数据集,它有时也被称为开发集(dev set)。

机器翻译技术

机器翻译(MT)是利用机器的力量「自动将一种自然语言(源语言)的文本翻译成另一种语言(目标语言)」。机器翻译方法通常可分成三大类:基于规则的机器翻译(RBMT)、统计机器翻译(SMT)和神经机器翻译(NMT)。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

均方根误差技术

平方平均数(Quadratic mean),简称方均根(Root Mean Square,缩写为 RMS),是2次方的广义平均数的表达式,也可叫做2次幂平均数。常用于计算误差

随机梯度下降技术

梯度下降(Gradient Descent)是遵循成本函数的梯度来最小化一个函数的过程。这个过程涉及到对成本形式以及其衍生形式的认知,使得我们可以从已知的给定点朝既定方向移动。比如向下朝最小值移动。 在机器学习中,我们可以利用随机梯度下降的方法来最小化训练模型中的误差,即每次迭代时完成一次评估和更新。 这种优化算法的工作原理是模型每看到一个训练实例,就对其作出预测,并重复迭代该过程到一定的次数。这个流程可以用于找出能导致训练数据最小误差的模型的系数。

过拟合技术

过拟合是指为了得到一致假设而使假设变得过度严格。避免过拟合是分类器设计中的一个核心任务。通常采用增大数据量和测试样本集的方法对分类器性能进行评价。

语音识别技术

自动语音识别是一种将口头语音转换为实时可读文本的技术。自动语音识别也称为语音识别(Speech Recognition)或计算机语音识别(Computer Speech Recognition)。自动语音识别是一个多学科交叉的领域,它与声学、语音学、语言学、数字信号处理理论、信息论、计算机科学等众多学科紧密相连。由于语音信号的多样性和复杂性,目前的语音识别系统只能在一定的限制条件下获得满意的性能,或者说只能应用于某些特定的场合。自动语音识别在人工智能领域占据着极其重要的位置。

前馈神经网络技术

前馈神经网络(FNN)是人工智能领域中最早发明的简单人工神经网络类型。在它内部,参数从输入层经过隐含层向输出层单向传播。与递归神经网络不同,在它内部不会构成有向环。FNN由一个输入层、一个(浅层网络)或多个(深层网络,因此叫作深度学习)隐藏层,和一个输出层构成。每个层(除输出层以外)与下一层连接。这种连接是 FNN 架构的关键,具有两个主要特征:加权平均值和激活函数。

推荐文章
暂无评论
暂无评论~