【DL学习笔记08】《深度学习进阶——自然语言处理》——ch01: 神经网络的复习

目录

1. 数学和Python的复习

2. 神经网络的推理

3. 神经网络的学习

4. 使用神经网络解决问题

Trainer类

5. 计算的高速化

位精度

GPU(CuPy)


1. 数学和Python的复习

  • 向量和矩阵(或张量)
  • 矩阵中对应元素(element-wise)的运算
  • 广播
  • 向量内积(一维数组)和矩阵乘积(二维数组)
  • 矩阵的现状检查(3X2 * 2X4 = 3X4)

2. 神经网络的推理

  • 全连接:
    • 所有相邻的神经元之间都存在由箭头表示的连接
    • 输出 = 输入 X 权重 + 偏置
    • 全连接层的变换时线性变换,使用非线性的激活函数可以增强神经网络的表现力
  • 层的类化及正向传播的实现
    • 全连接层为Affine层,sigmoid函数为Sigmoid层
    • 正向传播:神经网络的推理;反向传播:相反方向传播梯度
    • 实现层的代码规范
      • 所有的层都有forward()方法和backward()方法
      • 所有层都有params和grads实例变量,分别保存参数(权重和梯度)和各个参数的梯度

3. 神经网络的学习

  • 损失函数

    • 损失(loss):指示神经网络的性能,基于监督数据和预测结果计算;计算损失的函数称为损失函数(loss function)
    • 进行多类别分类的神经网络使用交叉熵误差(cross entrop error)作为损失函数
    • Softmax函数:可解释为概率
    • one-hot向量形式:只有1个1,其余为0
  • 导数和梯度

    • 将关于向量各个元素的导数罗列到一起,就得到了梯度
  • 链式法则

    • 链式法则是复合函数的求导法则
    • 可以认为神经网络是由多个函数复合而成的,误差反向传播法会利用链式法则求梯度
  • 计算图——计算过程的图像表示,各节点:

    节点反向传播
    加法节点原样的将上游传播的梯度传播出去
    乘法节点梯度 * 将正向传播时的输入替换后的值
    分支节点梯度之和
    repeat节点N个分支的梯度之和(广播可以通过该节点表示)
    sum节点通用的加法节点
    MatMul节点(矩阵乘积)见下方代码
class MatMul:
    def __init__(self, W):
        self.params = [W]
        self.grads = [np.zeros_like(W)]
        self.x = None

    def forward(self, x):
        W, = self.params  # 这里的逗号为了取出权重W而不是[W]
        out = np.dot(x, W)
        self.x = x
        return out

    def backward(self, dout):
        W, = self.params
        dx = np.dot(dout, W.T)
        dW = np.dot(self.x.T, dout)
        self.grads[0][...] = dW  # deep copy ,固定grads的内存地址,方便处理
        return dx

一些层的实现

  • Sigmoid层
class Sigmoid:
    def __init__(self):
        self.params, self.grads = [], []
        self.out = None
    
    def forward(self, x):
        out = 1 / (1 + np.exp(-x))
        self.out = out
        return out
    
    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out
        return dx
  • Affine层(MatMul节点进行矩阵乘积运算,Repeat节点实现广播)
class Affine:
    def __init__(self, W, b):
        self.params = [W, b]
        self.grads = [np.zeros_like(W), np.zeros_like(b)]
        self.x = None

    def forward(self, x):
        W, b = self.params
        out = np.dot(x, W) + b
        self.x = x
        return out

    def backward(self, dout):
        W, b = self.params
        dx = np.dot(dout, W.T)
        dW = np.dot(self.x.T, dout)
        db = np.sum(dout, axis=0)

        self.grads[0][...] = dW
        self.grads[1][...] = db
        return dx
  • Softmax with Loss层
class SoftmaxWithLoss:
    def __init__(self):
        self.params, self.grads = [], []
        self.y = None  # softmax的输出
        self.t = None  # 监督标签

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)

        # 在监督标签为one-hot向量的情况下,转换为正确解标签的索引
        if self.t.size == self.y.size:
            self.t = self.t.argmax(axis=1)

        loss = cross_entropy_error(self.y, self.t)
        return loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]

        dx = self.y.copy()
        dx[np.arange(batch_size), self.t] -= 1
        dx *= dout
        dx = dx / batch_size

        return dx
  • 权重的更新
    • 步骤:mini-batch→计算梯度→更新参数→重复前3步
    • 随机梯度下降法(SGD):将权重朝梯度发反方向更新

4. 使用神经网络解决问题

  • 这里先对一个螺旋状数据集进行了神经网络的学习,不展开

Trainer类

进行学习的类,提高代码复用率

  • 初始化程序接收神经网络和优化器
def __init__(self, model, optimizer):
        self.model = model
        self.optimizer = optimizer
        self.loss_list = []
        self.eval_interval = None
        self.current_epoch = 0
  • 然后调用fit( )方法开始学习
def fit(self, x, t, max_epoch=10, batch_size=32, max_grad=None, eval_interval=20):
		"""

    @param x: 输入数据
    @param t: 监督标签
    @param max_epoch: 进行学习的epoch数
    @param batch_size: mini-batch的大小
    @param max_grad: 梯度的最大范数
    @param eval_interval: 输出结果的间隔——迭代次数
    """
    data_size = len(x)
    max_iters = data_size // batch_size
    self.eval_interval = eval_interval
    model, optimizer = self.model, self.optimizer
    total_loss = 0
    loss_count = 0

    start_time = time.time()
    for epoch in range(max_epoch):
        # 打乱
        idx = numpy.random.permutation(numpy.arange(data_size))
        x = x[idx]
        t = t[idx]

        for iters in range(max_iters):
            batch_x = x[iters*batch_size:(iters+1)*batch_size]
            batch_t = t[iters*batch_size:(iters+1)*batch_size]

            # 计算梯度,更新参数
            loss = model.forward(batch_x, batch_t)
            model.backward()
            params, grads = remove_duplicate(model.params, model.grads)  # 将共享的权重整合为1个
            if max_grad is not None:
                clip_grads(grads, max_grad)
            optimizer.update(params, grads)
            total_loss += loss
            loss_count += 1

            # 评价
            if (eval_interval is not None) and (iters % eval_interval) == 0:
                avg_loss = total_loss / loss_count
                elapsed_time = time.time() - start_time
                print('| epoch %d |  iter %d / %d | time %d[s] | loss %.2f'
                      % (self.current_epoch + 1, iters + 1, max_iters, elapsed_time, avg_loss))
                self.loss_list.append(float(avg_loss))
                total_loss, loss_count = 0, 0

        self.current_epoch += 1
  • 画出损失值
def plot(self, ylim=None):
    x = numpy.arange(len(self.loss_list))
    if ylim is not None:
        plt.ylim(*ylim)
    plt.plot(x, self.loss_list, label='train')
    plt.xlabel('iterations (x' + str(self.eval_interval) + ')')
    plt.ylabel('loss')
    plt.show()

5. 计算的高速化

位精度

  • numpy默认使用64位的数据类型,但对于神经网络,32位浮点数也可以无损的推理和学习
  • 对于神经网络的推理,16位浮点数也足够了,但普通CPU或GPU运算是使用32位执行的所有可以将权重数据用16位精度保存

GPU(CuPy)

  • 深度学习有大量的乘法累加运算组成,且绝大部分可以并行运算,GPU比CUP擅长
  • CuPy是基于GPU进行并行计算的库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值