日常生活中,因为虚拟移动基站或者是因为信息泄漏我们总会收到一些算法看不懂但是人可以看懂的短信。例如赌博/诈骗/套路贷款/等等,在这里我们利用生成式模型基于双向预训练语言模型对这些人能看懂但是分类算法看不懂的模型,进行一次还原操作。
数据集原始形态
每条数据由\t分割,第一个列是id第二列是短信中的文本第三列是人工翻译后的文本。so我们的模型输入是第二列输出是第三列。我们可以做一个实验看一下第二列有多少数据是在rbtl3的词表之外的。我们可以加入词表之外的信息重新训练一个更适应于当前场景的预训练语言模型出来,从而提升整体效果。
首先看一下效果 其中用到了几种验证手段
作者:HiroLin 链接:中文文本摘要指标-ROUGE - 知乎 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.ROUGE-N
对应的N即为连续字个数。例如: 人工y:文章内容新颖 (6个字) 机器x:这篇文章内容是新颖的(10个字) 重叠的部分是6个字 候选句子摘要句子是x,人工摘要句子是y precision 两个句子重叠部分的n-gram/len(x) 6/10 recall 两个句子重叠部分的n-gram/len(y) 6/6 可以看出来机器生成的把人工的全部召回了,但是实际上机器生成的太多。此时精度就是来限制句子的关联程度的。 对应的range-2计算 人工y:文章内容新颖- 文章 章内 内容…… 共5个 机器x:这篇文章内容是新颖的(10个字)- 这篇 篇文 文章 …… 共9个 重叠的部分是5个词 precision 为5/9 recall 为5/5 优点:简洁且有词序 缺点:区分度不高,随着N的增大,值变小如上示例6/10 -> 5/9 2.ROUGE-L 最长公共子序列的重合率计算。 S是人工摘要,C是机器摘要
RLCS 表示召回率,而 PLCS 表示精确率,FLCS 就是 ROUGE-L。一般 beta 会设置为很大的数,因此 FLCS 几乎只考虑了 RLCS (即召回率) 优点:反应句子级别顺序,不需要制定n-gram的长度 缺点:只考虑了最长子序列的长度,忽略了其他子序列 适用于短摘要提取
以上信息来源:
HiroLin:中文文本摘要指标-ROUGE0 赞同 · 0 评论文章正在上传…重新上传取消
bleu
作者:一译 链接:BLEU:一种自动评估机器翻译的方法 - 知乎 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
通常,给定源语句有许多“完美”的翻译。 这些翻译的单词选择可能不同,或者即使它们使用相同的单词但单词顺序也可能不同。 然而,人类可以清楚地区分好的翻译和坏翻译。 例如,考虑这两个对一条中文源语句的候选翻译: 例1 候选翻译1: It is a guide to action which ensures that the military always obeys the commands of the party. 候选翻译2: It is to insure the troops forever hearing the activity guidebook that party direct. 虽然它们似乎是在同一主题上,但它们的质量明显不同。 为了比较,下面我们提供同一语句的三个参考人类翻译。 参考翻译1: It is a guide to action that ensures that the military will forever heed Party commands. 参考翻译2: It is the guiding principle which guarantees the military forces always being under the command of the Party. 参考翻译3: It is the practical guide for the army always to heed the directions of the party. 很明显,好的候选翻译1与这三个参考译文共享许多单词和短语,而候选翻译2则没有。 我们将在第2.1节中简要地量化这种共享概念。 但首先要注意候选翻译1与参考翻译1共享"It is a guide to action",与参考翻译2共享"which",与参考翻译1共享"ensures that the military",与参考翻译2和3共享"always",最后与参考翻译2共享"of the party"(全部忽略大小写)。 相比之下,候选翻译2表现出的匹配要少得多,而且它们的范围较小。 很明显,程序可以简单地通过比较每个候选翻译和参考翻译之间的n-gram匹配来将候选翻译1排名高于候选翻译2。 对第5节中提供的大量翻译的实验表明,这种区分能力是一种普遍现象,而不是人工编造的一些无聊示例。 BLEU实现者的主要编程任务是将候选翻译的n-gram与参考翻译的n-gram进行比较并计算匹配数。 这些匹配与位置无关。 匹配越多,候选翻译就越好。 为简单起见,我们首先关注计算unigram匹配。
以上信息来源
一译:BLEU:一种自动评估机器翻译的方法65 赞同 · 13 评论文章
我们采用的预训练语言模型部分选用的是由哈工大开源的rbtl3模型
github.com/ymcui/Chinese-BERT-wwm
代码是从bert4keras的example中修改而来
github.com/bojone/bert4keras/blob/master/examples/task_seq2seq_autotitle_csl.py
from __future__ import print_function
import numpy as np
from tqdm import tqdm
from bert4keras.backend import keras, K
from bert4keras.layers import Loss
from bert4keras.models import build_transformer_model
from bert4keras.tokenizers import Tokenizer, load_vocab
from bert4keras.optimizers import Adam
from bert4keras.snippets import sequence_padding, open
from bert4keras.snippets import DataGenerator, AutoRegressiveDecoder
from keras.models import Model
from rouge import Rouge # pip install rouge
from nltk.translate.bleu_score import sentence_bleu, SmoothingFunction
# 基本参数
maxlen = 256
batch_size = 16
epochs = 20
# bert配置
config_path = '/home/bert_config_rbt3.json'
checkpoint_path = '/home/bert_model.ckpt'
dict_path = '/home/vocab.txt'
def load_data(filename):
D = []
with open(filename, encoding='utf-8') as f:
for l in f:
id, title, content = l.strip().split('\t')
D.append((title, content))
return D
# 加载数据集
train_data = load_data('/home/train_public.csv')
valid_data = load_data('/home/train_public.csv')[:1000]
test_data = load_data('/home/train_public.csv')[1000:2000]
# 加载并精简词表,建立分词器
token_dict, keep_tokens = load_vocab(
dict_path=dict_path,
simplified=True,
startswith=['[PAD]', '[UNK]', '[CLS]', '[SEP]'],
)
tokenizer = Tokenizer(token_dict, do_lower_case=True)
class data_generator(DataGenerator):
"""数据生成器
"""
def __iter__(self, random=False):
batch_token_ids, batch_segment_ids = [], []
for is_end, (title, content) in self.sample(random):
token_ids, segment_ids = tokenizer.encode(
content, title, maxlen=maxlen
)
batch_token_ids.append(token_ids)
batch_segment_ids.append(segment_ids)
if len(batch_token_ids) == self.batch_size or is_end:
batch_token_ids = sequence_padding(batch_token_ids)
batch_segment_ids = sequence_padding(batch_segment_ids)
yield [batch_token_ids, batch_segment_ids], None
batch_token_ids, batch_segment_ids = [], []
class CrossEntropy(Loss):
"""交叉熵作为loss,并mask掉输入部分
"""
def compute_loss(self, inputs, mask=None):
y_true, y_mask, y_pred = inputs
y_true = y_true[:, 1:] # 目标token_ids
y_mask = y_mask[:, 1:] # segment_ids,刚好指示了要预测的部分
y_pred = y_pred[:, :-1] # 预测序列,错开一位
loss = K.sparse_categorical_crossentropy(y_true, y_pred)
loss = K.sum(loss * y_mask) / K.sum(y_mask)
return loss
model = build_transformer_model(
config_path,
checkpoint_path,
application='unilm',
keep_tokens=keep_tokens, # 只保留keep_tokens中的字,精简原字表
)
output = CrossEntropy(2)(model.inputs + model.outputs)
model = Model(model.inputs, output)
model.compile(optimizer=Adam(1e-5))
model.summary()
class AutoTitle(AutoRegressiveDecoder):
"""seq2seq解码器
"""
@AutoRegressiveDecoder.wraps(default_rtype='probas')
def predict(self, inputs, output_ids, states):
token_ids, segment_ids = inputs
token_ids = np.concatenate([token_ids, output_ids], 1)
segment_ids = np.concatenate([segment_ids, np.ones_like(output_ids)], 1)
return model.predict([token_ids, segment_ids])[:, -1]
def generate(self, text, topk=1):
max_c_len = maxlen - self.maxlen
token_ids, segment_ids = tokenizer.encode(text, maxlen=max_c_len)
output_ids = self.beam_search([token_ids, segment_ids],
topk) # 基于beam search
return tokenizer.decode(output_ids)
autotitle = AutoTitle(start_id=None, end_id=tokenizer._token_end_id, maxlen=32)
class Evaluate(keras.callbacks.Callback):
def __init__(self):
self.rouge = Rouge()
self.smooth = SmoothingFunction().method1
self.best_bleu = 0.
def on_epoch_end(self, epoch, logs=None):
metrics = self.evaluate(valid_data) # 评测模型
if metrics['bleu'] > self.best_bleu:
self.best_bleu = metrics['bleu']
model.save_weights('./gray production management.weights') # 保存模型
metrics['best_bleu'] = self.best_bleu
print('valid_data:', metrics)
def evaluate(self, data, topk=1):
total = 0
rouge_1, rouge_2, rouge_l, bleu = 0, 0, 0, 0
for title, content in tqdm(data):
total += 1
title = ' '.join(title)
pred_title = ' '.join(autotitle.generate(content, topk))
if pred_title.strip():
scores = self.rouge.get_scores(hyps=pred_title, refs=title)
rouge_1 += scores[0]['rouge-1']['f']
rouge_2 += scores[0]['rouge-2']['f']
rouge_l += scores[0]['rouge-l']['f']
bleu += sentence_bleu(
references=[title.split(' ')],
hypothesis=pred_title.split(' '),
smoothing_function=self.smooth
)
rouge_1 /= total
rouge_2 /= total
rouge_l /= total
bleu /= total
return {
'rouge-1': rouge_1,
'rouge-2': rouge_2,
'rouge-l': rouge_l,
'bleu': bleu,
}
if __name__ == '__main__':
evaluator = Evaluate()
train_generator = data_generator(train_data, batch_size)
model.fit_generator(
train_generator.forfit(),
steps_per_epoch=len(train_generator),
epochs=epochs,
callbacks=[evaluator]
)
else:
model.load_weights('./gray production management.weights')
数据来源于
数字安全公开赛
www.datafountain.cn/special/BDC…
快来报名比赛吧。这里我本地保存了数据,如果在比赛结束后还需要进行科研攻关的朋友可以加我的微信获取到这次比赛的数据集,如果有同学需要用到这次比赛的模型可以来找我要模型。模型参数的腾讯云COS下载地址。加载模型不会的同学也可以来找我。
re-1256602214.cos.ap-nanjing.myqcloud.com/gray%20prod…
re-1256602214.cos.ap-nanjing.myqcloud.com/gray%20production%20management.weights
下一步的工作计划,是通过文本相似度算法扩大预训练部分的训练语料。扩大词表。换几种语言模型架构跑一下。看一下各个模型的表现差异。
最后感谢autodl提供的GPU训练机器。AutoDL-品质GPU租用平台-租GPU就上AutoDL。 ———————————————— 版权声明:本文为CSDN博主「路人与大师」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:blog.csdn.net/weixin_4104…