Bert超长⽂本分类、⽂本摘要
Bert⼤规模超长⽂本分类
长⽂本分类
⽂本分类是把⽂本打上对应的类别标签,在互联⽹中的应⽤场景很多,如评论、弹幕等。作为⽐较强⼤的预训练模型Bert,⽤来做⽂本分类有很好的效果。本⽂介绍pytorch版本的Bert长⽂本分类,但由于Bert的输⼊长度有现在,最长只能输⼊512个字符,但长⽂本通常有⼏千或者⼏万个字,所以本⽂采⽤了两种策略来进⾏长⽂本分类,⼀是取⽂本开头的512字符输⼊到Bert,⼆是对⽂本先采⽤⽂本摘要算法,得到重要的部分再取前⾯512字符输⼊到Bert。
⽂本摘要算法Textrank介绍
Textrank算法的思想来⾃于PageRank,PageRank是⾕歌⽤来进⾏⽹页排序的算法,其思想是赋予每个⽹页⼀个权值,然后计算每个⽹页指向其他⽹页的权值,之后根据计算的权值求和来进⾏权值更新,⼀般,最后按权值来进⾏排名。
在⽂本中,就将每⼀个句⼦看成⼀个个体,句⼦与句⼦间的链接权值就⽤句⼦间的相似度来代替,只需要进⾏句⼦间相似度的计算就可以更新权值了,假设向量B是句⼦的rank权值,每⼀个元素代表⼀个句⼦
的排名权值,矩阵A是⼀个⼆维矩阵,它的维度数是句⼦的数量,⽤矩阵A*向量B来进⾏迭代,当向量B收敛之后就完成了,向量B中元素的值就代表对应句⼦的排名权值。
句⼦相似度计算
句⼦相似度的计算,⼀般⽤两个句⼦的向量来进⾏运算,⽐如计算余弦相似度。然⽽怎么取句⼦向量⽐较重要,句⼦向量要能充分表⽰句⼦的特征,这样计算的相似度才准确。现在⼀般取句⼦向量的话,会⽤到词向量,或者Bert。⽤词向量的话,是查表到每⼀个词的向量,在计算平均,得到句⼦的向量。⽽Bert则是输⼊⼀个句⼦,⽤输出的CLS代表整个句⼦的向量,当然也可以⽤Bert获取每个字的向量再求平均获得句⼦向量。
1、使⽤glove词向量来获取句⼦向量并进⾏Textrank
# -*- coding:utf-8 -*-
# 导⼊所需的库,没有的话⽤pip install 库名字安装
import numpy as np
import pandas as pd
import nltk
# networkx库内置了常⽤的图与复杂⽹络分析算法,可以⽅便的进⾏复杂⽹络数据分析、仿真建模等⼯作。
import networkx as nx
# 下载⼀次就⾏了,第⼀次下载完再注释掉
#nltk.download('punkt')
# 下载停⽤词,下载⼀次就⾏,同上
#nltk.download('stopwords')
# 加载进来
pus import stopwords
import re
# 将⽤余弦相似度计算两个句⼦之间的相似度
ics.pairwise import cosine_similarity
from bs4 import BeautifulSoup
def get_sentences_list(raw_text:str):
#BeautifulSoup对象,参数⽂档字符串,html解析器,⽂档编码
return[s for s in BeautifulSoup(raw_text,'html.parser')._all_strings()]
# 这⾥使⽤glove中⽂维基的词向量⽣成⼀个word_embeddings查列表
word_embeddings ={}
f =open('', encoding='utf-8')
# 按⾏读取
for line in f:
# 按照空格进⾏分割
values = line.split()
# values 数组的第⼀个位置是当前的英语单词
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
word_embeddings[word]= coefs
f.close()
# print("词表:",len(word_embeddings['我']))
# 停⽤词表
def stopwordslist():
stopwords =[line.strip()for line in open('',encoding ="utf-8").readlines()]
return stopwords
def text_import(text):
text_extract =''
sentence_list =[]
text = get_sentences_list(text)
for node in text[0].split('。'):
if len(node)!=0:
sentence_list.append(node)
sentence_num =len(sentence_list)
sentences_vectors =[]
print(len(sentence_list))
# print(sentence_list[0])
#去除⾮中⽂的字符
pre_sentences = pd.Series(sentence_list).place('[^\u4e00-\u9fa5]',' ')
stop_words = stopwordslist()
# print(stop_words)
# 定义移除停⽤词函数
def remove_stopwords(str):
# 遍历数组中的每个元素,如果这个元素不在停⽤词列表,则加⼊事先准备的字符串中
sen =' '.join([i for i in str if i not in stop_words])
return sen
# 去除停⽤词
pre_sentences =[remove_stopwords(r.split())for r in pre_sentences]
print(pre_sentences)
# 获取句⼦特征向量,⽤来计算后⾯的相似度,这⾥取每个句⼦中词向量合并的平均值来作为该句⼦的特征向量# 所有句⼦的词向量表⽰
sentences_vectors =[]
for sen in pre_sentences:
# 如果句⼦长度不为0
if len(sen)!=0:
v =sum([(w, np.zeros((300,)))for w in sen.split()])/(len(sen.split())+1e-2) else:
v = np.zeros((300,))
sentences_vectors.append(v)
# ⽤上⾯获取到的句⼦的向量计算⼀个相似度矩阵
# 这⾥使⽤余弦相似度来计算每个句⼦的相似性
# ⾸先定义⼀个n乘n的零矩阵,然后⽤句⼦间的余弦相似度填充矩阵,这⾥n是句⼦的总数。
similarity_matrix = np.zeros((len(pre_sentences),len(pre_sentences)))
print(len(pre_sentences))
for i in range(len(pre_sentences)):
for j in range(len(pre_sentences)):
# 这⾥的if⽤于排序⾃⼰与⾃⼰计算相似度
if i != j:
similarity_matrix[i][j]= cosine_similarity(
sentences_vectors[i].reshape(1,-1), sentences_vectors[j].reshape(1,-1)
)
# 输出相似度矩阵
print(similarity_matrix)
# 将上⾯获得的相似性矩阵sim_mat转换为图结构。这个图的节点为句⼦,边⽤句⼦之间的相似性分数表⽰。
# 在这个图上,使⽤networkx库提供的PageRank算法来得到句⼦排名,句⼦排名越⾼,说明其越重要,就是摘要
nx_graph = nx.from_numpy_array(similarity_matrix)
scores = nx.pagerank(nx_graph)
print(scores)
# 根据排名来选取句⼦作为摘要
# 遍历sentences数组,i是当前的位置⾓标,s是当前的句⼦
# scores[i]:从scores中取出第i个位置的分数与当前句⼦组成⼀对
# 将所有的分数,句⼦信息组成的list赋值给ranked_sentences
# sorted:并排序,reverse=True降序
ranked_sentences =sorted(
((scores[i], s)for i, s in enumerate(sentence_list)), reverse=True
)
# 排序
# for i in range(1):
# print(ranked_sentences[i][1])
# # 打印得分最⾼的前⾯⼏个句⼦,即为摘要,这⾥修改句⼦的数量就可以修改摘要
for i in range(sentence_num):
if len(text_extract)<512:
# 获取⽂本的摘要
text_extract += ranked_sentences[i][1]+'。'
else:
break
return text_extract[:512]
text="徐峥,回不到过去徐峥,回不到过去喜剧演员徐峥、爆⽶花商业⽚导演徐峥,同时也是⽂青的徐峥。毒眸《我和我的家乡》的五个单元故事⾥,若票选最令⼈印象深刻的⾓⾊,《最后⼀课》单元的中范伟饰演的“范⽼师”可能是⼈⽓最⾼的。⾖瓣⾼赞短评写道:“范伟把我的泪点掐住了”、“教科书级别的演技”;微博上,范伟⾬中奔跑的花絮冲上热搜第⼀,评论说:“范伟真的厉害,从他跑出教室我就开始哭,⼀直到单元结束”。也有观众能够指出,范伟动⼈的表演不⽌是范伟⾃⼰的功劳。作为这个单元的导演,恰好在徐峥的导演⽅法论⾥,表演也是重要的话题。“导演对表演,必须达到⼀种切⾝的理解,要完全能够站在演员的⽴场上,为演员的表演提供有帮助的指⽰。”10⽉12⽇,徐峥在丝绸之路国际电影节的⼤师班上,传递了这样⼀种观点。对表演的理解深度,或许是徐峥作品⾥容易诞⽣“⾼光演技”的原因之⼀:从《我和我的祖国》⾥惊艳的⼩演员“冬冬”韩昊霖,到《我和我的家乡》⾥“掐住观众泪点”的范伟,都凭借演技引发了话题。另⼀⽅⾯,叙事功⼒也是《最后⼀课》受到好评的另⼀个原因。⾖瓣⼀则热评写道:“(最后⼀课)展现出徐峥某个程度的细腻,他很擅长从⼩的切⾓去展开⼀个
宏⼤叙题。”《最后⼀课》中,村民为帮助⾝患阿尔兹海默症的范⽼师,设下“重返1992年”的,最终的败露,也揭⽰了家乡的发展变化遮掩不住。徐峥在⼤师班上这般解释如此构思的原因:“因为观众是⾮常害怕说教的”,所以要通过⼀个“过去⽆法重塑”的故事,去展现变化。⽽毒眸通过徐峥在⼤师班上的讲述,也感知到《最后⼀课》与徐峥个⼈轨迹的某种暗合:从演实验话剧的先锋⽂艺青年,到家喻户晓的影视演员、商业⽚导演,近年来的徐峥正在试图回归到更接近个⼈表达的状态。但过去⽆法重塑,徐峥要做的不是变回90年代那个⽂艺青年,⽽是带着对过去⾃我的同理⼼和多年积累的经验,介⼊到当下青年导演的创作中去——成为青年导演的电影监制。徐峥提到,⼤部分导演正如当年的⾃⼰⼀样,是因为热爱艺术⽽投⾝电影创作的⽂艺青年,⽽现在的徐峥和他所成⽴的真乐道⽂化,正在通过“监制”这⼀⾓⾊,去服务青年导演,帮助“曾经的徐峥”们缓解创作之外、全产业流程上的压⼒。某种程度上,范伟饰演的乡村教师,也带着⼏分徐峥的⾃我投射:⼀个⼈仅凭⾃⼰的⼒量是⽆法改变“家乡”或者“环境”的,但是把经验分享出来,帮助更多有能⼒改变的⼈,环境就会向好的⽅向变化。⽂青徐峥“程⽿我拍《犯罪分⼦》的时候,是在1998年,那时候我也是个⽂艺青年。”⼤师班上与青年导演对谈的徐峥,回溯了他的青年时代,但很快⼜调转话锋:“现在如果让他(程⽿)看我的电影,他肯定看不上我,觉得我已经不是⼀个艺术青年了。”⼆⼗年前,徐峥在⼤众的认知⾥是《春光灿烂猪⼋戒》⾥的猪⼋戒、《李卫当官》中的李卫。但其实在古装喜剧之外,他还是个演先锋话剧的艺术青年,这⼀度会让许多观众感到惊诧。但近年来,1999年问世的《犯罪分⼦》的重新流⾏,再度将⽂青时代的徐峥带回观众的视野。这部31分钟的⼩成本犯罪⽚拍摄时,导演程⽿还在北京电影学院毕
业读⼤四。作品有“北电史上最⽜学⽣作业”之称,⾖瓣评分7.4,⼀条2014年发布的热门短评⽆不惋惜地评价男主⾓徐峥:“⼤脑袋有⼤智慧,演技真实准确,可惜了现在的被定位。”《犯罪分⼦》剧照但彼时观众跨越时空的“惋惜”对徐峥来说,未免来得迟了⼀些——⽂青时代的徐峥是不为观众所青睐的。《⼗三邀》中,徐峥和许知远⾛进了上海话剧艺术中⼼——1994年从上海戏剧学院毕业后,徐峥的第⼀个⼯作单位。艺术中⼼进门处的墙上挂满了剧照,徐峥很快从中发现了⾃⼰的⾝影:《拥挤》《艺术》《股票的颜⾊》......⽽后者令徐峥在1998年摘得⽩⽟兰戏剧奖最佳男主⾓。根据徐峥的描述,从戏剧学院毕业后没有⼈⾃⼰拍戏,所以他⼀直在演话剧。那时,话剧演员徐峥⼀度“⼩有名⽓”,徐峥还和朋友组建了剧社,并⾃⼰担任导演排了两部先锋的实验作品《拥挤》和《母语》。“当时就受到很多质疑,别⼈说你排的戏看不懂,这那的,当时我就很激动,还会跟⼈争辩。”徐峥在《⼗三邀》⾥说道。但他很快转变了思路,开始反思过于先锋的内容是否有意义,他认为⾃⼰应该对作品的传播效果负责任。愿意主动做出这样的改变,是因为徐峥虽然接受过⾼屋建瓴的戏剧教育、具备做出先锋性表达的能⼒,但他并不是那类厌弃成功的、忧郁的、纯度很⾼的⽂艺青年。徐峥在艺术性和商业化两个⽅向⾥同样具有可能性。世纪之交,徐峥开始涉⾜影视圈,同时也仍然在排话剧,前者所带来的曝光⼀度让徐峥的话剧事业“沾光”。2000年1⽉《春光灿烂猪⼋戒》在各⼤卫视反复播出,据索福瑞收视数据,该剧在湖南卫视、⿊龙江卫视、⼭东和江西卫视播出的平均收视率均超过20%,最⾼平均收视达到31%。次年徐峥主演的喜剧话剧《艺术》在宣传不多的情况下,于上海连演15场。尽管徐峥⾃嘲现在的程⽿⼀定看不上⾃⼰,但事实上,2007年程⽿和徐峥⼜再度合作了悬疑惊悚剧《第三个⼈》。20
09年,徐峥主演两部公路⽚,⼀部是指向喜剧和商业成功的《⼈在囧途》,⼀部是暗⿊的《⽆⼈区》,后者⼊围了柏林国际电影节主竞赛单元。《⽆⼈区》海报⽂艺青年的⼈格从未离开徐峥的躯壳,只是⼀度被喜剧演员的光环盖住了——⾯向⼤众的商业喜剧⽚、古装电视剧能够辐射的受众,远⽐话剧和严肃电影来得多。但近年来,随着主演作品《我不是药神》的上映和徐峥个⼈导演作品中愈发明显的⼈⽂表达,他的“前⽂艺青年”⾝份不再显得太过违和。《我不是药神》在⾖瓣被150万⽤户打出9.0分,位列⾖瓣电影top250第47名——达到了近20年来华语电影鲜少能触碰到的⾦线。《最后⼀课》在《家乡》的五个单元之中,⼝碑亦属于上乘。徐峥延续了执导《我和我的祖国》单元《夺冠》的经验,从⼩⼈物的动机和情感出发,反⽽真实恳切;在叙事上,他在过去与现在的故事线反复切换,⽤重塑过去来反衬现在;细节也值得咂摸,⽐如颜料打翻在⽔⾥化成了彩虹的颜⾊、范⽼师⼀路⾛进教室那个调度复杂、明星云集的长镜头。"
# text=" "
print(len(text))
print(text_import(text))
2、使⽤在语料上预训练过的Bert来获取句⼦向量
# 导⼊所需的库,没有的话⽤pip install 库名字安装
import numpy as np
import pandas as pd
import nltk
import pickle
import json
# networkx库内置了常⽤的图与复杂⽹络分析算法,可以⽅便的进⾏复杂⽹络数据分析、仿真建模等⼯作。
import networkx as nx
# 下载⼀次就⾏了,第⼀次下载完再注释掉
#nltk.download('punkt')
# 下载停⽤词,下载⼀次就⾏,同上
#nltk.download('stopwords')20
# 加载进来
pus import stopwords
import re
# 将⽤余弦相似度计算两个句⼦之间的相似度
ics.pairwise import cosine_similarity
import torch
import tqdm
import bs4
from torch import nn
from tqdm import tqdm
from bs4 import BeautifulSoup
import transformers as tfs
BERT_TOKENZIER_PATH ='./chinese_wwm_ext_L-12_H-768_A-12/'
FINETUNED_BERT_ENCODER_PATH ='./预训练模型/finetuned_bert.bin'
def get_sentences_list(raw_text:str):
#BeautifulSoup对象,参数⽂档字符串,html解析器,⽂档编码
return[s for s in BeautifulSoup(raw_text,'html.parser')._all_strings()]
#这⾥⽤微调的bert来获取⽂本的句⼦向量,再⽤向量来计算相似度
class MyBertEncoder(nn.Module):
"""⾃定义的Bert编码器"""
def__init__(self, tokenizer_path, finetuned_bert_path):
super(MyBertEncoder, self).__init__()
model_class, tokenizer_class = tfs.BertModel, tfs.BertTokenizer
self.bert = torch.load(finetuned_bert_path)
def forward(self, batch_sentences):
batch_tokenized = kenizer.batch_encode_plus(batch_sentences, add_special_tokens=True,
max_length=512, pad_to_max_length=True)
input_ids = sor(batch_tokenized['input_ids']).cuda()
token_type_ids = sor(batch_tokenized['token_type_ids']).cuda()
attention_mask = sor(batch_tokenized['attention_mask']).cuda()
bert_output = self.bert(input_ids=input_ids, token_type_ids=token_type_ids, attention_mask=attention_mask) bert_cls_hidden_state=bert_output[1]
# bert_cls_hidden_state = bert_output[0][:, 0, :]
return bert_cls_hidden_state
encoder = MyBertEncoder(BERT_TOKENZIER_PATH, FINETUNED_BERT_ENCODER_PATH)
def text_import(text):
#以下操作不影响梯度
_grad():
encoder.eval()
print("我是⼀个⼩天使!")
text_test ="我是⼀个⼩天使!"
text_emb = np.array(encoder(text_test).cpu().detach().numpy())
print(text_emb[0])
text_extract=''
sentence_list=[]
text=get_sentences_list(text)
for node in text[0].split('。'):
if len(node)!=0:
sentence_list.append(node)
sentence_num=len(sentence_list)
sentences_vectors =[]
print(sentence_list)
print(sentence_list[0])
for sen in sentence_list:
# emb=padding_E2E_bert(np.array(encoder(sen).cpu()))
emb = np.array(encoder(sen).cpu())
# 取cls的向量作为句⼦向量
sentences_vectors.append(emb[0])
del emb
# ⽤上⾯获取到的句⼦的向量计算⼀个相似度矩阵
# 这⾥使⽤余弦相似度来计算每个句⼦的相似性
# ⾸先定义⼀个n乘n的零矩阵,然后⽤句⼦间的余弦相似度填充矩阵,这⾥n是句⼦的总数。
similarity_matrix = np.zeros((len(sentence_list),len(sentence_list)))
for i in range(len(sentence_list)):
for j in range(len(sentence_list)):
# 这⾥的if⽤于排序⾃⼰与⾃⼰计算相似度
if i != j:
similarity_matrix[i][j]= cosine_similarity(
sentences_vectors[i].reshape(1,-1), sentences_vectors[j].reshape(1,-1)
)
# 输出相似度矩阵
print(similarity_matrix)
# 将上⾯获得的相似性矩阵sim_mat转换为图结构。这个图的节点为句⼦,边⽤句⼦之间的相似性分数表⽰。
# 在这个图上,使⽤networkx库提供的PageRank算法来得到句⼦排名,句⼦排名越⾼,说明其越重要,就是摘要
nx_graph = nx.from_numpy_array(similarity_matrix)
scores = nx.pagerank(nx_graph)
# 根据排名来选取句⼦作为摘要
# 遍历sentences数组,i是当前的位置⾓标,s是当前的句⼦
# scores[i]:从scores中取出第i个位置的分数与当前句⼦组成⼀对
# 将所有的分数,句⼦信息组成的list赋值给ranked_sentences
# sorted:并排序,reverse=True降序
ranked_sentences =sorted(
((scores[i], s)for i, s in enumerate(sentence_list)), reverse=True
)
# 排序
for i in range(1):
print(ranked_sentences[i][1])范伟喜剧电影
# 打印得分最⾼的前⾯⼏个句⼦,即为摘要,这⾥修改句⼦的数量就可以修改摘要
for i in range(sentence_num):
if len(text_extract)<512:
#获取⽂本的摘要
text_extract+=ranked_sentences[i][1]+'。'
else:
break
return text_extract[:512]
text="这4种家电,有⼈相见恨晚,有⼈感觉鸡肋,主要是价格不⼀样同样⼀个产品,⼝碑却两极分化。感觉好⽤的⼈,天天喊着“后悔买晚了”;还有⼀些⼈,买完就感慨“果然是鸡肋”。在家电⾥也有⼀些这样的产品,⽐如我们今天要说的下⾯这四种。⽽且这四种家电有⼀个共同点——说好⽤的⼈,买得都挺贵的。没错,造成这四类家电⼝碑两极分化的原因,就是价格。如果你想买,请直接买贵的。"
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论