快速上手Pytorch实现BERT,以及BERT后接CNN/LSTM

news2024/9/24 1:22:16

快速上手Pytorch实现BERT,以及BERT后接CNN/LSTM

本项目采用HuggingFace提供的工具实现BERT模型案例,并在BERT后接CNN、LSTM等
HuggingFace官网
在这里插入图片描述

一、实现BERT(后接线性层)

1.引用案例源码:

from transformers import BertTokenizer, BertModel
import torch
model_name = 'bert-base-uncased'

tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertModel.from_pretrained(model_name)

inputs = tokenizer("Hello, my dog is cute", return_tensors="pt" , padding='max_length',max_length=10)
outputs = model(**inputs)
# print(inputs) # 字典类型的input_ids必选字段  101CLS  102SEP
last_hidden_states = outputs.last_hidden_state  # last_hidden_state 最后一层的输出  pooler_output / hidden_states 

在这里插入图片描述
程序会自行下载模型和配置文件,也可自行在官网上手动下载
在这里插入图片描述
模型返回的参数
在这里插入图片描述

2. 自定义类调用数据集

class MyDataSet(Data.Dataset) :
    def __init__(self , data ,label):
        self.data = data # ['今天天气很好', 'xxxx' , ……]
        self.label = label # [1 , 2 , 0]
        self.tokenizer = BertTokenizer.from_pretrained(model_name)
    def __getitem__(self , idx):
        text = self.data[idx] # str
        label = self.label[idx]
        inputs = self.tokenizer(text , return_tensors="pt" , padding='max_length',max_length=10 , truncation = True)  # truncation = True 是否进行截断操作
        input_ids = inputs.input_ids.squeeze(0) # squeeze(0) 对张量进行降维操作 为啥降维:输入的data是一句话(一维)但生成的input_ids默认是二维,因此需要降维
        token_type_ids = inputs.token_type_ids.squeeze(0)
        attention_mask = inputs.attention_mask.squeeze(0)
        return input_ids , token_type_ids , attention_mask,label
    def __len__(self):
        return len(self.data)

squeeze(0)的作用: 举个栗子

input_ids: tensor([[ 101, 7592, 1010, 2026, 3899, 2003, 10140, 102, 0, 0]])
b = input_ids.squeeze(0)
b: tensor([ 101, 7592, 1010, 2026, 3899, 2003, 10140, 102, 0, 0])
当张量是一个1 * n 维度的张量时,input_ids的维度是 1 * 10,调用squeeze(0) 将张量降成1维。
若不是1 * n的这种2维张量,如本就是1维的,或者m * n(其中m和n都是大于1的),调用这个函数没有效果。

squeeze(1)和squeeze(-1)作用相同 ,与squeeze(0)类似
将一个n*1维度的张量降成1维

3. 将数据集传入模型

data , label = [] , []
with open('./dataset/data.txt') as f:
    for line in f.readlines():
        a, b = line.strip().split(' ')
        data.append(a)
        label.append(int(b))
dataset = MyDataSet(data,label)
dataloader = Data.DataLoader(dataset , batch_size = 2,shuffle =True)

4.自定义模型

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel,self).__init__()
        self.bert = BertModel.from_pretrained(model_name)
        self.liner = nn.Linear(768, 3)  # "hidden_size": 768
    
    def forward(self , input_ids , token_type_ids , attention_mask) :
        output = self.bert(input_ids , token_type_ids ,attention_mask).pooler_output # [batch_size , hidden_size]
        # print(output.shape)
        output = self.linnear(output)
        return output

5.配置运行环境

device = torch.device('cuda')
model = MyModel().to(device)
loss_fun = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters() , lr = 1e-5)

6.训练模型,计算损失

for epoch in range(10):
    for input_ids,token_type_ids,attention_mask ,label in dataloader:
        input_ids,token_type_ids,attention_mask ,label = input_ids.to(device),token_type_ids.to(device),attention_mask.to(device) ,label.to(device)
        pred = model(input_ids,token_type_ids,attention_mask)
        
        loss = loss_fn(pred , label)
        print(loss.item())
        
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

在这里插入图片描述
易出现显存不够的错误,可以在服务器控制台中输入nvidia-smi //查看所有进程信息
在这里插入图片描述
选择需要杀死的进程taskkill /PID PTD号 /F //使用taskkill 进程id,杀死进程
在这里插入图片描述

二、BERT+CNN

添加卷积层,查看需要的参数
在这里插入图片描述
在这里插入图片描述
输入层和输出层之间的参数关系为:Wout = (Win + 2p - w)/ s +1 ; Hout = (Hin + 2p - w)/ s +1
其中Win = maxlen,Hin = hidden_size,卷积核大小为 w * h ,p表示padding(默认为0),s表示卷积步长(默认为1)
因此输出为 (10 + 2 * 0 - 2)/ 1 + 1 = 9 ,(768 + 2 * 0 - 768)/ 1 + 1 = 1

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.bert = BertModel.from_pretrained(model_name)

        '''
        BERT后接CNN
        '''
        self.conv = nn.Conv2d(1 ,3 ,kernel_size=(2,768)) # in_channels 输入的通道数 out_channels 经过卷积之后的通道数 kernel_size 卷积核大小
        self.linear = nn.Linear(27, 3)  # "hidden_size": 768

    def forward(self, input_ids, token_type_ids, attention_mask):
        '''

        x : [batch , channel , width , height]

        '''
        batch = input_ids.size(0)
        output = self.bert(input_ids, token_type_ids, attention_mask).last_hidden_state  # [batch_size , seq , hidden_size]
        output = output.unsqueeze(1) # [batch , 1, seq , hidden_size] 三维扩展成四维
        # print(output.shape)
        output = self.conv(output) # [batch , 3, 9 ,1]
        print(output.shape)
        # 为了进行分类,希望将四维转换成二维 # [batch , 3]
        output = output.view(batch , -1) # [batch , 3*9*1]

        output = self.linear(output)
        return output

输出结果

torch.Size([2, 3, 9, 1])
1.0467640161514282
torch.Size([1, 3, 9, 1])
1.6651103496551514
torch.Size([2, 3, 9, 1])
1.1516715288162231
torch.Size([1, 3, 9, 1])
1.0645687580108643
torch.Size([2, 3, 9, 1])
1.0910512208938599
torch.Size([1, 3, 9, 1])
0.9897172451019287
torch.Size([2, 3, 9, 1])
1.0313527584075928
torch.Size([1, 3, 9, 1])
1.0067516565322876
torch.Size([2, 3, 9, 1])
0.9847115278244019
torch.Size([1, 3, 9, 1])
1.01240873336792
torch.Size([2, 3, 9, 1])
0.9597381353378296
torch.Size([1, 3, 9, 1])
0.9435619115829468
torch.Size([2, 3, 9, 1])
0.9591015577316284
torch.Size([1, 3, 9, 1])
0.8384571075439453
torch.Size([2, 3, 9, 1])
0.9722234010696411
torch.Size([1, 3, 9, 1])
0.7264331579208374
torch.Size([2, 3, 9, 1])
0.9841375350952148
torch.Size([1, 3, 9, 1])
0.6240622997283936
torch.Size([2, 3, 9, 1])
0.7659112811088562
torch.Size([1, 3, 9, 1])
1.0371975898742676

三、BERT+LSTM

添加LSTM,查看需要哪些参数
在这里插入图片描述
在这里插入图片描述

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.bert = BertModel.from_pretrained(model_name)
        '''
        BERT后接LSTM
        '''
        self.lstm = nn.LSTM(input_size=768, hidden_size= 512 ,num_layers= 1 , batch_first= True , bidirectional=True) # batch_first = True 表示输入输出顺序(batch,seq,feature) LSTM默认(seq,batch,feature)
        self.linear = nn.Linear(1024, 3)  # "hidden_size": 768

    def forward(self, input_ids, token_type_ids, attention_mask):
        '''
        x : [batch , seq]
        '''
        batch = input_ids.size(0)
        output = self.bert(input_ids, token_type_ids, attention_mask).last_hidden_state  # [batch_size , seq , hidden_size]
        output , _ = self.lstm(output)
        print(output.shape) # [2 , seq ,2*hidden_size]

        # 使用LSTM最后一层的输出做分类
        output = output[: ,-1,:] # [batch , 1024]
        print('最后一层' ,output.shape)
        output = self.linear(output)
        return output

输出结果

{‘input_ids’: tensor([[ 101, 7592, 1010, 2026, 3899, 2003,
10140, 102, 0, 0]]), ‘token_type_ids’: tensor([[0, 0, 0, 0,
0, 0, 0, 0, 0, 0]]), ‘attention_mask’: tensor([[1, 1, 1, 1, 1, 1, 1,
1, 0, 0]])} [‘今天天气很好’, ‘今天天气很不好’, ‘明天天气非常好’] [1, 0, 2]

torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.0788244009017944 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.3834939002990723 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.155088186264038 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.0809415578842163 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.061639666557312 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.1302376985549927 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.0572789907455444 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.086378812789917 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.0700803995132446 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.0184061527252197 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
0.9948051571846008 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.203598976135254 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.1068116426467896 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
0.9117098450660706 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
0.9891176223754883 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.1974778175354004 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
1.0810655355453491 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
0.8861477375030518 torch.Size([2, 10, 1024]) 最后一层 torch.Size([2, 1024])
0.9180283546447754 torch.Size([1, 10, 1024]) 最后一层 torch.Size([1, 1024])
1.2292695045471191

要实现BERT后接各种模型,最重要的是需要知道模型经过每一层后的维度是多少,最粗暴的方式可以通过print输出维度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/498674.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开关电源基础01:电源变换器基础(2)

说在开头:关于德布罗意的电子波(3) 1923年,德布罗意在求出他的相波之前,康普顿刚好用光子说解释了康普顿效应(记性好的胖友们应该还记得:散射波的波长变长问题),从而带领…

开关电源基础02:基本开关电源拓扑(2)-BOOST-BUCKBOOST拓扑

说在开头:关于海森堡的矩阵(2) 海森堡写完论文就回到了哥廷根大学,他一看见玻恩就把这份论文拿出来请老师把关,还说要趁着假期去趟英国剑桥大学讲课交流。玻恩拿过论文一看,海森堡画的这个表格是啥玩意啊&…

【操作系统】高性能网络模式:Reactor 和 Proactor

【操作系统】高性能网络模式:Reactor 和 Proactor 参考资料: 高性能 RPC 通信的实现- 巧用 reactor 模式 高性能网络模式:Reactor 和 Proactor NIO Reactor模型 Netty「基石」之Reactor模式 高性能IO模型分析-Reactor模式和Proactor模式 【…

【服务器】无公网IP,异地远程连接威联通NAS

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 目录 前言 1. 威联通安装cpolar内网穿透 2. 内网穿透 2.1 创建隧道 2.2 测试公网远程访问 3. 配置固定二级子域名 3.1 保留二级子域名 3.2 配置二级子域名 4. 使用固定二级子…

Linux诊断原因:生产环境服务器变慢,诊断思路和性能评估

Linux诊断原因,生产环境服务器变慢,诊断思路和性能评估 1 整机:top,查看整机系统性能 使用top命令的话,重点关注的是 %CPU、%MEM 、load average 三个指标 load average三个指标:分别代表1、5、15时分钟系…

2022年NOC大赛编程马拉松赛道初赛图形化低年级A卷-正式卷,包含答案

目录 选择题: 下载文档打印做题: 2022年NOC大赛编程马拉松赛道【初赛】图形化低年级A卷-正式卷 2022NOC-图形化初赛低年级A卷正式卷 选择题: 1、答案:B 禾木是一个军事迷,他打算利用业余时间制作一款射击游戏。在游戏中,玩家可以通过鼠标控制手枪移动。请问,给手枪…

springboot+vue体质测试数据分析及可视化设计(源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的体质测试数据分析及可视化设计。项目源码以及部署相关请联系风歌,文末附上联系信息 。 💕💕作者&a…

[svg-icon]引入vue项目后,use标签为0,已解决

这个bug我之前遇到过一次,解决了也就没记录 但是好记性不如烂笔头,这次重新遇到,又重新排查bug花了1个多小时 svg引入vue项目,需要依赖svg-sprite-loader npm install svg-sprite-loader在vue.config.js中 chainWebpack(conf…

NOC大赛·核桃编程马拉松赛道知识点大纲(高年级及初中组)

NOC核桃编程马拉松知识点大纲(高年级及初中组) (一)基础语法 1.掌握运动积木的用法。 包括“移动 10 步”、“左/右转 X 度”、“面向 X 方向/鼠标指针/ 角色”、“移到 XY 坐标/鼠标/角色”、“X/Y 坐标的设定和增加”、 “滑行到 XY/鼠标/角色”等积木用法,详细如下。 1…

【数据结构】链表OJ:力扣160. 相交链表

最近这几篇内容都有关链表,接下来几篇内容会分享一些链表的OJ题,希望对你有所帮助。 今天要分享的内容是力扣160. 相交链表:160. 相交链表 - 力扣(LeetCode) 目录 题目: 题解 题目: 给你…

数据分析02——numpy模块的在jupyter中的使用

0、numpy: 在计算机中会把数学当中的矩阵叫做数组,在很多应用中的表格也就是通过矩阵表示的,所以numpy广泛用于机器学习,数据分析,和图像处理领域。 1、numpy常用方法和函数: 前言:在使用nump…

腾讯云轻量应用服务器使用限制说明(十大限制)

腾讯云轻量应用服务器和云服务器CVM相比具有一些限制,比如轻量服务器不支持更换内网IP地址,轻量服务器只能套餐整体升级且不支持降配,轻量不支持用户自定义配置私有网络VPC,还有如实例配额、云硬盘配额、备案限制和内网连通性等限…

Ububtu20.04 无法连接外屏(显卡驱动问题导致)

Ububtu20.04 无法显示第二个屏幕(显卡驱动问题) Ububtu20.04 无法显示第二个屏幕(显卡驱动问题) Ububtu20.04 无法显示第二个屏幕(显卡驱动问题) 1. 问题描述2. 解决方案 1. 问题描述 一开始我的ububt…

JavaGuide复习1——常见面试题总结部分

1、关于包装类的缓存机制 两种浮点数类型的包装类 Float,Double 并没有实现缓存机制。 对应源码: 拆装箱 都是调用了包装类的方法:valueOf(基本转包装)、xxxValue(包装转基本) 注意char char在Java中占用…

Illustrator如何进行文本的创建与编辑之实例演示?

文章目录 0.引言1.创建点文字2.串接文本3.石刻文字 0.引言 因科研等多场景需要进行绘图处理,笔者对Illustrator进行了学习,本文通过《Illustrator CC2018基础与实战》及其配套素材结合网上相关资料进行学习笔记总结,本文对文本的创建与编辑进…

shell脚本编程基础

shell 文件的建立和执行 shell脚本是将shell命令在文件中编写,从而实现一次执行很多shell命令。如: # ab.sh # !/bin/bash echo "Welcome Linux" cd mkdir myjsjsj echo "Your dir is" pwd可以看到这就是多个shell命令。 执行前需…

【数据结构】选择排序(详细)

选择排序 1. 直接选择排序2. 堆排序2.1 堆2.2 堆的实现(以大根堆为例)2.3 堆排序 3. 堆排序(topK问题) 1. 直接选择排序 思想 以排升序为例。以a[i]为最大值(或最小值),从a[i1]到a[n-1-i]比较选…

【5G RRC】NR 小区接入控制

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…

Wind10安装cuDNN,几分钟搞定

cuDNN的安装过程 1、下载cuDNN 因为之前的博文“目标检测第3步”下载的CUDA版本是11.1,那么我们就要找到与CUDA11.1版本对应的cuDNN版本。地址为:cuDNN Archive | NVIDIA Developer 2、安装cuDNN 下载到的cuDNN文件是一个压缩包,解压缩之后…

并发编程03:Java锁

文章目录 3.1 乐观锁和悲观锁3.2 通过8种情况演示锁运行案例,看看锁到底是什么3.2.1 锁相关的8种案例演示code3.2.2 synchronized有三种应用方式3.2.3 从字节码角度分析synchronized实现3.2.4 反编译synchronized锁的是什么3.2.5 对于Synchronized关键字 3.3 公平锁…