栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

贪心搜索抽取关键句,文本摘要生成

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

贪心搜索抽取关键句,文本摘要生成

1、文本给出通过贪心搜索的方式搜索源文本中关键句方法

nums指定抽取数目

import re
from datasets import load_dataset
from tqdm import tqdm

def load_data(filename,data_name):
    if data_name=="NLPCC2017":
        dataset = load_dataset('json', data_files=[
            filename
        ], field='data')
        title=dataset["train"].data["title"]
        content = dataset["train"].data["content"]

        D = []
        for idx,(t,c) in tqdm(enumerate(zip(title,content)),desc="读取中..."):
            D.append((str(c).replace(" ",""), str(t).replace(" ","")))
    else:
        return None
    return D
def _get_ngrams(n, text):
    """Calcualtes n-grams.

    Args:
      n: which n-grams to calculate
      text: An array of tokens

    Returns:
      A set of n-grams
    """
    ngram_set = set()
    text_length = len(text)
    max_index_ngram_start = text_length - n
    for i in range(max_index_ngram_start + 1):
        ngram_set.add(tuple(text[i:i + n]))
    return ngram_set
def _get_word_ngrams(n, sentences):
    """Calculates word n-grams for multiple sentences.
    """
    assert len(sentences) > 0
    assert n > 0

    # words = _split_into_words(sentences)

    words = sum(sentences, [])
    # words = [w for w in words if w not in stopwords]
    return _get_ngrams(n, words)
def cal_rouge(evaluated_ngrams, reference_ngrams):
    reference_count = len(reference_ngrams)
    evaluated_count = len(evaluated_ngrams)

    overlapping_ngrams = evaluated_ngrams.intersection(reference_ngrams)
    overlapping_count = len(overlapping_ngrams)

    if evaluated_count == 0:
        precision = 0.0
    else:
        precision = overlapping_count / evaluated_count

    if reference_count == 0:
        recall = 0.0
    else:
        recall = overlapping_count / reference_count

    f1_score = 2.0 * ((precision * recall) / (precision + recall + 1e-8))
    return {"f": f1_score, "p": precision, "r": recall}
def greedy_selection(doc_sent_list, abstract_sent_list, summary_size):
    def _rouge_clean(s):
        return s#re.sub(r'[^a-zA-Z0-9 ]', '', s)

    max_rouge = 0.0
    abstract = sum(abstract_sent_list, [])
    abstract = _rouge_clean(' '.join(abstract)).split()
    sents = [_rouge_clean(' '.join(s)).split() for s in doc_sent_list]
    evaluated_1grams = [_get_word_ngrams(1, [sent]) for sent in sents]
    reference_1grams = _get_word_ngrams(1, [abstract])
    evaluated_2grams = [_get_word_ngrams(2, [sent]) for sent in sents]
    reference_2grams = _get_word_ngrams(2, [abstract])

    selected = []
    for s in range(summary_size):
        cur_max_rouge = max_rouge
        cur_id = -1
        for i in range(len(sents)):
            if (i in selected):
                continue
            c = selected + [i]
            candidates_1 = [evaluated_1grams[idx] for idx in c]
            candidates_1 = set.union(*map(set, candidates_1))
            candidates_2 = [evaluated_2grams[idx] for idx in c]
            candidates_2 = set.union(*map(set, candidates_2))
            rouge_1 = cal_rouge(candidates_1, reference_1grams)['f']
            rouge_2 = cal_rouge(candidates_2, reference_2grams)['f']
            rouge_score = rouge_1 + rouge_2
            if rouge_score > cur_max_rouge:
                cur_max_rouge = rouge_score
                cur_id = i
        if (cur_id == -1):
            return selected
        selected.append(cur_id)
        max_rouge = cur_max_rouge

    return sorted(selected)
def sent_token_split_src(doc, is_short_summary = False):
    doc_modified = re.sub(r' ', "", doc)
    # doc_modified = re.sub(r':w+:', "", emoji.demojize(doc_modified))

    ### if the doc is a very short summary, just don't split sentence
    if is_short_summary:
        doc_split = [list(doc_modified)]
        return doc_split

    doc_modified = re.sub(r'。', "。 ", doc_modified)
    doc_modified = re.sub(r'!', "! ", doc_modified)
    doc_modified = re.sub(r'?', "? ", doc_modified)
    doc_modified = re.sub(r';', "; ", doc_modified)

    doc_split = re.split(r' ', doc_modified)
    doc_split = [i for i in doc_split if len(i)>=2]

    if len(doc_split)<2:
        doc_modified = re.sub(r',', ", ", doc_modified)
        doc_modified = re.sub(r',', ", ", doc_modified)

        doc_split = re.split(r' ', doc_modified)
        doc_split = [i for i in doc_split if len(i)>=2]

    doc_split = [list(i) for i in doc_split]

    return doc_split
def sent_token_split_tgt(doc, is_short_summary = False):
    doc_modified = re.sub(r' ', "", doc)
    # doc_modified = re.sub(r':w+:', "", emoji.demojize(doc_modified))

    ### if the doc is a very short summary, just don't split sentence
    if is_short_summary:
        doc_split = [list(doc_modified)]
        return doc_split

    doc_modified = re.sub(r'。', "。 ", doc_modified)
    doc_modified = re.sub(r'!', "! ", doc_modified)
    doc_modified = re.sub(r'?', "? ", doc_modified)
    doc_modified = re.sub(r';', "; ", doc_modified)
    doc_modified = re.sub(r',', ", ", doc_modified)
    doc_modified = re.sub(r',', ", ", doc_modified)
    doc_split = re.split(r' ', doc_modified)
    doc_split = [i for i in doc_split if len(i)>=2]
    doc_split = [list(i) for i in doc_split]

    return doc_split
def convert(data,nums):
    D= {}
    D["title"] = []
    D["content"] = []
    D["guide_sentence"] = []
    for inx in tqdm(range(len(data))):
        src_split = sent_token_split_src(data[inx][0])
        tgt_split = sent_token_split_tgt(data[inx][1])
        guide_index = greedy_selection(src_split,tgt_split,nums)
        guide = ["".join(src_split[i]) for i in guide_index]
        guide_sentences = ""
        for g in guide:
            if guide_sentences != "":
                guide_sentences += "[SEP]"+g
            else:
                guide_sentences += g
        D["content"].append(data[inx][0])
        D["title"].append(data[inx][1])
        D["guide_sentence"].append(guide_sentences)
    return D

data_json = r'NLPCC2017_original.json'

data = load_data(data_json,"NLPCC2017")
data = convert(data,nums=2)#指定抽取数目,如果无法抽取到指定数目则返回最小值
2、可以通过抽取到的关键句作为引导信息生成文本摘要

(1)该方法可以有效提升模型性能,训练的时候将引导关键句作为辅助信息进行摘要生成

(2)推理的时候有两种方案:

1)通过训练一个BERT模型,通过BERT+CLS或者BERT+AvgPooling+激活即可训练一个句子分类网络,对源文本中的句子进行0-1分类,完成关键句的抽取。

2)不训练BERT模型,首先取BERT的分句句向量,取完分句句向量后进行后处理,比如送入CNN(例如DGCNN)网络或者Transformer网络训练一个后处理分类网络,可以达到同样的效果。

步骤一:

 步骤二:

 这写错了,是BERT 的encoder,不是Bart

步骤三:

 

方法二可以有效处理长文本的抽取任务,更加推荐!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/987603.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号