利用卷积神经网络(cnn)实现文本分类.docx
利 卷 积 神 经 络 ( cnn) 实 现 本 分 类 卷 积 神 经 络 在 情 感 分 析 中 取 得 了 很 好 的 成 果 , 相 于 之 前 浅 层 的 机 器 学 习 法 如 NB、 SVM效 果 更 好 , 特 别 实 在 数 据 集 较 的 情 况 下 , 并且 CNN不 我 们 动 去 提 取 特 征 , 原 浅 层 ML是 需 要 进 本 特 征 提 取 、 本 特 征 表 、 归 化 、 最 后 进 本 分 类 , 本 特 征 提 取 主 要 可以 分 为 四 步 : ( 1) : 对 全 部 训 练 档 进 分 词 , 由 这 些 词 作 为 向 量 的 维 数 来 表 本 ;( 2) : 统 计 每 类 档 中 所 有 出 现 的 词 语 及 其 频 率 , 然 后 过 滤 , 剔 除 停 词 和 单 字 词 ;( 3) : 统 计 每 类 内 出 现 词 语 的 总 词 频 , 并 取 若 个 频 率 更 的 词 汇 作 为 这 类 的 特 征 词 集 ;( 4) : 去 除 每 类 别 中 都出 现 的 词 , 合并 所 有 类 别 的 特 征 词 集 , 形成 总 特 征 词 集 , 最 后 得 到的 特 征 词 集 是 我 们 到的 特 征 集 合, 再 该集 合去 筛选测试集 中 的 特 征 。 本 的 特 征 表 是 利 TF-IDF公式来 计 算词 的 权值, 这 也充分 利 的 是 特 征 提 取 时提 取 的 特 征 来 计 算特 征 权值 的 , 归 化 处理需 要 处理的 数 据 , 经 过 处理后 限制在 定范围内 , 经 过 处理后 , 我 们 原 来 的 本 信息已经 抽象成 个 向 量 化 的 样本 集 , 然 后 将样本集 和 训 练 好 的 模板进 相 似度计 算, 若 属于 该类 别 , 则与其 他类 别 的 模板 件进 计 算, 直到分 进 相 应的 类 别 , 这 是 浅 层 ML进 本 分 类的 式 ;CNN进 本 分 类 相 对 简单 些 , 我 结合最 近做的 些 实 验总 结了 下 : 在 利 CNN进 本 分 类 的 时候, 先要 将原 始 本 进 预处理, 主 要 还是 分 词 、 去 除 停 词 等, 然 后 对 预处理后 的 本 进 向 量 化 利 word2vec, 我 利 的 时word2vec中 的 skip-gram模型, 将搜狗数 据 集 表 为 了 200维 的 词 向 量 形式;转化 为 词 向 量 后 就可 以 将每 句话转化 为 个 矩阵的 形式, 这 样就跟利 CNN处理图像分 类 很 相 似;说 下 实 验, 我 的 实 验环境:# encoding=utf-from future import unicode_literalsimport tensorflow as tf import numpyas npclass TextCNN(object):"""使 CNN 于 情 感 分 析 整个 CNN架构包括词 嵌层 , 卷 积 层 ,max-pooling层 和 softmax层"""def init (self, sequence_length, num_classes,vocab_size,embedding_size, embedding_table, filter_sizes, num_filters, l2_reg_lambda=0.0):# 输, 输出 , dropout的 placeholderself.input_x= tf.placeholder(tf.int32, None, sequence_length, name="input_x")self.input_y= tf.placeholder(tf.float32, None, num_classes, name="input_y") self.dropout_keep_prob = tf.placeholder(tf.float32, name="dropout_keep_prob")#eeping track of l2 regularization loss (optional) l2_loss = tf.constant(0.0)# 词 嵌层with tf.device('/cpu:0'), tf.name_scope("embedding"):W = tf.Variable(embedding_table,name="W")#embedding_table就是 词 向 量 表 , W还有 另 种简单 的 表 达#W=tf.Variable(vocab_size,embedding_size,-1.0,1.0),随机 初始化 这 个 词 向 量 表 ;self.embedded_chars = tf.nn.embedding_lookup(W, self.input_x)#这 个 tf.nn.embedding_lookup()的 作 就是 从词 向 量 表 中 去 找input_x所 对 应的 词 向 量 ;self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)tensorflow1.2、 gpu1050Ti、 Ubuntu16.04、 pycharm、 python2.7#由 于 CNN输 都 是 四 维 , 所 以 在 最 后 维 添 加 个 维 度 , 与 CNN的 输 维 度 对 照 起 来 。 # 成 卷 积 层 和max-pooling层pooled_outputs = for i, filter_size in enumerate(filter_sizes):with tf.name_scope("conv-maxpool-%s" % filter_size): # Convolution Layerfilter_shape = filter_size, embedding_size, 1, num_filtersW = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W") b = tf.Variable(tf.constant(0.1, shape=num_filters), name="b")conv = tf.nn.conv2d( self.embedded_chars_expanded, W,strides=1, 1, 1, 1, padding="VALID", name="conv")# Applynonlinearity# h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu") h=tf.nn.relu6(tf.nn.bias_add(conv,b),name="relu")#axpooling over the outputs # pooled = tf.nn.max_pool(#h,#ksize=1, sequence_length - filter_size + 1, 1, 1,#strides=1, 1, 1, 1, #padding='VALID', #name="pool")# pooled_outputs.append(pooled) pooled = tf.nn.avg_pool(h,ksize=1, sequence_length - filter_size + 1, 1, 1,strides=1, 1, 1, 1, padding='VALID', name="pool")pooled_outputs.append(pooled)# 将 max-pooling层 的 各 种 特 征 整 合 在 起 num_filters_total = num_filters * len(filter_sizes)self.h_pool = tf.concat(pooled_outputs,3)self.h_pool_flat = tf.reshape(self.h_pool, -1, num_filters_total)# 添 加 全 连 接 层 , 于 分 类with tf.name_scope("full-connection"):W_fc1 = tf.Variable(tf.truncated_normal(num_filters_total,500, stddev=0.1) b_fc1 = tf.Variable(tf.constant(0.1,shape=500)self.h_fc1 = tf.nn.relu6(tf.matmul(self.h_pool_flat, W_fc1) + b_fc1)# 添 加 dropout层 于 缓和 过拟化with tf.name_scope("dropout"):# self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob) self.h_drop = tf.nn.dropout(self.h_fc1, self.dropout_keep_prob)# 产 最 后 的 输 出和 预测with tf.name_scope("output"):# W = tf.get_variable( #"W",#shape=num_filters_total, num_classes,#initializer=tf.contrib.layers.xavier_initializer() W = tf.get_variable("W",shape=500, num_classes, initializer=tf.contrib.layers.xavier_initializer()b = tf.Variable(tf.constant(0.1, shape=num_classes), name="b") l2_loss += tf.nn.l2_loss(W)l2_loss += tf.nn.l2_loss(b)self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores")self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores")self.predictions = tf.argmax(self.scores, 1, name="predictions")定 义 模 型 的 损 失 函 数 with tf.name_scope("loss"):losses = tf.nn.softmax_cross_entropy_with_logits(logits=self.scores, labels=self.input_y) self.loss = tf.reduce_mean(losses) + l2_reg_lambda * l2_loss定 义 模 型 的 准 确 率 with tf.name_scope("accuracy"):correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, 1) self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, "float"), name="accuracy")以 上 时 TextCNN的 模 型 结 构 代 码 , 然 后 开 始 进 train, 并 利summary和checkpoints来记录模 型 和训练时 的 参数 等等, 利折交叉验证来产准 确 率 , 最后 利tensorboard查看accuracy、loss、w、b等等变化图;训练py的 代 码 :/usr/bin/env python encoding=utf-8import tensorflow as tf import numpy as np import osimport time import datetimeimport data_loaderfrom cnn_graph import TextCNN from tensorflow.contrib import learn from sklearn import cross_validation import preprocessingtf.global_variables伴随tensorflow的 summary和checkout=odelyperparameterstf.flags.DEFINE_integer("embedding_dim", 200, "Dimensionality of character embedding (default: 128)") tf.flags.DEFINE_string("filter_sizes", "3,4,5", "Comma-separated filter sizes (default: '3,4,5')") tf.flags.DEFINE_integer("num_filters", 40, "Number of filters per filter size (default: 128)") tf.flags.DEFINE_float("dropout_keep_prob", 0.5, "Dropout keep probability (default: 0.5)") tf.flags.DEFINE_float("l2_reg_lambda", 3.0, "L2 regularizaion lambda (default: 0.0)")Training parameterstf.flags.DEFINE_integer("batch_size", 50, "Batch Size (default: 64)") tf.flags.DEFINE_integer("num_epochs", 100, "Number of training epochs (default: 200)")tf.flags.DEFINE_integer("evaluate_every", 100, "Evaluate model on dev set after this many steps (default: 100)") tf.flags.DEFINE_integer("checkpoint_every", 100, "Save model after this many steps (default: 100)")isc Parameterstf.flags.DEFINE_boolean("allow_soft_placement", True, "Allow device soft device placement") tf.flags.DEFINE_boolean("log_device_placement", False, "Log placement of ops on devices")w2v件路径tf.flags.DEFINE_string("w2v_path", "./w2v_model/retrain_vectors_100.bin", "w2v file") tf.flags.DEFINE_string("file_dir","./data_process/jd","train/test dataSet")FLAGS = tf.flags.FLAGS FLAGS._parse_flags() print("nParameters:")for attr, value in sorted(FLAGS. flags.items(): print("=".format(attr.upper(), value)print("")Data Preparatopn=Load dataLoad data print("Loading data.")files = "reviews.neg","reviews.pos"加 载 所 有 的 未 切 分 的 数 据 x_text, y_labels,neg_examples,pos_examples = data_loader.load_data_and_labels(data_dir=FLAGS.file_dir,files=files,splitable=False)获 取 消 极 数 据 的2得 ,到 的 评 论 的 长 度 离 散 度 更 低 neg_accept_length = preprocessing.freq_factor(neg_examples,percentage=0.8, drawable=False) neg_accept_length = item0 for item in neg_accept_lengthneg_examples = data_loader.load_data_by_length(neg_examples,neg_accept_length)获 取 积 极 数 据 的2得 ,到 的 评 论 的 长 度 离 散 度 更 低 pos_accept_length = preprocessing.freq_factor(pos_examples,percentage=0.8, drawable=False) pos_accept_length = item0 for item in pos_accept_lengthpos_examples = data_loader.load_data_by_length(pos_examples,pos_accept_length)x_text = neg_examples + pos_examples neg_labels = 1,0 for _ in neg_examples pos_labels = 0,1 for _ in pos_examplesy_labels = np.concatenate(neg_labels,pos_labels, axis=0) print("Loading data finish")uild vocabularymax_document_length = max(len(x.split(" ") for x in x_text)最 长 的 句 的 长 度 print(max_document_length)vocab_processor = learn.preprocessing.VocabularyProcessor(max_document_length) x = np.array(list(vocab_processor.fit_transform(x_text)加 载 提前训练的w2v数 据 集word_vecs = data_loader.load_bin_vec(fname=FLAGS.w2v_path, vocab=list(vocab_processor.vocabulary_._mapping),ksize=FLAGS.embedding_dim)加 载 嵌层的tableW = data_loader.get_W(word_vecs=word_vecs, vocab_ids_map=vocab_processor.vocabulary_._mapping, k=FLAGS.embedding_dim,is_rand=False)随机化数 据 np.random.seed(10)shuffle_indices = np.random.permutation(np.arange(len(y_labels) x_shuffled = xshuffle_indicesy_shuffled = y_labelsshuffle_indicesout_path = os.path.abspath(os.path.join(os.path.curdir, "runs","parameters") parameters = "新全连接+jd数 据 +10n" "embedding_dim: ,n" "filter_sizes:,n" "num_filters:,n" "dropout_keep_prob:,n" "l2_reg_lambda:,n" "num_epochs:,n" "batch_size:".format(FLAGS.embedding_dim,FLAGS.filter_sizes,FLAGS.num_filters, FLAGS.dropout_keep_prob,FLAGS.l2_reg_lambda,FLAGS.num_epochs, FLAGS.batch_size)open(out_path, 'w').write(parameters)raining=def train(X_train, X_dev, x_test, y_train, y_dev, y_test): with tf.Graph().as_default():session_conf = tf.ConfigProto( allow_soft_placement=FLAGS.allow_soft_placement, log_device_placement=FLAGS.log_device_placement) sess = tf.Session(config=session_conf)log_device_placement=FLAGS.log_device_placement) sess = tf.Session(config=session_conf)with sess.as_default(): cnn = TextCNN(sequence_length=max_document_length, num_classes=2, vocab_size=len(vocab_processor.vocabulary_), embedding_size=FLAGS.embedding_dim, embedding_table=W,filter_sizes=list(map(int, FLAGS.filter_sizes.split(","), num_filters=FLAGS.num_filters, l2_reg_lambda=FLAGS.l2_reg_lambda)efine Training procedureglobal_step = tf.Variable(0, name="global_step", trainable=False) optimizer = tf.train.AdamOptimizer(1e-3)grads_and_vars = pute_gradients(cnn.loss)train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)eep track of gradient values and sparsity (optional) grad_summaries = for g, v in grads_and_vars: if g is not None:grad_hist_summary = tf.summary.histogram("/grad/hist".format(v.name), g) sparsity_summary = tf.summary.scalar("/grad/sparsity".format(v.name), tf.nn.zero_fraction(g) grad_summaries.append(grad_hist_summary)grad_summaries.append(sparsity_summary) grad_summaries_merged = tf.summary.merge(grad_summaries)Output directory for models and summaries timestamp = str(int(time.time()out_dir = os.path.abspath(os.path.join(os.path.curdir, "runs", timestamp) print("Writing to n".format(out_dir)Summaries for loss and accuracy loss_summary = tf.summary.scalar("loss", cnn.loss)acc_summary = tf.summary.scalar("accuracy", cnn.accuracy)Train Summariestrain_summary_op = tf.summary.merge(loss_summary, acc_summary, grad_summaries_merged) train_summary_dir = os.path.join(out_dir, "summaries", "train")train_summary_writer = tf.summary.FileWriter(train_summary_dir, sess.graph)ev summariesdev_summary_op = tf.summary.merge(loss_summary, acc_summary) dev_summary_dir = os.path.join(out_dir, "summaries", "dev") dev_summary_writer = tf.summary.FileWriter(dev_summary_dir, sess.graph)Checkpoint directory. Tensorflow assumes this directory already exists so we need to create it checkpoint_dir = os.path.abspath(os.path.join(out_dir, "checkpoints")checkpoint_prefix = os.path.join(checkpoint_dir, "model") if not os.path.exists(checkpoint_dir):os.makedirs(checkpoint_dir)saver = tf.train.Saver(tf.global_variables()Write vocabulary vocab_processor.save(os.path.join(out_dir, "vocab")nitialize all variables sess.run(tf.initialize_all_variables()sess.run(tf.global_variables_initializer()def train_step(x_batch, y_batch): """A single training step """"""feed_dict = cnn.input_x: x_batch, cnn.input_y: y_batch,cnn.dropout_keep_prob: FLAGS.dropout_keep_prob_, step, summaries, loss, accuracy = sess.run(train_op, global_step, train_summary_op, cnn.loss, cnn.accuracy, feed_dict)_, step, loss, accuracy = sess.run(train_op, global_step, cnn.loss, cnn.accuracy, feed_dict)time_str = datetime.datetime.now().isoformat()print(": step , loss :g, acc :g".format(time_str, step, loss, accuracy) train_summary_writer.add_summary(summaries, step)def dev_step(x_batch, y_batch, writer=None): """Evaluates model on a dev set """feed_dict = cnn.input_x: x_batch, cnn.input_y: y_batch,cnn.dropout_keep_prob: 1.0step, summaries, loss, accuracy = sess.run(global_step, dev_summary_op, cnn.loss, cnn.accuracy, feed_dict)step, loss, accuracy = sess.run( global_step, cnn.loss, cnn.accuracy, feed_dict)time_str = datetime.datetime.now().isoformat()print(": step , loss :g, acc :g".format(time_str, step, loss, accuracy) if writer:writer.add_summary(summaries, step)Generate batchesbatches = data_loader.batch_iter(list(zip(X_train, y_train), FLAGS.batch_size, FLAGS.num_epochs) raining loop. For each batch.for batch in batches:x_batch, y_batch = zip(*batch) train_step(x_batch, y_batch)current_step = tf.train.global_step(sess, global_step) if current_step % FLAGS.evaluate_every = 0:print("nEvaluation:")dev_step(X_dev, y_dev, writer=dev_summary_writer) dev_step(X_dev, y_dev, writer=None)print("")if current_step % FLAGS.checkpoint_every = 0:path = saver.save(sess, checkpoint_prefix, global_step=current_step) print("Saved model checkpoint to n".format(path)est loopGenerate batches for one epochbatches = data_loader.batch_iter(list(x_test), FLAGS.batch_size, 1, shuffle=False) ollect the predictions hereall_predictions = for x_test_batch in batches:batch_predictions = sess.run(cnn.predictions, cnn.input_x: x_test_batch, cnn.dropout_keep_prob:1.0) all_predictions = np.concatenate(all_predictions, batch_predictions)correct_predictions = float(sum(all_predictions = np.argmax(y_test,axis=1)all_predictions = np.argmax(y_test,axis=1)print("Total number of test examples: ".format(len(y_test) print("Accuracy: :g".format(correct_predictions / float(len(y_test)open(os.path.join(out_dir,"test"),'a').write("Accuracy: :g".format(correct_predictions / float(len(y_test) out_path = os.path.abspath(os.path.join(os.path.curdir, "runs","test") open(out_path,'a').write(":g,".forma