词向量操作
1、余弦相似度
2、单词类比任务
3、消除偏倚词向量
第五门课:序列模型
第二周:自然语言处理与词嵌入
由于词嵌入的训练成本非常高,因此大多数 ML 从业者会加载一组预先训练的嵌入。
完成此任务后,您将能够:
1、加载预先训练的词向量,并使用余弦相似度来衡量相似性
2、使用词嵌入来解决词类比问题,例如男人之于女人,就像国王之于__。
3、修改词嵌入以减少其性别偏见
import numpy as np
from w2v_utils import *
接下来,让我们加载词向量。对于此作业,我们将使用 50 维 GloVe 向量来表示单词。运行以下单元格以加载word_to_vec_map。
words, word_to_vec_map = read_glove_vecs('data/glove.6B.50d.txt')
您已加载:
1、单词:词汇表中的一组单词。
2、word_to_vec_map:字典将单词映射到其 GloVe 向量表示。
one-hot 向量不能很好地解释哪些单词是相似的。GloVe 向量提供了有关单个单词含义的更多有用信息。现在让我们看看如何使用 GloVe 向量来确定两个单词的相似程度。
一、余弦相似度
为了测量两个单词的相似程度,我们需要一种方法来测量两个单词的两个嵌入向量之间的相似程度。给定两个向量 u和 v,余弦相似度定义如下:
其中 u.v是两个向量的点积(或内积),||u||2 是向量 u 的范数(或长度)和 θ是 u 之间的夹角 和 v .这种相似性取决于 u 之间的角度
和 v.如果 u 和 v非常相似,它们的余弦相似度将接近 1;如果它们不同,则余弦相似度将取较小的值。
余弦相似度反映了 u 和 v 之间的相似程度
参数:
u -- 形状为 (n,) 的词向量
v -- 形状为 (n,) 的词向量
返回:cosine_similarity -- 由上述公式定义的 u 和 v 之间的余弦相似度。
# GRADED FUNCTION: cosine_similarity
def cosine_similarity(u, v):
distance = 0.0
# Compute the dot product between u and v (≈1 line)
dot = np.dot(u, v)
# Compute the L2 norm of u (≈1 line)
norm_u = np.sqrt(np.sum(u**2))
# Compute the L2 norm of v (≈1 line)
norm_v = np.sqrt(np.sum(v**2))
# Compute the cosine similarity defined by formula (1) (≈1 line)
cosine_similarity = dot / (norm_u * norm_v)
return cosine_similarity
father = word_to_vec_map["father"]
mother = word_to_vec_map["mother"]
ball = word_to_vec_map["ball"]
crocodile = word_to_vec_map["crocodile"]
france = word_to_vec_map["france"]
italy = word_to_vec_map["italy"]
paris = word_to_vec_map["paris"]
rome = word_to_vec_map["rome"]
print("cosine_similarity(father, mother) = ", cosine_similarity(father, mother))
print("cosine_similarity(ball, crocodile) = ",cosine_similarity(ball, crocodile))
print("cosine_similarity(france - paris, rome - italy) = ",cosine_similarity(france - paris, rome - italy))
在获得正确的预期输出后,请随意修改输入并测量其他单词对之间的余弦相似度!研究其他输入的余弦相似性将使您更好地了解词向量的行为方式。
二、单词类比任务
在类比任务这个词中,我们完成了“a 对 b 就像 c 对 ____ 一样”这句话。一个例子是“男人之于女人,就像国王之于王后”。详细来说,我们试图找到一个单词 d,使得相关的词向量 ea,eb,ec,ed按以下方式关联:eb−ea≈ed−ec .我们将测量 eb−ea 之间的相似性和 ed−ec使用余弦相似性。
练习:完成下面的代码,以便能够进行单词类比!
执行如上所述的单词类比任务:a 对 b 就像 c 对 ____ 一样。
参数:
word_a -- 一个单词,字符串
word_b -- 一个单词,字符串
word_c -- 一个单词,字符串
word_to_vec_map -- 将单词映射到其对应向量的字典。
返回:best_word - v_b - v_a接近 v_best_word - v_c 的单词,以余弦相似度来衡量
# GRADED FUNCTION: complete_analogy
def complete_analogy(word_a, word_b, word_c, word_to_vec_map):
# convert words to lower case
word_a, word_b, word_c = word_a.lower(), word_b.lower(), word_c.lower()
# Get the word embeddings v_a, v_b and v_c (≈1-3 lines)
e_a, e_b, e_c = word_to_vec_map[word_a], word_to_vec_map[word_b], word_to_vec_map[word_c]
words = word_to_vec_map.keys()
max_cosine_sim = -100 # Initialize max_cosine_sim to a large negative number
best_word = None # Initialize best_word with None, it will help keep track of the word to output
# loop over the whole word vector set
for w in words:
# to avoid best_word being one of the input words, pass on them.
if w in [word_a, word_b, word_c] :
continue
# Compute cosine similarity between the vector (e_b - e_a) and the vector ((w's vector representation) - e_c) (≈1 line)
cosine_sim = cosine_similarity(e_b - e_a, word_to_vec_map[w] - e_c)
# If the cosine_sim is more than the max_cosine_sim seen so far,
# then: set the new max_cosine_sim to the current cosine_sim and the best_word to the current word (≈3 lines)
if cosine_sim > max_cosine_sim:
max_cosine_sim = cosine_sim
best_word = w
return best_word
triads_to_try = [('italy', 'italian', 'spain'), ('india', 'delhi', 'japan'), ('man', 'woman', 'boy'), ('small', 'smaller', 'large')]
for triad in triads_to_try:
print ('{} -> {} :: {} -> {}'.format( *triad, complete_analogy(*triad,word_to_vec_map)))
获得正确的预期输出后,请随时修改上面的输入单元格以测试您自己的类比。试着找到一些其他有效的类比对,但也要找到一些算法没有给出正确答案的地方:例如,你可以尝试小>小作为大>?。
记住的要点:
1、余弦相似度:比较词向量对之间相似度的好方法。(虽然 L2 距离也有效。)
2、对于 NLP 应用程序,使用一组来自互联网的预先训练的词向量通常是一个很好的入门方法。
三、消除偏倚词向量
您将检查可以反映在单词嵌入中的性别偏见,并探索减少偏见的算法。除了学习去偏见的主题外,这个练习还将有助于磨练你对词向量在做什么的直觉。
让我们首先看看 GloVe 词嵌入与性别的关系。您将首先计算向量 g=ewoman−eman,其中 ewoman表示与单词 woman 和对应的词向量,而 eman对应于单词 man 对应的词向量。得到的向量 g大致编码了“性别”的概念。(如果计算 g1=emother−efather,可能会得到更准确的表示, g2=egirl−eboy等,并取平均值。但只是使用 ewoman−eman现在会给出足够好的结果。
g = word_to_vec_map['woman'] - word_to_vec_map['man']
print(g)
现在,您将考虑不同单词与 g 的余弦相似性.考虑相似度的正值与负余弦相似度的含义。
print ('List of names and their similarities with constructed vector:')
# girls and boys name
name_list = ['john', 'marie', 'sophie', 'ronaldo', 'priya', 'rahul', 'danielle', 'reza', 'katy', 'yasmin']
for w in name_list:
print (w, cosine_similarity(word_to_vec_map[w], g))
正如你所看到的,女性名字往往与我们构造的向量g具有正余弦相似性,而男性名字往往具有负余弦相似性。这并不令人怀疑,结果似乎是可以接受的。
但是,让我们尝试使用其他一些词。
print('Other words and their similarities:')
word_list = ['lipstick', 'guns', 'science', 'arts', 'literature', 'warrior','doctor', 'tree', 'receptionist',
'technology', 'fashion', 'teacher', 'engineer', 'pilot', 'computer', 'singer']
for w in word_list:
print (w, cosine_similarity(word_to_vec_map[w], g))
你注意到什么令人惊讶的事情吗?令人惊讶的是,这些结果如何反映出某些不健康的性别刻板印象。例如,“计算机”更接近“男人”,而“文学”更接近“女人”。哎哟!
我们将在下面看到如何使用 Boliukbasi 等人,2016 年的算法来减少这些向量的偏差。请注意,一些词对,如“演员”/“女演员”或“祖母”/“祖父”应保持性别特异性,而其他词,如“接待员”或“技术”应被中和,即不与性别相关。在去偏见时,您将不得不以不同的方式对待这两种类型的词。
1、消除对非性别特定词语的偏见
下图应该可以帮助您直观地了解中和的作用。如果使用 50 维词嵌入,则 50 维空间可以分为两部分: 偏置方向 g,以及剩余的 49 个维度,我们称之为 g⊥.在线性代数中,我们说 49 维 g⊥垂直(或“耳角线”)于 g,这意味着它与 g 成 90 度.中和步骤采用向量,例如接待员
并将 g 方向上的分量归零,给我们edebiased接待员.
即使 g⊥是 49 维的,鉴于我们可以在屏幕上绘制的内容的限制,我们使用下面的 1 维轴来说明它。
通过将“word”投影到与偏置轴正交的空间上来消除“word”的偏置。
此函数可确保性别中性词在性别子空间中为零。
参数:
word -- 指示要去偏差的单词的字符串
g -- 形状为 (50,) 的 numpy-array,对应于偏置轴(如性别)
word_to_vec_map -- 字典将单词映射到其对应的向量。
返回: e_debiased -- 输入“word”的中和词向量表示
def neutralize(word, g, word_to_vec_map):
# Select word vector representation of "word". Use word_to_vec_map. (≈ 1 line)
e = word_to_vec_map[word]
# Compute e_biascomponent using the formula give above. (≈ 1 line)
e_biascomponent = np.dot(e, g) / np.square(np.linalg.norm(g)) * g
# Neutralize e by substracting e_biascomponent from it
# e_debiased should be equal to its orthogonal projection. (≈ 1 line)
e_debiased = e - e_biascomponent
return e_debiased
e = "receptionist"
print("cosine similarity between " + e + " and g, before neutralizing: ", cosine_similarity(word_to_vec_map["receptionist"], g))
e_debiased = neutralize("receptionist", g, word_to_vec_map)
print("cosine similarity between " + e + " and g, after neutralizing: ", cosine_similarity(e_debiased, g))
2、性别特定词的均衡算法
接下来,让我们看看如何将去偏见也应用于“女演员”和“演员”等词对。均衡适用于您可能希望仅通过性别属性进行差异的单词对。举个具体的例子,假设“女演员”比“演员”更接近“保姆”。通过将中和应用于“保姆”,我们可以减少与保姆相关的性别刻板印象。但这仍然不能保证“演员”和“女演员”与“保姆”的距离相等。均衡算法会处理这个问题。
均衡背后的关键思想是确保一对特定的单词与 49 维 g 的距离相等⊥.均衡步骤还确保两个均衡步骤现在与edebiasedreceptionist的距离相同,或来自任何其他已被中和的作品。在图片中,这就是均衡的工作原理:
线性代数的推导要复杂一些。(详见Bolukbasi et al., 2016.)但关键方程式是:
练习:实现以下功能。使用上面的等式来获得该单词对的最终均衡版本。
按照上图中描述的均衡方法对特定性别的单词进行去偏见。
参数:
pair -- 一对用于消除偏见的性别特定单词字符串,例如(“女演员”、“演员”)
bias_axis -- 形状为 (50,) 的 numpy-array,对应于偏置轴的向量,例如性别
word_to_vec_map -- 字典将单词映射到其对应的向量
返回:
e_1 -- 与第一个单词对应的词向量
e_2 -- 与第二个单词对应的词向量
def equalize(pair, bias_axis, word_to_vec_map):
# Step 1: Select word vector representation of "word". Use word_to_vec_map. (≈ 2 lines)
w1, w2 = pair
e_w1, e_w2 = word_to_vec_map[w1], word_to_vec_map[w2]
# Step 2: Compute the mean of e_w1 and e_w2 (≈ 1 line)
mu = (e_w1 + e_w2) / 2
# Step 3: Compute the projections of mu over the bias axis and the orthogonal axis (≈ 2 lines)
mu_B = np.dot(mu, bias_axis) / np.sum(bias_axis**2) * bias_axis
mu_orth = mu - mu_B
# Step 4: Use equations (7) and (8) to compute e_w1B and e_w2B (≈2 lines)
e_w1B = np.dot(e_w1, bias_axis) / np.sum(bias_axis**2) * bias_axis
e_w2B = np.dot(e_w2, bias_axis) / np.sum(bias_axis**2) * bias_axis
# Step 5: Adjust the Bias part of e_w1B and e_w2B using the formulas (9) and (10) given above (≈2 lines)
#等式9和10有误,应该是范数
corrected_e_w1B = np.sqrt(np.abs(1-np.sum(mu_orth**2))) * (e_w1B - mu_B)/np.linalg.norm(e_w1-mu_orth-mu_B)
corrected_e_w2B =np.sqrt(np.abs(1-np.sum(mu_orth**2))) * (e_w2B - mu_B)/np.linalg.norm(e_w2-mu_orth-mu_B)
# Step 6: Debias by equalizing e1 and e2 to the sum of their corrected projections (≈2 lines)
e1 = corrected_e_w1B + mu_orth
e2 = corrected_e_w2B + mu_orth
return e1, e2
print("cosine similarities before equalizing:")
print("cosine_similarity(word_to_vec_map[\"man\"], gender) = ", cosine_similarity(word_to_vec_map["man"], g))
print("cosine_similarity(word_to_vec_map[\"woman\"], gender) = ", cosine_similarity(word_to_vec_map["woman"], g))
print()
e1, e2 = equalize(("man", "woman"), g, word_to_vec_map)
print("cosine similarities after equalizing:")
print("cosine_similarity(e1, gender) = ", cosine_similarity(e1, g))
print("cosine_similarity(e2, gender) = ", cosine_similarity(e2, g))
请随意使用上面单元格中的输入单词,以将均衡应用于其他单词对。
这些去偏差算法对于减少偏差非常有帮助,但并不完美,也不能消除所有偏差痕迹。例如,这种实现的一个弱点是偏置方向 g仅使用“女人”和“男人”这两个词来定义。如前所述,如果 g通过计算 G1=Ewoman−Eman 定义; g2=母亲−父亲; g3=egirl−eboy;依此类推,对它们进行平均,您将在 50 维词嵌入空间中获得对“性别”维度的更好估计。也可以随意使用此类变体。
引用:
1、去偏见算法来自 Bolukbasi 等人,2016 年,男人之于计算机程序员,就像女人之于家庭主妇?消除单词嵌入的偏差
2、GloVe 词嵌入归功于 Jeffrey Pennington、Richard Socher 和 Christopher D. Manning。(https://nlp.stanford.edu/projects/glove/)