Как использовать вложения слов (например, Word2vec, GloVe или BERT) для вычисления наибольшего сходства слов в наборе из N слов?

Я пытаюсь рассчитать семантическое сходство, вводя список слов и выводя слово, которое является самым сходным словом в списке.

E.g.

Если я передам список слов

words = ['portugal', 'spain', 'belgium', 'country', 'netherlands', 'italy']

Это должно вывести меня что-то вроде этого-

['country']

person H M    schedule 24.06.2020    source источник
comment
Я думаю, что это может быть не случай встраивания. Это тот случай, когда вы определяете the most word similarity. Мне интересно, что вы действительно хотите вывести.   -  person luoshao23    schedule 24.06.2020


Ответы (2)


Во-первых, предварительно обученный word2vec, обученный новостям Google, необходимо загрузить с https://drive.google.com/file/d/0B7XkCwpI5KDYNlNUTTlSS21pQmM/edit.

Затем косинусное сходство между вложениями слов можно вычислить следующим образом:

import gensim
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')
from gensim.models.keyedvectors import KeyedVectors
from numpy import dot
from numpy.linalg import norm

def cosine_sim(a,b):
    return dot(a, b)/(norm(a)*norm(b))

# load the w2v model
path_pretraind_model='./GoogleNews-vectors-negative300.bin/GoogleNews-vectors-negative300.bin'  #set as the path of pretraind model 
model = KeyedVectors.load_word2vec_format(path_pretraind_model, binary=True)


wlist = ['portugal', 'spain', 'belgium', 'country', 'netherlands', 'italy']
lenwlist=len(wlist)
avrsim=[]
#compute cosine similarity between each word in wlist with the other words in wlist  
for i in range(lenwlist):
    word=wlist[i]
    totalsim=0
    wordembed=model[word] 
    for j in range(lenwlist):
        if i!=j:
            word2embed=model[wlist[j]] 
            totalsim+=cosine_sim(wordembed, word2embed)
    avrsim.append(totalsim/ (lenwlist-1)) #add the average similarity between word and any other words in wlist   

index_min=avrsim.index(min(avrsim)) #get min similarity        
print(wlist[index_min])

Под сходством, если вы имеете в виду косинусное сходство между вложениями слов, страна имеет наименьшее сходство с другими словами.

person Roohollah Etemadi    schedule 24.06.2020
comment
Также обратите внимание, что существует вспомогательный метод .doesnt_match() для вычисления того, какое слово наименее похоже на среднее значение всех слов: radimrehurek.com/gensim/models/ — и любой, кому нужен «самый важный» расчет, может его смоделировать после исходного кода этого метода. - person gojomo; 24.06.2020
comment
Спасибо за старания, но когда я обратился в этот список wlist=['экран', 'память', 'ноутбук', 'процессор'] оказалось, что экран больше всего похож. - person H M; 25.06.2020
comment
Обратите внимание, что приведенный выше код находит наименее похожее слово на другие. Потому что вы хотели получить страну, а страна имеет наименьшее сходство с другими словами в ['португалия', 'испания', 'бельгия', 'страна', 'нидерланды', 'италия']. Если вы хотите получить наиболее похожий, вам нужно использовать index_min=avrsim.index(max(avrsim)) вместо min(avrsim). В случае wlist=[ 'экран', 'память', 'ноутбук', 'процессор'], наименее похожее слово на другие слова — это экран, а наиболее похожее — ноутбук. - person Roohollah Etemadi; 25.06.2020

Встраивание в перчатки

Чтобы загрузить предварительно обученные вложения GloVe, мы будем использовать пакет с именем torchtext. Он содержит другие полезные инструменты для работы с текстом, которые мы увидим позже в курсе. Документация по векторам torchtext GloVe доступна по адресу: https://torchtext.readthedocs.io/en/latest/vocab.html#glove

Начните с загрузки набора вложений GloVe. При первом запуске приведенного ниже кода Python загрузит большой файл (862 МБ), содержащий предварительно обученные встраивания.

import torch
import torchtext

glove = torchtext.vocab.GloVe(name="6B", # trained on Wikipedia 2014 corpus of 6 billion words
                              dim=50)   # embedding size = 100

Давайте посмотрим, как выглядит вложение слова car:

glove['cat']

Tensor ([0.4528, -0.5011, -0.5371, -0.0157, 0.2219, 0.5460, -0,6730, -0,6891, 0,6349, -0,1973, 0.6349, -0,1973, 0.3368, 0,7735, 0,9009, 0,3849, 0.3837, 0,2657, -0,0806, 0.6109, -1.2894, 0.2231, -0.6158, 0.2170, 0.3561, 0.2170, 0.3561, 0.4450, 0.6089, -1.1633, -1.1579, 0.3612, 0.1047, -0.7832, 1.4352, 0.1863, -0.2611, 0,8328, -0.2312, 0.3248, 0,1449, -0,4455, 0,3350, -0,9595, -0,0975, 0,4814, -0,4335, 0,6945, 0,9104, -0,2817, 0,4164, -1,2609, 0,7128, 0,2378])

Это факельный тензор размерности (50,). Трудно определить, что означает каждое число в этом вложении, если вообще что-либо. Однако мы знаем, что в этом пространстве вложения есть структура. То есть расстояния в этом пространстве вложения имеют смысл.

Измерение расстояния

Чтобы исследовать структуру пространства вложения, необходимо ввести понятие расстояния. Вы, вероятно, уже знакомы с понятием евклидова расстояния. Евклидово расстояние двух векторов x=[x1,x2,...xn] и y=[y1,y2,...yn] есть просто 2-норма их разности x−y.

Функция PyTorch torch.norm вычисляет для нас 2-норму вектора, поэтому мы можем вычислить евклидово расстояние между двумя векторами следующим образом:

x = glove['cat']
y = glove['dog']
torch.norm(y - x)

тензор (1,8846)

Косинусное сходство – это альтернативная мера расстояния. Косинусное подобие измеряет угол между двумя векторами и имеет то свойство, что оно учитывает только направление векторов, а не их величины. (Мы будем использовать это свойство в следующем классе.)

x = torch.tensor([1., 1., 1.]).unsqueeze(0)
y = torch.tensor([2., 2., 2.]).unsqueeze(0)
torch.cosine_similarity(x, y) # should be one

тензор([1.])

Косинусное сходство — это мера подобия, а не мера расстояния: чем больше сходство, тем ближе вложения слов друг к другу.

x = glove['cat']
y = glove['dog']
torch.cosine_similarity(x.unsqueeze(0), y.unsqueeze(0))

тензор ([0,9218])

Сходство слов

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

word = 'cat'
other = ['dog', 'bike', 'kitten', 'puppy', 'kite', 'computer', 'neuron']
for w in other:
    dist = torch.norm(glove[word] - glove[w]) # euclidean distance
    print(w, float(dist))

собака 1.8846031427383423

велосипед 5.048375129699707

котенок 3.5068609714508057

щенок 3.0644655227661133

воздушный змей 4.210376262664795

компьютер 6.030652046203613

нейрон 6.228669166564941

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

def print_closest_words(vec, n=5):
    dists = torch.norm(glove.vectors - vec, dim=1)     # compute distances to all words
    lst = sorted(enumerate(dists.numpy()), key=lambda x: x[1]) # sort by distance
    for idx, difference in lst[1:n+1]:                         # take the top n
        print(glove.itos[idx], difference)

print_closest_words(glove["cat"], n=10)

собака 1.8846031

кролик 2.4572797

обезьяна 2.8102052

кошки 2.8972247

крыса 2.9455352

зверь 2.9878407

монстр 3.0022194

домашнее животное 3.0396757

змея 3.0617998

щенок 3.0644655

print_closest_words(glove['nurse'])

врач 3.1274529

дантист 3.1306612

медсестры 3,26872

педиатр 3.3212206

советник 3.3987114

print_closest_words(glove['computer'])

компьютеры 2.4362664

программное обеспечение 2.926823

технология 3.190351

электронный 3.5067408

вычисления 3,5999784

Мы также можем посмотреть, какие слова ближе всего к середине двух слов:

print_closest_words((glove['happy'] + glove['sad']) / 2)

счастливый 1.9199749

чувствует 2,3604643

извините 2.4984782

вряд ли 2.52593

представь 2.5652788

print_closest_words((glove['lake'] + glove['building']) / 2)

окружающие 3.0698414

поблизости 3.1112068

мост 3.1585503

вдоль 3.1610188

берег 3.1618817

Аналогии

Один удивительный аспект векторов GloVe заключается в том, что направления в пространстве вложений могут иметь смысл. Структура векторов GloVe имеет определенную аналогию, подобную этой:

король-мужчина+женщина≈королева

print_closest_words(glove['king'] - glove['man'] + glove['woman'])

королева 2.8391209

принц 3.6610038

Элизабет 3.7152522

дочь 3.8317878

вдова 3.8493774

Мы получаем разумные ответы, такие как королева, трон и имя нашей нынешней королевы.

Мы также можем перевернуть аналогию:

print_closest_words(glove['queen'] - glove['woman'] + glove['man'])

король 2.8391209

принц 3.2508988

корона 3.4485192

рыцарь 3.5587437

коронация 3.6198905

Или попробуйте другую, но родственную аналогию по гендерной оси:

print_closest_words(glove['king'] - glove['prince'] + glove['princess'])

королева 3.1845968

король 3.9103293

невеста 4.285721

леди 4.299571

сестра 4.421178

print_closest_words(glove['uncle'] - glove['man'] + glove['woman'])

бабушка 2.323353

тетя 2.3527892

внучка 2.3615322

дочь 2.4039288

дядя 2.6026237

print_closest_words(glove['grandmother'] - glove['mother'] + glove['father'])

дядя 2.0784423

отец 2.0912483

внук 2.2965577

племянник 2.353551

старший 2.4274695

print_closest_words(glove['old'] - glove['young'] + glove['father'])

отец 4.0326614

сын 4.4065413

дедушка 4.51851

внук 4.722089

дочь 4.786716

Мы можем переместить вложение в сторону добра или зла:

print_closest_words(glove['programmer'] - glove['bad'] + glove['good'])

универсальный 4.381561

креатив 4.5690007

предприниматель 4.6343737

включает 4.7177725

умный 4.7349973

print_closest_words(glove['programmer'] - glove['good'] + glove['bad'])

хакер 3.8383653

глюк 4.003873

составитель 4.041952

взломать 4.047719

серийный номер 4.2250676

Смещение векторов Word

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

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

Начнем с примера аналогии:

врач-мужчина+женщина≈??

Давайте используем векторы GloVe, чтобы найти ответ на приведенную выше аналогию:

print_closest_words(glove['doctor'] - glove['man'] + glove['woman'])

медсестра 3.1355345

беременная 3.7805371

ребенок 3,78347

женщина 3.8643107

мать 3.922231

Аналогия врач-мужчина+женщина≈медсестра очень важна. Просто чтобы убедиться, тот же результат не появится, если мы перевернем термины пола:

print_closest_words(glove['doctor'] - glove['woman'] + glove['man'])

мужчина 3.9335632

коллега 3.975502

сам 3.9847782

брат 3.9997008

другой 4.029071

Подобные гендерные предубеждения мы наблюдаем и в других профессиях.

print_closest_words(glove['programmer'] - glove['man'] + glove['woman'])

вундеркинд 3.6688528

психотерапевт 3.8069527

терапевт 3.8087194

вводит 3.9064546

швед 4.1178856

Помимо первого результата, ни одно из других слов даже не связано с программированием! Напротив, если мы перевернем гендерные термины, мы получим совсем другие результаты:

print_closest_words(glove['programmer'] - glove['woman'] + glove['man'])

настройка 4.002241

новатор 4.0661883

программисты 4.1729574

хакер 4.2256656

гений 4.3644104

Вот результаты для инженера:

print_closest_words(glove['engineer'] - glove['man'] + glove['woman'])

техник 3.6926973

механик 3.9212747

пионер 4.1543956

новаторский 4.1880875

воспитатель 4.2264576

print_closest_words(glove['engineer'] - glove['woman'] + glove['man'])

строитель 4.3523865

механик 4.402976

инженеры 4.477985

работало 4.5281315

замена 4.600204

person Abhi25t    schedule 29.09.2020