吴恩达深度学习 | (25) 序列模型专项课程第二周编程作业实验1

吴恩达深度学习专项课程的所有实验均采用iPython Notebooks实现,不熟悉的朋友可以提前使用一下Notebooks。

完整代码(中文翻译版带答案)

目录

1.实验综述

2.加载必要的包

3.余弦相似度

4.单词类比任务

5.消除词向量的偏差(选做)


1.实验综述

2.加载必要的包

import numpy as np
from w2v_utils import * #在当前项目目录下 ./w2v_utils.py

words, word_to_vec_map = read_glove_vecs('./data/glove.6B.50d.txt')

查看 w2v_utils.py中的 read_glove_vecs函数:

def read_glove_vecs(glove_file):
    with open(glove_file, 'r') as f: #打开.txt文件 读取
        words = set() #定义一个words集合
        word_to_vec_map = {} #定义词到向量的映射字典
        
        for line in f:  #遍历f中的每一行
            line = line.strip().split() #去掉首尾空格,每一行以空格切分  返回一个列表  第一项为单词 其余为单词的嵌入表示
            curr_word = line[0]  #取出单词
            words.add(curr_word) #加到集合/词典中
            #定义词到其嵌入表示的映射字典
            word_to_vec_map[curr_word] = np.array(line[1:], dtype=np.float64)
            
    return words, word_to_vec_map

查看./data/glove.6B.50d.txt:

每一行是首先是一个单词,然后是该单词对应的词嵌入/词向量(50维).

 

3.余弦相似度

# GRADED FUNCTION: cosine_similarity

def cosine_similarity(u, v):
    """
    余弦相似度:来反映向量u和v之间的相似程度
    
    参数:
        u -- 一个词向量  一维数组 (n,)          
        v -- 一个词向量  一维数组 (n,)

    Returns:
        余弦相似度 --通过上述定义的公式,来计算向量u和v的余弦相似度。
    """
    
    distance = 0.0 #初始化距离
    
    # 计算u和v的点积
    dot = u.dot(v)
    # 计算u的L2范数
    norm_u = np.linalg.norm(u)
    
    # 计算v的L2范数
    norm_v = np.linalg.norm(v)
    # 基于公式 (1) 计算余弦相似度
    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))

apple = word_to_vec_map['apple']
orange = word_to_vec_map['orange']
print('cosine_similarity(apple,orange) = ',cosine_similarity(apple,orange))

doctor = word_to_vec_map['doctor']
print('cosine_similarity(apple,doctor) = ',cosine_similarity(apple,doctor))

4.单词类比任务

# GRADED FUNCTION: complete_analogy

def complete_analogy(word_a, word_b, word_c, word_to_vec_map):
    """
    执行上述的单词类比任务: a is to b as c is to ____. 
    
    Arguments:
    word_a -- 一个单词,字符串
    word_b -- 一个单词,字符串
    word_c -- 一个单词,字符串
    word_to_vec_map -- 词和其对应向量的映射字典
    
    Returns:
    best_word --  满足 v_b - v_a 和 v_best_word - v_c的余弦相似度非常接近(接近1)的单词 
    """
    
    # 把单词转换为小写
    word_a, word_b, word_c = word_a.lower(), word_b.lower(), word_c.lower()
    

    # 得到单词 v_a, v_b 和 v_c 的词嵌入
    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              #初始化最大的余弦相似度为很大的负数
    best_word = None                   # 初始化 best_word 为None

    # 遍历词典中所有的单词
    for w in words:        
        # 跳过输入单词
        if w in [word_a, word_b, word_c] :
            continue
        

        # 计算向量(e_b - e_a) 和((w's vector representation) - e_c)  余弦相似度
        cosine_sim = cosine_similarity(e_b-e_a,word_to_vec_map[w]-e_c)
        
        #更新最大的余弦相似度和最佳单词
        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)))

triad = ('small','smaller','big') 
print ('{} -> {} :: {} -> {}'.format( *triad, complete_analogy(*triad,word_to_vec_map)))

 

5.消除词向量的偏差(选做)

g = word_to_vec_map['woman'] - word_to_vec_map['man']
print(g)

print ('List of names and their similarities with constructed vector:')

# 一些男孩和女孩的名字
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))

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 et al., 2016.中提到的算法来消除这些向量的偏差。 注意一些单词对,如actor/actress 或 grandmother/grandfather有明显的性别关联,而其他单词如receptionist或technology应该是中立的,与性别没什么关联。在进行偏差消除时,我们应该区别对待两种不同类型的词。

  • 中和非性别特定词的偏差

def neutralize(word, g, word_to_vec_map):
    """
    通过将词嵌入投影在与(性别)偏差轴正交的空间上来消除“单词(与性别无关)”的在性别方向上的偏差。
     此功能可确保性别中性词在性别子空间中为零
    
    Arguments:
        word -- 需要消除偏差的词 字符串
        g -- 一维数组 (50,), 对应偏差轴 (如 性别)
        word_to_vec_map -- 词与其嵌入向量的映射字典
    
    Returns:
        e_debiased -- 输入 "word"在消除(性别)偏差后的嵌入表示
    """
    
   
    # 得到word的词嵌入
    e = word_to_vec_map[word]
    
    # 用上述公式计算 e_biascomponent
    e_biascomponent = e.dot(g)/(np.linalg.norm(g)**2)*g
 
    # 中和e,通过减去e_biascomponent
    # e_debiased 应该和它的正交映射相等
    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))

 

  • 性别特定词的均衡算法

均衡算法的线性代数推导有点复杂,详见论文Boliukbasi et al., 2016.下面是一些关键方程:

def equalize(pair, bias_axis, word_to_vec_map):
    """
    按照上述描述的均衡算法,对一对性别特定词进行处理
    
    Arguments:
    pair -- 一对性别特定词 e.g. ("actress", "actor") 
    bias_axis --  一维数组 (50,), 对应偏差轴 (如 性别)
    word_to_vec_map -- 词与其嵌入向量的映射字典
    
    Returns
    e_1 -- 第一个单词均衡后的词向量
    e_2 -- 第二个单词均衡后的词向量
    """

    # 得到单词及其词向量
    w1, w2 = pair
    e_w1, e_w2 = word_to_vec_map[w1],word_to_vec_map[w2]
    
    # 计算 e_w1 和 e_w2 的均值
    mu = (e_w1 + e_w2)/2

    # 计算mu在偏差轴和正交轴上的映射
    mu_B = mu.dot(bias_axis)/(np.linalg.norm(bias_axis)**2) * bias_axis
    mu_orth = mu - mu_B

    # 使用公式 (7) 和 (8) 计算 e_w1B 和 e_w2B 
    e_w1B = e_w1.dot(bias_axis)/(np.linalg.norm(bias_axis)**2) * bias_axis
    e_w2B = e_w2.dot(bias_axis)/(np.linalg.norm(bias_axis)**2) * bias_axis
        
    # 调整 e_w1B 和 e_w2B 的偏差部分 使用公式 (9)和(10)
    corrected_e_w1B = np.sqrt(np.abs(1-np.linalg.norm(mu_orth)**2))*((e_w1B-mu_B)/(np.abs(e_w1-mu_orth-mu_B)))
    
    corrected_e_w2B = np.sqrt(np.abs(1-np.linalg.norm(mu_orth)**2))*((e_w2B-mu_B)/(np.abs(e_w2-mu_orth-mu_B)))

    # 公式(11) (12)
    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))

  • 参考

The debiasing algorithm is from Bolukbasi et al., 2016, Man is to Computer Programmer as Woman is to Homemaker? Debiasing Word Embeddings

The GloVe word embeddings were due to Jeffrey Pennington, Richard Socher, and Christopher D. Manning. (https://nlp.stanford.edu/projects/glove/)

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值