J'essaie d'utiliser scikit-learn pour classer un grand nombre de documents texte, bien que j'utilise la fonctionnalité extra-core (avec SGDClassifier
et HashingVectorizer
) le programme semble consommer beaucoup de RAM (> 10GB). J'ai effectué la lemmatisation et supprimé les mots vides des données de texte avant cela. J'ai l'impression de manquer quelque chose d'important ici. Pouvez-vous repérer une erreur dans mon code?Scikit-apprendre la consommation de mémoire de classification de texte hors-core
Merci beaucoup pour votre suggestion!
Ceci est mon code python:
import time
import numpy as np
import os
import re
import pyprind
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.linear_model import SGDClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
directory = "mydirectory"
batch_size = 1000
n_batches = 44
pbar = pyprind.ProgBar(n_batches)
class Doc_Iterable:
def __init__(self, file):
self.file = file
def __iter__(self):
for line in self.file:
line = re.sub('[^\w\s]|(.\d{1,4}[\./]\d{1,2}[\./]\d{1,4})|(\s\d{1,})', '', line)
yield line
def stream_docs(path, texts_file, labels_file):
with open(path + texts_file, 'r') as fX, open(path + labels_file, 'r') as fy:
for text in fX:
label = next(fy)
text = re.sub('[^\w\s]|(.\d{1,4}[\./]\d{1,2}[\./]\d{1,4})|(\s\d{1,})', '', text)
yield text, label
def get_minibatch(doc_stream, size):
X, y = [], []
for _ in range(size):
text, label = next(doc_stream)
X.append(text)
y.append(label)
return X, y
classes = set()
for label in open(directory + 'y_train', 'r'):
classes.add(label)
for label in open(directory + 'y_test', 'r'):
classes.add(label)
classes = list(classes)
validation_scores = []
training_set_size = []
h_vectorizer = HashingVectorizer(lowercase=True, ngram_range=(1,1))
clf = SGDClassifier(loss='hinge', n_iter=5, alpha=1e-4, shuffle=True)
doc_stream = stream_docs(path=directory, texts_file='X_train', labels_file='y_train')
n_samples = 0
iteration = 0
for _ in range(n_batches):
print("Training with batch nr.", iteration)
iteration += 1
X_train, y_train = get_minibatch(doc_stream, size=batch_size)
n_samples += len(X_train)
X_train = h_vectorizer.transform(X_train)
clf.partial_fit(X_train, y_train, classes=classes)
pbar.update()
del X_train
del y_train
print("Training complete. Classifier trained with " + str(n_samples) + " samples.")
print()
print("Testing...")
print()
X_test = h_vectorizer.transform(Doc_Iterable(open(directory + 'X_test')))
y_test = np.genfromtxt(directory + 'y_test', dtype=None, delimiter='|').astype(str)
prediction = clf.predict(X_test)
score = metrics.accuracy_score(y_test, prediction)
print("Accuracy: ", score)
print()
Quelle est la taille totale de votre ensemble de données: 44000 documents? Avez-vous essayé d'appliquer un HashingVectorizer à l'ensemble de données complet? D'après mon expérience, l'extraction de fonctions à partir de 700 000 courriels textuels sans approche hors noyau nécessite moins de 16 Go de RAM, de sorte que vos chiffres sont assez importants. À moins que les documents ne soient très longs. Réduire le nombre de fonctionnalités ne changera pas de manière significative de toute façon car ce sont des tableaux clairsemés avec peu de collisions de hachage (je ne suis pas d'accord avec la réponse ci-dessous). – rth
Merci. J'ai 3 millions de documents, je vais probablement devoir en faire plus en termes de pré-traitement pour réduire le nombre de fonctionnalités/taille de vocabulaire. L'utilisation de Tf-idf semble fonctionner correctement pour un sous-ensemble de 1 Go de fichiers texte en entrée. Je vais également essayer d'utiliser le 'HashingVectorizer' sans apprentissage hors-core ... – cookiedealer
3 millions de documents est assez grand. Vous devriez faire un profilage ligne par ligne avec 'memory_profiler' pour comprendre où la mémoire est allouée (ou non libérée). S'il s'agit d'un script, l'exécuter avec 'python -m memory_profiler' devrait suffire ... – rth