BERTopic 将参数和结果保存到日志文件中

pu3pd22g  于 4个月前  发布在  其他
关注(0)|答案(5)|浏览(81)

我发现将参数和结果保存到日志文件中很有用。
我扩展了BERTopic类以满足我的需求,这里你可以看一下:
https://github.com/buscon/fg_analysis_with_BERT/blob/main/classes/custom_log_bertopic.py
这是一个基本实现,它应该被扩展和完善。
如果你对@MaartenGr有兴趣将此类功能集成到BERTopic中,我可以将其分支并在BERTopic结构内实现此功能并发起PR。

s1ag04yj

s1ag04yj1#

感谢@buscon分享您的实现。阅读起来真的很有趣。我对日志记录也有些兴趣,我想补充一下我的想法。

我不确定将这个添加到BERTopic中是否完全必要。我认为这行代码确实可以从类中受益:

self.logger.info(f"Initialized BERTopic with parameters: {args}, {kwargs}")

我很好奇,当您提供自己的umap模型给BERTopic时,它会打印出什么?它只是给您提供了umap的参数和关键字参数吗?
所以也许将其添加到BERTopic现有的日志记录中是有意义的,但其他行也可以很容易地放入您的主脚本中,可能对用户非常特定。

# Logging the end of the method and results
        self.logger.info("Completed fit_transform method")
        self.logger.info(f"Topics: {predictions}")
        self.logger.info(f"Topics: {self.get_topic_info()}")
        self.logger.info(f"Topic Names: {self.get_topic_info().Name}")
        self.logger.info(f"Probabilities: {self.probabilities_}")

我个人其实不需要记录概率,而且我也不确定是否需要记录整个topic_info表,尤其是当我有数百个主题的时候。
我想了解的是@MaartenGr如何让内置的BERTopic日志输出到文件。我喜欢详细的日志记录,因为它记录了不同阶段所花费的时间(我不介意为CountVectorizer/CTFIDF阶段记录时间,它们比大量文本的UMAP花费更长),但我一直无法让它输出到文件。
我使用以下函数设置我的日志记录。我可以得到自己的日志以及sentence_transformers中的日志,但从BERTopic中没有得到任何日志,尽管它确实输出到了控制台。添加一个FileHandler似乎不起作用。

def setup_logging():
    """enable logging from internal modules and common packages"""

    logging.basicConfig(
        format="%(asctime)s [%(levelname)s] [%(module)s] %(message)s",
        handlers=[
            logging.FileHandler("debug.log", mode="w"),
            logging.StreamHandler(sys.stdout)
        ]
    )

    logging.getLogger().setLevel(logging.WARNING)
    logger = logging.getLogger("Notebook")
    logger.setLevel(logging.INFO)

    logging.getLogger("BERTopic").setLevel(logging.INFO)
    logging.getLogger("BERTopic").addHandler(logging.FileHandler("debug.log", mode="a"))
    logging.getLogger("sentence_transformers").setLevel(logging.INFO)
    logging.getLogger("sentence_transformers").addHandler(logging.FileHandler("debug.log", mode="a"))

    return logger

logger = setup_logging()
logger.info("Starting clustering pipeline...")
...

如果我们能够成功地将内置的BERTopic日志输出到文件,那么我认为您可以基本上让用户记录他们想要记录的其他内容

xqnpmsa8

xqnpmsa82#

我想了解的是,如何让内置的BERTopic日志记录器输出到文件。我喜欢详细的日志记录,因为它记录了不同阶段所需的时间(顺便说一下,我不介意为CountVectorizer/CTFIDF阶段设置一个时间,它们比大量文本的UMAP耗时更长),但我还没有找到让它输出到文件的方法。
当然,这应该相对容易实现(相对于CV/cTFIDF阶段)。我需要检查一下具体细节,但应该是可以自动输出模型的日志的。然而,我认为当用户运行BERTopic时,自动创建日志并不是最佳体验。在这里,手动选择会更好一些。让我犹豫的是,参数的数量越来越大,以至于影响到了用户体验(我已经在使用当前设置时经历过这种情况)。因此,为了尽可能避免添加非核心功能的其他参数。

8xiog9wr

8xiog9wr3#

我想了解的是,如何让内置的BERTopic日志记录器输出到文件。我喜欢详细的日志记录,因为它记录了不同阶段所花费的时间(顺便说一下,我不介意CountVectorizer/CTFIDF阶段的时间,它们比大量文本的UMAP耗时更长),但我还没有找到让它输出到文件的方法。
当然,这应该相对容易实现(相对于CV/cTFIDF阶段)。我需要检查一下具体细节,但应该是可以自动输出模型的日志的。然而,我认为当用户运行BERTopic时自动创建日志并不是最好的体验。在这里,手动选择会更好一些。让我犹豫的是参数的数量越来越大,以至于影响用户体验(我已经在使用当前设置时体验到了这一点)。所以,尽可能避免为非核心功能添加另一个参数。
我完全理解你的担忧,我也不想在BERTopic主类中添加它。但是,关于扩展类,比如BERTopicLogger怎么样?
或者,BERTopic类中添加一个额外的方法来执行日志记录?这样用户可以在需要时使用它。
我不确定是否有必要将此添加到BERTopic中。我认为唯一从类中受益的那一行是:
我同意你的看法,最有用的日志材料是BERTopic参数。另一方面,将其作为其他输出参数添加也是不错的选择。我目前还没有在我当前的类中这样做。

pwuypxnk

pwuypxnk4#

抱歉回复晚了。
然而,我认为对于用户来说,每当他们运行BERTopic时自动创建日志并不是最好的体验。让我犹豫的是参数的数量开始变得越来越大,以至于影响用户体验(我已经在使用当前设置时体验到了这一点)。因此,为了尽可能避免添加另一个非核心功能参数。
是的,完全同意。对不起,我不是想建议BERTopic自动执行这个功能,或者成为你需要添加的功能。一般来说,用户可以通过获取内部记录器并向其添加额外的处理程序来拦截和重定向包的内部记录器。例如:

logging.getLogger({package name}).addHandler({handler})

这就是我一直试图用BERTopic实现的。今天我在那里解决了自己的问题。我只是在运行logging.basicConfig()时添加了force=True来重置根记录器(不是很清楚为什么,没关系,都很开心)。
@buscon 我认为有一种更好的方法来记录这些参数,而不是将其作为BERTopic的一个特性融入其中,这将给你(和其他用户)更多的控制权,而不需要增加功能空间。在你链接的例子中,你已经将umap和hdbscan参数放在了一个配置文件中,这是很好的。如果你只是将BERTopic超参数添加到那里,它们就会变得很容易自己记录,并传递给所需的函数。例如:

from umap import UMAP 
from bertopic import BERTopic
from sklearn.datasets import fetch_20newsgroups
import logging
import sys

# set general logging
logging.basicConfig(
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("my_log_file.log", mode="w"),
        logging.StreamHandler(sys.stdout)
    ],
    force=True
)

logging.getLogger().setLevel(logging.WARNING)
logger = logging.getLogger("Notebook")
logger.setLevel(logging.INFO)

# redirect logging for BERTopic
handler = logging.FileHandler("my_log_file.log", mode="a")
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
logging.getLogger("BERTopic").setLevel(logging.INFO)
logging.getLogger("BERTopic").addHandler(handler)

# you can substitute this with your config.ini file
config = {
    'UMAP': {
        'n_neighbors': 17, 
        'n_components': 3, 
        'min_dist': 0.0
    },
    'BERTopic': {
        'top_n_words': 10, 
        'verbose': True, 
        'calculate_probabilities': True,
    }
    # etc...
}

logger.info(f"UMAP parameters: {config['UMAP']}")
logger.info(f"BERTopic hyper parameters: {config['BERTopic']}")

topic_model = BERTopic(
    umap_model=UMAP(**config['UMAP']),
    # etc...
    **config['BERTopic']
)

# get newsgroups data
data = fetch_20newsgroups(subset='all',  remove=('headers', 'footers', 'quotes'))
docs = data['data'][0:500]

topics, _ = topic_model.fit_transform(docs)

# log the probs, topics, whatever else you want

这将导致一个日志文件看起来像这样:

2024-01-29 13:38:11,887 - INFO - UMAP parameters: {'n_neighbors': 17, 'n_components': 3, 'min_dist': 0.0}
2024-01-29 13:38:11,888 - INFO - BERTopic hyper parameters: {'top_n_words': 10, 'verbose': True, 'calculate_probabilities': True}
2024-01-29 13:38:13,026 - INFO - Embedding - Transforming documents to embeddings.
2024-01-29 13:38:16,541 - INFO - Embedding - Completed ✓
2024-01-29 13:38:16,542 - INFO - Dimensionality - Fitting the dimensionality reduction algorithm
2024-01-29 13:38:21,283 - INFO - Dimensionality - Completed ✓
2024-01-29 13:38:21,285 - INFO - Cluster - Start clustering the reduced embeddings
2024-01-29 13:38:21,319 - INFO - Cluster - Completed ✓
2024-01-29 13:38:21,322 - INFO - Representation - Extracting topics from clusters using representation models.
2024-01-29 13:38:21,412 - INFO - Representation - Completed ✓

通过保持对你自己的日志记录的控制,你可以将其定制为你的使用场景和你实际感兴趣的内容。

5lwkijsr

5lwkijsr5#

感谢您分享这个!目前,由于使用场景有限,类似的东西还不在我的项目路线图上。尽管如此,如果其他用户对此有足够的兴趣,它完全可以实现。我会保持开放的态度,看看其他人的React。

相关问题