图学习参考资料 词向量word2vec( 六 )


  • 给定一个中心词和一个需要预测的上下文词,把这个上下文词作为正样本 。
  • 通过词表随机采样的方式,选择若干个负样本 。
  • 把一个大规模分类问题转化为一个2分类问题,通过这种方式优化计算速度 。
#max_window_size代表了最大的window_size的大小,程序会根据max_window_size从左到右扫描整个语料#negative_sample_num代表了对于每个正样本,我们需要随机采样多少负样本用于训练,#一般来说,negative_sample_num的值越大,训练效果越稳定,但是训练速度越慢 。def build_data(corpus, word2id_dict, word2id_freq, max_window_size = 3, negative_sample_num = 4):#使用一个list存储处理好的数据dataset = []#从左到右,开始枚举每个中心点的位置for center_word_idx in range(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] for idx in range(positive_word_range[0], positive_word_range[1]+1) if idx != center_word_idx]#对于每个正样本来说,随机采样negative_sample_num个负样本,用于训练for positive_word in positive_word_candidates:#首先把(中心词,正样本,label=1)的三元组数据放入dataset中,#这里label=1表示这个样本是个正样本dataset.append((center_word, positive_word, 1))#开始负采样i = 0while i < negative_sample_num:negative_word_candidate = random.randint(0, vocab_size-1)if negative_word_candidate not in positive_word_candidates:#把(中心词,正样本,label=0)的三元组数据放入dataset中,#这里label=0表示这个样本是个负样本dataset.append((center_word, negative_word_candidate, 0))i += 1return datasetdataset = build_data(corpus, word2id_dict, word2id_freq)for _, (center_word, target_word, label) in zip(range(50), dataset):print("center_word %s, target %s, label %d" % (id2word_dict[center_word],id2word_dict[target_word], label))训练数据准备好后,把训练数据都组装成mini-batch,并准备输入到网络中进行训练,代码如下:
#我们将不同类型的数据放到不同的tensor里,便于神经网络进行处理#并通过numpy的array函数,构造出不同的tensor来,并把这些tensor送入神经网络中进行训练def build_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 = []for epoch in range(epoch_num):#每次开启一个新epoch之前,都对数据进行一次随机打乱,提高训练效果random.shuffle(dataset)for center_word, target_word, label in dataset:#遍历dataset中的每个样本,并将这些数据送到不同的tensor里center_word_batch.append([center_word])target_word_batch.append([target_word])label_batch.append(label)#当样本积攒到一个batch_size后,我们把数据都返回回来#在这里我们使用numpy的array函数把list封装成tensor#并使用python的迭代器机制,将数据yield出来#使用迭代器的好处是可以节省内存if len(center_word_batch) == batch_size:yield np.array(center_word_batch).astype("int64"), \np.array(target_word_batch).astype("int64"), \np.array(label_batch).astype("float32")center_word_batch = []target_word_batch = []label_batch = []if len(center_word_batch) > 0:yield np.array(center_word_batch).astype("int64"), \np.array(target_word_batch).astype("int64"), \np.array(label_batch).astype("float32")for _, batch in zip(range(10), build_batch(dataset, 128, 3)):print(batch)

经验总结扩展阅读