其实该论文作者已经将文章代码提供了出来,该代码用的是Theano实现的,但是因为最近看了TensorFlow,所以想着用用练练手,所以本文主要参考Denny Britz的一篇博文 来实现CNN和本篇论文,其代码也上传到了github上。说到Denny Britz,大神就是大神,之前也读过他一篇介绍CNN在NLP领域应用场景和方法的文章,写的很透彻也被很多国内网友翻译和转载,他的博客上有很多好的文章,有事Ian一定要好好读一遍,瞻仰和膜拜一下==
因为刚接触TensorFlow,之前只是安装好跑过一两个例子,对其大致了解了一下,知道了Graph、Tensor、Session等一些基本概念。这里就分析一下大神的代码,自己按着撸一遍,边学习TensorFlow边实现论文仿真。好了,废话不多说,开始看代码。
1,实验数据
实验所用的数据集是Movie Review data from Rotten Tomatoes,即MR电影评论数据,其中包含10662条评论,一半正面评论,一般负面。共包含18758个单词(vocab_size),最长的评论有56个单词(Padding,sequence_len),保存在data目录下的rt-polarity.neg和rt-poliarity.pos文件中。这里我们使用10%作为验证集,剩下的作为训练集。数据预处理部分写在data_helpers.py文件中,其实代码很简单,这里仅对load_data_and_labels函数进行介绍:
def load_data_and_labels(positive_data_file, negative_data_file):
#读取正面、负面评论保存在列表中
positive_examples = list(open(positive_data_file, "r").readlines())
positive_examples = [s.strip() for s in positive_examples]
negative_examples = list(open(negative_data_file, "r").readlines())
negative_examples = [s.strip() for s in negative_examples]
#调用clean_str()函数对评论进行处理,安单词进行分割,保存在x_text列表中
x_text = positive_examples + negative_examples
x_text = [clean_str(sent) for sent in x_text]
#为每个评论添加标签,并保存在y中
positive_labels = [[0, 1] for _ in positive_examples]
negative_labels = [[1, 0] for _ in negative_examples]
y = np.concatenate([positive_labels, negative_labels], 0)
return [x_text, y]
读取完之后还要对样本进行处理以获得vocabulary并将每个样本转化为单词索引列表。这一部分的代码在train.py中实现。代码入下:
#载入实验数据
x_text, y = data_helpers.load_data_and_labels(FLAGS.positive_data_file, FLAGS.negative_data_file)
#获得句子的最大长度,用于padding。这里其值为56
max_document_length = max([len(x.split(" ")) for x in x_text])
#调用tf内部函类VocabularyProcessor,其会读取x_text,按照词语出现顺序构建vocabulary,并给每个单词以索引,然后返回的x是形如[[1,2,3,4...],...,[55,66,777...]]的嵌套列表。内列表代表每个句子,其值是评论中每个词在vocabulary中的索引。所以x是10662*56维
vocab_processor = learn.preprocessing.VocabularyProcessor(max_document_length)
x = np.array(list(vocab_processor.fit_transform(x_text)))
# Randomly shuffle data将数据进行随机打乱
np.random.seed(10)
shuffle_indices = np.random.permutation(np.arange(len(y)))
x_shuffled = x[shuffle_indices]
y_shuffled = y[shuffle_indices]
# Split train/test set构建训练集和验证集
dev_sample_index = -1 * int(FLAGS.dev_sample_percentage * float(len(y)))
x_train, x_dev = x_shuffled[:dev_sample_index], x_shuffled[dev_sample_inde