人工智能A7论坛 >> Tensorflow和深度学习笔记_论坛版 >> 6 CNN 在自然语言处理中的应用 >> 6.3 CNN在文本分类中的应用

6.3.3 Tensorflow实现

1) 代码

这里我们采用多分类的代码。

多分类代码实例:银行投诉文本多分类

https://github.com/jiegzhan/multi-class-text-classification-cnn-rnn

(另有一份二分类代码实例:https://github.com/dennybritz/cnn-text-classification-tf 仅供参考)

 

2) Tensorflow Graph

具体在Tensorflow中实现时,graph如下图

注意,在这个graph中,输入层并没有用两个channel。这一点上和前面阐述的经典结构不同。

 

3) 核心代码:

import numpy as np

import tensorflow as tf

 

class TextCNN(object):

def __init__(self, sequence_length, num_classes, vocab_size, embedding_size, filter_sizes, num_filters, l2_reg_lambda=0.0):

# Placeholders for input, output and dropout

self.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')

 

# Keeping track of l2 regularization loss (optional)

l2_loss = tf.constant(0.0)

 

# Embedding layer

        # 由于word embedding不能支持在GPU上训练,所以需要限定word embeddingCPU上计算

with tf.device('/cpu:0'), tf.name_scope('embedding'):

            # 通过trainable属性,可以控制embedding层的权值在初始化以后,是否能够在训练过程中改变,默认值是True。这个属性在使用预训练好的词向量时很有用

#self.W = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0), name='W', trainable="False")

self.W = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0), name='W')

self.embedded_chars = tf.nn.embedding_lookup(self.W, self.input_x)

self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

 

# Create a convolution + maxpool layer for each filter size

pooled_outputs = []

for i, filter_size in enumerate(filter_sizes):

with tf.name_scope('conv-maxpool-%s' % filter_size):

# Convolution Layer

filter_shape = [filter_size, embedding_size, 1, num_filters]

W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name='W')

b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name='b')

                # 卷积的strides padding 两个属性在CNN概念部分已经讲了

conv = tf.nn.conv2d(

self.embedded_chars_expanded,

W,

strides=[1, 1, 1, 1],

padding='VALID',

name='conv')

 

# Apply nonlinearity

h = tf.nn.relu(tf.nn.bias_add(conv, b), name='relu')

 

# Maxpooling 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)

 

# Combine all the pooled features

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])

 

# Add dropout

with tf.name_scope('dropout'):

self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob)

 

# Final (unnormalized) scores and predictions

with tf.name_scope('output'):

W = tf.get_variable(

'W',

shape=[num_filters_total, 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.predictions = tf.argmax(self.scores, 1, name='predictions')

 

# Calculate mean cross-entropy loss

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

 

# Accuracy

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')

 

with tf.name_scope('num_correct'):

correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, 1))

self.num_correct = tf.reduce_sum(tf.cast(correct_predictions, 'float'), name='num_correct')

 

代码中提到了一种参数初始化方式:xavier_initializer。参数初始化的详细过程参考附录10.6 “参数初始化”。Tensorflow默认的初始化方式tf.global_variables_initializer的分析见本笔记3.2.2