当前位置:   article > 正文

笔记:《动手学深度学习》——NLP

笔记:《动手学深度学习》——NLP

一、困惑度(perplexity)

  1. 衡量语言模型的好坏,即生成文本的质量
    ppl = exp^( - (1 / n) * Σ log₂ P(xt|xt–1,xt-2,…,x1) )
      最坏的情况下,P=0(预测标签次元的概率为0%),此时困惑度正无穷大
      最好的情况下,P=1(预测标签次元的概率为100%),此时困惑度为1
  2. 自己理解:书上训练语言模型求ppl时,ppl = math.exp(metric[0] / metric[1]) 。其中,metric[0]为loss * y.numel(),netric[1]为y.numel()(P235)。为什么可以使用损失loss来替代 - (1 / n) * Σ log₂ P(xt|xt–1,xt-2,…,x1) ?
    因为我们训练目的是让loss下降为0(尽管不可能为0),使得困惑度ppl达到1,这就和 - (1 / n) * Σ log₂ P(xt|xt–1,xt-2,…,x1) 的目的类似了,即为了让ppl达到1,则必须使概率P(xt|xt–1,xt-2,…,x1)达到1,所以可以使用loss来代替求困惑度。

二、N-gram

  1. N-gram 是一种统计语言模型,用于描述自然语言中的概率分布。这个模型中,N 表示一个词语序列的长度,也就是连续 N 个词语。在 N-gram 模型中,每个词语的概率分布取决于它前面的 N-1 个词语,这种依赖关系构成了 N-gram 模型的核心思想。
  2. 通过使用 N-gram 模型,可以预测给定上下文中词语的出现概率

三、梯度截断(Gradient Clipping)

  1. 主要用于解决梯度消失和梯度爆炸问题。在深度神经网络训练过程中,梯度信息用于更新模型参数,但在反向传播过程中,梯度的值可能会变得非常大或非常小,导致模型无法有效地学习。梯度截断技术通过限制梯度的大小,可以解决这些问题,使模型更容易学习并提高训练稳定性
  2. 具体操作是在梯度计算完成后,对每个参数的梯度值进行截断,使其落在一个预先设定的范围内。
  3. 公式:g = min(1,theta / ||g||) * g
       g–梯度,为根号下所有梯度的平方和。 g/norm=torch.sqrt(sum(torch.sum((p.grad ^2)) for p in params))
       theta–自定义梯度范数,一般为1。
       通过这个公式,梯度范数永远小于等于theta
  4. 自己理解:为什么梯度爆炸或者梯度消失会导致模型无法有效的学习
         深度学习中,我们通常使用梯度下降法或者其他优化算法(如 Adam、RMSProp 等)来更新模型参数。这些算法依赖于梯度信息,梯度是损失函数关于参数的偏导数,用于表示参数变化对损失函数的影响。在反向传播过程中,梯度会从输出层传递到输入层,这个过程会受到网络结构和参数规模的影响。
         当梯度爆炸发生时,梯度的值会变得非常大,可能导致模型参数更新过大,使模型无法收敛。而梯度消失则是指梯度的值变得非常小,这会使模型参数更新过慢,导致收敛速度变慢,甚至无法收敛。这两种情况都会使模型的学习效果受到影响,无法有效地学习。

四、预热期

文本生成时,生成prefix字符串后面锝文本时,需要先循环遍历prefix的初始字符,用于更新隐状态H。我们不断的将隐状态H传递到下一个时间步,但不生成任何输出,这个称为预热期。预热期结束后,隐状态的值通常会比初始值更适合预测。因为隐状态包含了之前文本(prefix)的信息。

五、自定义优化器和已定义优化器区别

  1. 优化器通过梯度更新参数
    自定义优化器,使用时直接调用sgd函数
     def sgd(params, lr, batch_size):
      with torch.no_grad():
       for param in params:
        param -= lr * param.grad / batch_size //使用-=,若改为param = param = lr * param.grad / batch_size ,第一个和第二个param不是一个值,指向不同的地址,原模型参数还是没有变化,会出现问题。而使用-=,前后两个param指向的其实是一个地址
        param.grad_zero_() //梯度清0,否则下一次会在该次的基础上进行梯度累加
    已定义优化器,使用时调用updator.step()和update.zero_grad()
    updater = torch.optim.SGD(net.parameters(),lr) //还有Adam优化器,它对lr不敏感
  2. 自己理解:自定义优化器和已定义优化器其实都做了梯度清0操作,防止梯度累积

六、判断模型是否自定义

isinstance(net,nn.Module)判断模型是否自定义:
  使用库内预先包装好的模型:net.parameters() 获取模型参数
  使用自定义模型:net.params获取模型参数(params为自定义属性)

七、Animator,Accumulate,Timer

Animator,Accumulate为d2l包中包装好的类,Timer为timer包中的类。

  1. Accumulate用法;
    metric = d2l.Accumulator(2)
    metric.add(l * y.numel(),y.numel()) 可多次调用累加,metric为数组,metric[0]为l * y.numel()累加,metric[1]为y.numel()累加
  2. Animator用法:
    animator = d2l.Animator(xlabl=‘epoch’,y_label=‘perplexity’,legend=[‘train’, 'test],xlim=[10, num_epochs])
      xlabl,y_label–横、纵坐标说明
      legend–添加图例说明
      xlim–横坐标
    animator.add(epoch+1, [ppl]) 增加xy点,需要注意y可以为数组,即一张图上可以画多条曲线。
  3. 上述Accumulate和Animator用于计算loss,并绘制曲线图
  4. Timer用法:
    d2l将Timer包重新封装用于计时,内部使用了time.time()–返回时间戳(单位为:s)
    timer = d2l.Timer() //开始计时
    t = timer.stop() //结束计时,并返回时间

八、RNN模型输入输出shape:

抽取的批量:(批量,时间步数)
one-hot编码:(批量,时间步数,词表)
input:(时间步数,批量,词表)
x:(批量,词表)
y:(批量,词表)
output: (时间步数 * 批量,词表) 由y通过torch.cat(outputs, dim=0)连接。
使用d2l包装好的模型,需要自己设置Linear将包装的RNN的输出(时间步数 * 批量,hidden)变为(时间步数 * 批量,词表)

九、论述以下书上我理解的为什么进行独热编码one-hot是要对X进行转置X.T?(P231)

因为这样更好通过最外层来一步一步更新隐状态,25 热编码变成了 52*词表,这样读取时就可以先读取出两个句子的各自第一个词x1,然后根据它来生成各自句子的隐变量,然后再继续下一个词,直到把两个句子各五个词读取完为止,得到了两个句子各自的隐变量h5。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/344400?site
推荐阅读
相关标签
  

闽ICP备14008679号