Scikit learn 将语料库流式传输到管道中的矢量器

Scikit learn 将语料库流式传输到管道中的矢量器,scikit-learn,streaming,gensim,corpus,Scikit Learn,Streaming,Gensim,Corpus,我有一个很大的语言语料库,我使用sklearn-tfidf向量器和gensim-Doc2Vec来计算语言模型。我的总语料库有大约100000个文档,我意识到我的Jupyter笔记本一旦超过某个阈值就停止计算。我猜在应用网格搜索和交叉验证步骤后,内存已满 甚至下面的示例脚本也在某个时候停止了Doc2Vec: %%time import pandas as pd import numpy as np from tqdm import tqdm from sklearn.externals impor

我有一个很大的语言语料库,我使用sklearn-tfidf向量器和gensim-Doc2Vec来计算语言模型。我的总语料库有大约100000个文档,我意识到我的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.")

有没有办法“流式”处理文档中的每一行,而不是将完整数据加载到内存中?还是另一种提高内存效率的方法?我读了一些关于这个主题的文章,但没有发现任何包含管道示例的文章。

只有100000个文档,除非它们是巨大的,否则不一定是将数据加载到内存中导致了问题。特别注意:

  • 在您开始scikit learn pipelines/grid搜索之前,加载和标记文档已经成功,内存使用的进一步倍增是在必要的重复替代模型中,而不是在原始文档中
  • scikit learn API倾向于假设训练数据完全在内存中–因此,即使最内部的gensim类(
    Doc2Vec
    )对任意大小的流数据感到满意,也很难将其应用到scikit learn中
因此,您应该看看其他地方,所显示的代码还有其他问题

scikit learn在并行性方面的尝试(通过
n_jobs
-类参数启用)经常会导致内存或锁定问题,尤其是在Jupyter笔记本中。它分叉整个操作系统进程,这往往会增加内存使用。(每个子进程都会获得父进程内存的完整副本,可以有效地共享,直到子进程开始移动/更改内容为止。)有时一个进程或进程间通信失败,而主进程只是等待响应——这似乎特别让Jupyter笔记本电脑感到困惑

因此,除非您有大量内存并且绝对需要scikit learn parallelism,否则我建议您先尝试使用
n_jobs=1
工作,然后再尝试更多的工作

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

而且:您正在代码中执行一系列冗余操作,这些操作的值不明确。从初始列车测试分割中提取的测试集从未使用过。(也许您正在考虑将其作为最终验证集放在一边?这是对您的最终结果在未来看不见的数据上的性能进行良好估计的最严格的方法,但在许多情况下,数据是有限的,而这种估计并不像在有限的数据下尽可能做到最好那样重要。)

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

因此,您无需再次执行
cross\u val\u score()
——您可以从
GridSearchCV
读取结果