尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

长文本新闻情感分析实战:BERT分段+GRU显存优化与预训练模型微调

发布时间:2026/9/28 22:30:15

资讯中心
01
ARTICLE

长文本新闻情感分析实战:BERT分段+GRU显存优化与预训练模型微调

长文本新闻情感分析实战:BERT分段+GRU显存优化与预训练模型微调
简介面向计算机相关专业课程设计、毕业设计及期末大作业场景这份新闻情感分析系统以预训练模型BERT/BERT-wwm为核心整合roberta_wwm_ext_large、roberta_large等模型进行文本分类支持数据kfold处理、信息查看、多模型投票ensemble以及训练结果自动存档可帮助学习者快速搭建完整的情感分析实验流程。压缩包共128个文件约2.72MB以py源码为主70个辅以sh训练脚本、pyc编译文件、csv数据与md项目说明目录划分清晰backup-models、data、pretrained_model、ensemble_submits等模块便于直接对照使用。资源附有项目说明和真实训练/测试数据集详细给出了从数据预处理、kfold划分到修改run_xxxx.sh参数、单卡/多卡显存配置及梯度累积策略的完整指引并支持训练完成后自动保存模型与结果。目前已有255人学习下载整体方案验证可运行适合需要动手实践NLP分类任务的入门进阶用户也可直接作为课程设计或毕设初期的项目基础。1. BERT-wwm新闻情感分析项目能跑通也能改的预训练模型实战资源期末大作业要做新闻情感分析最省力的思路是拿一个预训练模型直接finetune但网上现成代码大多只处理短文本碰到动辄上千字的新闻就尴尬要么截断丢信息要么直接爆显存。这个项目的思路很有意思把一条新闻截成k段分别输入BERT这类预训练模型再用GRU在顶层把各段结果拼接起来显存占用从平方级降到线性。整套资源基于python实现提供了roberta_wwm_ext_large和roberta_large两套中文预训练模型方案含完整数据集、训练脚本、kfold切分和投票ensemble适合课程设计、毕业设计和第一次接触预训练模型的NLP初学者。我把这份资源完整拆了一遍下面从目录结构讲到你最关心的显存参数和踩坑点。2. 项目结构与数据流从文件名看懂训练主流程这套项目没有把代码堆在一个notebook里而是按训练流程拆成了目录和脚本。先看懂目录等于先看懂整个pipeline这比直接上来跑run脚本要稳得多。和很多只给一个main.py的毕业设计源码不同这个项目的backup、data、pretrained_model、ensemble_submits分工明确每个环节都有对应入口。我建议下载后先把目录结构过一遍再动手跑任何脚本。# 只看目录层级避免文件列表刷屏 tree -L 2 -d .-d只显示目录-L 2限制两层。如果你的机器没有tree用find . -maxdepth 2 -type d效果一样。到这一步你只需要确认目录是否完整不完整的话后面会具体报错在哪个环节。2.1 文件目录速览哪类文件负责哪一段训练目录/文件职责backup-models训练完成后自动存档模型与输出结果data存放train.csv/test.csv数据分析与kfold切分也在这里完成pretrained_model放置中文预训练模型权重run_bert.py具体训练代码模型结构、loss、训练循环都在这里run_bert.sh训练入口脚本max_seq_length、batch_size等参数在sh里配置preprocess.py读取csv完成数据预处理并按kfold切分analysis.py分析数据集分布、类别比例、文本长度combine.py对多个模型的输出结果做投票ensembleensemble_submits存放融合后的结果文件这么多文件初看会慌其实关键入口只有一个先跑analysis.py看数据再跑preprocess.py切分数据然后bash run_bert.sh开始训练最后把多个模型的result文件交给combine.py投票。项目根目录还会看到modeling_bert.py、modeling_utils.py、test_sentencepiece.model这类文件这是为了兼容老版本transformers而打包进来的建模代码和分词资源日常训练不会直接改动但别删某些tokenizer初始化时会去读它们。值得一提的是backup-models我切换模型重训时特别依赖它。它会在每次训练后自动把模型权重、配置、运行结果存一份调参失败想回退直接翻它就行不用重新训练。另外run目录里可能有xlnet相关文件但项目说明里xlnet_large标注了to do先绕过它别浪费时间。2.2 数据文件格式train.csv、test.csv、submit_example.csv各管哪一段这是一个标准的文本分类任务监督学习必须有标注数据。train.csv用于训练和验证test.csv用于最终预测submit_example.csv是提交模板。先用命令看一眼实际内容cd data wc -l train.csv test.csv submit_example.csv head -5 train.csvwc -l统计行数一眼能看出训练集规模这决定了你用base模型还是large模型。head -5看表头和样例确认哪一列是文本、哪一列是标签。新闻情感二分类通常要么是两列文本、标签要么带id列具体列名以你手中的csv表头为准不要假设。我见过有人把id列和text列位置搞反预处理阶段直接报错所以这一步别跳。submit_example.csv是提交模板字段必须和最终result一致。课设平台一般就比对两列id和预测标签。后面第6章会写一个自检脚本就是拿这个文件当标尺。2.3 完整训练流程从数据到投票一条命令穿起来cd data python analysis.py # 查看数据分布 cd .. python preprocess.py # 预处理 kfold 切分 bash run_bert.sh # 训练首个模型 bash run_roberta_wwm.sh # 训练第二个模型可选用于后续投票 python combine.py # 对多个结果投票融合第一步分析数据是为了下游决定max_seq_length和是否做类别平衡第二步预处理会按kfold把train.csv切成训练集和验证集保证每次实验的验证指标不抖第三步是真正的训练如果显存和时间允许再跑一个不同结构的模型最后combine.py做投票。投票ensemble通常比单模型更稳两个模型一个roberta_wwm_ext_large、一个roberta_large结构有差异融合后错误相关性低不用调参就能白捡一点准确率。实际操作时先把sh脚本里的参数保持默认能跑通再去动参数默认配置翻车概率最小。3. 数据预处理与kfold二分类改多分类要动四处新闻情感分析项目默认是二分类如果你做的是多分类毕业设计比如把新闻分成6类情绪不能只改一个“类别数”数字。项目把这部分分散在多个文件里漏改任何一处都会导致标签错乱甚至loss变成nan。我先从数据分析讲起再讲改多分类时要动的四处。3.1 先用analysis.py看数据分布类别不均衡比想象中常见cd data python analysis.py这个脚本会把训练样本量、列名、每个类别的样本数、文本长度分布打印出来。这些输出对后续参数设置很关键文本普遍在1000字以上那max_seq_length乘以split_num就要设到1024左右如果某一类只占5%直接训练得到的acc虚高对少数类基本是废的。如果不放心脚本输出用pandas手动核一下import pandas as pd df pd.read_csv(data/train.csv) print(df.shape) # 行数和列数 print(df[label].value_counts()) # 各类别样本量列名按实际数据改value_counts()按类别数量降序排列加normalizeTrue可以看占比。这里特别注意df[label]里的取值要和后面num_labels对得上。比如二分类数据里只有0和1你改成6分类但数据本身只有两类训练不会报错但predict阶段永远只会输出0和1性能上限锁死。这一步是核对数据不是跑流程走过场。3.2 执行preprocess.pykfold切分是怎么落盘的python preprocess.pypreprocess.py做两件事一是把文本和标签按模型需要的格式整理二是按kfold把训练集切成k份轮流做验证集。折数一般能直接在脚本里看到常见写法是KFold(n_splits5)5折就是做5次完整训练每次用其中4折训练、1折验证最后指标取平均。如果你的课设数据量只有几千条5折完全够用数据量大、训练时间紧改成3折也能接受。切分完成后data目录下会多出fold相关文件run脚本会自动读取。注意preprocess.py和run_bert.py是配套的如果你改过train.csv的列名或者改了标签映射这边要同步改。只改一边的结果通常是在训练log里看到Num examples少了一半或者类别数对不上直接报错。3.3 二分类改多分类四个位置的联动修改这个项目二分类时run_bert.py底层的输出大概率是这个模式num_labels 2 logits model(...) # [batch, 2] loss_fct nn.BCEWithLogitsLoss() # 二分类专用改成6分类至少要动四个地方。第一preprocess.py里的标签映射要加上所有新类别第二run_bert.py的num_labels改成6同时把BCEWithLogitsLoss换成CrossEntropyLoss第三预测阶段原来用sigmoid再按0.5阈值多分类要改成softmax后取argmax第四combine.py投票时不能再按二分类的票数阈值判而是把各家模型的概率平均后取最大值。# preprocess.py 中的标签映射从 0/1 扩展到 0~5 label_map {负向: 0, 正向: 1, 中性: 2, ...} # 以你的数据标签为准 # run_bert.py 中的改动 num_labels 6 loss_fct nn.CrossEntropyLoss() # 分类数大于2时别再抱sigmoid pred logits.argmax(dim-1) # 预测时直接取最大概率的下标 # combine.py 中的改动多个模型平均概率后取最大值 probs sum([model_probs[i] for model_probs in results]) / len(results) final_label probs.argmax(axis1)上面是示意代码以实际文件为准。为什么必须联动num_labels决定输出维度loss决定梯度怎么算输出层决定pred怎么读投票层决定融合怎么判。只改第一个后面三个还按二分类逻辑走结果是loss对不上、预测全是一个类。我当年改多分类漏了loss跑了20个epoch看acc一路直线浪费一下午这个坑第5章再细说。4. 长文本分段与显存预算max_seq_length、split_num、batch_size怎么配这个项目最核心的设计就是对长文本的处理策略也是和网上大部分BERT情感分析代码拉开差距的地方。项目说明里写得很清楚将文本截成k段分别输入语言模型顶层用GRU拼接。这不是炫技是实打实的显存优化。4.1 为什么整篇新闻不能一次塞进BERT预训练模型对输入长度有硬上限BERT类模型通常是512 token新闻文本动辄上千字。有人直接截断前512但新闻观点往往在文末或者由后半段决定截断等于让模型盲猜。而在显存层面transformer的注意力矩阵随序列长度平方增长输入翻倍那部分显存翻四倍小卡硬塞整篇长文本立刻爆。用一个小脚本感受一下这个量级total_len 1024 # 一篇新闻的实际token数 for k in (1, 2, 4, 8): seg_len total_len // k cells k * seg_len * seg_len print(fk{k:2d} 每段长度{seg_len:4d} attention量≈{cells/1e6:.2f}M)k1时是1.05M个元素k8时约0.13M差8倍。这不是精确的显存占用但attention logits矩阵是最主要的显存消耗之一量级差距是实打实的。这就是为什么这个项目要把长文本切成k段分别处理而不是硬塞。4.2 分段输入GRU拼接显存从平方级降到线性项目说明里的原话是“将文本截成k段分别输入语言模型然后顶层用GRU拼接起来”。实际做法通常是整篇文本按token切k段每段分别过预训练模型然后把每段的输出向量按顺序喂给GRUGRU最后输出代表整篇文档的表示再送到分类层。这样显存占用里与长度平方相关的部分被大幅压缩代价是训练时间随k线性上涨。关键公式实际输入长度 max_seq_length × split_num同样处理1024字你可以配512×2、256×4、128×8。分段越多单段attention矩阵越小显存更低但每段过短会丢失句子级上下文。切分边界通常按token或标点就近切避免把句子拦腰截断具体看preprocess.py里怎么实现。参数组合实际输入长度显存压力适用场景max_seq_length512, split_num1512基准文本短、显存充足max_seq_length256, split_num41024中等常见新闻长文本默认首选max_seq_length128, split_num81024较低单卡小显存max_seq_length128, split_num162048更低但质量下降超长文本探索没有绝对最优组合我一般用256×4起步既覆盖常见新闻长度显存压力也可控。如果实测显存还剩很多就把max_seq_length加到384或512观察acc变化。4.3 batch size、梯度累积与GPU数量一条公式和一组实践值batch size公式来自项目说明实际batch size per_gpu_train_batch_size × GPU数量多卡脚本样例里per_gpu是44卡总batch是16。单卡要去掉乘数。显存不够用gradient_accumulation_steps它让模型跑N次小batch后再更新一次参数等效于更大的batch但速度慢N倍训练步数要相应调高。# 单卡 小显存的 roberta_wwm_ext_large 训练配置 export CUDA_VISIBLE_DEVICES0 # 只使用一张卡 MAX_SEQ_LENGTH128 # 每段长度 SPLIT_NUM8 # 分段数实际长度128*81024 PER_GPU_TRAIN_BATCH_SIZE2 # 单卡batch GRADIENT_ACCUMULATION_STEPS4 # 累积4次等效batch8 TRAIN_STEPS10000 # 步数翻倍因为梯度更新频率低这样配置单次显存压力被拆成4份模型更新节奏等价于batch8。跑起来以后第一时间看log里三行数字Num examples、Batch size、Num steps。如果显示Batch size2而不是你脑补的8说明log打印的是per_gpu值核对时要把GPU数和累积步数乘进去。如果显存占用率稳定在80%上下说明参数合适还有余量就把PER_GPU_TRAIN_BATCH_SIZE调大一级。理解了这条公式调参就没有玄学。5. 避坑排查新闻情感分析训练中最常见的五个翻车点这五个问题是我实际复现这个项目时碰到过或见别人频繁问的按“现象→原因→解决”记录照着排查能省一个下午。5.1 显存OOMsplit_num调大了max_seq_length却还在现象训练跑到一半日志忽然报CUDA out of memory前面还好好的。原因很多人以为只要分段就省显存于是把split_num从4改成8但max_seq_length还是256实际长度从1024变到2048反而更费显存。分段省显存的前提是实际输入长度不变不是无脑加大k。解决先算max_seq_length乘split_num固定目标长度再去调参数。1024字的新闻用128×8或256×4而不是256×8。改完参数用nvidia-smi实时看显存占用峰值不超过卡显存的90%才敢继续跑。5.2 Batch size4但单卡跑不动per_gpu不是总batch现象从项目多卡脚本复制参数per_gpu_train_batch_size4单卡直接爆。原因per_gpu的意思是每张GPU的量。项目原本用4卡模型权重占的显存被摊到4张卡上单卡要同时放下完整模型和4条样本加上max_seq_length可能还是512爆掉很正常。原文也提醒过如果只有1卡batch建议设4但max_length要调小这两者是联动的。解决单卡先把per_gpu_train_batch_size调到2max_seq_length降到128split_num按长度补上跑通后逐步加batch以显存不涨到90%为界。不要从多卡配置直接照搬。5.3 多分类改了num_labels预测结果全是同一个类现象二分类改成6分类训练loss正常下降predict时所有样本输出同一个标签acc就像没训过。原因只改了num_labels没改loss和输出层。二分类用BCEWithLogitsLosspred取sigmoid后按0.5阈值多分类得用CrossEntropyLosspred取softmax后的argmax。两者混用模型学到的是错误的目标分布。解决按第3.3节统一改四处。改完跑预测前先核对logits形状import torch # 假设已经拿到模型输出 logits model(batch)[logits] if hasattr(model, logits) else model(batch) assert logits.size(-1) num_labels如果形状还是2说明模型配置里输出维度没吃到num_labels参数去检查项目里的建模文件和config配置。5.4 ensemble投票时行数对不上先按id排序再合并现象用combine.py融合两个模型的result.csv报错说行数不一致或者融合结果缺行、错位。原因不同模型预测时样本顺序可能不同比如roberta run在kfold之后重新shuffle了数据两个csv的行顺序错开按行索引合并必然错位。解决投票前先按id列排序再合并import pandas as pd result_bert pd.read_csv(output_bert.csv).sort_values(id) result_rbt pd.read_csv(output_roberta_wwm.csv).sort_values(id) assert len(result_bert) len(result_rbt)排序后两个DataFrame的行一一对应再喂给combine.py。最终结果出来后还要和submit_example.csv比对行数这在第6章展开。5.5 预训练权重加载失败目录缺文件或形式不对现象启动训练报找不到pytorch_model.bin或者加载时出现KeyError、模型结构对不上。原因pretrained_model目录下放的是老版本的ckpt文件或者缺少文件。transformers加载预训练模型要求目录里同时有模型权重文件、config、vocab文件文件名和代码里写死的路径还要一致。解决先列出目录确认文件齐全ls pretrained_model/roberta_wwm_ext_large/期望能看到pytorch_model.bin和config相关文件。缺哪个补哪个权重下载时注意选pytorch版本而不是tensorflow版本否则load进来是乱码。项目根目录带的那几个modeling_bert.py是早期transformers的实现如果你用的是新版库优先用transformers自带的类避免旧类和新版config不兼容。6. 提交前自检用三行脚本对齐result.csv与submit_example.csv训练跑完、多个模型也融合完result.csv生成之后大部分人直接就交了然后被平台提示文件格式不对。这类问题不在模型在数据格式解决成本三分钟但翻车率极高。6.1 backup-models是你的后悔药先确认存档生成了这个项目训练结束后会自动把模型、配置和输出结果存到backup-models按次分开目录。我调参失败、想回到上一版结果时直接翻这个目录拿回对应的模型权重和result文件不用重新训练。很多类似源码不会自动存档这份资源在这点做得比较省心。提交前先看一眼backup-models里有没有最新一次的存档有就说明这次实验完整闭环了。6.2 三行自检脚本把它放进每次提交前# check_submit.py提交前强制运行 import pandas as pd result pd.read_csv(result.csv) template pd.read_csv(data/submit_example.csv) assert result.shape[0] template.shape[0], 行数不一致检查漏样本 assert list(result.columns) list(template.columns), 列名不一致检查输出格式 assert not result.isnull().any().any(), 存在NaN无法直接提交 print(自检通过可以提交)要过三件事行数完全相等列名顺序和模板一致不能有NaN。这三条只要过了提交阶段基本不会再翻车。如果跑了ensemble建议把自检放到combine.py执行完的最后一行每次融合完自动触发。从那以后我每次提交前都强制把自检脚本跑一遍哪怕只是改了一个batch size也会顺手验证格式没被破坏。这个习惯帮我避开了好几次“模型acc不错交上去全是无效行”的尴尬。这套资源本身已经做了自动存档再配上这个小脚本整个训练到提交的流程就比较稳了希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。