字幕组双语原文:Keras教程:伯特文本摘要
英语原文:用于文本提取的伯特(来自拥抱变形金刚)
翻译:雷锋字幕组(yhfwww、wiige)
介绍
这个演示使用了斯坦福大学问答数据集。在班数据集中,输入由一个问题和一个上下文段落组成。目标是找到回答问题的段落的跨度。我们使用”精确匹配(完全匹配)”指标来评估我们在这些数据上的表现,它度量了精确匹配任何一个真实答案的预测的百分比。
我们对一个伯特模型进行微调,如下所示:
将上下文和问题作为输入,输入给伯特。
取两个向量S和T它们的维数等于伯特中隐藏状态的维数。
计算每个代币作为答案范围的开始和结束的概率。一个代币作为答案开始的概率是由S和在最后一层伯特中表示的代币之间的点积给出的,然后是所有代币的softmax。代币作为最终答案的概率的计算方法与向量T类似。
微调伯特,学习S和t。
参考:
伯特
班
设置:
导入操作系统
进口是
导入数据
导入字符串
将数组作为铭牌导入
将张量流作为法国南部(French Southern Territories的缩写)导入
从张量流导入深度学习
从张量流导入图层
从标记化者导入BertWordPieceTokenizer
从变压器进口伯特托肯泽
Configmax_len=384
配置=BertConfig
伯特的默认参数和配置
设置伯特分词器#保存慢预训练tokenizers low _ tokenizer=bertokenizer。from _ pre trained(\ ‘ Bert-base-un cased \ ‘)Save _ path=\ ‘ Bert _ base _ un cased/\ ‘如果不是os.path.exists(保存路径):
OS。使目录(保存路径)成为slow _ tokenizer。save _ pre trained(保存路径)#从保存的文件中加载快速令牌化器tokenizer=bertwodpiecetokenizer(\ ‘ Bert _ base _ un cased/vocab。txt \ ‘,小写=真)
载入数据
train _ data _ URL=\ ‘ https://rajpurkar。github。io/小队-探索者/数据集/训练-v 1.1。JSON \ ‘ train _ path=keras。utils。get _ file(\ ‘ train。JSON \ ‘,train _ data _ URL)eval _ data _ URL=\ ‘ https://rajpurkar。github。io/SQuAD-explorer/dataset/dev-v 1.1。JSON \ ‘ eval _ path=keras。utils。get _ file(\ ‘ eval。
数据预处理
遍历数据文件,把每行记录都保存为小组示例对象。
遍历每个小组示例对象来创建x_train,y_train,x_eval,y_eval .
班级班示例: def __init__(自身,问题,上下文,start_char_idx,answer_text,all_answers):
自我提问=提问
自我.上下文=上下文
自我。start _ char _ idx=开始_ char _ idx
self.answer_text=答案_text
self.all_answers=所有答案
self.skip=False
定义预处理(自身):
上下文=自我。上下文
问题=自我。问题
answer_text=自我
start_char_idx=self
#清理上下文,答案和问题上下文=\’ \ ‘。join(str(context ).拆分)
问题=\’ \ ‘。join(str(question ).拆分)
答案=\’ \ ‘。join(str(answer_text).拆分)
#在上下文中查找答案的结束字符索引end _ char _ idx=start _ char _ idx len(答案)
if end _ char _ idx=len(context):
self.skip=True
返回#标记答案中上下文中的字符索引is_char_in_ans=[0] * len(上下文)
对于范围内的idx(start _ char _ idx,end_char_idx):
is _ char _ in _ ans[idx]=1 # Tokenize context tokenized _ context=tokenizer。编码(上下文)
#查找由答案字符ans_token_idx=创建的令牌
对于idx,枚举(tokenized_context.offsets)中的(开始,结束):
if sum(is _ char _ in _ ans[start : end])0:
ans_token_idx.append
if len(ans_token_idx)==0:
self.skip=True
返回# Find从答案start _ token _ idx=ans _ token _ idx[0]中查找令牌的开始和结束令牌索引
end _ token _ idx=ans _ token _ idx[-1]
# token ize question token ized _ question=token izer。编码(问题)
# Create inputs input _ ids=token ized _ context。ids令牌ized _ question。ids[1:]
token _ type _ ids=[0]* len(token ized _ context。ids)[1]* len(
tokenized_question.ids[1:]
)
attention_mask=[1] * len(输入标识)
#填充并创建注意屏蔽。#如果需要截断,则跳过填充长度=最大长度-长度(输入标识)
if padding _ length 0: # padding input _ ids=input _ ids([0]* padding _ length)
注意掩码=注意掩码([0] *填充长度)
令牌类型标识=令牌类型标识([0] *填充长度)
elif padding _ length返回self。输入标识=输入标识
自我。令牌类型标识=令牌类型标识
自我。注意_屏蔽=注意_屏蔽
自我。开始令牌idx=开始令牌idx
自我。结束令牌idx=结束令牌idx
自我。context _ token _ to _ char=token ized _ context。开(train _ path)的偏移为f : raw _ train _ data=JSON。load(f)with open(eval _ path)as f : raw _ eval _ data=JSON。load(f)def create _ squad _ examples(raw _ data):
小队_示例=
对于raw_data[\’data\’]:中的项目
对于项目[\ ‘段落\’]:中的段落
context=para[\’context\’]
对于第:段中的质量保证
question=qa[\’question\’]
answer _ text=QA[\ ‘ answers \ ‘][0][\ ‘ text \ ‘]
all _ answers=[_[\ ‘ text \ ‘]for _ in QA[\ ‘ answers \ ‘]]
start _ char _ idx=QA[\ ‘ answers \ ‘][0][\ ‘ answer _ start \ ‘]
squad_eg=SquadExample(
问题,上下文,start_char_idx,answer_text,所有答案
)
小队_eg。预处理
squad_examples.append(squad_eg)
返回squad _ examples def create _ inputs _ targets(squad _ examples):
数据集_字典={
\’input_ids\’:
\’token_type_ids\’:
\’attention_mask\’:
\’start_token_idx\’:
\’end_token_idx\’:
}
对于小队中的物品_ examples 3360如果物品。skip==false : for key in dataset _ dict : dataset _ dict[key].append(getattr(item,key))
for key in dataset _ dict : dataset _ dict[key]=NP。数组(dataset _ dict[key])
x=[
dataset_dict[\’input_ids\’],
dataset _ dict[\ ‘ token _ type _ ids \ ‘],
dataset _ dict[\ ‘ attention _ mask \ ‘]
]
y=[数据集_字典[\ ‘开始_令牌_idx\’],数据集_字典[\ ‘结束_令牌_idx\’]]
return x,y train _ squad _ examples=create _ squad _ examples(raw _ train _ data)x _ train,y _ train=create _ inputs _ targets(train _ squad _ examples)print(f \ ‘ { len(train _ squad _ examples)}已创建的训练点. \ ‘)eval _ squad _ examples=create _ squad _ examples(raw _ eval _ data)x _ eval,y _ eval=create _ inputs _ targets(eval _ squad _ examples)print(f \ ‘ { len(eval _ squad _ examples)}创建的评估点。\’)
创建了87599个培训点。创建了10570个评估点。
用伯特和函数式应用程序接口来构建问答模块
def create _ model : # # BERT encoder编码器=tfbertmodel。from _预训练(\ ‘ BERT-base-un cased \ ‘)
##问答模型input_ids=层。输入(shape=(max_len,),dtype=tf.int32)
令牌类型标识=图层。输入(shape=(max_len,),dtype=tf.int32)
注意_屏蔽=图层。输入(shape=(max_len,),dtype=tf.int32)
嵌入=编码器(
输入标识,令牌类型标识=令牌类型标识,注意掩码=注意掩码
)[0]
start_logits=layers .Dense(1,name=\’start_logit\ ‘,use_bias=False)(嵌入)
start_logits=layers .扁平化(start_logits)
end_logits=layers .Dense(1,name=\’end_logit\ ‘,use_bias=False)(嵌入)
end_logits=layers .扁平化(end_logits)
start_probs=layers .激活(keras。激活。软最大值)(start _ logits)
end_probs=层。激活(keras。激活。软最大值)(end _ logits)
型号=keras .型号(
inputs=[input_ids,token_type_ids,attention_mask],
outputs=[start_probs,end_probs],
)
损失=克拉斯。损失。sparsecategoricalcrossentropy(from _ logits=False)
优化器=keras。优化器。亚当(lr=5e-5)
模型.编译(优化器=优化器,损失=[损失,损失])
回报模型
这段代码很适合用谷歌TPU实验室来跑。用Colab TPUs,每个世大概花5-6分钟即可。
use_tpu=Trueif use_tpu:
#创建分发策略TPU=TF。分发。群集解析器.TPUClusterResolver
TF。配置。实验连接集群(TPU)
TF。tpu。实验性的。初始化_ TPU _系统(TPU)
策略=TF。分发。实验性的。贸易战略(TPU)
#使用战略范围:创建模型
model=create _ modelelse:
模型=创建_模型模型。摘要
信息absl :进入主设备范围:/作业:工作人员/副本:0/任务:0/设备: CPU :0信息:传感器流:初始化TPU系统: grpc ://10。48 .10传感器流33365信息:传感器流量:发现TPU系统:信息:传感器流量: * * * TPU内核数: 8信息:传感器流量: * * * TPU工作线程数: 1信息:传感器流量: * * * TPU每个工作线程数: 8型号: \ ‘型号\ ‘ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _工作线程数
构建评价回调函数
这个回调函数会在每个世后用验证集数据计算匹配值。
def normalize_text(text):
text=text.lower
#移除标点符号exclude=set(字符串.标点符号)
text=\’\ ‘ .join(ch for ch in text if ch not in exclude)
#删除文章regex=re。编译(r \ ‘ \ b(a | an | the)\ b \ ‘,重新编译.UNICODE)
text=re.sub(regex,\’ \ ‘,text)
#移除多余的空白text=\’ \ ‘ .连接(文本。拆分)
返回文本类完全匹配(keras。复试。回调):
\’\’\ ‘每个’团队范例’对象包含其输入段落中每个标记的字符级偏移量。我们使用它们来取回对应于我们预测的开始和结束标记之间的标记的文本范围。所有基本事实的答案也存在于每个”班示例”对象中。我们计算从模型预测中获得的文本范围与一个真实答案相匹配的数据点的百分比\ ‘ \ ‘ \ ‘ \ ‘ \ ‘ def _ _ init _ _(self,x_eval,y_eval):
self.x_eval=x_eval
self.y_eval=y_eval
def on_epoch_end(self,epoch,logs=None):
pred_start,pred _ end=self。模型。预测(自我。x _ eval)
count=0 eval _ examples _ no _ skip=[_ for _ in eval _ squad _ examples if _ .skip==False]
对于idx,枚举中的(开始,结束)(zip(pred _ start,pred_end)):
squad _ eg=eval _ examples _ no _ skip[idx]
offsets=squad _ eg . context _ token _ to _ char
start=np.argmax(start)
end=np.argmax(end)
if start=len(offsets):
继续
pred _ char _ start=offsets[start][0]
if end pred _ char _ end=offsets[end][1]
pred _ ans=squad _ eg . context[pred _ char _ start : pred _ char _ end]
else:
pred _ ans=squad _ eg . context[pred _ char _ start :]
normalized _ pred _ ans=normalize _ text(pred _ ans)
normalized _ true _ ans=[normalize _ text(_)for _ in squad _ eg . all _ answers]
if normalized _ pred _ ans in normalized _ true _ ans :
count=1 ACC=count/len(self . y _ eval[0])
print(f\’\nepoch={epoch 1},精确匹配分数={acc:2f}\ ‘)
培训和评估
exact _ match _ callback=exact match(x _ eval,y_eval)model.fit(
x _火车,
y _火车,
epochs=1,#为了演示,建议使用3个verbose=2,
batch_size=64
回调=[精确匹配回调],)
epoch=1,精确匹配分数=0.781346/1346-350s-activation _ 7 _ loss : 1.3488-loss : 2.5905-activation _ 8 _ loss : 1.2417
雷锋字幕组是由AI爱好者组成的翻译团队,汇聚500多名志愿者的力量,分享海外最新AI资讯,交流人工智能技术领域的行业变革和技术创新。
团队由大数据专家、算法工程师、图像处理工程师、产品经理、产品运营、IT顾问、师生组成;志愿者来自IBM、AVL、Adobe、阿里、百度等知名企业,以及北京大学、清华大学、港大、中科院、南卡罗来纳大学、早稻田大学等国内外科研院所。
如果,你也是一个爱分享的AI爱好者。欢迎和雷锋字幕组一起学习新知识,分享成长。
雷锋。com