《深度学习图解》基本概念与前向传播


基本概念

什么是深度学习?

深度学习是机器学习方法的一个子集。深度学习是机器学习的一个子集,机器学习是一个专门研究和开发能够学习的机器的领域(有时候最终目标是获得通用人工智能)。

深度学习在业内,深度学习被用于解决多个领域的实际任务,如计算机视觉(图像)、自然语言处理(文本)和自动语音识别(音频)。简而言之,深度学习是机器学习工具箱中众多方法的子集。

什么是机器学习?

简而言之,机器观察某项任务中存在的模式,并试图以某种直接或间接的方式模仿它:

机器学习的主要类型:

  • 有监督的:可以直接模仿两个数据集之间的模式。它总是尝试获取一个输入数据集并将其转换为对应的输出数据集:
    • 使用图像的像素来检测猫存在与否
    • 使用你喜欢的电影来预测你可能喜欢的电影
    • 使用人们所说的话来预测他们是高兴还是难过
    • 使用天气传感器数据预测下雨的概率
    • 使用汽车发动机传感器预测最佳调节设置
    • 使用新闻数据预测明天的股价
  • 无监督的:它总是尝试获取一个输入数据集并将其转换为对应的输出数据集,但是得到的数据集不是已知的。你只需要告诉一个无监督算法“在这些数据中找到某种模式,然后告诉我它是什么。”
    • 将数据集进行聚类:用数字对一系列数据点进行相应的标记,因为算法不会告诉你每个类别具体是什么含义。

机器学习也可分为参数学习和非参数学习:试错学习计数和概率

image-20231126205145425

如上图,实际上存在四种不同类型的算法,关于监督特性(有监督的或无监督的)的部分主要关注被学习的模式的类型,而参数特性(参数的或非参数的)则主要关注存储学习参数的方式,即关注学习的方法。

  • 参数学习:特征是具有固定数量的参数;倾向于使用试错法。
  • 非参数学习:参数数量是无限的(由数据决定);倾向于使用计数法。

参数学习

监督参数学习

使用旋钮进行试错学习,即这项机器学习是通过把旋钮转到不同角度来完成的。

  1. 例如想预测(波士顿)红袜队赢得世界系列赛的概率,那么这个模型首先需要—些已知数据(如体育方面的统计数据,包括球队的输赢记录或每个球员脚趾的平均数量)并基于此做出预测(如98%胜率)。

  2. 接下来,模型将观察红袜队是否真的赢了。当知道红袜队是否获胜后, 机器学习算法会更新这些旋钮,以便下次看到同样或类似的输入数据时,做出更准确的预测。

  3. 如果球队的输贏记录是一个很好的预测依据,也许它会调高“输赢记录”对应的旋钮。相反,如果球员的平均脚趾数量不是一个好的预测依据,它可能会调低“平均脚趾数”对应的旋钮。这就是参数模型的学习方法!

    注意:

    1. 在给定的任何时间,我们都可以从旋钮位置中得知模型所学到的全部内容。你也可以将这种类型的学习模型看作一种搜索算法。你正在通过不断调整旋钮设置,观察结果并再次尝试来“搜索”适当的旋钮配置。
    2. 需要进一步注意的是,试错这一概念并不是正式定义,但它是参数模型的一个常见属性(也有例外)。当存在任意(固定)数量的旋钮需要被转动时,我们需要花费一定程度的搜索工作来找到最优配置。这与通常基于计数的非参数学习形成了鲜明对比:当它发现需要计数的新内容时,会或多或少地添加新旋钮。

下面,我们把监督参数学习分解为三个步骤:

  1. 预测

    收集体育统计数据,把它们传给机器,并对红袜队获胜的可能性做出预测。

  2. 与真值进行比较

    将预测结果(98%)与你关心的结果(红袜队是否获胜)进行比较。即如果模型预测结果为0,那么它就能完美地预测红袜队即将到来的失败(目前的预测值是98%)。

  3. 学习模式

    通过研究模型生成的结果错了多少(98%)以及预测时的输入数据是什么来调整旋钮。模型学习算法会试着转动旋钮,以在给定的输入数据下做出更准确的预测。

    理论上,下次这个模型看到相同的输入数据时,预测的值将低于98%。

    注意:每个旋钮的档位表示这个模型对不同类型的输入数据的敏感度。

无监督参数学习

无监督参数学习用的方法非常类似。无监督学习是对数据进行分组,那么无监督参数学习就是使用旋钮对数据进行分组。

但这种情况下,它通常为每个类别都设置了几个旋钮,每个旋钮都反映了输入数据到那个特定类别的相似度(这是笼统的描述,也会存在一定例外和细微差别)。让我们看一个示例,假设你希望将下列数据分成三组:

image-20231126214512846

根据这一数据集,我已经确定了三个类别,也希望参数模型能够找到它们。借助于不同的字体颜色和底色,不妨用组1、组2和组3来标识它们。现在,让我们将第一个数据点传到训练好的无监督模型中,如下所示。注意,最大概率会映射到组1。

image-20231126214850899

每个组的模型都尝试将输入数据转换为 0 到 1 之间的数字,告诉我们输入数据属于该组的概率。从更高抽象层次看,它们都致力于调整参数以将输入数据转换为标签。

非参数学习

即基于计数的方法

非参数学习是一类参数个数以数据为基础(而不是预先定义好)的算法。这通常适用于以某种方式计数作为输入的方法,因为非参数学习能够根据数据中存在的具体项目数量相应增加参数的数量。

例如,在监督学习中,一个非参数模型会记录某一种特定颜色的街灯导致汽车“行驶”的次数。只需要在计算数个样本之
后,这个模型就能预测出中间的灯光总是导致汽车行驶(100%的概率),而右边的灯光只是有时导致汽车行驶(比如说50%概率)。

注意:这个模型将有三个参数:表示每种颜色的灯亮的同时,汽车行驶的次数(可能除以总观察次数)的三个计数。如果有5个灯,就会有5项计数(5个参数)。

这个简单模型被归类为非参数模型的原因是,模型参数的数量会根据数据(在本例中,是灯的数量)而变化。这与从一组设定好的参数开始学习的参数模型恰恰相反,更重要的是,参数模型中的参数数量可多可少,纯粹由训练模型的科学家自由裁量(与数据无关)。

其实大多数参数模型仍然需要基于数据中的类别数的某种输入。即使参数模型也会受到数据中的类别数的影响,即使它的参数数量并非显式地由计数模式确定。

前向传播

什么是预测

我们将深入研究的第一步:预测。

  1. 数据

    一次处理的数据点的数量对网络的形态有很大影响。如何确定一次处理的数据点的数量?答案取决于你是否认为神经网络可以通过你提供的这批数据变得更精确。

    注意:神经网络总是需要你提供足够的信息:足够的信息指的是人类为了做出相同的预测可能需要的信息量。

  2. 本例中这个拥有一项权重的网络一次接受一个数据点(棒球队球员脚趾数目的平均值),然后输出一个预测结果(它是否认为球队会赢)。

代码示例:

# The network:

weight = 0.1 # 定义权重
def neural_network(input, weight): 
    prediction = input * weight # 将输入与权重相乘,得到一个预测结果
    return prediction

# How we use the network to predict something:

number_of_toes = [8.5, 9.5, 10, 9]
input = number_of_toes[0]
pred = neural_network(input,weight)
print(pred)

注意:

  1. 本例中,信息是比赛前所统计的棒球队球员脚趾的平均数量。神经网络除了当前的实例,不能记住任何信息。之后将会学习到如何通过同时提供多个输入,给神经网络一个“短期记忆”。
  2. 神经网络中的权重值的理解,可以将它作为网络的输入和预测之间敏感度的度量。如果权重非常高,那么即使最小的输入也可以对预测结果产生非常大的影响!反之亦然。
  3. 神经网络不仅可以预测正数,还可以预测负数,甚至将负数作为输入。也许你想预测人们今天穿外套的概率。如果温度是-10℃,那么一个负的权重(-8.9)将会预测出人们穿外套是高概率事件。

使用多个输入进行预测

如果能一次性给网络提供更多的信息,而不仅仅是每个球员的平均脚趾数,结果会是怎样?理论上,该网络应该能够做出更准确的预测。

image-20231127122046825

image-20231127122054496

image-20231127122224333

image-20231127122231198

代码示例:

def w_sum(a,b):
    assert(len(a) == len(b)) # 确保 a 和 b 的长度相等
    output = 0
    for i in range(len(a)): # 注意此处使用了for循环,速度会比较慢
        output += (a[i] * b[i]) # 输入与权重的加权和
    return output

weights = [0.1, 0.2, 0] 
    
def neural_network(input, weights):
    pred = w_sum(input,weights)
    return pred

# This dataset is the current
# status at the beginning of
# each game for the first 4 games
# in a season.

# toes = current number of toes
# wlrec = current games won (percent)
# nfans = fan count (in millions)

toes =  [8.5, 9.5, 9.9, 9.0]
wlrec = [0.65, 0.8, 0.8, 0.9]
nfans = [1.2, 1.3, 0.5, 1.0]

# Input corresponds to every entry
# for the first game of the season.

input = [toes[0],wlrec[0],nfans[0]]
pred = neural_network(input,weights)

print(pred)

这个神经网络做了什么?

它将三个输入乘以三项权重,并对它们求和,得到加权和。

而上述神经网络可以同时接受多个输入并做出预测,这使得网络能够结合多种形式的信息,做出更明智的决定,但是它使用权重的基本机制并没有改变。换句话说,它将每个输入乘以对应的权重。

  • 有些人会将加权和称为点积。
  • 事实证明,当想要涉及多组数字的运算时,向量是特别有用的。

如何粗略理解权重含义?

假设在执行加权和,而这些 if 语句后面跟着的 then 可以抽象地理解为 then give high score(然后就可以获得更高得分):

image-20231127124339798

注意:最后一行中,weights[0]=0.5 表示对应的 input[0] 必须更大,以补偿较小的权重。

那么神经网络做出预测,这意味着什么?意味着网络根据输入和权重的相似程度给出相应的分数。

上例中:

  • nfans在预测中完全被忽略,因为与它关联的权重为0;
  • 而影响最大的输入数据为 wlrec,因为它的权重为0.2;
  • 但是产生较高得分的主导因素是队员脚趾的平均数量(ntoes),不是因为它的权重最大,而是因为这项输入与权重的乘积是目前为止最高的。

Numpy操作

对于创建向量和执行常见函数(如点积运算)来说,它的代码效率很高,比使用for循环高得多。

代码示例:

import numpy as np
weights = np.array([0.1, 0.2, 0])
def neural_network(input, weights):
    pred = input.dot(weights) # 运行速度更快
    return pred
    
toes =  np.array([8.5, 9.5, 9.9, 9.0])
wlrec = np.array([0.65, 0.8, 0.8, 0.9])
nfans = np.array([1.2, 1.3, 0.5, 1.0])

# Input corresponds to every entry
# for the first game of the season.

input = np.array([toes[0],wlrec[0],nfans[0]])
pred = neural_network(input,weights)

print(pred)

使用多个输入和输出进行预测

基于给定的多个输入,神经网络可以对多个输出进行预测。

  1. 它对输入数据执行三次独立的加权和操作,产生三个预测结果。

    将这个神经网络想象成三个独立的点积操作,针对输入分别做三次独立的求加权和。每个输出节点都会针对输入节点进行自己的加权和操作,并做出相应预测。

    image-20231127165132371

    image-20231127165217917

  2. 其中和之前不相同的是该函数对每一行权重进行遍历(每一行都是向量),并使用加权和函数进行预测。实际上它连续执行了三个加权和,然后将结果存储在一个向量中:

    image-20231127165428152

注意:更正式的定义是将权重存储/处理为列向量,而不是行向量。

代码示例:

            #toes %win #fans
weights = [ [0.1, 0.1, -0.3], #hurt?
            [0.1, 0.2, 0.0], #win?
            [0.0, 1.3, 0.1] ] #sad?

def w_sum(a,b): # 计算两个向量的加权和
    assert(len(a) == len(b))
    output = 0
    for i in range(len(a)):
        output += (a[i] * b[i])
    return output

def vect_mat_mul(vect,matrix): # 用于将一个输入向量和一个权重矩阵相乘
    assert(len(vect) == len(matrix))
    output = [0,0,0]
    for i in range(len(vect)):
        output[i] = w_sum(vect,matrix[i])
        
    return output

def neural_network(input, weights):
    pred = vect_mat_mul(input,weights)
    return pred

# This dataset is the current
# status at the beginning of
# each game for the first 4 games
# in a season.

# toes = current number of toes
# wlrec = current games won (percent)
# nfans = fan count (in millions)

toes =  [8.5, 9.5, 9.9, 9.0]
wlrec = [0.65,0.8, 0.8, 0.9]
nfans = [1.2, 1.3, 0.5, 1.0]

# Input corresponds to every entry
# for the first game of the season.

input = [toes[0],wlrec[0],nfans[0]]
pred = neural_network(input,weights)

print(pred)

与预测结果进一步预测

image-20231127170708127

image-20231127170716685

image-20231127170909239

代码示例:

            #toes %win #fans
ih_wgt = [ [0.1, 0.2, -0.1], #hid[0]
           [-0.1,0.1, 0.9], #hid[1]
           [0.1, 0.4, 0.1] ] #hid[2]

           #hid[0] hid[1] hid[2]
hp_wgt = [ [0.3, 1.1, -0.3], #hurt?
           [0.1, 0.2, 0.0], #win?
           [0.0, 1.3, 0.1] ] #sad?

weights = [ih_wgt, hp_wgt]

def neural_network(input, weights):
    hid = vect_mat_mul(input,weights[0])
    pred = vect_mat_mul(hid,weights[1])
    return pred

toes =  [8.5, 9.5, 9.9, 9.0]
wlrec = [0.65,0.8, 0.8, 0.9]
nfans = [1.2, 1.3, 0.5, 1.0]

# Input corresponds to every entry
# for the first game of the season.

input = [toes[0],wlrec[0],nfans[0]]
pred = neural_network(input,weights)

print(pred)

Numpy操作

import numpy as np

#toes %win #fans # 表示输入层到隐藏层的权重矩阵
ih_wgt = np.array([ # 矩阵的行表示隐藏层的神经元,列表示输入层的特征
            [0.1, 0.2, -0.1], #hid[0] 例如[0,0]表示输入层的第一个特征与隐藏层的第一个神经元之间的权重
            [-0.1,0.1, 0.9], #hid[1]  例如[1,2]表示输入层的第三个特征与隐藏层的第二个神经元之间的权重
            [0.1, 0.4, 0.1]]).T #hid[2]


# hid[0] hid[1] hid[2] # 表示隐藏层到输出层的权重矩阵
hp_wgt = np.array([   # 矩阵的行表示输出层的神经元,列表示隐藏层的神经元
            [0.3, 1.1, -0.3], #hurt?
            [0.1, 0.2, 0.0], #win?
            [0.0, 1.3, 0.1] ]).T #sad?

weights = [ih_wgt, hp_wgt] # 包含两个权重矩阵

def neural_network(input, weights):

    hid = input.dot(weights[0]) # 先得到隐藏层的输出
    
    pred = hid.dot(weights[1]) # 将隐藏层的输出与隐藏层到输出层的权重矩阵相乘
    return pred


toes =  np.array([8.5, 9.5, 9.9, 9.0])
wlrec = np.array([0.65,0.8, 0.8, 0.9])
nfans = np.array([1.2, 1.3, 0.5, 1.0])

input = np.array([toes[0],wlrec[0],nfans[0]])

pred = neural_network(input,weights)
print(pred)

总结

为了预测,神经网络对输入重复执行加权求和操作。


文章作者: QT-7274
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 QT-7274 !
评论
  目录