预训练word2vec

http://zh-v2.d2l.ai/chapter_natural-language-processing-pretraining/word2vec-pretraining.html

有同学在训练的时候遇到这个问题吗:
AttributeError: Can’t pickle local object ‘load_data_ptb..PTBDataset’
EOFError: Ran out of input

我也遇到了这个问题
AttributeError: Can’t pickle local object ‘load_data_ptb..PTBDataset’
Traceback (most recent call last):
File “”, line 1, in
File “D:\Study\soft_ware\anaconda\envs\nlp\lib\multiprocessing\spawn.py”, line 99, in spawn_main
new_handle = reduction.steal_handle(parent_pid, pipe_handle)
File “D:\Study\soft_ware\anaconda\envs\nlp\lib\multiprocessing\reduction.py”, line 87, in steal_handle
_winapi.DUPLICATE_SAME_ACCESS | _winapi.DUPLICATE_CLOSE_SOURCE)
PermissionError: [WinError 5] 拒绝访问。

我也遇到了这个问题,把d2l.laod_data_ptb里面的num_works改成零就可以了,多线程的问题。

请问如何修改?谢谢!
“d2l.laod_data_ptb里面的num_works改成零就可以了”

14.3.3 小节中最后一段打印的实际上应该是“中心词-上下文词对”中上下文词元总数吧?

  1. 先找到d2l包的安装位置:conda info --envs
  2. 在到torch.py文件中修改: get_dataloader_workers() 函数 return 0
    (torch.py文件的路径 类似:C:\Users\dell.conda\envs\d2l\Lib\site-packages\d2l)
class SigmoidBCELoss(nn.Module):
    # 带掩码的二元交叉熵损失
    def __init__(self):
        super().__init__()

    def forward(self, inputs, target, mask=None):
        out = nn.functional.binary_cross_entropy_with_logits(
            inputs, target, weight=mask, reduction="none")
        return out.mean(dim=1)

loss = SigmoidBCELoss()

这个forword函数里 return out.mean(dim=1) 这句话写的不好,导致后面使用起来还得绕一绕。
因为out里只对unmask token计算了logits,所以应该按unmask token的个数求平均才合理,而out.mean(dim=1)是按mask.shape1来求平均。

正是因为这个,导致了后面每次使用loss的时候,都需要先乘以mask.shape[1]恢复到求平均之前,再除以mask.sum(axis=1)。。。

改成下面比较好:

        if mask is None:
             return out.mean(dim=1)
       return  (out * mask).sum(dim=1) / mask.sum(dim=1)  # 仅返回unmask token的均值

第2个问题:“同一中心词在不同的训练迭代轮数可以有不同的上下文词或噪声词。这种方法的好处是什么?”

回答:
不同epoch之间窗口的大小变化可以提高训练的效果和稳定性。具体来说:

  • 多样性:随机采样窗口大小可以引入更多的多样性,使得模型不仅仅关注固定大小的上下文窗口。这样可以更好地捕捉不同距离的关系,避免过于集中在一个特定的上下文范围内。
  • 平衡计算复杂度:较大的上下文窗口可能会引入更多的噪声,因为与中心词距离较远的词可能与中心词的语义关联较弱。同时,较大的窗口可能会增加计算的复杂度,因为要考虑更多的上下文词。通过随机采样窗口大小,可以在捕捉不同距离关系的同时,平衡计算的复杂度。
  • 训练稳定性:随机窗口大小可以提高模型的训练稳定性。如果总是使用固定的max_window_size,可能会使模型对于固定距离范围内的关系过于敏感,从而导致训练不稳定。
  • 对罕见词的处理:对于罕见词,较大的上下文窗口可能会导致模型将与中心词无关的词考虑在内,从而影响预测的准确性。随机窗口大小可以在一定程度上缓解这个问题。

如何实现呢,也比较简单:

  1. 核心思路:train()函数中for epoch in range(num_epochs)语句之后,每轮epoch刚开始的时候,重新调用load_data_ptb()函数刷新一下内部的all_negatives即可。
  2. 效率问题:反复调用原始的load_data_ptb()函数会导致反复加载和预处理整个数据集,效率相当底下。所以需要对load_data_ptb()函数调整一下,添加必要的缓存机制,让其他数据都走缓存,仅all_negatives重置刷新即可。

应该是一样的,只是摆放位置不同而已。。。

可能误会了。原始加载数据集是已经对packed examples 进行shuffle了,现在 是对contexts, negatives 进一步shuffle。我试过,效果是no significant changes. 因为原来的 window size, negatives本身已经是random sampling

some questions:
a. how to metric ‘semantically similarity’
b. why uses cosine to do similarity rather than ‘dot product’ ? the latter is used in training step