介绍词向量word2evc概念,及CBOW和Skip-gram的算法实现( 六 )


print("%dtokensinthecorpus"%len(corpus))
print(corpus[:50])
在完成语料数据预处理之后 , 需要构造训练数据 。 根据上面的描述 , 我们需要使用一个滑动窗口对语料从左到右扫描 , 在每个窗口内 , 中心词需要预测它的上下文 , 并形成训练数据 。
在实际操作中 , 由于词表往往很大(50000 , 100000等) , 对大词表的一些矩阵运算(如softmax)需要消耗巨大的资源 , 因此可以通过负采样的方式模拟softmax的结果 。 给定一个中心词和一个需要预测的上下文词 , 把这个上下文词作为正样本 。 通过词表随机采样的方式 , 选择若干个负样本 。 把一个大规模分类问题转化为一个2分类问题 , 通过这种方式优化计算速度 。
#构造数据 , 准备模型训练
#max_window_size代表了最大的window_size的大小 , 程序会根据max_window_size从左到右扫描整个语料
#negative_sample_num代表了对于每个正样本 , 我们需要随机采样多少负样本用于训练 ,
#一般来说 , negative_sample_num的值越大 , 训练效果越稳定 , 但是训练速度越慢 。
defbuild_data(corpus,word2id_dict,word2id_freq,max_window_size=3,negative_sample_num=4):
#使用一个list存储处理好的数据
dataset=[]
#从左到右 , 开始枚举每个中心点的位置
forcenter_word_idxinrange(len(corpus)):
#以max_window_size为上限 , 随机采样一个window_size , 这样会使得训练更加稳定
window_size=random.randint(1,max_window_size)
#当前的中心词就是center_word_idx所指向的词
center_word=corpus[center_word_idx]
#以当前中心词为中心 , 左右两侧在window_size内的词都可以看成是正样本
positive_word_range=(max(0,center_word_idx-window_size),min(len(corpus)-1,center_word_idx+window_size))
positive_word_candidates=[corpus[idx]foridxinrange(positive_word_range[0],positive_word_range[1]+1)ifidx!=center_word_idx]
#对于每个正样本来说 , 随机采样negative_sample_num个负样本 , 用于训练
forpositive_wordinpositive_word_candidates:
#首先把(中心词 , 正样本 , label=1)的三元组数据放入dataset中 ,
#这里label=1表示这个样本是个正样本
dataset.append((center_word,positive_word,1))
#开始负采样
i=0
whilei<negative_sample_num:
negative_word_candidate=random.randint(0,vocab_size-1)
ifnegative_word_candidatenotinpositive_word_candidates:
#把(中心词 , 正样本 , label=0)的三元组数据放入dataset中 ,
#这里label=0表示这个样本是个负样本
dataset.append((center_word,negative_word_candidate,0))
i+=1
returndataset
dataset=build_data(corpus,word2id_dict,word2id_freq)
for_,(center_word,target_word,label)inzip(range(50),dataset):
print("center_word%s,target%s,label%d"%(id2word_dict[center_word],
id2word_dict[target_word],label))
训练数据准备好后 , 把训练数据都组装成mini-batch , 并准备输入到网络中进行训练 , 代码如下:
#构造mini-batch , 准备对模型进行训练
#我们将不同类型的数据放到不同的tensor里 , 便于神经网络进行处理
#并通过numpy的array函数 , 构造出不同的tensor来 , 并把这些tensor送入神经网络中进行训练
defbuild_batch(dataset,batch_size,epoch_num):
#center_word_batch缓存batch_size个中心词
center_word_batch=[]
#target_word_batch缓存batch_size个目标词(可以是正样本或者负样本)
target_word_batch=[]
#label_batch缓存了batch_size个0或1的标签 , 用于模型训练
label_batch=[]
forepochinrange(epoch_num):
#每次开启一个新epoch之前 , 都对数据进行一次随机打乱 , 提高训练效果
random.shuffle(dataset)