Keras文本处理


Keras文本处理

任务

1.只用带标签的数据和标签 不要关键字 用LSTM分一次类 tokennizer

2.Word2vec

3.用标签 + 关键字 用1、2准确度高的方法做 cnn lstm双输入,智能合约放lstm,关键字放CNN

4.把dataset没有标签的分配标签和关键字,重复上面三个

5.选出文件最大的前几个,执行4

结果: 召回率 准确率 F1 迭代次数 2或5代

Word2Vec

Tokenizer

[Keras中文文档——关于文本预处理](https://keras-cn.readthedocs.io/en/latest/preprocessing/text/#_1 ↩︎)

Tokenizer是一个用于向量化文本,或将文本转换为序列(即单个字词以及对应下标构成的列表,从1算起)的类。是用来文本预处理的第一步:分词。结合简单形象的例子会更加好理解些。

1.语法

官方语法如下:

1
2
3
4
5
keras.preprocessing.text.Tokenizer(num_words=None,
filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~\t\n',
lower=True,
split=" ",
char_level=False)

1.1 构造参数

  • num_words: 默认是None,处理所有字词。
            但是如果设置成**一个整数**,那么最后返回的是最常见的、出现**频率最高的num_words个字词**。
    
  • filters:过滤一些特殊字符,默认上文的写法就可以了。
  • lower:全部转为小写
  • split:字符串,单词的分隔符,如空格
  • char_level: 如果为 True, 每个字符将被视为一个标记

1.2 返回值

字符串列表

1.3 类方法

下面是相关的类方法,部分示例在下一节中均有描述应用。

方法 参数 返回值 备注
fit_on_texts(texts) texts:要用以训练的文本列表
texts_to_sequences(texts) texts:待转为序列的文本列表 序列的列表,列表中每个序列对应于一段输入文本
texts_to_sequences_generator(texts) texts:待转为序列的文本列表 每次调用返回对应于一段输入文本的序列 本函数是texts_to_sequences的生成器函数版
texts_to_matrix(texts, mode) texts:待向量化的文本列表 mode:‘binary’,‘count’,‘tfidf’,‘freq’之一,默认为‘binary’ 形如(len(texts), nb_words)的numpy array
fit_on_sequences(sequences) sequences:要用以训练的序列列表
sequences_to_matrix(sequences) sequences:待向量化的序列列表 mode:‘binary’,‘count’,‘tfidf’,‘freq’之一,默认为‘binary’ 形如(len(sequences), nb_words)的numpy array

1.4 属性

  • word_counts:字典,将单词(字符串)映射为它们在训练期间出现的次数。仅在调用fit_on_texts之后设置。
  • word_docs: 字典,将单词(字符串)映射为它们在训练期间所出现的文档或文本的数量。仅在调用fit_on_texts之后设置。
  • word_index: 字典,将单词(字符串)映射为它们的排名或者索引。仅在调用fit_on_texts之后设置。
  • document_count: 整数。分词器被训练的文档(文本或者序列)数量。仅在调用fit_on_texts或fit_on_sequences之后设置。

2.简单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
>>>from keras.preprocessing.text import Tokenizer
Using TensorFlow backend.

# 创建分词器 Tokenizer 对象
>>>tokenizer = Tokenizer()

# text
>>>text = ["今天 北京 下 雨 了", "我 今天 加班"]

# fit_on_texts 方法, 将要训练的文本传入
>>>tokenizer.fit_on_texts(text)

# word_counts属性,将单词(字符串)映射为它们在训练期间出现的次数。仅在调用fit_on_texts之后设置。
>>>tokenizer.word_counts
OrderedDict([('今天', 2),
('北京', 1),
('下', 1),
('雨', 1),
('了', 2),
('我', 1),
('加班', 1)])

# word_docs属性,将单词(字符串)映射为它们在训练期间所出现的文档或文本的数量。仅在调用fit_on_texts之后设置。
>>>tokenizer.word_docs
defaultdict(int, {'下': 1, '北京': 1, '今天': 2, '雨': 1, '了': 2, '我': 1, '加班': 1})

# word_index属性,将单词(字符串)映射为它们的排名或者索引。仅在调用fit_on_texts之后设置。
>>>tokenizer.word_index
{'今天': 1, '了': 2, '北京': 3, '下': 4, '雨': 5, '我': 6, '加班': 7}

# document_count属性
>>>tokenizer.document_count
2

3.常用示例

还以上面的tokenizer对象为基础,经常会使用texts_to_sequences()方法 和 序列预处理方法 keras.preprocessing.sequence.pad_sequences一起使用。

Code.3.1 常用示例

1
2
3
4
5
>>>tokenizer.texts_to_sequences(["下 雨 我 加班"])
[[4, 5, 6, 7]]

>>>keras.preprocessing.sequence.pad_sequences(tokenizer.texts_to_sequences(["下 雨 我 加班"]), maxlen=20)
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7]],dtype=int32)

有关pad_sequences用法见python函数——序列预处理pad_sequences()序列填充

序列预处理pad_sequences()序列填充

为了实现的简便,keras只能接受长度相同的序列输入。因此如果目前序列长度参差不齐,这时需要使用pad_sequences()。该函数是将序列转化为经过填充以后的一个长度相同的新序列

语法

1
2
3
4
5
6
keras.preprocessing.sequence.pad_sequences(sequences, 
maxlen=None,
dtype='int32',
padding='pre',
truncating='pre',
value=0.)

参数

  • sequences:浮点数或整数构成的两层嵌套列表
  • maxlen:None或整数,为序列的最大长度。大于此长度的序列将被截短,小于此长度的序列将在后部填0.
  • dtype:返回的numpy array的数据类型
  • padding:‘pre’或‘post’,确定当需要补0时,在序列的起始还是结尾补`
  • truncating:‘pre’或‘post’,确定当需要截断序列时,从起始还是结尾截断
  • value:浮点数,此值将在填充时代替默认的填充值0

返回值

返回的是个2维张量,长度为maxlen

实例

1
2
3
4
5
6
7
>>>list_1 = [[2,3,4]]
>>>keras.preprocessing.sequence.pad_sequences(list_1, maxlen=10)
array([[0, 0, 0, 0, 0, 0, 0, 2, 3, 4]], dtype=int32)

>>>list_2 = [[1,2,3,4,5]]
>>>keras.preprocessing.sequence.pad_sequences(list_2, maxlen=10)
array([[0, 0, 0, 0, 0, 1, 2, 3, 4, 5]], dtype=int32)

过程总结:

1. 下载数据集(或者从文件中加载),读取到一个变量/数组中
2. 使用Tokenizer,将数组fit进去,生成一个字典
3. 再使用token.texts_to_sequences,将数据放进去生成序列(数字列表)
4. 然后可以使用pad_sequences对生成的序列进行长度控制,让他们长度一致
5. 建立模型,模型中第一个是Embedding词嵌入层,将数字列表转换为向量
6. 然后中间就开始搭建神经网络,训练,评测即可。

具体:

Tokenizer函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# tokennizer
def get_data():
all = train_x
tokenizer = Tokenizer(num_words=80000) # 分词MAX_NB_WORDS

tokenizer.fit_on_texts(train_x) # 将数据放入

sequences_context = tokenizer.texts_to_sequences(train_x) # 受num_words影响

# 词语数据,截取长度
data_context = sequence.pad_sequences(sequences_context, maxlen=500) # 将长度不足 100 的新闻用 0 填充(在前端填充)

# 标签,改为one-hot
labels = utils.to_categorical(np.asarray(label_y)) # 最后将标签处理成 one-hot 向量,比如 6 变成了 [0,0,0,0,0,0,1,0,0,0,0,0,0],
labels_test = utils.to_categorical(np.asarray(label_y))

print('Shape of data tensor:', data_context.shape)
print('Shape of label tensor:', labels.shape)
return data_context, labels
# 不用feature

这时候就将文本转换为数字列表了。因为神经网络里面只能输入数字。

搭建模型,训练数据

划分为训练集和测试集

1
2
3
4
5
6
7
8
# 训练模型,并保存
def train():
# 通过tokenizer取得数据,标签
data_context, labels = data_vector.get_data()
# 划分训练和测试集
x_train, x_test, y_train, y_test = train_test_split(data_context, labels, test_size=0.2)
# 这里搭建好模型就直接一起训练了
train_lstm(x_train, y_train, x_test, y_test)

搭建模型和训练的代码放一个函数里了:

搭建模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14

##定义网络结构
def train_lstm(x_train, y_train, x_test, y_test):
print('train')
model = Sequential() # or Graph or whatever
model.add(Embedding(output_dim=vocab_dim,
input_dim=input_dim,
mask_zero=True,
input_length=input_length)) # Adding Input Length
model.add(LSTM(units=50))
model.add(Dropout(0.5))
model.add(Dense(16))
model.add(Activation('softmax'))

训练模型

1
2
3
4
5
6
7
8
9
10
11
12
13
metrics = Metrics()

model.compile(loss='binary_crossentropy',
optimizer='adam', metrics=['accuracy'])

model.fit(x_train, y_train,
batch_size=batch_size,
epochs=n_epoch,
validation_data=(x_test, y_test),
callbacks=[metrics])
score, acc = model.evaluate(x_test, y_test, batch_size=batch_size)
print('Test score:', score)
print('Test accuracy:', acc)

存储模型

1
2
3
4
yaml_string = model.to_yaml()
with open('lstm.yml', 'w') as outfile:
outfile.write(yaml.dump(yaml_string, default_flow_style=True))
model.save_weights('lstm.h5')

其中Metrics是一个回调类,用来输出f1,召回率,准确率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Metrics(Callback):
def on_train_begin(self, logs={}):
self.val_f1s = []
self.val_recalls = []
self.val_precisions = []

def on_epoch_end(self, epoch, logs={}):
val_predict = (np.asarray(self.model.predict(self.validation_data[0]))).round() ##.model
val_targ = self.validation_data[1] ###.model
_val_f1 = f1_score(val_targ, val_predict, average='micro')
_val_recall = recall_score(val_targ, val_predict, average='micro') ###
_val_precision = precision_score(val_targ, val_predict, average='micro') ###
self.val_f1s.append(_val_f1)
self.val_recalls.append(_val_recall)
self.val_precisions.append(_val_precision)
print('_val_f1: ', _val_f1)
print('_val_recall: ', _val_recall)
print('_val_precision: ', _val_precision)
fls.append(_val_f1)
rec.append(_val_recall)
pre.append(_val_precision)
# print("— val_f1: %f — val_precision: %f — val_recall: %f" %(_val_f1, _val_precision, _val_recall))
return

文章作者: SongX64
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SongX64 !
  目录