关于Keras中skipgrams()函数输出结果不符预期的技术问询
理解Keras skipgrams()函数的行为差异
你的疑惑主要来自对Keras skipgrams() 负样本生成逻辑的误解,以及它的随机采样特性。我们一步步拆解问题:
1. 为什么会出现同一配对既有label=1又有label=0?
Keras的skipgrams()生成负样本的方式不是枚举所有非上下文词对,而是基于正样本数量随机采样,默认参数negative_samples=1.0意味着每生成1个正样本,就对应生成1个负样本。
具体来说,负样本的生成逻辑是:
- 从所有正样本的第一个词中随机选取一个词作为配对的第一个元素
- 然后从整个词汇表中随机选取一个词作为第二个元素(甚至可能选到当前词本身,比如你输出里的
(i,i)->0)
当你的词汇表极小(只有3个词)时,随机采样很容易重复生成已经是正样本的配对,这时候这个配对会被标记为0——因为它是作为负样本被随机选中的,不管它本身是不是正样本对。
比如你输出里的(love,i)->0,就是在负采样阶段,随机选了love作为第一个词,又随机抽到了i作为第二个词,所以被标记为负样本。
2. 为什么预期的(i,money)和(money,i)配对没出现?
还是因为负样本是随机采样,而不是生成所有可能的非上下文词对。你的词汇表只有3个词,负采样的样本量是4个(和正样本数量一致,正样本有4个:(love,i),(love,money),(i,love),(money,love)),这次运行时随机采样的结果刚好没抽到(i,money)和(money,i),如果多运行几次代码,你大概率会看到这两个配对出现在负样本里。
3. 纠正你对负样本的理解偏差
你之前认为负样本是所有"单词+非窗口内单词"的配对,但Keras的skipgrams()并不是这么实现的:
- 正样本:严格按照窗口大小生成所有"目标词+窗口内上下文词"的配对(你预期的正样本是对的,输出里的4个label=1的配对也符合预期)
- 负样本:是随机从词汇表中选取词对,数量由
negative_samples参数控制,而非枚举所有非正样本对。这种随机负采样是Word2Vec等模型常用的方式,目的是减少计算量,同时保证模型能学到足够的负例。
验证修改建议
如果你想更清晰地看到所有可能的负样本,可以调整参数:
- 增大
negative_samples的值(比如设为3.0),这样会生成更多负样本,更容易抽到你预期的(i,money)和(money,i) - 或者查看Keras的
skipgrams()源码,自定义负样本生成逻辑(如果需要枚举所有非正样本对的话)
另外,你的代码里缺少id2word的定义,补充后才能正确打印单词:
id2word = {v: k for k, v in word2id.items()}
内容的提问来源于stack exchange,提问作者Raven Cheuk
相关产品推荐
相关产品推荐

