【问题标题】:Streaming corpus to a vectorizer in a pipeline将语料库流式传输到管道中的矢量化器
【发布时间】:2019-01-16 08:37:46
【问题描述】:

我有一个大型语言语料库,我使用 sklearn tfidf 矢量化器和 gensim Doc2Vec 来计算语言模型。我的总语料库有大约 100,000 个文档,我意识到一旦我越过某个阈值,我的 Jupyter 笔记本就会停止计算。我猜在应用网格搜索和交叉验证步骤后内存已满。

即使下面的示例脚本在某些时候已经停止用于 Doc2Vec:

%%time
import pandas as pd
import numpy as np
from tqdm import tqdm
from sklearn.externals import joblib

from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import TfidfVectorizer
from gensim.sklearn_api import D2VTransformer

from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from gensim.utils import simple_preprocess

np.random.seed(1)

data = pd.read_csv('https://pastebin.com/raw/dqKFZ12m')
X_train, X_test, y_train, y_test = train_test_split([simple_preprocess(doc) for doc in data.text],
                                                    data.label, random_state=1)

model_names = [
               'TfidfVectorizer',
               'Doc2Vec_PVDM',
              ]

models = [
    TfidfVectorizer(preprocessor=' '.join, tokenizer=None, min_df = 5),
    D2VTransformer(dm=0, hs=0, min_count=5, iter=5, seed=1, workers=1),
]

parameters = [
              {
              'model__smooth_idf': (True, False),
              'model__norm': ('l1', 'l2', None)
              },
              {
              'model__size': [200],
              'model__window': [4]
              }
              ]

for params, model, name in zip(parameters, models, model_names):

    pipeline = Pipeline([
      ('model', model),
      ('clf', LogisticRegression())
      ])

    grid = GridSearchCV(pipeline, params, verbose=1, cv=5, n_jobs=-1)
    grid.fit(X_train, y_train)
    print(grid.best_params_)

    cval = cross_val_score(grid.best_estimator_, X_train, y_train, scoring='accuracy', cv=5, n_jobs=-1)
    print("Cross-Validation (Train):", np.mean(cval))

print("Finished.")

有没有办法“流式传输”文档中的每一行,而不是将完整数据加载到内存中?或者另一种提高内存效率的方法?我阅读了几篇关于该主题的文章,但找不到任何包含管道示例的文章。

【问题讨论】:

    标签: scikit-learn streaming gensim corpus


    【解决方案1】:

    只有 100,000 个文档,除非它们是巨大的,否则给您带来问题的不一定是将数据加载到内存中。特别注意:

    • 在您开始 scikit-learn 管道/网格搜索之前,加载和标记文档已经成功,并且内存使用量的进一步增加是在必然重复的替代模型中,不是原始文档
    • scikit-learn API 倾向于假设训练数据完全在内存中 - 因此即使最里面的 gensim 类 (Doc2Vec) 对任意大小的流数据感到满意,但很难将其适应 scikit-learn李>

    所以你应该看看别处,你显示的代码还有其他问题。

    在 scikit-learn 的并行尝试(通过 n_jobs-like 参数启用)时,我经常遇到内存或锁定问题,尤其是在 Jupyter 笔记本中。它分叉了完整的操作系统进程,这往往会破坏内存使用。 (每个子进程都会获得父进程内存的完整副本,这可能会被有效地共享——直到子进程开始移动/更改事物。)有时一个进程或进程间通信失败,而主进程只是等待寻求回应——这似乎特别让 Jupyter 笔记本感到困惑。

    所以,除非您有大量内存并且绝对需要 scikit-learn 并行性,否则我建议您先尝试使用 n_jobs=1,然后再尝试更多工作。

    相比之下,Doc2Vec 类(和D2VTransformer)的workers 使用更轻量级的线程,你应该至少使用workers=3,也许8 个(如果你至少有那么多内核,而不是您现在使用的workers=1

    而且:您在代码中执行了一堆价值不明确的冗余操作。从未使用过来自初始训练测试拆分的测试集。 (也许您正在考虑将其作为最终验证集放在一边?这是对您的最终结果在未来看不见的数据上的表现进行良好估计的最严格方法,但在许多情况下,数据是有限的,并且该估计并不像重要的是尽可能利用有限的数据做到最好。)

    GridSearchCV 本身会进行 5 路训练/测试拆分,作为其工作的一部分,完成后其最佳结果会在其属性中被记住。

    因此您无需再次执行cross_val_score() - 您可以从GridSearchCV 读取结果。

    【讨论】:

      猜你喜欢
      • 2020-11-12
      • 2012-11-10
      • 2015-07-12
      • 2020-02-19
      • 1970-01-01
      • 2016-09-17
      • 1970-01-01
      • 2014-08-17
      相关资源
      最近更新 更多