频道栏目
首页 > 网络 > 云计算 > 正文
Tensorflow实例-CNN处理句子相似度(上)
2017-04-08 09:19:11           
收藏   我要投稿

上一篇文章中,提到了在Tensorflow中关键的两个问题,第一对数据进行处理,转化为合适的tensor作为input输入到图中。第二使用tensorflow对神经网络进行构建。代码上传至github上(https://github.com/Irvinglove/TF_Sentence_Similarity_CNN),感兴趣的同学可以下载并进行仿真,加深对tensorflow的理解。代码较长,因此分为上下两篇对该实例进行讲解。上篇讲解句子相似度问题中数据处理的相关工作。

1、 读取glove词向量文件。

选用glove文件是google预先训练好的文件,因为是pretrained,所以我们直接进行读取。值得一提的是,这里新建了两个变量embedding_w,embedding_dic。因为我们在实际操作过程中发现,如果直接使用词向量作为input的话,那么placeholder中传入的shape就是[s_count,sentence_length,embedding_size],其中,s_count是数据集大小,sentence_length就是最大句子长度,embedding_length就是词向量的大小。那么placeholder的维度就太大,然后程序就变得特别卡顿。所以,参考Text Classification(CNN)(https://github.com/dennybritz/cnn-text-classification-tf)的方法,使用embedding层进行转换,即embedding_w的shape为[vocabulary_size,embedding_size],考虑这个矩阵纵坐标是glove的词汇大小,横坐标是词向量长度。placeholder的shape就变成了[s_count,sentence_length],以词汇在embedding_w的索引值代替词向量,这样就大大节省了placeholder的空间,embedding_dic就是将word转化为索引值的字典。

比如句子“cat sit on the mat”,一般的思路是用“cat”,”sit”,”on”,”the”,”mat”这五个单词的词向量表示这句话:

[[1,1,1],

[2,2,2],

def build_glove_dic():

#

# 从文件中读取pre-trained的glove文件,对应每个词的词向量

#

embedding_dic = {}

embedding_w = []

glove_dir = "glove.6B.50d.txt"

for i, line in enumerate(open(glove_dir, 'r')):

arr = line.split(" ")

embedding_dic[arr[0]] = i

embedding_w.append(np.array(arr[1:]).astype(float))

embedding_w = np.array(embedding_w, dtype='float32')

return embedding_w,embedding_dic

[3,3,3],

[4,4,4],

[5,5,5]]

那么整个数据集为9840行,placeholder就变成了9840*5*3大小的tensor,采用embedding_w以后呢,我们采用“cat”,”sit”,”on”,”the”,”mat”这五个词在embedding_w中的索引代替该词:

[1,2,3,4,5]

然后placeholder就变成了9840*5大小的tensor,然后在之后的操作中,根据索引查找embedding_w的词向量即可,当embedding_size为3时,影响不大,但是当embedding_size为50、100或者更大时,节省的时间就很可观了。

def build_glove_dic():

#

# 从文件中读取pre-trained的glove文件,对应每个词的词向量

#

embedding_dic = {}

embedding_w = []

glove_dir = "glove.6B.50d.txt"

for i, line in enumerate(open(glove_dir, 'r')):

arr = line.split(" ")

embedding_dic[arr[0]] = i

embedding_w.append(np.array(arr[1:]).astype(float))

embedding_w = np.array(embedding_w, dtype='float32')

return embedding_w,embedding_dic

2、读取数据集。本实例中数据集选取SICK(https://clic.cimec.unitn.it/composes/sick.html)。数据集主要包括两个句子和它们之间的相似度。整个函数的想法就是从数据集中提取数据,使用s1,s2,score存储两个句子和它们之间的相似度。然后对句子进行处理,记数据集中句子的最大长度sentence_length,不够该长度的使用‘unk’进行填充。

值得一提的是,这里的s1_image和s2_image的形状是[s_count,sentence_length

],label的形状是[s_count,1]。这里说道的s1_image和s2_image刚好和placeholder的input的形状保持一致,然后通过

def read_data_sets(train_dir):

#

# s1代表数据集的句子1

# s2代表数据集的句子2

# score代表相似度

# s_count代表数据总共有多少行

#

s1 = []

s2 = []

score = []

s_count = 0

SICK_DIR = "SICK_data/SICK.txt"

for line in open(SICK_DIR, 'r'):

arr = line.split("\t")

s1.append(clean_str(arr[1]))

s2.append(clean_str(arr[2]))

score.append(arr[4])

s_count = s_count + 1

# 填充句子

s1, s2 = padding_sentence(s1, s2)

# 引入embedding矩阵和字典

embedding_w, embedding_dic = build_glove_dic()

# 将每个句子中的每个单词,转化为embedding矩阵的索引

# 如:s1_words表示s1中的单词,s1_vec表示s1的一个句子,s1_image代表所有s1中的句子

s1_image = []

s2_image = []

label = []

for i in range(s_count):

s1_words = s1[i].split(" ")

s2_words = s2[i].split(" ")

s1_vec = []

s2_vec = []

# 如果在embedding_dic中存在该词,那么就将该词的索引加入到s1的向量表示s1_vec中,不存在则用代替

for j,_ in enumerate(s1_words):

if embedding_dic.has_key(s1_words[j]):

s1_vec.append(embedding_dic[s1_words[j]])

else:

s1_vec.append(embedding_dic[''])

if embedding_dic.has_key(s2_words[j]):

s2_vec.append(embedding_dic[s2_words[j]])

else:

s2_vec.append(embedding_dic[''])

s1_image.append(np.array(s1_vec))

s2_image.append(np.array(s2_vec))

label.append(np.array(np.array([score[i]]).astype(float)))

# 求得训练集与测试集的tensor并返回

s1_image = np.array(s1_image)

s2_image = np.array(s2_image)

label = np.array(label,dtype='float32')

train_end = int(s_count*0.7)

return s1_image[0:train_end], s2_image[0:train_end], label[0:train_end],\

s1_image[train_end:s_count], s2_image[train_end:s_count], label[train_end:s_count],\

embedding_w

3、填充句子

def padding_sentence(s1, s2):

#

# 得到句子s1,s2以后,很直观地想法就是先找出数据集中的最大句子长度,

# 然后用对句子进行填充

#

s1_length_max = max([len(s.split(" ")) for s in s1])

s2_length_max = max([len(s.split(" ")) for s in s1])

sentence_length = max(s1_length_max, s2_length_max)

print "已经求得最大长度sentence_length"

for i,s in enumerate(s1):

sen_len_cur = len(s.split(" "))

if (sen_len_cur < sentence_length):

reduces = sentence_length - sen_len_cur

for reduce in range(reduces):

s += " "

s1[i] = s

for i,s in enumerate(s2):

sen_len_cur = len(s.split(" "))

if (sen_len_cur < sentence_length):

reduces = sentence_length - sen_len_cur

for reduce in range(reduces):

s += " "

s2[i] = s

print "9840个句子填充完毕"

return s1, s2

注意:在处理数据的过程中,要把列表转化成np数组,不然传入placeholder中会一直报错“setting an array element with a sequence”。np数组的转换也很简单,使用np.array()就可以进行转换,但是np数组在插入过程不是很熟练,因此也可以采用先对列表进行操作,在转换为np数组。但一定要注意,多维的列表的每一层都需要转化成np数组,可以在tensorflow的调试过程中慢慢处理。

点击复制链接 与好友分享!回本站首页
上一篇:大数据技术原理与引用—上机实验报告之一
下一篇:基于hadoop2.2.0分布式搭建
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站