窗口大小与word2vec中实际句子长度的关系

3

我试着在一组.txt文件上运行word2vec(使用gensim实现的skip-gram模型,窗口大小为5)。我使用的迭代器类似于:

class Corpus(object):
    """Iterator for feeding sentences to word2vec"""
    def __init__(self, dirname):
        self.dirname = dirname

    def __iter__(self):

        word_tokenizer = TreebankWordTokenizer()
        sent_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
        text = ''

        for root, dirs, files in os.walk(self.dirname):

            for file in files:

                if file.endswith(".txt"):

                    file_path = os.path.join(root, file)


                    with open(file_path, 'r') as f:

                         text = f.read().decode('utf-8')
                         sentences = sent_tokenizer.tokenize(text)

                         for sent in sentences:
                             yield word_tokenizer.tokenize(sent)

我在这里使用nltk包中的punkt标记器(该标记器使用无监督算法来检测句子边界)将文本分成句子。但是,当我将其替换为简单的line.split(),即只将每个句子视为一行并拆分单词时,我得到了比使用nltk解析器快1.5倍的时间效率。 'with open'内部的代码大致如下:

                 with open(file_path, 'r') as f:
                    for line in f:
                    line.decode('utf-8')
                    yield line.split()

我的问题是,word2vec算法被提供实际句子(我试图使用punkt分词器做到这一点)有多重要?对于算法中的每个单词来说,接收到所在行周围单词的上下文是否足够(在跨越多行的情况下,这些单词可能不是实际的句子),而不是单词在跨越多行的句子中可能具有的上下文。此外,窗口大小在其中扮演什么角色?例如,当窗口大小设置为5时,由Sentences迭代器产生的句子大小是否不再起作用?那么只有窗口大小决定上下文单词吗?在这种情况下,我应该只使用line.split()而不是尝试使用punkt分词器检测实际的句子边界吗?
希望我已经足够描述了这个问题,我真的很感激任何关于这个问题的意见、指针或帮助。

我也对此很感兴趣。你最终有没有找到答案? - aKzenT
@aKzenT 我其实没有这样做。但我的直觉是,line.split() 可能和找到逻辑句子一样有效。 - QPTR
有趣的问题 - samsamara
1个回答

4

window是上下文窗口。如果window设置为5,则对于当前单词w,周围10个单词将被视为上下文单词。根据原始的word2vec代码,单词只在出现在句子中的上下文中进行训练。如果单词+上下文单词超出了句子边界,则其余的上下文单词将被简单地忽略(一种近似方法)。

例如: 考虑句子:I am a boy 如果当前单词是boy并且window为2,则我们可以观察到没有正确的上下文。在这种情况下,代码将取向量ama的平均值,并将其视为boy的上下文(针对word2vec的CBOW模型)。

至于第二个疑问,我使用了没有句子边界的文本语料库,word2vec仍然表现良好。(在Wikipedia语料库中测试过)

希望这解决了您的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接