как я могу выполнить задачу классификации текста, используя меньше памяти



(1) Моя цель:
Я пытаюсь использовать SVM для классификации 10000 документов (каждый из которых содержит 400 слов) в 10 классов(равномерно распределенных). Особенности, изученные в моей работе, включают слово n-грамм(n=1~4),символ n-грамм (n=1~6).



(2) Мой подход: я представляю каждый документ, используя векторы значений частоты для каждого элемента в документе. И использование TF-IDF для формализации векторов. ниже приведены части моего кода:



def commonVec(dicts,count1,count2):
''' put features with frequency between count1 and count2 into a common vector used for SVM training'''
global_vector = []
master = {}
for i, d in enumerate(dicts):
for k in d:
master.setdefault(k, []).append(i)
for key in master:
if (len(master[key])>=count1 and len(master[key])<=count2):
global_vector.append(key)
global_vector1 = sorted(global_vector)
return global_vector1
def featureComb(mix,count1,count2,res1):
'''combine word n-gram and character n-gram into a vector'''
if mix[0]:
common_vector1 = []
for i in mix[0]:
dicts1 = []
for res in res1: #I stored all documents into database. res1 is the document result set and res is each document.
dicts1.append(ngram.characterNgrams(res[1], i)) # characterNgrams()will return a dictionary with feature name as the key, frequency as the value.
common_vector1.extend(commonVec(dicts1, count1, count2))
else:
common_vector1 = []
if mix[1]:
common_vector2 = []
for j in mix[1]:
dicts2 = []
for res in res1:
dicts2.append(ngram.wordNgrams(res[1], j))
common_vector2.extend(commonVec(dicts2, count1, count2))
else:
common_vector2 = []
return common_vector1+common_vector2

def svmCombineVector(mix,global_combine,label,X,y,res1):
'''Construct X vector that can be used to train SVM'''
lstm = []
for res in res1:
y.append(label[res[0]]) # insert class label into y

dici1 = {}
dici2 = {}
freq_term_vector = []
for i in mix[0]:
dici1.update(ngram.characterNgrams(res[1], i))
freq_term_vector.extend(dici1[gram] if gram in dici1 else 0 for gram in global_combine)
for j in mix[1]:
dici2.update(ngram.wordNgrams(res[1], j))
freq_term_vector.extend(dici2[gram] if gram in dici2 else 0 for gram in global_combine)
lstm.append(freq_term_vector)
freq_term_matrix = np.matrix(lstm)
transformer = TfidfTransformer(norm="l2")
tfidf = transformer.fit_transform(freq_term_matrix)
X.extend(tfidf.toarray())

X = []
y = []
character = [1,2,3,4,5,6]
word = [1,2,3,4]
mix = [character,word]
global_vector_combine = featureComb(mix, 2, 5000, res1)
print len(global_vector_combine) # 542401
svmCombineVector(mix,global_vector_combine,label,X,y,res1)
clf1 = svm.LinearSVC()
clf1.fit(X, y)


(3) Моя проблема: однако, когда я запустил исходный код, память произошла ошибка.



Traceback (most recent call last):
File "svm.py", line 110, in <module>
functions.svmCombineVector(mix,global_vector_combine,label,X,y,res1)
File "/home/work/functions.py", line 201, in svmCombineVector
X.extend(tfidf.toarray())
File "/home/anaconda/lib/python2.7/site-packages/scipy/sparse/compressed.py", line 901, in toarray
return self.tocoo(copy=False).toarray(order=order, out=out)
File "/home/anaconda/lib/python2.7/site-packages/scipy/sparse/coo.py", line 269, in toarray
B = self._process_toarray_args(order, out)
File "/home/anaconda/lib/python2.7/site-packages/scipy/sparse/base.py", line 789, in _process_toarray
_args
return np.zeros(self.shape, dtype=self.dtype, order=order)
MemoryError


Мне действительно тяжело с этим и нужна помощь от stackoverflow.




    Может ли кто-нибудь объяснить некоторые детали и дать мне некоторое представление о том, как это решить?
    Может ли кто-нибудь проверить мой исходный код и показать мне некоторые другие методы более эффективного использования памяти?
676   1  

1 ответ:

Основная проблема, с которой вы столкнулись, заключается в том, что вы используете слишком много функций. Это на самом деле довольно необычно, что вам удалось создать 542401 функцию из документов, которые содержат всего 400 слов! Я видел, как классификаторы SVM отделяют спам от не-спама с высокой точностью, используя всего 150 функций-количество слов выбранных слов, которые много говорят о том, является ли документ спамом. Они используют стемминг и другие приемы нормализации, чтобы сделать функции более эффективными.

Вам нужно потратить некоторое время на истончение ваших черт. Подумайте о том, какие функциис наибольшей вероятностью содержат информацию, полезную для этой задачи. Экспериментируйте с различными функциями. Пока вы продолжаете выбрасывать все, кроме кухонной раковины, вы получите ошибки памяти. Прямо сейчас вы пытаетесь передать 10000 точек данных с 542401 измерениями каждая в ваш SVM. Вот это да 542401 * 10000 * 4 = 21 гигабайты (консервативно) данных. Мой компьютер имеет только 4 гигабайта БАРАН. Ты должен пройти этот путь вниз.1

Первым шагом к этому было бы подумать о том, насколько велик ваш общий словарный запас. Каждый документ содержит всего 400 слов, но предположим, что эти 400 слов взяты из словаря в 5000 слов. Это значит, что будут 5000 ** 4 = 6.25 * 10 ** 14 возможно 4 грамма. Этополовина квадриллиона возможных 4-граммов . Конечно, не все эти 4 грамма появятся в ваших документах, но это далеко не объясняет, почему у тебя кончается память. Вам действительно нужны эти 4 грамма? Вы могли бы получить только 2 грамма? Есть жалкие 5000 * * 2 = 25 миллионов возможных 2-граммов. Это будет гораздо легче укладываться в память, даже если появятся все возможные 2 грамма (маловероятно).

Также имейте в виду, что даже если SVM может обрабатывать квадриллионы точек данных, это, вероятно, даст плохие результаты, потому что, когда вы даете любому алгоритму обучения слишком много функций, он будет склонен перестраиваться, подбирая несущественные паттерны и сверхгенерализация из них. Есть способы справиться с этим, но лучше всего не, чтобы справиться с этим вообще, если вы можете помочь ему.

Я также отмечу, что это не проблемы" новичков". Это проблемы, с которыми приходится иметь дело специалистам по машинному обучению с докторскими степенями. Они придумывают много умных решений, но мы не настолько умны, чтобы быть умными по-другому.

Хотя я не могу предложить вам конкретных предложений для ума. не зная больше, я бы сказал, что, во-первых, стемминг-это хорошая идея, по крайней мере, в некоторых случаях. Стемминг просто устраняет грамматическую флексию, так что различные формы одного и того же слова ("плавать" и "плавать") рассматриваются как идентичные. Это, вероятно, значительно сократит ваш словарный запас, по крайней мере, если вы имеете дело с английским текстом. Общим выбором является Портер стеммер , который входит в состав nltk, так же как и в ряде других пакеты . Кроме того, если вы этого еще не сделали, вам, вероятно, следует убрать знаки препинания и сократить все слова до строчных. Оттуда, это действительно зависит. Стилометрия (идентификация авторов) иногда требует только частицы ("а", "Ан", "the"), союзы ("и", "но") и другие очень распространенные слова; спам, с другой стороны, имеет свои собственные странные словари, представляющие интерес. На этом уровне очень трудно заранее сказать, что будет работать; вам почти наверняка нужно попробовать разные подходы, чтобы увидеть, какие именно наиболее эффективный. Как всегда, тестирование имеет решающее значение!

1. Ну, возможно, у вас есть огромное количество оперативной памяти в вашем распоряжении. Например, у меня есть доступ к машине с 48G оперативной памяти на моем текущем рабочем месте. Но я сомневаюсь, что он сможет справиться и с этим, потому что SVM будет иметь свое собственное внутреннее представление данных, что означает, что в какой-то момент будет по крайней мере одна копия; если в какой-то момент понадобится вторая копия-Бах.

Comments

    Ничего не найдено.