Doc2Vec模型中tqdm函数的问题



我正在使用这篇文章https://actsusanli.medium.com/来实现Doc2Vec模型,我在训练步骤中遇到了一个问题。

model_dbow.train(utils.shuffle([x for x in tqdm(train_tagged.values)]), total_examples=len(train_tagged.values), epochs = 40)

如您所见,我正在使用tqdm函数。当我运行代码时,tqdm是100%,几分钟后,但算法仍然在同一个shell中运行很长时间。

你知道这是tqdm函数的问题还是别的什么吗?

通过使用"列表推导式"([……])…

[x for x in tqdm(train_tagged.values)]

…你让tqdm在你的train_tagged.values序列上迭代一次,进入一个实际的内存中的Python列表。这将很快显示tqdm的进度-然后完全完成与tqdm的任何参与。

然后,您将该普通结果列表(没有任何tqdm功能)传递到Doc2Vec.train(),其中Doc2Vec执行其epochs=40训练通过。不再涉及tqdm,因此不会有增量进度条输出。

您可能会尝试(或已经尝试过)跳过额外的list创建,直接传递tqdm包装的序列,如:

corpus = utils.shuffle(train_tagged.values)
model_dbow.train(tqdm(corpus), total_examples=len(corpus), epochs = 40)

但是这有一个不同的问题:tqdm-包装器只允许(&在包装序列上报告一个迭代的进度。因此,这将显示一次迭代的增量进度。

但是当.train()尝试下一个必要的39次重新迭代,以完成其epochs=40训练运行时,单次通过的tqdm对象将被耗尽,从而阻止完整的&适当的培训。

请注意,在Gensim中有一个进程日志的选项,通过将Python日志级别(全局的,或者仅针对Doc2Vec类)设置为INFO。然后,Doc2Vec将在每个epoch内和epoch之间大约每1秒发出一条显示进度的日志线。但是,您也可以通过为.train()的可选report_delay参数提供不同的秒值来降低日志记录的频率,例如report_delay=60(用于每分钟而不是每秒钟的日志行)。

如果你真的想要一个进度条,应该可以使用tqdm——但是你必须绕过它的假设,即你用tqdm()包装的可迭代对象只迭代一次。

我相信有两种可能的方法,每种方法都有不同的权衡:

(1)与其让.train()重复语料库N次,不如自己做——调整另一个。train()参数。粗略地说,这意味着改变一行,比如…

model.train(corpus, total_examples=len(corpus), epochs=40)

…变成了一些东西,把你想要的40个epoch变成了一些东西,看起来就像一个迭代tqdm&Gensim的.train(),像…

repeated_corpus = itertools.chain(*[corpus]*40)
repeated_len = 40 * len(corpus)
model.train(tqdm(repeated_corpus, total=repeated_len), total_examples=repeated_len, epochs=1)

(注意,现在tqdm一个序列长度的提示,因为itertools.chain()的一次性链迭代器不报告它自己的长度。)

然后你将在整个训练语料库中得到一个进度条-模型现在将其视为一个更大的语料库的一次传递,但最终涉及相同的40次传递。

您将需要重新解释任何剩余的日志行,并且您将失去通过模型的epoch结束回调机制安装自己的每个epoch回调的机会。(但是,无论如何,这是一个很少使用的功能。)

(2)代替用单个tqdm()包装语料库(它只能在一次迭代中显示进度条),将语料库包装为一个新的完全可重复迭代的对象,它自己每次都会启动一个新的tqdm()。例如:

class TqdmEveryIteration(object):
def __init__(self, inner_iterable):
self.inner_iterable = inner_iterable
def iter(self):
return tqdm(inner_iterable)
然后,使用这个新的额外的tqdm添加包装器,您应该能够做到:
corpus = utils.shuffle(train_tagged.values)
model_dbow.train(TqdmEveryIteration(corpus), total_examples=len(corpus), epochs = 40)

在这种情况下,您应该得到一个进度条每个epoch,因为一个新的tqdm()包装器将启动每个训练通过。

(如果您尝试这两种方法中的任何一种&他们工作得很好,请告诉我!它们应该是大致正确的,但我还没有测试过。)

单独:如果您正在为您的工作建模的actsusanli.medium.com作者的文章是…

https://towardsdatascience.com/multi-class-text-classification-with-doc2vec-logistic-regression-9da9947b43f4

…注意,它使用了一个过于复杂的& &;脆弱的反模式,在手动alpha管理的循环中多次调用.train()。这在另一个答案中也有问题。但是这种方法也有副作用,每次在新的tqdm中重新包装语料库(如上面的TqdmEveryIteration类),因此尽管存在其他问题,每次调用.train()将实现一个实际的进度条。

(大约一个月前,我就这个问题通过Medium给作者发了一封私人信件。)

最新更新