读书笔记:深度学习进阶-自然语言处理(俗称鱼书二)

文章目录

  • 前言
  • 一、神经网络的复习
  • 二、自然语言和单词的分布式表示
    • 2.1什么是自然语言处理
    • 2.2同义词词典
    • 2.3基于计数的方法
      • 2.3.1基于python的语料库的预处理
      • 2.3.2单词的分布式表示
      • 2.3.3分布式假设
      • 2.3.4共现矩阵
      • 2.3.5向量间的相似度
      • 2.3.6相似单词的排序
    • 2.4基于计数的方法的改进
      • 2.4.1点互信息
      • 2.4.2降维
      • 2.4.3基于SVD的降维
      • 2.4.4PBT数据集
      • 2.4.5基于PTB数据集的评价
    • 2.5小结
  • 三、word2vec
    • 3.1基于推理的方法和神经网络
      • 3.1.1基于计数的方法的问题
      • 3.1.2基于推理的方法概要
      • 3.1.3神经网络中单词的处理方法
    • 3.2简单的word2vec
      • 3.2.1CBOW模型的推理
      • 3.2.2CBOW模型的学习
      • 3.2.3word2vec的权重和分布式表示
    • 3.3学习数据的准备
      • 3.3.1上下文和目标词
      • 3.3.2转化为one-hot表示
  • 四、word2vec的高速化
    • 1.
    • 2.
  • 五、RNN
    • 1.
    • 2.
  • 六、Gated RNN
    • 1.
    • 2.
  • 七、基于RNN生成文本
    • 1.
    • 2.
  • 八、Attention
    • 1.
    • 2.
  • 总结


前言

还记得半年前开始看并给鱼书一做笔记的热情,现在想进一步了,作者和翻译作者都非常高效给力了,那么快就出了第二本鱼书-《深度学习进阶-自然语言处理》,本书一共八章,希望每周可以看完并完成一个章节的笔记,深度学习冲冲冲~
在啃第一本鱼书的时候,是采用了先看在总结的方式,这次看第二本决定边看边总结,看完一遍可能还得回去再看第二遍,希望这次边学边思的效率高些,加油加油!


一、神经网络的复习

这一张主要是对上一本书内容的总结,复习可戳https://blog.csdn.net/qq_45461377/article/details/124915144?spm=1001.2014.3001.5501

二、自然语言和单词的分布式表示

2.1什么是自然语言处理

自然语言处理是让计算机处理自然语言的技术。自然语言是柔软的,而计算机语言(编程)是硬的,让计算机读懂并处理自然语言的技术目前主要分为三类:1、基于同义词词典的方法;2、基于计数的方法;3基于推理的方法(word2vec)。本章将先介绍前两种。

2.2同义词词典

同义词词典是人为定义的单词之间粒度关系的词典,把意思相近的单词放得更近,同时表示单词之间上下、左右关系的词典。
最著名的同义词词典是WordNet。
同义词词典存在的问题:1、难以顺应时代变化;2、人工成本高;3、无法表示单词的微妙差异。

2.3基于计数的方法

基于计数的方法使用语料库来处理自然语言。

2.3.1基于python的语料库的预处理

text='You say goodbye and I say hello.'
text=text.lower()
text=text.replace('.',' .')
print(text)

输出:you say goodbye and i say hello .

words=text.split(' ')
print(words)

输出:[‘you’, ‘say’, ‘goodbye’, ‘and’, ‘i’, ‘say’, ‘hello’, ‘.’]

word_to_id={}
id_to_word={}

for word in words:
    if word not in word_to_id:
        new_id=len(word_to_id)
        word_to_id[word]=new_id
        id_to_word[new_id]=word

print(id_to_word)
print(word_to_id)

输出:{0: ‘you’, 1: ‘say’, 2: ‘goodbye’, 3: ‘and’, 4: ‘i’, 5: ‘hello’, 6: ‘.’}
{‘you’: 0, ‘say’: 1, ‘goodbye’: 2, ‘and’: 3, ‘i’: 4, ‘hello’: 5, ‘.’: 6}

print(id_to_word[1])
print(word_to_id['hello'])

输出:say
5

import numpy as np
corpus=[word_to_id[w] for w in words]
corpus=np.array(corpus)
print(corpus)

输出:[0 1 2 3 4 1 5 6]
把上面的部分合成一个函数得:

def preprocess(text):
    text=text.lower()
    text=text.replace('.',' .')
    word_to_id={}
    id_to_word={}

    for word in words:
        if word not in word_to_id:
            new_id=len(word_to_id)
            word_to_id[word]=new_id
            id_to_word[new_id]=word
    
    corpus=[word_to_id[w] for w in words]

    return corpus, word_to_id, id_to_word

text='You say goodbye and I say hello.'
corpus, word_to_id, id_to_word=preprocess(text)

2.3.2单词的分布式表示

将颜色表示类比到单词表示,颜色可以用向量来表示,同样地,单词也可以。

2.3.3分布式假设

分布式假设指某个单词的含义由他周围的单词决定。
上下文指某个单词周围的单词。
窗口大小指周围的单词有多少个。

2.3.4共现矩阵

print(corpus)
print(id_to_word)

输出:[0, 1, 2, 3, 4, 1, 5, 6]
{0: ‘you’, 1: ‘say’, 2: ‘goodbye’, 3: ‘and’, 4: ‘i’, 5: ‘hello’, 6: ‘.’}

def create_co_matrix(corpus,vocab_size,window_size=1):
    corpus_size=len(corpus)
    co_matrix=np.zeros((vocab_size,vocab_size),dtype=np.int32)

    for idx, word_id in enumerate(corpus):
        for i in range(1,window_size+1):
            left_idx=idx-i
            right_idx=idx+i

            if left_idx>=0:
                left_word_id=corpus[left_idx]
                co_matrix[word_id,left_word_id]+=1

            if right_idx<corpus_size:
                right_word_id=corpus[right_idx]
                co_matrix[word_id,right_word_id]+=1
    return co_matrix
print(create_co_matrix(corpus,vocab_size=len(word_to_id)))

输出:[[0 1 0 0 0 0 0]
[1 0 1 0 1 1 0]
[0 1 0 1 0 0 0]
[0 0 1 0 1 0 0]
[0 1 0 1 0 0 0]
[0 1 0 0 0 0 1]
[0 0 0 0 0 1 0]]

2.3.5向量间的相似度

余弦相似度表示两个向量在多大程度上指向同一方向。
L2范数指向量个元素的平方和的平方根。

def cos_similarity(x,y):
    nx=x/np.sqrt(np.sum(x**2))
    ny=y/np.sqrt(np.sum(y**2))
    return np.dot(nx,ny)
def cos_similarity(x,y,eps=1e-8):
    nx=x/np.sqrt(np.sum(x**2)+eps)
    ny=y/np.sqrt(np.sum(y**2)+eps)
    return np.dot(nx,ny)
C=create_co_matrix(corpus,vocab_size=len(word_to_id))

c0=C[word_to_id['you']]
c1=C[word_to_id['i']]
print(cos_similarity(c0,c1))

输出:0.7071067758832467

2.3.6相似单词的排序

定义一个查询词相似的单词按降序显示出来的函数。

def most_similar(query, word_to_id, id_to_word, word_matrix, top=5):
    # 取出查询词
    if query not in word_to_id:
        print('%s is not found' % query)
        return

    print('\n[query] ' + query)
    query_id = word_to_id[query]
    query_vec = word_matrix[query_id]

    # 计算余弦相似度
    vocab_size = len(id_to_word)
    similarity = np.zeros(vocab_size)
    for i in range(vocab_size):
        similarity[i] = cos_similarity(word_matrix[i], query_vec)
    
    # 基于余弦相似度,按降序输出值
    count = 0
    for i in (-1 * similarity).argsort():
        if id_to_word[i] == query:
            continue
        print(' %s: %s' % (id_to_word[i], similarity[i]))

        count += 1
        if count >= top:
            return
x=np.array([100,-20,2])
x.argsort()
(-x).argsort()

输出:array([0, 2, 1])

most_similar('you', word_to_id, id_to_word, C)

输出为
[query] you
goodbye: 0.7071067758832467
i: 0.7071067758832467
hello: 0.7071067758832467
say: 0.0
and: 0.0

2.4基于计数的方法的改进

基于计数的方法使用语料库来处理自然语言。

2.4.1点互信息

点互信息PMI,用来表示词之间的相关性。
正的点互信息PPMI,为解决共出现为0的情况。

def ppmi(C,verbose=False,eps=1e-8):
    M=np.zeros_like(C,dtype=np.float32)
    N=np.sum(C)
    S=np.sum(C,axis=0)
    total=C.shape[0]*C.shape[1]
    cnt=0

    for i in range(C.shape[0]):
        for j in range(C.shape[1]):
            pmi=np.log2(C[i,j]*N/S[j]*S[i]+eps)
            M[i,j]=max(0,pmi)

            if verbose:
                cnt+=1
                if cnt%(total//100+1)==0:
                    print('%.1f%% done'%(100*cnt/total))
    
    return M
W=ppmi(C)
print(W)

输出:[[0. 1.8073549 0. 0. 0. 0. 0. ]
[5.807355 0. 4.807355 0. 4.807355 4.807355 0. ]
[0. 2.807355 0. 3.807355 0. 0. 0. ]
[0. 0. 3.807355 0. 3.807355 0. 0. ]
[0. 2.807355 0. 3.807355 0. 0. 0. ]
[0. 2.807355 0. 0. 0. 0. 4.807355 ]
[0. 0. 0. 0. 0. 2.807355 0. ]]
PPMI矩阵的问题,随着语料库词汇量的增加,各单词向量的维度也会增加。

2.4.2降维

降维指保留重要信息,降低向量维度。
降维可以将稀疏矩阵转化为密集矩阵。
本书举例奇异值分解法(SVD),其可将任意矩阵转化为3个矩阵的乘积。

2.4.3基于SVD的降维

U,S,V=np.linalg.svd(W)
print(C[0]) #共现矩阵
print(W[0]) #PPMI矩阵
print(U[0]) #SVD矩阵
print(U[0,:2]) #降维为2

输出:[0 1 0 0 0 0 0]
[0. 1.8073549 0. 0. 0. 0. 0. ]
[ 0.0000000e+00 1.7478172e-01 3.8205594e-02 -1.1102230e-16
-1.1102230e-16 -9.8386568e-01 -1.2717195e-16]
[0. 0.17478172]

import matplotlib.pyplot as plt
for word, word_id in word_to_id.items():
    plt.annotate(word, (U[word_id,0], U[word_id,1]))

plt.scatter(U[:,0],U[:,1],alpha=0.5)
plt.show()

2.4.4PBT数据集

from dataset import ptb

corpus,word_to_id,id_to_word=ptb.load_data('train')
print('corpus size:', len(corpus))
print('corpus[:30]:', corpus[:30])
print()
print('id_to_word[0]:', id_to_word[0])
print('id_to_word[1]:', id_to_word[1])
print('id_to_word[2]:', id_to_word[2])
print()
print("word_to_id['car']:", word_to_id['car'])
print("word_to_id['happy']:", word_to_id['happy'])
print("word_to_id['lexus']:", word_to_id['lexus'])

输出:corpus size: 929589
corpus[:30]: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29]

id_to_word[0]: aer
id_to_word[1]: banknote
id_to_word[2]: berlitz

word_to_id[‘car’]: 3856
word_to_id[‘happy’]: 4428
word_to_id[‘lexus’]: 7426

2.4.5基于PTB数据集的评价

window_size = 2
wordvec_size = 100

corpus, word_to_id, id_to_word = ptb.load_data('train')
vocab_size = len(word_to_id)
print('counting  co-occurrence ...')
C = create_co_matrix(corpus, vocab_size, window_size)
print('calculating PPMI ...')
W = ppmi(C, verbose=True)

print('calculating SVD ...')
try:
    # truncated SVD (fast!)
    from sklearn.utils.extmath import randomized_svd
    U, S, V = randomized_svd(W, n_components=wordvec_size, n_iter=5,
                             random_state=None)
except ImportError:
    # SVD (slow)
    U, S, V = np.linalg.svd(W)

word_vecs = U[:, :wordvec_size]

querys = ['you', 'year', 'car', 'toyota']
for query in querys:
    most_similar(query, word_to_id, id_to_word, word_vecs, top=5)

输出:

2.5小结

本章我们重点学习了单词的向量表示的发展,从预处理到共现矩阵,再到表示单词间关系的PPMI矩阵,最后到将为的SVD矩阵,学会处理词向量,是这个部分代码所重点强调的。

三、word2vec

3.1基于推理的方法和神经网络

上一章我们说到表示词向量流行的方法有两种:基于计数的方法和基于推理的方法,两者都是基于分布式假设,这一章就来介绍基于推理的方法。

3.1.1基于计数的方法的问题

消耗大量的计算资源和时间。
基于计数的方法一次性处理全部学习数据,而基于推理的方法使用部分学习数据逐步学习。

3.1.2基于推理的方法概要

分布式假设:单词含义由周围单词构成。

3.1.3神经网络中单词的处理方法

通过one-hot矩阵进行表示


3.2简单的word2vec

3.2.1CBOW模型的推理


3.2.2CBOW模型的学习


3.2.3word2vec的权重和分布式表示


3.3学习数据的准备

3.3.1上下文和目标词


3.3.2转化为one-hot表示



四、word2vec的高速化

1.


2.


五、RNN

1.


2.


六、Gated RNN

1.


2.


七、基于RNN生成文本

1.


2.


八、Attention

1.


2.



总结

你可能感兴趣的:(深度学习,自然语言处理,python)