Task01包含了线性回归模型,softmax模型,多层感知机,文本预处理,语言模型,循环神经网络这几块内容
这里主要记录一些零碎的笔记,
主要是关于理论
1、线性回归模型就是使用了一个线性函数去拟合样本,得到预测值,当然这是一个回归模型,所以是连续的。
2、softmax模型则是首先通过一个全连接层将特征空间变换为我们我们所需要的类别维度空间,然后将类别维度空间利用sigmoid函数放缩到[0,1],变成概率的形式,概率大的就是我们需要的那一类
tips:softmax(t)=sotfmax(t+constant)这是课后习题总某人归纳出来的
3、多层感知机就是一个两层的全连接层,对特征空间进行变换,最后利用softmax输出概率
4、文本预处理就是先构建字典,然后利用字典的序号表示文本中的单词
5、n-gram语言模型是基于n阶马尔科夫假设,认为一个单词出现仅与前n-1个单词有关
语言序列进行采样的时候,有两种采样方式,一种是随机采样,一种是相邻采样。
我们的目标是从序列中每次获取[batch_size,num_step]个小样本,
随机采样就是先将总的序列划分成一个个num_step大小的小区间,也就是一个个小序列,然后从一个个小序列里面随机获取batch_size个作为当前的输入;
相邻采样则不一样,它先将总的序列划分成batch_size个分区,当然要抛去多余的,并保证每个分区都是一样大小,且可以被num_step整除,所以要再次抛去多余的。然后采样的时候从每个分区里面取出num_step个元素作为序列,就有了batch_size个小序列了
6、循环神经网络是一种处理序列输入的模型,因此可以用来处理语言,基本的循环神经网络拥有一个可以传递的隐藏层,序列的当前输入会通过上一个时间步的隐藏层获取信息。
根据不同的采样方式,循环神经网络里面隐藏层参数的初始化也有不同,具体来说就是,相邻采样由于不同批次的数据是联系到一起的,所以在一个epoch里面可以使用同一个隐藏层,一直传递下去,而且关键是,这个梯度也可以一直传递下去,只需要在不同的epoch之间,将隐藏层进行重新初始化。
而随机采样,由于不同batch之间没有内在联系,所以每一个batch之间都需要将隐藏层进行梯度截断,但是可以保留数值作为初始化值。
关于相邻采样进行梯度截断的一些同学的解释:
相邻采样为什么在每次迭代之前都需要将参数detach
是因为pytorch动态计算图构建的原因,这里主要结合本次的视频内容(循环神经网络使用相邻采样时)
分享自己的理解,下图是知乎上找到的,需要详细了解pytorch动态图相关的东西可以看下面给出
的参考链接
从上图可以看出,一个动态图是从叶子节点到叶子节点的一张图,如上图中的输入是x,y,输出是z.但是
需要注意的是,输入的叶子节点其中有个参数requires_grad = False, 而最后输出的叶子节点是
requires_grad = True. 当参数值为True的时候表示的是,该节点可以计算梯度,为False表示不能计算
节点梯度,而在反向传播的时候对于不可以计算梯度的节点可以认为是图反向传播的终点。
现在来理解一下循环神经网络使用相邻采样的时候为什么要detach参数。
我们知道相邻采样的前后两个批量的数据在在时间步上是连续的,所以模型会使用上一个批量的隐藏
状态初始化当前的隐藏状态,表现形式就是不需要在一个epoch的每次迭代时随机初始化隐藏状态,那么
根据上面所说的。假如没有detach的操作,每次迭代之后的输出是一个叶子节点,并且该叶子节点的
requires_grad = True(从上面的计算图就可以看出),也就意味着两次或者说多次的迭代,计算图一直都是连着
的,因为没有遇到梯度计算的结束位置,这样将会一直持续到下一次隐藏状态的初始化。所以这将会导致
计算图非常的大,进而导致计算开销非常大。而每次将参数detach出来,其实就是相当于每次迭代之后虽然是
使用上一次迭代的隐藏状态,只不过我们希望重新开始,具体的操作就是把上一次的输出节点的参数requires_grad
设置为False的叶子节点。
我们知道循环神经网络的梯度反向传播是沿着时间进行反向传播的,而时间是不会停止的,所以我们会每隔一段时间、
进行一次反向传播,而我们这里的一段时间其实指的就是时间步,我们希望每间隔时间步之后进行一次反向传播,这样
来减小在梯度反向传播时带来的计算开销以及一定程度上缓解梯度消失或者爆炸的问题
以上是我对循环神经网络使用相邻采样为什么要detach参数的理解,可能也有问题,如果有问题希望可以指出来
参考链接:https://zhuanlan.zhihu.com/p/79801410
当我们再训练网络的时候可能希望保持一部分的网络参数不变,只对其中一部分的参数进行调整;或者值训练部分分支网络,并不让其梯度对主网络的梯度造成影响,这时候我们就需要使用detach()函数来切断一些分支的反向传播
detach():
返回一个新的Variable,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个Variable永远不需要计算其梯度,不具有grad。 即使之后重新将它的requires_grad置为true,它也不会具有梯度grad .这样我们就会继续使用这个新的Variable进行计算,后面当我们进行反向传播时,到该调用detach()的Variable就会停止,不能再继续向前进行传播
detach_()
将一个Variable从创建它的图中分离,并把它设置成叶子variable .其实就相当于变量之间的关系本来是x -> m -> y,这里的叶子variable是x,但是这个时候对m进行了.detach_()操作,其实就是进行了两个操作:
1.将m的grad_fn的值设置为None,这样m就不会再与前一个节点x关联,这里的关系就会变成x, m -> y,此时的m就变成了叶子结点。
2.然后会将m的requires_grad设置为False,这样对y进行backward()时就不会求m的梯度。
其实detach()和detach()很像,两个的区别就是detach()是对本身的更改,detach()则是生成了一个新的variable 。比如x -> m -> y中如果对m进行detach(),后面如果反悔想还是对原来的计算图进行操作还是可以的 。但是如果是进行了detach_(),那么原来的计算图也发生了变化,就不能反悔了。
参考https://www.cnblogs.com/wanghui-garcia/p/10677071.html;参考:https://pytorch-cn.readthedocs.io/zh/latest/package_references/torch-autograd/#detachsource。