TensorFlow 学习笔记(二)word2vec(1)

来源:互联网 发布:马哥python网盘下载 编辑:程序博客网 时间:2024/06/05 19:44
python语言使用tensorflow 框架实现word2vec算法

今天,学习了使用tensorflow 的自然语言处理方向的word2vec。通过深度学习算法,把语料库中的词转化成为向量。并且相似单词的向量的余弦相似度会很高。
我们使用Skip-Gram模式进行算法设计,可以从原始词汇推测语句。预测模型我们使用最大似然估计法,在给定前面的一些单词后,计算接下来的一个单词最大的概率是哪个。因为要统计所有单词可能性,所以计算量巨大。我们这里使用一个编造噪声的方法,来快速的最优化目标。
我们只选择k个词而非全部词,并使用Noise-Contrastive Estimation Loss进行优化 。(tf.nn.nec_loss())





首先倒入我们在这个算法中要用到的所有的包如下:
import  collectionsimport  mathimport osimport randomimport zipfileimport numpy as npimport tensorflow as tfimport urllib.requestfrom sklearn.manifold import TSNEimport matplotlib.pyplot as plt

第二步,我使用了tensorflow自带的一个文档,里面含有大量英文语句,与英文单词。先使用代码进行下载并验证大小。
url = 'http://mattmahoney.net/dc/'def maybe_download(filename,expectde_byteds):    if not os.path.exists(filename):        filename,_ = urllib.request.urlretrieve(url + filename,filename)    statinfo = os.stat(filename)    if statinfo.st_size == expectde_byteds:        print("found",filename)    else:        print(statinfo.st_size)    return filenamefilename = maybe_download('text8.zip',31344016)print(filename)
ef read_data(filename):    with zipfile.ZipFile(filename) as f:        data = tf.compat.as_str(f.read(f.namelist()[0])).split()    return datawords = read_data(filename)print("Data size ", len(words))



或也可以使用我们自己的语料库训练自己需要的模型,我简单的训练了一个微博博文的语料库,语料库之前用jieba分词,对微博内容进行分词,并去除掉所有停用词且只留下了名词。
内容如图:


这里贴出了前三行分词结果,每行为一条博文的分词结果。
之后我使用如下代码对文件进行读取,合并为一行并存入一个列表里。
f = open("/Users/zhaozhengyang/Desktop/weibo/fenci_result.txt","r")lines = f.readlines()allwords = []for line in lines:    line = line.replace("\n","")    words = line.split()    for i in words:        allwords.append(i)


接下来,我们开始定义一个生成词汇表的方法。我们使用collection.Counter方法来统计单词数量,并取出词频排名前50000的单词。作为词汇表。并放入一个字典中以便快速查询。我们认为未知单词编号为0,并统计其数量,然后遍历全部单词,判断是否出现在字典中,如果出现则转为他的编号,否则编号为0。最后返回转换好的编码(data),每个单词的词频统计(count)、词汇表(dictionary)、以及反转的词汇表(reverse_dictionary)。
代码如下:
vocabulary_size = 50000def build_dateset(words):    count = [["UNK",-1]]    count.extend(collections.Counter(words).most_common(vocabulary_size-1))    dictionary = dict()    i = 0    for word , _ in count:        dictionary[word]=len(dictionary)        # if i<10:        #     print(dictionary)        #     i += 1    data = list()    unk_count=0    for word in words:        if word in dictionary:            index = dictionary[word]        else:            index = 0            unk_count +=1        data.append(index)    count[0][1] = unk_count    reverse_dictionary = dict(zip(dictionary.values(),dictionary.keys()))    return  data,count,dictionary,reverse_dictionary

接下来,生成训练样本,batch size为一组训练数据的长度(一次训练多少个单词),skip window表示词联系的距离,设为1表示每个词只关心他前后的词,只与相邻的词产生关联。num_skips为对每个单词生成多少组样本,这个数值不能大于skip window的两倍,且batch size必须为他的整数倍。
我们定义全局变量data_index之后定义assert 保证参数满足条件,然后使用np.ndarray将batch和labels 初始化为数组。
定义span为某个单词创建样本时会用到的单词数量大小为span = 2*skip_window+1.并创建一个容量为span的双向队列。
代码如下:
data_index = 0##生成训练样本def generate_batch(batch_size,num_skips,skip_window):#一组训练集的大小,                                                        # 对每单词生成多少训练样本,                                                        # 单词最远联系距离    global data_index#单词序号,为全局变量    assert batch_size % num_skips ==0 #每组训练量必须是单词生成样本的整数倍    assert num_skips <=2 * skip_window #生成样本数量不大于窗口长度的2倍    batch = np.ndarray(shape=(batch_size),dtype=np.int64) #生成训练组    labels = np.ndarray(shape=(batch_size,1),dtype=np.int64)#生成标签组    span = 2 * skip_window +1  #单词创建样本时需要的单词数量    buffer = collections.deque(maxlen=span) #缓存器(双向队列)

我们从序号为data_index的单词开始读入span个单词,然后开始第一层循环,对循环内每一个单词都生成样本,所以循环次数为batch size//num_skips,并把单词与目标单词存入buffer,之后我们定义target = skip_window,制定这个单词为目标单词,对其进行匹配,并且,把匹配过的词加入到避免词当中,防止重复。最后返回全部匹配好的词汇表代码如下:
    for _ in range(span):        buffer.append(data[data_index])        data_index = (data_index+1) % len(data)    #产生生成样本时需要避免的单词    for i in range(batch_size // num_skips):#循环(一组数据/每个单词生成多少样本)的倍数次        target = skip_window #定义buffer中第skipwindow为目标单词        targets_to_voide = [skip_window]#定义需要避免的单词,为        for j in  range (num_skips): #循环产生数量次            while target in targets_to_voide:#循环抽取随机数,直到抽取的随机单词不在避免单词中                                            #防止已被抽取的单词再次倍抽取。                target = random.randint(0,span-1)            targets_to_voide.append(target)            batch[i * num_skips + j] = buffer[skip_window]#目标词放入batch            labels[i * num_skips + j,0] = buffer[target]#目标词相关词放入lable        buffer.append(data[data_index])        data_index=(data_index+1)% len(data)    return batch,labels