CNN——对文章类型进行分类

引言:最进在搞机器学习,写了几篇东西,这准备用NLP技术,写一个对文章类型分类的模型。

一、搜集训练数据、验证数据和测试数据:
在这里插入图片描述
上面图中,分别是 :

essay.test(测试数据):
在这里插入图片描述

essay.train(训练数据):
在这里插入图片描述

essay.val(验证数据):
在这里插入图片描述
essay.vocab(词表):

在这里插入图片描述
二、训练数据特征提取:

1、定义文件路径

# 主目录
root_path = 'data/essayData/data'
# 训练数据路径
train_path = os.path.join(root_path, 'essay.train.txt')
# 验证数据路径
val_path = os.path.join(root_path, 'essay.val.txt')
# 测试数据路径path
test_path = os.path.join(root_path, 'essay.test.txt')
# 总的词表数据路径
vocab_path = os.path.join(root_path, 'essay.vocab.txt')

2、此次训练的文本一共分为10类(‘体育’, ‘财经’, ‘房产’, ‘家居’, ‘教育’, ‘科技’, ‘时尚’, ‘时政’, ‘游戏’, ‘娱乐’):

def read_labels():
    labels = ['体育', '财经', '房产', '家居', '教育', '科技', '时尚', '时政', '游戏', '娱乐']

    label_to_id = dict(zip(labels, range(len(labels))))

    return  label_to_id

label_to_id = read_labels()  
print(label_to_id)

输出:

{'体育': 0, '财经': 1, '房产': 2, '家居': 3, '教育': 4, '科技': 5, '时尚': 6, '时政': 7, '游戏': 8, '娱乐': 9}

3、把词表(vocab_path = os.path.join(root_path, ‘essay.vocab.txt’))里面每个词都用不同的数字标记,生成序列:

# 总的词表数据路径
vocab_path = os.path.join(root_path, 'essay.vocab.txt')
def read_vocab(vocab_path):
    with open_file(vocab_path) as fp:
        words = [word.strip() for word in fp.readlines()]       # 因为这里用的是 python3,因此不需要对中文进行其他编码
    word_to_id = dict(zip(words, range(len(words))))                      
    return words, word_to_id
words,word_to_id = read_vocab(vocab_path)
print(words)
print(word_to_id)

输出:
词数量太多了这里指 放前面一部分输出数据

['<PAD>', ',', '的', '。', '一', '是', '在', '0', '有', '不', '了', '中', '1', '人',...]
{'<PAD>': 0, ',': 1, '的': 2, '。': 3, '一': 4, '是': 5, '在': 6, '0': 7, '有': 8,...}

这样就有了 word——>id 的映射。

4、对训练样本操作(后面的 验证样本和测试样本也是同样的操作):

#读取文件,并把文本 类型 和 内容分开
def read_file(filename):
    contexts, labels = [], []
    with open_file(filename) as f:
        for line in f:
            label, content = line.strip().split('\t')
            contexts.append(list(content))
            labels.append(label)
    return contexts, labels

# 训练数据路径
train_path = os.path.join(root_path, 'essay.train.txt')
contexts, labels = read_file(train_path)

输出(由于一些数量太多 ,这边输出一些关键信息):

contexts:
[['马','晓','旭'...]
 [...]
 .
 .
 .
]
contexts一共有5000行,每一行是一篇文章的所有词;

labels:
['体育', '体育', '体育', '体育', '体育', '体育', '体育', '体育', '体育', '体育'...]
labels一共有5000行,每一行是一篇文章的类别;
contexts和labels是互相对应的。
# 每个文章提取max_length个词,并且把没个词转成word_to_id里的数值,把每个类别也转成label_to_id里对应的数值
def data_file(word_to_id, label_to_id, max_length,contexts,labels):
    context_id, label_id = [], []
    for i in range(len(contexts)):
        context_id.append([word_to_id[x] for x in contexts[i] if x in word_to_id])
        label_id.append(label_to_id[labels[i]])

    #将文本设为固定长度
    x_txt= kr.preprocessing.sequence.pad_sequences(data_id, max_length)   # 将句子都变成max_length大小的句子,超过max_length的从后边开始数,去除前边的
    y_lbl= kr.utils.to_categorical(label_id, num_classes=len(label_to_id))  # 将标签转换为one-hot表示

    return x_txt, y_lbl
   
x_txt, y_lbl = data_file(word_to_id, label_to_id, max_length,contexts,labels)
x_txt:一共是5000行,每行都是数字,每个数字对应word_to_id里的词; 
y_lbl:一共是5000行,每行有10个数,其中只有一个数字为1,其他都为01所在的那列,代表x_txt对应行文章的类别;

现在,数据特征以及提取完毕。

三、模型的搭建:

# 文本分类,CNN模型
class ContextClassifyByCNN():
    def __init__(self):
        # 三个待输入的数据
        self.seqNum = 600  # self.seqNum 每个文章提取多少个词
        self.classNum = 10 # self.seqNum 总的类别数
        self.embedding_dim = 64 # 每个词的词向量大小
        self.vocab_size = 5000 # 词表里词总个数
        self.num_filters = 256 # 卷积核个数
        self.kernel_size = 5 # 卷积核大小
        self.hidden_dim = 128 # 全连接层神经元数量
        self.input_x = tf.placeholder(tf.int32, [None, self.seqNum], name='input_x')
        self.input_y = tf.placeholder(tf.float32, [None,self.classNum], name='input_y')
        self.k_prob = tf.placeholder(tf.float32, name='k_prob ')#drop比例
        self.cnnFun()

    def cnnFun(self):
        # 词向量映射
        with tf.device('/cpu:0'):
            self.embedding = tf.get_variable('embedding', [self.vocab_size, self.embedding_dim])
            embedding_inputs = tf.nn.embedding_lookup(self.embedding, self.input_x)

        with tf.name_scope("cnn"):
            conv = tf.layers.conv1d(embedding_inputs, self.num_filters, self.kernel_size, name='conv')
            # 池化层
            gmp = tf.reduce_max(conv, reduction_indices=[1], name='gmp')

        with tf.name_scope("score"):
            # 全连接层,后面接dropout以及relu激活
            fc = tf.layers.dense(gmp, self.hidden_dim, name='fc1')
            fc = tf.contrib.layers.dropout(fc, self.k_prob )
            fc = tf.nn.relu(fc)

            # 分类器
            self.logits = tf.layers.dense(fc, self.classNum, name='fc2')
            self.y_pred_cls = tf.argmax(tf.nn.softmax(self.logits), 1)  # 预测类别

        with tf.name_scope("optimize"):
            # 损失函数,交叉熵
            cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.input_y)
            self.loss = tf.reduce_mean(cross_entropy)
            # 优化器
            self.optim = tf.train.AdamOptimizer(learning_rate=0.001).minimize(self.loss)

        with tf.name_scope("accuracy"):
            # 准确率
            correct_pred = tf.equal(tf.argmax(self.input_y, 1), self.y_pred_cls)
            self.acc = tf.reduce_mean(tf.cast(correct_pred, tf.float32))            # tf.cast()将correct_pred 转化成tf.float32类型

四、建立模型和训练模型

    # 载入训练集
    x_txt, y_lbl = data_file(word_to_id, label_to_id, max_length,contexts,labels)

	# 初始化model
	model= ContextClassifyByCNN()   

    # 创建session
    session = tf.Session()
    session.run(tf.global_variables_initializer())
  
	# 配置 Saver
    saver = tf.train.Saver()    
    
    total_batch = 0  # 总批次
    best_acc_val = 0.0  # 最佳验证集准确率
    last_improved = 0  # 记录上一次提升批次
    require_improvement = 1000  # 如果超过1000轮未提升,提前结束训练

    flag = False
    for epoch in range(10000):
        print('Epoch:', epoch + 1)
        batch_train = batch_iter(x_txt, y_lbl, 64)
        for x_batch, y_batch in batch_train:
            feed_dict=feed_dict = {
        		model.input_x: x_batch,
        		model.input_y: y_batch,
        		model.k_prob : 0.5
    		}
            
            if total_batch % 100 == 0:
                # 每多少轮次输出在训练集和验证集上的性能
                feed_dict[model.k_prob ] = 1.0
                loss_train, acc_train = session.run([model.loss, model.acc], feed_dict=feed_dict)
                loss_val, acc_val = evaluate(session, x_val, y_val)  # todo

                if acc_val > best_acc_val:
                    # 保存最好结果
                    best_acc_val = acc_val
                    last_improved = total_batch
                    saver.save(sess=session, save_path=save_path)

            session.run(model.optim, feed_dict=feed_dict)  # 运行优化 真正开始运行,因为是相互依赖,倒着找的
            total_batch += 1

            if total_batch - last_improved > require_improvement or acc_val > 0.98:
                # 验证集正确率长期不提升,提前结束训练
                print("No optimization for a long time, auto-stopping...")
                flag = True
                break  # 跳出循环
                

五、总结
整个文本分类一共分为2个部分:特征数据提取、模型建立和模型训练。还有一点:最终模型ContextClassifyByCNN里面的self.embedding,是训练出来的词表里词的词向量。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值