ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

吴恩达深度学习课程第五章第二周编程作业(pytorch实现)

2022-01-12 18:04:03  阅读:180  来源: 互联网

标签:map 吴恩达 word index self pytorch 第二周 vec words


文章目录


前言

  本博客只是记录一下本人在深度学习过程中的学习笔记和编程经验,大部分代码是参考了【中文】【吴恩达课后编程作业】Course 5 - 序列模型 - 第二周作业 - 词向量的运算与Emoji生成器这篇博客,对其代码实现了复现,但是原博客中代码使用的是tensorflow,而我在学习中主要用到的是pytorch,所以此次作业我使用pytorch框架来完成。代码或文字表述中还存在一些问题,请见谅,之前的博客也是主要参考这个大佬。下文中的完整代码已经上传到百度网盘中,提取码:00cz。
  所以开始作业前,请大家安装好pytorch的环境,我代码是在服务器上利用gpu加速运行的,但是cpu版本的pytorch也能运行,只是速度会比较慢。

一、词向量运算

1.数据准备

  训练得到词嵌入数据是需要消耗庞大的资源,这里我们就用已经训练好的glove词向量代替。
  读取glove英文词向量:

def read_glove_vecs(glove_file):
    """
    加载glove英文词向量
    :param glove_file: 文件路径
    :return:
    """
    with open(glove_file, 'r', encoding="utf-8") as f:
        words = set()
        word_to_vec_map = {}

        for line in 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
words:列表类型数据,记录了词典中的全部词
word_to_vec_map:字典类型,构造"词-词向量"键值对,可以方便的查找指定词的词向量

  查看英文词向量:

words, word_to_vec_map = w2v_utils_pytorch.read_glove_vecs('data/glove.6B.50d.txt')
print(word_to_vec_map["hello"])
[-0.38497   0.80092   0.064106 -0.28355  -0.026759 -0.34532  -0.64253
-0.11729  -0.33257   0.55243  -0.087813  0.9035    0.47102   0.56657
0.6985   -0.35229  -0.86542   0.90573   0.03576  -0.071705 -0.12327
0.54923   0.47005   0.35572   1.2611   -0.67581  -0.94983   0.68666
0.3871   -1.3492    0.63512   0.46416  -0.48814   0.83827  -0.9246
-0.33722   0.53741  -1.0616   -0.081403 -0.67111   0.30923  -0.3923
-0.55002  -0.68827   0.58049  -0.11626   0.013139 -0.57654   0.048833
0.67204 ]

  glove中包含了40000个英文单词的词向量,每个词向量的维度是50维。在了解数据的基本情况后,可以运用这些词向量做一些简单的计算了。

2.余弦相似度

  根据余弦相似度的计算公式可以编程计算两个词的相似度情况,不清楚余弦相似度的可以自行百度:

def cosine_similarity(u, v):
    """
    计算两个词向量的余弦相似度
    :param u:单词u的词向量
    :param v:单词v的词向量
    :return:
    """
    dot = np.dot(u, v)
    norm_u = np.sqrt(np.sum(np.power(u, 2)))
    norm_v = np.sqrt(np.sum(np.power(v, 2)))

    distance = np.divide(dot, norm_v * norm_u)

    return distance

  简单计算一些词的余弦相似度:

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

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) = ", w2v_utils_pytorch.cosine_similarity(father, mother))
print("cosine_similarity(ball, crocodile) = ",w2v_utils_pytorch.cosine_similarity(ball, crocodile))
print("cosine_similarity(france - paris, rome - italy) = ",w2v_utils_pytorch.cosine_similarity(france - paris, rome - italy))
cosine_similarity(father, mother) =  0.8909038442893616
cosine_similarity(ball, crocodile) =  0.27439246261379424
cosine_similarity(france - paris, rome - italy) =  -0.6751479308174201

  可以看出约相似的词,其词向量在空间中的夹角越小,计算得到的余弦相似度就越大,这也说明了glove词向量的质量比较优秀。

3.词类类比

  当我们拥有优秀的词向量后可以完成词类类比任务:“A与B相比就类似于C与____相比一样”,比如:“男人与女人相比就像国王与 女皇 相比”。具体原理就是在词典中找到一个词D,使得vector(B)-vector(A) ≈ \approx ≈ vector(D)-vector©,依旧采用余弦公式计算两者的相似度。

def complete_analogy(word_a, word_b, word_c, word_to_vec_map):
    """
    词类比问题:解决“A与B相比就类似于C与____相比一样”问题,比如“男人与女人相比就像国王与 女皇 相比一样”
    其实就是在词库里面找到一个词word_d满足:word_b - word-a 与 word_d - word_c 近似相等
    :param word_a:词a
    :param word_b:词b
    :param word_c:词c
    :param word_to_vec_map:词典
    :return:
    """
    # 将单词转换为小写
    word_a, word_b, word_c = word_a.lower(), word_b.lower(), word_c.lower()

    # 找到单词的词向量
    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_similarity = -100
    best_word = None

    # 遍历整个词典
    for word in words:
        if word in [word_a, word_b, word_c]:
            continue
        cosine_sim = cosine_similarity((e_b - e_a), (word_to_vec_map[word] - e_c))

        if cosine_sim > max_cosine_similarity:
            max_cosine_similarity = cosine_sim
            best_word = word

    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, w2v_utils_pytorch.complete_analogy(*triad, word_to_vec_map)))
italy -> italian <====> spain -> spanish
india -> delhi <====> japan -> tokyo
man -> woman <====> boy -> girl
small -> smaller <====> large -> larger

  可以看出,glove词向量处理词类类比任务时效果还是非常好的。
  原作业中提到了去除词向量中的偏见属于选学部分,本人还未完全理解,感兴趣的同学可以参考我前言中原博客中的内容。

二、表情生成器V1

  表情生成器其实就是情感分类,本质上是多分类问题。在原作业中想要打印表情符号需要安装emoji包,这里我简化一下问题,只针对情感分类任务。

在这里插入图片描述
  我们首先使用一个简单的前馈神经网络来完成这个分类任务,网络的结构如下:
在这里插入图片描述

1.将英文句子进行分词
2.将每个词转换成50维的glove向量,计算得到平均值,作为神经网络的输入
3.经过一层全连接层后,进行softmax操作,得到预测的分类结果

主控模型:

def model(X, Y, word_to_vec_map, learning_rate=0.01, num_iterations=400):
    np.random.seed(1)

    m = Y.shape[0]
    n_y = 5
    n_h = 50

    W = np.random.randn(n_y, n_h) / np.sqrt(n_h)
    b = np.zeros((n_y,))

    Y_oh = emo_utils.convert_to_one_hot(Y, C=n_y)

    for epoch in range(num_iterations):
        for i in range(m):
            avg = sentence_to_avg(X[i], word_to_vec_map)

            # 前向传播
            z = np.dot(W, avg) + b
            a = emo_utils.softmax(z)

            # 计算第i个训练的损失
            cost = -np.sum(Y_oh[i] * np.log(a))

            # 计算梯度
            dz = a - Y_oh[i]
            dW = np.dot(dz.reshape(n_y, 1), avg.reshape(1, n_h))
            db = dz

            # 更新参数
            W = W - learning_rate * dW
            b = b - learning_rate * db
        if epoch % 100 == 0:
            print("第{epoch}轮,损失为{cost}".format(epoch=epoch, cost=cost))
            pred = emo_utils.predict(X, Y, W, b, word_to_vec_map)
    return pred, W, b

计算平均词向量:

def sentence_to_avg(sentence, word_to_vec_map):
    """
    将句子转换为单词列表,提取Glove向量,取平均值
    :param sentence: 输入的句子
    :param word_to_vec_map: 词典
    :return:
    """
    # 将句子拆成单词列表
    words = sentence.lower().split()

    # 初始化均值向量
    avg = np.zeros(50, )

    for w in words:
        avg = avg + word_to_vec_map[w]
    avg = np.divide(avg, len(words))
    return avg

训练测试模型:

words, word_to_vec_map = w2v_utils_pytorch.read_glove_vecs('data/glove.6B.50d.txt')
pred, W, b = model(X_train, Y_train, word_to_vec_map)
print("=====训练集====")
pred_train = emo_utils.predict(X_train, Y_train, W, b, word_to_vec_map)
print("=====测试集====")
pred_test = emo_utils.predict(X_test, Y_test, W, b, word_to_vec_map)
X_my_sentences = np.array(
        ["i adore you", "i love you", "funny lol", "lets play with a ball", "food is ready", "you are not happy"])
Y_my_labels = np.array([[0], [0], [2], [1], [4], [3]])

pred = emo_utils.predict(X_my_sentences, Y_my_labels, W, b, word_to_vec_map)
emo_utils.print_predictions(X_my_sentences, pred)

训练结果如下:

第0轮,损失为1.952049881281007
Accuracy: 0.3484848484848485
第100轮,损失为0.07971818726014794
Accuracy: 0.9318181818181818
第200轮,损失为0.04456369243681379
Accuracy: 0.9545454545454546
第300轮,损失为0.03432267378786059
Accuracy: 0.9696969696969697
=====训练集====
Accuracy: 0.9772727272727273
=====测试集====
Accuracy: 0.8571428571428571

i adore you ❤️
i love you ❤️
funny lol 

标签:map,吴恩达,word,index,self,pytorch,第二周,vec,words
来源: https://blog.csdn.net/qq_44218195/article/details/122453767

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有