在本次实战中我们要完成的是下游的文字分类任务不做预训练输入是语句输出是它的情感类别一句话在输入的时候首先要经过分词处理1. 训练前的知识储备1.1 分词器(tokenizer)一句话进入分词器就会被拆开变成一个字一个字的会产生三个东西input ids 汉字编号mask 这句话有多长seq_ids 句子编码模型的输入是固定的————不能一会长一会短所以要以mask为准超出就截断不够就paddingmask只是用来确定字数后面不再出现1.2 embeddinginput ids————linear21128768————Token Embeddingsseq_ids————linear2768————Segment Embeddingsidx————linear512768————position Embeddingsposition Embeddings的最大长度不是句子的长度而是模型的长度所以是512到768但是实际上使用的话一句话配的idx长度应该就是mask长度啊1.3 bert参数计算embeddinglinear21128768linear2768linear512768bert layersqkv3*768*768addnorm中的dense768*768 负责进一步提取维度特征feed forward768*4*7684*768*7681.4 hagging-face如果想自己下载模型可以直接进入hf-mirror去搜索然后从 model card 转到 files and versions 只下 pytorch 版及其他配置文件1.5 config介绍一下模型中的参数attention_probs_dropout_prob: 0.1, 残差丢弃率 directionality: bidi, hidden_act: gelu,损失函数 hidden_dropout_prob: 0.1,残差 hidden_size: 768,模型维度 initializer_range: 0.02, intermediate_size: 3072,前向传播那里的中间维度 layer_norm_eps: 1e-12, max_position_embeddings: 512,位置长度 model_type: bert, num_attention_heads: 12,注意力头数量 num_hidden_layers: 12,bert层数 pad_token_id: 0, pooler_fc_size: 768, pooler_num_attention_heads: 12, pooler_num_fc_layers: 3, pooler_size_per_head: 128, pooler_type: first_token_transform, type_vocab_size: 2,几种句子 vocab_size: 21128 词汇总数词表1.6 bert的参数量与结构bert模型代码长的原因是其中很多兼容性代码1.6.1 模型参数接下来我们先计算模型参数测试模型是否真的是使用下载下来的文件结论确实会使用自己下载来的bert模型会在同一目录文件夹下去找本地有bert模型参数量为102267648本地无bert尝试自己计算模型参数量emb_num21128*7682*768512*768 #忽略bias偏置 self_att_num768*768*3768*768768*30283028*768 all_att_num12*self_att_num print(emb_numall_att_num)差距很少因为只是少算了些偏置项还可以再看每一层的参数#每一层的参数 for name,para in bert.named_parameters(): print( name, para.shape )报错shape不用加括号size()才需要括号结果如下开头结尾可以发现其中的pooler层是有参数的所以再重新手动计算参数这次加上pooler层差距又变小了但是不是每个模型的pooler层都有参数1.6.2 分词器将padding设为max_length2. data数据集来源某酒店的评价data.py这个文件中我们要产生的是两个dataloader数据文件中没有训练集和验证集需要我们自己来分在哪里去分get_data_loader():函数中去分这里要用到sklearn这个包strip(\n) 可以去除空格split(,,1) 把这句话按 , 来分割分割次数为1stratify按标签的比例对数据进行分割比如此时比例为0.2如果使用stratify那么可以将各个标签之下的数据都分百分之二十出来作为验证集然后注意一下self.Y我们文本中的1和0都是字符型需要转为整形label [int(i) for i in label]然后转为pytorch中的LongTensordata.py代码如下from torch.utils.data import Dataset,DataLoader import torch from sklearn.model_selection import train_test_split from tqdm import tqdm import numpy as np def read_txt_data(path): label [] data [] with open(path, r, encodingutf-8) as f: for i, line in tqdm(enumerate(f)): if i 0: continue #跳过第一行 line line.strip() line line.split(,,1) #1表示分割次数 label.append(line[0]) data.append(line[1]) print(len(data)) print(len(label)) return data, label class My_jdDataset(Dataset): def __init__(self, data, label): self.X data label [int(i) for i in label] self.Y torch.LongTensor(label) def __len__(self): return len(self.X) def __getitem__(self, idx): return self.X[idx], self.Y[idx] def get_dataloader(path, batch_size, val_size0.2): data,label read_txt_data(path) train_data, val_data, train_label, val_label train_test_split(data, label, test_sizeval_size, shuffleTrue, stratifylabel) train_set My_jdDataset(train_data, train_label) val_set My_jdDataset(val_data, val_label) train_loader DataLoader(train_set, batch_sizebatch_size, shuffleTrue) val_loader DataLoader(val_set, batch_sizebatch_size, shuffleFalse) return train_loader, val_loader if __name__ __main__: get_dataloader(../jiudian.txt,batch_size4)这样最重要的模块就写好了3. model要注意的有两处注意tokenizer的输出包含input_ids, attention_mask, token_type_ids需要分别取出bert层有两个输出一个是原始输出一个是池化输出还要记得return_tensorspt 返回张量return_dictFalse 简化输出代码如下import torch import torch.nn as nn from transformers import BertModel, BertTokenizer class myBertModel(nn.Module): def __init__(self, bert_path, num_class): super(myBertModel, self).__init__() self.bert BertModel.from_pretrained(bert_path) self.cls_heads nn.Linear(768, num_class) self.tokenizer BertTokenizer.from_pretrained(bert_path) def forward(self, text): input self.tokenizer(text , return_tensorspt,truncationTrue, paddingmax_length, max_length128) # 注意tokenizer的输出包含input_ids, attention_mask, token_type_ids需要分别取出 input_ids input[input_ids] attention_mask input[attention_mask] token_type_ids input[token_type_ids] # bert层有两个输出一个是原始输出一个是池化输出 sequence_out, pooled_output self.bert(input_idsinput_ids, attention_maskattention_mask, token_type_idstoken_type_ids, return_dictFalse) out self.cls_heads(pooled_output) pass return out modelmyBertModel(../bert-base-chinese,2) predmodel(今天天气不错)4. train要注意的还是只有两点scheduler.step() 可以动态调整学习率每次优化之后就调整学习率torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) 防止梯度爆炸代码如下import torch import time import matplotlib.pyplot as plt import numpy as np from tqdm import tqdm def train_val(para): ######################################################## model para[model] train_loader para[train_loader] val_loader para[val_loader] scheduler para[scheduler] optimizer para[optimizer] loss para[loss] epoch para[epoch] device para[device] save_path para[save_path] max_acc para[max_acc] val_epoch para[val_epoch] ################################################# plt_train_loss [] plt_train_acc [] plt_val_loss [] plt_val_acc [] val_rel [] for i in range(epoch): start_time time.time() model.train() train_loss 0.0 train_acc 0.0 val_acc 0.0 val_loss 0.0 for batch in tqdm(train_loader): model.zero_grad() text, labels batch[0], batch[1].to(device) pred model(text) bat_loss loss(pred, labels) bat_loss.backward() optimizer.step() scheduler.step() optimizer.zero_grad() torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) train_loss bat_loss.item() #.detach 表示去掉梯度 train_acc np.sum(np.argmax(pred.cpu().data.numpy(),axis1) labels.cpu().numpy()) plt_train_loss . append(train_loss/train_loader.dataset.__len__()) plt_train_acc.append(train_acc/train_loader.dataset.__len__()) if i % val_epoch 0: model.eval() with torch.no_grad(): for batch in tqdm(val_loader): val_text, val_labels batch[0], batch[1].to(device) val_pred model(val_text) val_bat_loss loss(val_pred, val_labels) val_loss val_bat_loss.cpu().item() val_acc np.sum(np.argmax(val_pred.cpu().data.numpy(), axis1) val_labels.cpu().numpy()) val_rel.append(val_pred) if val_acc max_acc: torch.save(model, save_pathstr(epoch)ckpt) max_acc val_acc plt_val_loss.append(val_loss/val_loader.dataset.__len__()) plt_val_acc.append(val_acc/val_loader.dataset.__len__()) print([%03d/%03d] %2.2f sec(s) TrainAcc : %3.6f TrainLoss : %3.6f | valAcc: %3.6f valLoss: %3.6f % \ (i, epoch, time.time()-start_time, plt_train_acc[-1], plt_train_loss[-1], plt_val_acc[-1], plt_val_loss[-1]) ) if i % 50 0: torch.save(model, save_path-epoch:str(i) -%.2f%plt_val_acc[-1]) else: plt_val_loss.append(plt_val_loss[-1]) plt_val_acc.append(plt_val_acc[-1]) print([%03d/%03d] %2.2f sec(s) TrainAcc : %3.6f TrainLoss : %3.6f % \ (i, epoch, time.time()-start_time, plt_train_acc[-1], plt_train_loss[-1]) ) plt.plot(plt_train_loss) plt.plot(plt_val_loss) plt.title(loss) plt.legend([train, val]) plt.show() plt.plot(plt_train_acc) plt.plot(plt_val_acc) plt.title(Accuracy) plt.legend([train, val]) plt.savefig(acc.png) plt.show()5. mian这部分用于写超参数和调试运行5.1 超参batchsize4 要小因为文字占显存使用小批量但是又不能太小会引发新的问题epochs5 文字不用太多轮5.2 调试5.2.1 报错pred还在cpu模型也要记得放入gpu报错信息5.2.2 现象val_acc的固定原因1 数据不平衡先修改data让它只读前200张结果valAcc一直为1这是不正常的导致它的原因是我们只取前200张图里面标签全为1所以模型就只会把结果设为一原因2 batchsize太小模型不知道该往哪里走结果模型一直是平的5.2.3 只用架构如果只用大佬们的模型而不用参数结果跳不出数据不平衡的坑因为自己训练的效果太差了对比一下大佬的模型结论就是使用大佬的模型实在是太重要了6. bert代码初始化如下总体结构上的三层经过embedding层16128————》16128768接下来深度分析一下转到BertModel转到BertEncoder转到BertLayer转到BertAttention如下qkv如下第一个token[cls]return_dict False 的原因简化输出作业外卖数据集自己调试bert模型变化暂无
企业数字化 ERP 产品动态
相关推荐
PostgreSQL查询阻塞检测与优化实战 1. 理解PostgreSQL查询阻塞的本质 当PostgreSQL数据库出现性能下降或应用超时,查询阻塞往往是首要怀疑对象。我处理过数十起生产环境阻塞案例,发现90%的DBA新手会直接重启服务,但这就像用消防水管灭蜡烛——不仅过度,还可能引发更… · 2026/11/4 20:33:38
Wireshark抓包入门:从安装到协议分析实战指南 网络这行干久了,你会发现一个挺有意思的现象:排查故障时,大家第一反应往往是 ping 一下通不通、telnet 端口开没开,再不行就重启设备试试。这些手段当然有用,但它们只能告诉你"结果",告诉不了你&… · 2026/11/4 20:33:38
SSH安全远程登录:原理、配置与最佳实践 1. Linux远程登录基础与SSH核心价值作为Linux系统管理员,远程登录服务器是最基础的日常工作。想象一下,当你管理的服务器分布在全国各地的机房,而你需要随时随地进行系统维护时,远程登录技术就是你的"千里眼"和"顺… · 2026/11/4 20:33:38
PHP内存存储方案对比:tmpfs与shmop性能优化实践 1. 项目背景与核心问题在PHP后端开发中,我们经常遇到需要高频读写临时数据的场景。比如会话存储、缓存中间结果、进程间通信等。传统方案是将这些数据写入磁盘文件,但磁盘I/O往往成为性能瓶颈。于是开发者们开始探索更高效的方案——内存存储。本次要对比… · 2026/11/4 20:33:38
IBM PMAT 实战:GC 日志分析与 JVM 调优全流程 简介:IBM Pattern Modeling and Analysis Tool for Java(简称GA)是一款面向Java开发者与系统管理员的GC性能分析与诊断工具,用于解析JDK生成的GC日志,帮助定位GC停顿过长、内存泄漏、分配不合理等性能问题,… · 2026/11/4 20:33:38
基于.NET的微度假平台开发实践与毕业设计指导 1. 项目背景与核心价值最近帮几个计算机专业的学生指导毕业设计,发现"微度假信息交流平台"是个挺有意思的选题。这个项目本质上是用.NET技术栈搭建一个垂直领域的旅游社交网站,专门服务于那些喜欢周末短途游、城市周边游的年轻群体。不同于大型… · 2026/11/4 20:32:36
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38