TensorFlow入门--实现多层感知机

第1关:实现全连接层的前向传播

本文章内容均来自头歌实践教学平台,还望各位同学好好学习!

相关知识

为了完成本关任务,你需要掌握:

神经网络的结构;
全连接层的定义。
本实训内容可参考《深度学习入门——基于 Python 的理论与实现》一书中第 3.1-3.5 章节的内容。

神经网络的结构

在上一个实训中,我们对感知机和多层感知机进行了学习,也了解了利用感知机的堆叠构建多层感知机,从而得到表达能力更强的模型的方法。在本实训中,我们更进一步,来学习神经网络的结构。神经网络由若干神经网络层堆叠而成,不同的层能够有效的提取数据的特征,实现对输入数据从低阶特征到高阶特征的逐渐提取,并完成分类、回归等机器学习任务。多层感知机其实已经是一种非常简单的神经网络。常见的神经网络包括多层感知机、卷积神经网络、循环神经网络等。下图展示了一个简单的神经网络模型。

图1
图1 简单神经网络

神经网络在实现上包括前向传播和反向传播两个部分。前向传播在训练和预测时都会用到,用于计算网络模型的预测结果和损失函数。而反向传播则在训练过程中,用来计算参数的梯度,使用梯度下降法来对网络模型进行训练。在下面的几个实训中,我们将关注神经网络模型的前向传播,而将反向传播放在后面的实训介绍。

从本实训开始,你将会使用numpy来实现一个简单的深度学习框架,包括常见的神经网络层的前向和反向传播,以及神经网络训练的基本方法。

全连接层的定义
回顾之前使用感知机实现逻辑门的例子,每个输出都是所有输入信号的线性组合。把每个输入和输出信号都看作是一个神经元,那么输出神经元和输入神经元之间是两两互相连接的,这种网络层叫做全连接层。

形式化地,一个包含N个输入神经元,M个输出神经元的全连接层包含两组参数:权重W∈R N×M和偏置b∈R M,其输入可以看作是一个N维的(列)向量x∈R N,此时全连接层的计算可以表示为:

y=xTW+b

通过全连接层,可以将输入特征进行线性变换,得到一组新的特征。

全连接层的实现
实训已经预先定义了一个FullyConnected类,在该类的构造函数中,其接受对应的权重W和偏置b。权重W是一个N×M的numpy.ndarray,偏置b是一个长度为M的numpy.ndarray,其中N是全连接层的输入通道数,M是全连接层的输出通道数。

在本实训中,你需要实现前向传播函数forward()。forward()函数的输入x是一个维度大于等于2的numpy.ndarray,形状为(B,dim 1,dim 2,…,dim k),其中B是 batch size,即数据的个数。首先,你需要对x的形状进行调整,将其转化为形状为(B,N)的2维numpy.ndarray。同时还需要记录x的原始形状,并记录在original_x_shape中。最后返回线性变换后的结果。

编程要求

根据提示,在右侧编辑器中 Begin 和 End 之间补充代码,实现上述全连接层的前向传播。

样例输入:

W:
[[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]]
b:
[0.1, 0.2, 0.3]
x:
[[1, 2],
[3, 4]]
则对应的输出神经元为:

[[1.0, 1.4, 1.8],
[2.0, 2.8, 3.6]]

开始你的任务吧,祝你成功!

参考代码:

import numpy as np


class FullyConnected:
    def __init__(self, W, b):
        r'''
        全连接层的初始化。

        Parameter:
        - W: numpy.array, (D_in, D_out)
        - b: numpy.array, (D_out)
        '''
        self.W = W
        self.b = b

        self.x = None
        self.original_x_shape = None

    def forward(self, x):
        r'''
        全连接层的前向传播。

        Parameter:
        - x: numpy.array, (B, d1, d2, ..., dk)

        Return:
        - y: numpy.array, (B, M)
        '''
        
        ########## Begin ##########
        return np.matmul(x, self.W) + self.b
        ########## End ##########



第2关:实现常见激活函数的前向传播

相关知识

为了完成本关任务,你需要掌握:常见激活函数的定义。

本实训内容可参考《深度学习入门——基于 Python 的理论与实现》一书中第 3.1-3.5 章节的内容。

激活函数的作用

我们首先来考虑这样一种神经网络,它由两个全连接层组成。假设这两个全连接层的权重和偏置分别为W 1、b1和W2、b 2,输入为x,那么由上一个关中全连接层的计算公式,我们可以得到一些结论:
y=(x×W 1+b1)×W2+b2=x×W 1×W2+b1×W 2+b 2
因为矩阵乘法满足结合律,令W 0=W1×W 2,b0=b1×W2+b2,那么上面的两层全连接层就可以写为:y=x×W0 +b0

这就说明这样堆叠两个全连接层与一个全连接层是等效的,那么这种堆叠就是无效的,并不能增强模型的拟合能力。为了解决这一问题,通常在每一层的后面接一个非线性激活函数。通过引入非线性激活函数,可以极大的增强模型的拟合能力。

回顾之前我们使用感知机实现逻辑门的时候,我们在线性变换之后使用了符号函数,其实就是一种激活函数。也正是因为使用了符号函数,使得我们能够通过将感知机堆叠成多层感知机的方式实现异或门。

常见激活函数的定义
1. sigmoid激活函数

sigmoid 激活函数是一个 S 型函数,可以将任意范围的输入转化到[0,1]的范围内,而这一范围与概率的范围是相同的,因此可以借此实现“概率”。另一方面,sigmoid 激活函数在x的绝对值较大时,梯度非常接近0,会导致“梯度消失”的问题,使得网络难以收敛。其函数表达式如下:

sigmoid(x)=1/(1+e−x)

目前,sigmoid 激活函数的应用场景主要包含两种:第一是用于计算概率,这与 sigmoid 函数的本身性质吻合;第二是用于计算注意力,注意力是在计算机视觉和自然语言处理领域常用的技术,这留给感兴趣的学员自行学习。

2. ReLU激活函数

ReLU 激活函数是目前深度学习中最常用的激活函数,其只保留输入张量大于0的部分,而将小于0的部分置为0。与之前的 sigmoid 不同,ReLU 激活函数不会受到梯度消失的影响。其函数表达式如下:

ReLU(x)=max(0,x)

ReLU 是目前卷积神经网络中应用最多的激活函数,其特点是计算简单,同时不会受到梯度消失问题的影响。但是 ReLU 也存在着一定的问题,例如 ReLU 的输出都是非负数,因此 ReLU 输出的平均值一定是个正数,而不是 0。这可能会对网络的训练产生一定的影响。针对这一问题,研究者们也提出了 LReLU、PReLU 等方法进行改进,有兴趣的学员可以查找相关资料进行学习。

常见激活函数的实现

本实训希望你实现 sigmoid 和 ReLU 激活函数的前向传播。实训已经预先定义了一个Sigmoid类和一个ReLU类。在本实训中,你需要实现前向传播函数forward()。forward()函数的输入x是一个维度大于等于2的numpy.ndarray,形状为(B,d1,d2,…,d k),其中B是batch size。返回经过激活函数处理的输出值。

编程要求

根据提示,在右侧编辑器中 Begin 和 End 之间补充代码,实现上述激活函数。为了以后实现反向传播的方便,这里希望你:

在实现 sigmoid 时,将输出结果记录在self.out中;
在实现 ReLU 时,将小于 0 的元素按照 mask 的形式记录在self.mask中。

参考代码:

import numpy as np


class Sigmoid:
    def __init__(self):
        self.out = None

    def forward(self, x):
        r'''
        Sigmoid激活函数的前向传播。

        Parameter:
        - x: numpy.array, (B, d1, d2, ..., dk)

        Return:
        - y: numpy.array, (B, d1, d2, ..., dk)
        '''
        ########## Begin ##########
        out = self.out = 1 / (1 + np.exp(-x))
        self.out = out
        return out
        ########## End ##########


class ReLU:
    def __init__(self):
        self.mask = None

    def forward(self, x):
        r'''
        ReLU激活函数的前向传播。

        Parameter:
        - x: numpy.array, (B, d1, d2, ..., dk)

        Return:
        - y: numpy.array, (B, d1, d2, ..., dk)
        '''
        ########## Begin ##########
        self.mask = (x <= 0)
        res = x.copy()
        res[self.mask] = 0
        return res
        ########## End ##########

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值