Введение в получение векторов предложений на естественном языке

NLP

Многие последующие задачи НЛП (классификация текста, анализ настроений, вывод о намерениях и т. д.) основаны на первом шаге — преобразовании текстовых строк в векторы признаков предложений.

Есть два способа получить векторы предложений в НЛП:

(1) Вектор предложения получается путем постобработки вектора слов;

(2) Получить вектор предложения напрямую

GloVe не будет представлен здесь

1. Постобработка вектора слов для получения вектора предложения

Все мы знаем, что предложения состоят из слов, а технология вектора слов просто преобразует одно слово в вектор фиксированной размерности.

Так как же получить вектор предложения, состоящего из нескольких слов?

В этой статье будут представлены следующие неконтролируемые методы генерации векторов предложений из векторов слов, а именно: метод накопления, метод среднего, метод взвешенного среднего TF-IDF и метод встраивания SIF.

1.1 Метод накопления

Накопление — самый простой способ получить векторы предложений

Допустим, есть такой текст:я очень счастлив

НЛП, обрабатывающий фрагмент текста, сначала должен сегментировать фрагмент текста и удалить стоп-слова.После удаления стоп-слов приведенный выше текст может получить следующее расстояние до слова:

["Я очень счастлив"]

В этой статье используется модель Word2vec в gensim Python для получения векторов слов, и могут быть получены следующие векторы слов из приведенных выше слов (для более четкой визуализации для демонстрации используются 5-мерные векторы слов)

i: [[-0,46499524 -2,8825798 1,1845024 -1,6874554 -0,05758076]]

Очень: [[-2,26874 0,99428487 -0,9092457 -0,67786723 4,244918 ]]

счастливый: [[-1,0627153 -0,7416505 0,41102988 -0,39201248 0,6933297 ]]

Метод накопления заключается в наложении векторов слов всех непрерывных слов в предложении.Если в предложении есть n непрерывных слов, векторы слов предложения получаются следующими способами:

Vsentence = Vword1 + Vword2 + ... + Vwordn

По этому методу его можно получить»я очень счастливВектор предложения ":

Vsentence = V1+ Vn2+ V3

Вектор предложения: [[-3,79645047 -2,62994546 0,68628651 -2,75733513 4,8806668 ]]

Анализ: не может выразить общую семантику предложения. Когда добавление нескольких векторов слов равно добавлению других слов, выражаемые значения различны.

Общий код:

import numpy as npfrom gensim.models.word2vec  import Word2Vecimport jiebafrom sklearn.model_selection import train_test_splitdef readgh(path):    res=[]    label=[]    f=open(path, "r", encoding='utf-8-sig')    for line in f:        if int(line.split(' ', 1)[0])==-1 :            label.append([1,0])        else:            label.append([0,1])        res.append(line.split(' ',1)[1])    return res,labeldef divide(result,label):   x_train, x_test, y_train, y_test = train_test_split(result,label, test_size=0.3,                                          random_state=666)   return x_train, x_test, y_train, y_testdef fenci1(data,stopword):   result = []   for text in data:      word_list = ' '.join(jieba.cut(text)).split(" ")      result.append(list(filter(lambda x : x not in stopword, word_list)))   return resultdef buildWordVector(sentence,size,w2v_model):   vec   = np.zeros(size).reshape((1,size))   count = 0.   for word in sentence:      try:         vec += w2v_model[word].reshape((1,size))         count += 1      except KeyError:         continue   if count != 0:      vec /= count   return vecdef buildWordVector1(sentence,size,w2v_model):    vec =np.zeros(size).reshape((1,size))    data_vec=np.zeros(size).reshape((1,size))    for word in sentence:        print(word)        vec=w2v_model[word].reshape((1,size))        print(vec)        data_vec +=vec    print("句子向量:")    print(data_vec)    return data_vec#计算词向量def get_train_vecs(x_train,x_test):    n_dim = 5    #Initialize model and build vocab    w2v_model = Word2Vec(size = n_dim,min_count = 10)    w2v_model.build_vocab(x_train)    #在训练集训练词向量模型    w2v_model.train(x_train,total_examples = w2v_model.corpus_count,epochs = w2v_model.iter)    #生成训练集词向量    train_vecs = np.concatenate([buildWordVector(line,n_dim,w2v_model) for line in x_train])    #保存训练集词向量文件    print("Train word_vector shape:",train_vecs.shape)    #在测试集训练词向量模型    w2v_model.train(x_test,total_examples = w2v_model.corpus_count,epochs = w2v_model.iter)    #生成测试集词向量    test_vecs = np.concatenate([buildWordVector(line,n_dim,w2v_model) for line in x_test])    #保存测试集词向量文件    print("Test word_vector shape:",test_vecs.shape)    #保存词向量模型    w2v_model.save('D:\\学习资料\\项目\\邮件网关\\zh_cnn_text_classify-master\\test_model.pkl')    return train_vecs,test_vecstext=["我很开心"]with open('D:\\学习资料\\项目\\情感分析\\stopwords.txt', encoding='utf8') as f:    stopword = f.read().splitlines()result = fenci1(text, stopword)model=Word2Vec.load("D:\\学习资料\\项目\\邮件网关\\zh_cnn_text_classify-master\\test_model.pkl")test_vec=test_vecs = np.concatenate([buildWordVector1(line,5,model) for line in result])print(test_vec)

Метод накопления:

def buildWordVector1(sentence,size,w2v_model):    vec =np.zeros(size).reshape((1,size))    data_vec=np.zeros(size).reshape((1,size))    for word in sentence:        print(word)        vec=w2v_model[word].reshape((1,size))        print(vec)        data_vec +=vec    print("句子向量:")    print(data_vec)    return data_vec

1.2 Средний метод

Метод усреднения аналогичен методу накопления, он также должен сложить все векторы непрерывных слов в предложении, но в конце наложенный вектор нужно разделить на количество непрерывных слов.Вектор слова предложения получается следующими способами:

Vsentence = (Vword1 + Vword2 + ... + Vwordn) / n

Вектор предложения:[[-1.26548349 -0.87664849 0.22876217 -0.91911171 1.62688893]]

Код:

def buildWordVector(sentence,size,w2v_model):   vec   = np.zeros(size).reshape((1,size))   count = 0.   for word in sentence:      try:         vec += w2v_model[word].reshape((1,size))         count += 1      except KeyError:         continue   if count != 0:      vec /= count   return vec

1.3 Средневзвешенный метод TF-IDF

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

Метод взвешивания TF-IDF должен не только получить вектор слов для каждого непрерывного слова в предложении, но также должен получить значение TFIDF для каждого непрерывного слова в предложении. Часть TF каждого непрерывного слова легко вычислить.Часть IDF зависит от того, какой корпус использует пользователь.Если это для поиска запроса, то корпус, соответствующий части IDF, представляет собой все предложения запроса;если это сделать самоподобная кластеризация текста, то корпус, соответствующий части IDF, представляет собой целое предложение, подлежащее классификации. Затем вектор взвешенного предложения TF-IDF получается следующими средствами_:_

Vsentence = TFIDFword1*Vword1+TFIDFword2 *Vword2 +... +TFIDFwordn *Vwordn

Если предположить, что фраза «Я очень счастлив» означает поиск запроса, то корпус, соответствующий вычислению IT-IDF, состоит из всех предложений запроса. Если всего имеется 100 предложений-запросов, то 60 предложений-запросов содержат слово I, 65 предложений-запросов содержат слово очень и 7 предложений-запросов содержат слово счастливый. Тогда количество TF-IDF для каждого непрерывного слова в этом предложении будет следующим:

Я: 1/(1+1+1) * log(100/(1+60)

очень: 1/(1+1+1) * log(100/(1+65)

счастливый: 1/(1+1+1) * log(100/(1+7)

Таким образом, взвешенный вектор данных IT-IDF для этого предложения:

Vsentence = TFIDF*V+ TFIDF*V + … + TFIDFg*V

Код TF-IDF:

s1_words=['今天','上','NLP','课程']s2_words=['今天','的','课程','有','意思']s3_words=['数据','课程','也','有','意思']data_set = [s1_words,s2_words,s3_words]from collections import Counterfrom collections import defaultdictword_dict = ['今天','上','NLP','的','课程','有','意思','数据','也']N=len(data_set)    #文档总数In_doc=defaultdict(int)  #表示含有该单词的文档数目for word in word_dict:    for doc in data_set:        In_doc[word]+=1tfidfs_all=[]for doc in data_set:    n=len(doc)  #文档中的单词总数    cont=Counter(doc)    tfidf=[]    for word in word_dict:        if word not in cont:            tfidf.append(0)        else:            tf=cont[word]/n            idf=In_doc[word]/N            tfidf.append(tf*idf)    tfidfs_all.append(tfidf)print(tfidfs_all)

1.4 Метод внедрения SIF

Метод средневзвешенного значения ISF аналогичен методу средневзвешенного значения TF-IDF.Этот метод может хорошо получить вектор предложения всего предложения в соответствии с каждым вектором слова. Метод встраивания SIF требует использования анализа основных компонентов и оценки вероятности каждого слова.Конкретная операция метода встраивания SIF заключается в следующем:

Прежде всего, на вход всего алгоритма входят: (1) вектор слов каждого слова (2) все предложение в корпусе (3) регулируемый параметр a (4) оценочная вероятность каждого слова

Результат всего алгоритма:
вектор предложения

Конкретные шаги алгоритма:
(1) Получить начальный вектор предложения

Пройдите каждое предложение в корпусе, предполагая, что текущее предложение равно s, и получите начальный вектор предложения текущего предложения s по следующей формуле расчета:

                                       

То есть процесс взвешенного усреднения, каждый вектор слов умножается на коэффициент a/(a+p(w) и затем накладывается, а конечный вектор суперпозиции представляет собой количество слов в предложении s. Для регулируемого параметра a , автор использует в статье 0,001 и 0,0001. 2. P(w) — униграммная вероятность слова во всем корпусе, то есть частота слов слова w равна сумме частот слов всех слов в корпусе.

(2) Расчет главного компонента
Выполните анализ основных компонентов для всех векторов предварительных предложений, чтобы вычислить первый главный компонент u всех векторов предварительных предложений.

(3) Получить вектор целевого предложения
Посредством следующего вычисления исходный вектор предложений подвергается вторичной обработке для получения целевого вектора предложений.

Я просто грубо прогнал код, который в основном содержит английские предложения и слова. Я изучу его позже, если у меня будет возможность реального боя. Здесь я буду лениться...

Код:GitHub.com/Princeton мл…

2 Получите вектор предложения напрямую

Один из самых больших недостатков описанного выше метода заключается в том, что он игнорирует влияние порядка в середине слов на все предложение.

Обычно используемые методы прямого получения векторов предложений — Doc2Vec и Bert.

2.1 doc2vec

Doc2vec — это усовершенствование, основанное на Word2vec, которое учитывает не только семантику между словами, но и порядок слов. Модель Doc2Vec Doc2Vec имеет две модели, а именно:

Модель распределенной памяти векторов абзацев (PV-DM: модель распределенной памяти векторов абзацев)

PV-DBOW: версия вектора абзаца с распределенным пакетом слов Модель PV-DM предсказывает вероятность появления слова с учетом контекста и вектора документа.

Конкретные принципы см. в других дополнительных материалах, которые здесь не представлены.

Модель DM Doc2vec очень похожа на CBOW Word2vec, а модель DBOW очень похожа на Skip-gram Word2vec. Doc2Vec обучает векторы одинаковой длины для абзацев разной длины; векторы слов разных абзацев не являются общими; векторы слов, обученные в обучающем наборе, имеют одинаковое значение и могут использоваться совместно.

Код:

#coding:utf-8import jiebaimport sysimport gensimimport sklearnimport numpy as npfrom gensim.models.doc2vec import Doc2Vec, LabeledSentenceTaggededDocument = gensim.models.doc2vec.TaggedDocument#进行中文分词def  cut_files(path):    f = open(path, "r", encoding='utf-8-sig')    res=[]    text=[]    for line in f:        res.append(line.split(' ', 1)[1])    for line in res:        curLine =' '.join(list(jieba.cut(line)))        text.append(curLine)    return text#读取分词后的数据并打标记,放到x_train供后续索引,但是这样的话占用很大内存(这种小数据量使用)def get_datasest(data):    x_train = []    for i, text in enumerate(data):        word_list = text.split(' ')        l = len(word_list)        word_list[l - 1] = word_list[l - 1].strip()        document = TaggededDocument(word_list, tags=[i])        x_train.append(document)    return x_train#模型训练def train(x_train, size=50):    model_dm = Doc2Vec(x_train, min_count=5, window=3, size=size, sample=1e-3, negative=5, workers=4)    model_dm.train(x_train, total_examples=model_dm.corpus_count, epochs=70)    model_dm.save('model_dm_doc2vec')    return model_dm#实例def test():    model_dm = Doc2Vec.load("model_dm_doc2vec")    test_text = ['我不想上班','我喜欢你']    text=[]    for line in test_text:        curLine =' '.join(list(jieba.cut(line)))        text.append(curLine)    inferred_vector_dm = model_dm.infer_vector(text)    sims = model_dm.docvecs.most_similar([inferred_vector_dm], topn=10)    return simsif __name__ == '__main__':    path="D:\\学习资料\\项目\\情感分析\\neg.txt"    path1="D:\\学习资料\\项目\\情感分析\\pos.txt"    text1=cut_files(path)    text2=cut_files(path1)    text=text1+text2    x_train=get_datasest(text)    model_dm = train(x_train)    sims = test()    for count, sim in sims:        sentence = x_train[count]        words = ''        for word in sentence[0]:            words = words + word + ' '        print (words, sim, len(sentence[0]))

2.2 Bert

Самый большой недостаток использования векторов слов для постобработки векторов предложений с помощью различных методов заключается в том, что они не могут понять семантику контекста.Одно и то же слово может иметь разные значения в разных контекстах, но оно будет представлено как одно и то же слово. что отрицательно влияет на семантическое вычисление многозначных предложений. Векторы предложений, сгенерированные Бертом, не имеют вышеуказанных дефектов. Векторы одного и того же слова в разных контекстах различны, а многозначные слова генерируют разные векторы из-за разных контекстов. Таким образом, векторы предложений, созданные Бертом, действительно можно использовать в семантических вычислениях. Преимущество BERT для генерации векторов предложений заключается не только в том, что он может понимать смысл предложений, но также устраняет ошибку, вызванную взвешиванием векторов слов.

Код:

from bert_serving.client import BertClientimport numpy as npdef main():    bc = BertClient()    doc_vecs = bc.encode(['今天天空很蓝,阳光明媚', '今天天气好晴朗', '现在天气如何', '自然语言处理', '机器学习任务'])    print(len(doc_vecs[0]))if __name__ == '__main__':    main()

Теперь общий метод bert в основном заключается в том, чтобы загрузить китайскую модель на github для вызова, а затем получить вектор слова.

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

Модель BERT требует фиксированной длины последовательности.например 128. Если этого недостаточно, заполнение будет выполнено позже, в противном случае лишний Token будет перехвачен, чтобы гарантировать, что вход представляет собой последовательность Token фиксированной длины.

У меня будет время изучить берта позже