Когда мы обрабатываем текст, мы можем столкнуться с требованием вычисления сходства текста или нахождения приблизительного выражения текста.В этой статье, с точки зрения практической работы, мы вручную обучаем модели word2vec и doc2vec для вычисления сходства текста.
Когда мы упоминаем word2vec, многие люди могут подумать о CBOW (Continuous Bag of Words), модели Skip-gram и ее алгоритме.
Примечание. Модели CBOW и Skip-gram получены исследователями с сохранением их основных частей на основе моделей NNLM (языковая модель нейронной сети) и моделей C&W.
Когда мы упоминаем docs2vec, мы думаем о моделях DM (распределенная память) и DBOW (распределенный пакет слов) и их алгоритмах.
Мы не будем углубляться в содержание этих алгоритмов в этой статье, мы просто применяем их, я буду максимально использовать просторечие, чтобы объяснить, где это необходимо, основное содержание этих алгоритмов будет подробно проанализировано в следующих статьях.
Примечание: все мои коды выполняются под python2 MAC.Если вы обнаружите ошибку при работе в Windows или python3, возможно, это связано с кодировкой.
1 Почему нам нужно использовать word2vec
Мы знаем, что компьютер не имеет возможности распознавать шрифты.Если вы введете «какая сегодня погода», он может не получить никакого ответа и может выдать вам ошибку, но вычислительная мощность компьютера все еще хороша, тогда мы можем преобразовать язык в числа и позволить компьютеру сделать математику, а векторы — хороший вариант для нас, чтобы представить язык.
В прошлом при естественной обработке слова часто преобразовывались в векторы с помощью горячего кодирования (One-Hot Encoder).
Для иллюстрации на примере: предположим, у нас теперь есть тысяча различных китайских слов, включая банан, ананас, фрукт, бегемот и так далее.
А горячее кодирование создает тысячемерный вектор для представления этих слов:
Начните с объединения всех слов в один набор: [погода, ананас, плато, кино, банан, код, фрукты, ..........., экватор, солнце, бегемот, бег, звезда]
Примечание. Порядок слов в этом одномерном векторе является случайным.
Тогда векторы слов банан, ананас, фрукт, бегемот можно представить следующим образом
- банан [0, 0, 0, 0, 1, 0, 0, .........., 0, 0, 0, 0, 0]
- ананас [0, 1, 0, 0, 0, 0, 0, .........., 0, 0, 0, 0, 0]
- фрукты [0, 0, 0, 0, 0, 0, 1, .........., 0, 0, 0, 0, 0]
- бегемот [0, 0, 0, 0, 0, 0, 0, .........., 0, 0, 1, 0, 0]
После приведенного выше преобразования каждое слово представляется векторным методом. Затем в идеальной ситуации нам нужно только рассчитать расстояние между каждыми двумя векторами, чтобы получить связь между двумя словами.Если расстояние ближе, корреляция между двумя словами сильна.
Но это только идеальная ситуация, и здесь есть две трудности:
- Во-первых, это катастрофа размерности: временная сложность расчета тысячемерного вектора по-прежнему очень высока.
- Во-вторых, порядок 1000-мерного вектора генерируется случайным образом, поэтому возможная связь между словами не видна.
На этом этапе наступает очередь word2vec.Word2vec преобразует One-Hot Encoder в непрерывное значение с низкой широтой, то есть в плотный вектор, и сопоставляет слова с похожими значениями с аналогичными позициями в векторе.
Примечание. Конкретный алгоритм здесь будет подробно описан в следующей статье.
Банан, ананас, фрукты, гиппопотам после обработки:
- Банан [0,2, 0,6]
- Ананас [0,3, 0,4]
- фрукты [0,6, 0,6]
- бегемот [0,9, 0,2]
Из приведенной выше системы координат мы можем видеть расстояние между словами, и чем ближе расстояние, тем выше корреляция.
Примечание. Слова, обрабатываемые word2vec, как правило, не являются двумерными, и это просто для удобства.
2. Начать обучение нашей модели
Из вышеизложенного мы знаем, что пока мы используем алгоритм для создания вектора, который может распознать компьютер, компьютер поможет нам вычислить сходство слов.
Для создания такого вектора, модели word2vec, нам нужен некоторый корпус, здесь мы используем корпус из Википедии, размер которого составляет 1,72G.
Вот адрес загрузки:dumps.wiki Media.org/after wiki/lat…
Поскольку многие китайские веб-страницы в Википедии написаны традиционными китайскими иероглифами, нам сначала нужно преобразовать традиционные китайские иероглифы в корпусе в упрощенные китайские иероглифы, а затем выполнить сегментацию слов в этих корпусах.
2.1 Обработка полученного корпуса
Здесь мы используем библиотеку gensim, чтобы помочь нам.
def my_function():
space = ' '
i = 0
l = []
zhwiki_name = './data/zhwiki-latest-pages-articles.xml.bz2'
f = open('./data/reduce_zhiwiki.txt', 'w')
# 读取xml文件中的语料
wiki = WikiCorpus(zhwiki_name, lemmatize=False, dictionary={})
for text in wiki.get_texts():
for temp_sentence in text:
# 将语料中的繁体字转化为中文
temp_sentence = Converter('zh-hans').convert(temp_sentence)
# 使用jieba进行分词
seg_list = list(jieba.cut(temp_sentence))
for temp_term in seg_list:
l.append(temp_term)
f.write(space.join(l) + '\n')
l = []
i = i + 1
if (i %200 == 0):
print('Saved ' + str(i) + ' articles')
f.close()
После описанной выше обработки мы получаем упрощенный файл сегментации китайских слов.
2.2 Векторизованное обучение
После вышеперечисленных операций мы получаем обработанный корпус.Далее мы используем Word2Vec в gensim, чтобы помочь нам завершить преобразование слов в векторы.
# -*- coding: utf-8 -*-
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
def my_function():
wiki_news = open('./data/reduce_zhiwiki.txt', 'r')
# Word2Vec第一个参数代表要训练的语料
# sg=0 表示使用CBOW模型进行训练
# size 表示特征向量的维度,默认为100。大的size需要更多的训练数据,但是效果会更好. 推荐值为几十到几百。
# window 表示当前词与预测词在一个句子中的最大距离是多少
# min_count 可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5
# workers 表示训练的并行数
model = Word2Vec(LineSentence(wiki_news), sg=0,size=192, window=5, min_count=5, workers=9)
model.save('zhiwiki_news.word2vec')
if __name__ == '__main__':
my_function()
2.3 Проверьте окончательный эффект
Теперь, когда у нас есть векторная модель, на этот раз мы можем посмотреть на фактический эффект.
#coding=utf-8
import gensim
import sys
reload(sys)
sys.setdefaultencoding('utf8')
def my_function():
model = gensim.models.Word2Vec.load('./data/zhiwiki_news.word2vec')
print(model.similarity(u'香蕉',u'菠萝')) # 相似度为0.52
print(model.similarity(u'香蕉',u'水果')) # 相似度为0.53
word = '河马'
if word in model.wv.index2word:
for item in model.most_similar(unicode(word, "utf-8")):
print item[0] # 长颈鹿 狒狒 犰狳 斑马 亚洲象 猫科 黑猩猩 驯鹿 仓鼠 豹猫
if __name__ == '__main__':
my_function()
Из окончательного результата выше мы видим, что сходство между «бананом» и «ананасом» составляет 0,52, а сходство между «бананом» и «фруктом» составляет 0,53. Возможно, окончательный эффект отображения не соответствует вашим ожиданиям. познания, вы можете подумать, что сходство первых должно быть больше, чем сходство вторых, и возможная причина такого результата в конце концов заключается в том, что корпус Википедии, который мы используем, сравнивает соседние падежи «банан» и «фрукт». многие.
Итак, теперь вам не терпится попробовать это на себе?
Это код, используемый для обработки обучения и тестирования.Из-за ограничения размера загружаемого файла облака кода вам необходимо вручную загрузить корпус Википедии и поместить загруженный корпус в папку данных.
Вы можете загрузить код из облака кода на свой локальный сервер.
Первый шаг — запустить файл data_pre_process.py.
Второй шаг запускает файл training.py.
Третий шаг — запустить файл test.py.
Один из первых и вторых шагов и занять некоторое время.
Три слова word2vec применяются к статьям
С помощью вышеуказанных операций теперь вы можете получить отношение подобия между словами, но в обычных требованиях мы также можем столкнуться с проблемой подобия всего документа. Затем в это время мы можем сначала извлечь ключевые слова всей статьи, затем векторизовать ключевые слова, а затем добавить полученные векторы слов. Наконец, сумма полученных векторов слов представляет собой векторизованное представление статьи. Используя этот общий вектор Рассчитать схожесть статей.
3.1 Извлечение ключевых слов статьи
Извлечение ключевых слов мы используем сегментацию слов jieba для извлечения
# -*- coding: utf-8 -*-
import jieba.posseg as pseg
from jieba import analyse
def keyword_extract(data, file_name):
tfidf = analyse.extract_tags
keywords = tfidf(data)
return keywords
def getKeywords(docpath, savepath):
with open(docpath, 'r') as docf, open(savepath, 'w') as outf:
for data in docf:
data = data[:len(data)-1]
keywords = keyword_extract(data, savepath)
for word in keywords:
outf.write(word + ' ')
outf.write('\n')
Функция двух вышеупомянутых функций заключается в извлечении ключевых слов.
После извлечения ключевых слов нам нужно векторизовать ключевые слова.
3.2 Векторизация ключевых слов
# -*- coding: utf-8 -*-
import codecs
import numpy
import gensim
import numpy as np
from keyword_extract import *
import sys
reload(sys)
sys.setdefaultencoding('utf8')
wordvec_size=192
def get_char_pos(string,char):
chPos=[]
try:
chPos=list(((pos) for pos,val in enumerate(string) if(val == char)))
except:
pass
return chPos
def word2vec(file_name,model):
with codecs.open(file_name, 'r') as f:
# 初始化一个192维的向量
word_vec_all = numpy.zeros(wordvec_size)
for data in f:
# 判断模型是否包含词语
space_pos = get_char_pos(data, ' ')
# 获取关键词每行的第一个词
try:
first_word=data[0:space_pos[0]]
except:
pass
# 判断模型中是否存在first_word,为真时将其添加到word_vec_all
if model.__contains__(unicode(first_word, "utf-8")):
word_vec_all= word_vec_all+model[unicode(first_word, "utf-8")]
# 遍历space_pos
for i in range(len(space_pos) - 1):
word = data[space_pos[i]:space_pos[i + 1]]
if model.__contains__(unicode(word, "utf-8")):
word_vec_all = word_vec_all+model[unicode(word, "utf-8")]
return word_vec_all
Функция двух вышеупомянутых функций заключается в векторизации полученных ключевых слов.Стоит отметить, что, поскольку наш корпус относительно небольшой, мы будем судить о том, существуют ли ключевые слова в корпусе в процессе векторизации.
Поскольку я использую python2, вы можете увидеть функцию unicode в приведенном выше коде, если вы используете python3, возможно, потребуется изменить место функции unicode.
3.3 Расчет подобия
С помощью описанных выше двухэтапных операций мы получили вектор слов, который может представлять статью, и следующим шагом является использование этого вектора для вычисления сходства текста.
def simlarityCalu(vector1,vector2):
vector1Mod=np.sqrt(vector1.dot(vector1))
vector2Mod=np.sqrt(vector2.dot(vector2))
if vector2Mod!=0 and vector1Mod!=0:
simlarity=(vector1.dot(vector2))/(vector1Mod*vector2Mod)
else:
simlarity=0
return simlarity
if __name__ == '__main__':
model = gensim.models.Word2Vec.load('data/zhiwiki_news.word2vec')
p1 = './data/P1.txt'
p2 = './data/P2.txt'
p1_keywords = './data/P1_keywords.txt'
p2_keywords = './data/P2_keywords.txt'
getKeywords(p1, p1_keywords)
getKeywords(p2, p2_keywords)
p1_vec=word2vec(p1_keywords,model)
p2_vec=word2vec(p2_keywords,model)
print(simlarityCalu(p1_vec,p2_vec)) # 0.9880877789981191
Эта функция является функцией для вычисления сходства. Судя по приведенным выше результатам, сходство между двумя статьями все еще очень велико, вы можете попробовать сами.
Для более удобной практической практики я также поместил только что упомянутые коды в облако кода, потому что все они обучены с использованием одного и того же корпуса, поэтому вы можете поместить модели, которые вы обучали в версиях 2.1–2.3, в облако кода. так что вам не нужно повторять обучение.
Примечание. Код под этим адресом также включает код с 2.1 по 2.3.
Если вы поместили обученную модель под данные, вы можете напрямую запустить word2vec_sim.py, чтобы увидеть результат.
Боюсь, что некоторые люди запутаются, и объяснять файлы, которые должны быть в нормальных программах.
Четыре незаменимых doc2vec
После того, как вы пройдете описанную выше практическую практику, вы сможете вычислить сходство между словами и артиклями, но вы думаете, что есть только один способ вычислить сходство между артиклями и артиклями?
Нет, doc2vec также может вычислять сходство между статьями, и doc2vec сосредоточится на порядке между словами в статье, а также интегрирует информацию о порядке слов из контекста.
Например: Ву Сун убил тигра Это предложение будет разделено на «Ву Сун», «убит» и «тигр» при сегментации слов (это стоп-слово, которое удаляется), word2vec будет рассчитываться в соответствии с векторы этих трех слов усредняются, но семантическая информация не сохраняется.Вы не знаете, был ли это тигр, убитый Ву Сонгом, или Ву Сун, который был убит тигром.
Стоит отметить, что doc2vec не обязательно лучше, чем word2vec при анализе статей, его необходимо использовать в сочетании с вашими конкретными бизнес-сценариями.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gensim.models as g
from gensim.corpora import WikiCorpus
import logging
from langconv import *
#enable logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
docvec_size=192
class TaggedWikiDocument(object):
def __init__(self, wiki):
self.wiki = wiki
self.wiki.metadata = True
def __iter__(self):
import jieba
for content, (page_id, title) in self.wiki.get_texts():
yield g.doc2vec.LabeledSentence(words=[w for c in content for w in jieba.cut(Converter('zh-hans').convert(c))], tags=[title])
def my_function():
zhwiki_name = './data/zhwiki-latest-pages-articles.xml.bz2'
wiki = WikiCorpus(zhwiki_name, lemmatize=False, dictionary={})
documents = TaggedWikiDocument(wiki)
model = g.Doc2Vec(documents, dm=0, dbow_words=1, size=docvec_size, window=8, min_count=19, iter=5, workers=8)
model.save('data/zhiwiki_news.doc2vec')
if __name__ == '__main__':
my_function()
Приведенный выше код используется для обучения модели doc2vec. Как и в случае с word2vec, обучение в основном делится на два этапа: предварительная обработка данных и обучение вектору абзаца. Здесь мы используем функцию TaggedWikiDocument для предварительной обработки наших ожиданий из Википедии. Разница здесь Вместо сегментации документы каждого корпуса Википедии, преобразованный упрощенный текст сохраняется напрямую.Когда ваше обучение будет завершено, ваш файл данных должен выглядеть следующим образом.
Я провел в общей сложности 15 часов обучения, если вы не хотите так долго ждать, вы можете скачать файл модели, которую я тренировал, по ссылке ниже.
Ссылка на сайт:share.weiyun.com/5HekNcqПароль: pd9i3n
Точно так же я также помещаю приведенный выше код в облако кода.
Если вы хотите обучить модель самостоятельно, просто запустите файл train_model.py, а затем запустите doc2vec_sim.py, чтобы увидеть результаты.
Если вы загрузили файл модели, который я предоставил на Weiyun, вам нужно только поместить файл модели в папку данных и запустить doc2vec_sim.py напрямую, чтобы увидеть результат.
5 Вам нужны новые модели
Модель, использованная выше, была обучена с помощью Википедии, вы можете чувствовать себя не очень хорошо, не паникуйте, я предоставлю вам 64-мерную модель, обученную новостями, энциклопедией Baidu и романами.Эта модель 1,5G, я сказал на Weiyun для вашего удобства загрузки и использования.
Ссылка на сайт:share.weiyun.com/507zMyFПароль: sk5g4y
#!/usr/bin/python
#-*-coding:utf-8 -*-
import gensim
import jieba
import numpy as np
from scipy.linalg import norm
import re
import sys
reload(sys)
sys.setdefaultencoding('utf8')
model_file = './data/model.bin'
model = gensim.models.KeyedVectors.load_word2vec_format(model_file, binary=True)
if __name__ == '__main__':
print(model.similarity(u'香蕉',u'菠萝')) # 相似度为0.90
print(model.similarity(u'香蕉',u'水果')) # 相似度为0.79
word = '河马'
if word in model.wv.index2word:
for item in model.most_similar(unicode(word, "utf-8")):
print item[0] # 猩猩 海象 袋鼠 狒狒 浣熊 长颈鹿 大猩猩 乌贼 鲸鱼 松鼠
Вам нужно скачать файл модели на Weiyun и положить его под данные.
Поскольку код для этого относительно прост, код не помещается в облако кода.
Вышеприведенный код является результатом, полученным с использованием новой модели. Мы видим, что этот результат все еще является определенным улучшением по сравнению с Википедией. Это интуитивное преимущество, которое, как ожидается, будет большим.
6 Это только начало
В приведенном выше вы, возможно, научились использовать корпус для создания моделей word2vec и doc2vec и проверили свои сгенерированные результаты с помощью некоторых слов и статей, но это только начало, в будущих статьях мы вместе узнаем, что стоит за word2vec и doc2vec Математические алгоритмы и идеи и прочее НЛП.
Из-за моих ограниченных когнитивных способностей и ограниченных способностей к самовыражению, если в статье есть какие-либо неточности или неправильные объяснения, пожалуйста, сообщите об этом вовремя и с нетерпением ждем вместе с вами прогресса.