书接上回
上回说到 RNN 和 CNN 在文本分类上存在的区别和联系Tensorflow使用Char-CNN实现中文文本分类(1),并准备使用 CNN 的方式进行中文文本分类。在这里把代码给补一下。
代码如下
代码还在是之前Tensorflow使用LSTM实现中文文本分类(2)的代码中进行修改,其中关于CNN的内容写的比较简单,只使用了一个卷积层进行卷积操作,后接全连接层,其他代码还是使用以前的。
# -*- coding:utf-8 -*-
# 构建计算图-lstm
# embeding
# lstm
# fc
# train_op
# 训练流程代码
# 数据集的封装
# api: next_batch(batch_size): 输出的都是 id
# 词表封装
# api:sentence2id(text_sentence):将句子转化为id
# 类别的封装:
# api:category2id(text_category): 将类别转化为id
import tensorflow as tf
import os
import sys
import numpy as np
import math
# 打印出 log
tf.logging.set_verbosity(tf.logging.INFO)
# lstm 需要的参数
def get_default_params():
return tf.contrib.training.HParams(
num_embedding_size = 16, # 每个词语的向量的长度
# 指定 lstm 的 步长, 一个sentence中会有多少个词语
# 因为执行的过程中是用的minibatch,每个batch之间还是需要对齐的
# 在测试时,可以是一个变长的
num_timesteps = 50, # 在一个sentence中 有 50 个词语
num_filters = 128,
num_kernel_size = 3,
num_fc_nodes = 32, # 全连接的节点数
batch_size = 100,
learning_rate = 0.001,
num_word_threshold = 10, # 词频太少的词,对于模型训练是没有帮助的,因此设置一个门限
)
hps = get_default_params() # 生成 参数 对象
# 设置文件路径
train_file = './news_data/cnews.train.seg.txt'
val_file = './news_data/cnews.val.seg.txt'
test_file = './news_data/cnews.test.seg.txt'
vocab_file = './news_data/cnews.vocab.txt' # 统计的词频
category_file = './news_data/cnews.category.txt' # 标签
output_folder = './news_data/run_text_rnn'
if not os.path.exists(output_folder):
os.mkdir(output_folder)
class Vocab:
'''
词表的封装
'''
def __init__(self, filename, num_word_threahold):
# 每一个词,给她一个id,另外还要统计词频。ps:前面带下划线的为私有成员
self._word_to_id = {
}
self._unk = -1 # 先给 unk 赋值一个 负值,然后根据实际情况在赋值
self._num_word_theshold = num_word_threahold # 低于 这个值 就忽略掉该词
self._read_dict(filename) # 读词表方法
def _read_dict(self, filename):
'''
读这个词表
:param filename: 路径
:return: none
'''
with open(filename, 'r') as f:
lines = f.readlines()
for line in lines:
word, frequency = line.strip('\n').split('\t')
word = word # 获得 单词
frequency = int(frequency) # 获得 频率
if frequency < self._num_word_theshold:
continue # 门限过滤一下
idx = len(self._word_to_id) #这里使用了一个id递增的小技巧
if word == '<UNK>': # 如果是空格,就把上一个id号给它
# 如果是 unk的话, 就特殊处理一下
self._unk = idx
self._word_to_id[word] = idx
# 如果 word 存在,就把 idx 当做值,将其绑定到一起
# 如果 word 在词表中不存在,就把nuk的值赋予它
def word_to_id(self, word):
'''
为单词分配id值
:param word: 单词
:return:
'''
# 字典.get() 如果有值,返回值;无值,返回默认值(就是第二个参数)
return self._word_to_id.get(word, self._unk)
def sentence_to_id(self, sentence):
'''
将句子 转换成 id 向量
:param sentence: 要输入的句子(分词后的句子)
:return:
'''
# 单条句子的id vector
word_ids = [self.word_