当前位置: 首页 > news >正文

【实战】自然语言处理--长文本分类(1)DPCNN算法

1.数据集

1. 来源与简介

  • 名称:THUCNews
  • 发布机构:清华大学自然语言处理与社会人文计算实验室(THUNLP)
  • 规模:约 740 万篇中文新闻文本(完整版),本次使用子集共计 65 000 条样本
  • 任务类型:多分类文本分类,针对长文本新闻内容进行主题判别

2. 本次使用的子集

文件名样本数说明
cnews.train.txt50 000训练集
cnews.val.txt5 000验证集
cnews.test.txt10 000测试集

每行格式通常为:

<类别标签>\t<新闻正文文本>

3. 类别分布

本次精选了其中 10 个主题类别:

  1. 体育
  2. 财经
  3. 房产
  4. 家居
  5. 教育
  6. 科技
  7. 时尚
  8. 时政
  9. 游戏
  10. 娱乐

各类别样本数大致均衡,均在 5 000~7 000 条左右,可有效避免类别极度倾斜。

4. 文本特点

  • 平均长度:每篇新闻正文常在 500~2 000 字之间,属于中长文本范畴。
  • 内容风格:覆盖新闻报道、评论、特写、资讯等多种写作风格。
  • 语言特点:专业术语、专有名词较多,需做好词表扩充或使用预训练模型词表。

2.DPCNN算法

在这里插入图片描述

1. 算法定义与背景

Deep Pyramid Convolutional Neural Network(DPCNN)是一种针对长文本分类任务设计的深度卷积神经网络,首次发表于 2016 年。它在传统卷积神经网络(CNN)基础上引入金字塔式下采样和残差连接,旨在以更少的参数和计算开销,高效捕获长文本的全局与局部特征。

2. 核心原理

2.1 区域嵌入(Region Embedding)

代码位置:模型初始化中 self.region_conv = nn.Conv1d(...)

# 在 DPCNN.__init__ 中
self.region_conv = nn.Conv1d(in_channels=self.embedding_dim,out_channels=self.num_filters,kernel_size=3,padding=1
)
  • 作用:将词向量在局部窗口内(3-gram)进行卷积运算,提取低层次 n-gram 特征。
  • 输入/输出维度
    • 输入:(batch_size, embedding_dim, seq_len)
    • 输出:(batch_size, num_filters, seq_len)

2.2 卷积块与残差连接(ConvBlock + Residual)

代码位置

for i in range(self.repeat_blocks):block = nn.Sequential(nn.ReLU(),nn.Conv1d(self.num_filters, self.num_filters, kernel_size=3, padding=1),nn.ReLU(),nn.Conv1d(self.num_filters, self.num_filters, kernel_size=3, padding=1),)self.conv_blocks.append(block)
  • 每个 ConvBlock 包含两层带 ReLU 的一维卷积。

  • 残差连接

    • 第一个块不下采样: out = block(x); x = x + out
    • 后续块先池化再卷积:
      x = self.pool(x)
      out = block(x)
      x = x + out
      
  • 残差结构保证深层网络中梯度稳定传递,加速收敛。

2.3 金字塔下采样(Pyramid Pooling)

代码位置self.pool = nn.MaxPool1d(kernel_size=3, stride=2, padding=1)

  • 每隔一个 ConvBlock,通过池化将序列长度减半。金字塔式下采样使感受野逐层扩大,兼具全局信息。
  • 下采样后的序列长度 L' = ceil((L + 2*pad - kernel) / stride + 1) ≈ L/2

3. 模型结构流程(结合 forward 代码)

def forward(self, x):# 1) Embedding: [B, L] -> [B, L, E]x = self.embedding(x)# 2) Dropout + 转置: [B, L, E] -> [B, E, L]x = self.embed_dropout(x).transpose(1, 2)# 3) 区域卷积: [B, E, L] -> [B, F, L]x = self.region_conv(x)# 4) 首个残差块x = self.embed_dropout(x)for idx, block in enumerate(self.conv_blocks):if idx == 0:out = block(x)x = x + outelse:# 5) 下采样 + 残差x = self.pool(x)out = block(x)x = x + out# 6) 全连接输出logits = self.fc(x)return logits
  1. Embedding → Dropout:对输入词 ID 序列进行向量化并随机失活。

  2. 区域卷积:提取初级局部特征。

  3. 卷积+残差

    • 第一个 ConvBlock:保持序列长度。
    • 后续块:池化后卷积,序列长度逐步缩减。
  4. Flatten → FC:将最终特征图展平,输出 num_classes 类别得分。

4. 代码流程详解

4.1 数据预处理与词表

# 清洗与分词
def clear_text(text):p = re.compile(r"[^一-龥0-9a-zA-Z\-…]")return p.sub('', text)def tokenize(text):text = clear_text(text)segs = jieba.lcut(text)return [w for w in segs if w not in STOPWORDS_SET]
  1. 正则只保留中英文、数字和常用标点。
  2. jieba.lcut 精准分词,去掉停用词。
# 词表构建或加载
def load_or_build_vocab(texts, force_rebuild=False):if os.path.exists(counter_path) and not force_rebuild:vocab = pickle.load(open(counter_path, 'rb'))else:vocab = build_vocab_from_iterator(map(tokenize, texts),max_tokens=total_words,specials=['<unk>','<pad>'])with open(counter_path, 'wb') as f:pickle.dump(vocab, f)vocab.set_default_index(vocab['<unk>'])return vocab
  • 保存词表映射 word->index,并添加 <unk><pad>

4.2 数据加载与迭代

def load_data(path, train=False, vocab=None):texts, labels = read_data(path)if train:vocab = load_or_build_vocab(texts, force_rebuild=True)else:if vocab is None:vocab = pickle.load(open(counter_path, 'rb'))dataset = TextDataset(texts, labels, vocab, doc_maxlen)loader = DataLoader(dataset, batch_size=batch_size,shuffle=train, collate_fn=collate_fn)return loader, vocab
  • 训练阶段重建词表;验证阶段仅加载或复用。
  • TextDataset 中将文本切分、映射为固定长度 ID 序列。

4.3 训练与验证

def train_step(model, batch, optimizer):model.train()x, y = batchoptimizer.zero_grad()logits = model(x.to(device))loss = loss_func(logits, y.to(device))loss.backward()optimizer.step()pred = logits.argmax(dim=1).cpu().numpy()acc = accuracy_score(y.numpy(), pred)return loss.item(), acc
  • 反向传播:计算梯度并更新参数。
  • 指标:使用 accuracy_score 评估批准确率。
@torch.no_grad()
def validate_step(model, batch):model.eval()x, y = batchlogits = model(x.to(device))loss = loss_func(logits, y.to(device))pred = logits.argmax(dim=1).cpu().numpy()acc = accuracy_score(y.numpy(), pred)return loss.item(), acc
  • 在验证集上关闭梯度计算,加快速度并节省显存。

4.4 完整训练循环

for epoch in range(1, EPOCHS+1):# 训练for batch in train_loader:train_loss, train_acc = train_step(model, batch, optimizer)# 验证for batch in val_loader:val_loss, val_acc = validate_step(model, batch)# 日志记录 & 模型保存if val_acc > best_acc:torch.save(...)
  • 每轮完成后打印损失/准确率,保存最佳模型。

5. 优缺点与扩展

优点

  • 高效:金字塔下采样显著减少序列长度,降低计算开销。
  • 易训练:残差连接缓解梯度消失。
  • 参数量少:相比 RNN/LSTM 速度更快。

缺点

  • 信息丢失:下采样会丢弃部分细节。
  • 感受野固定:卷积核及层数需手工调优。

可扩展方向

  • 多通道卷积:引入不同窗口大小并行卷积。
  • 注意力机制:在下采样后加入自注意力,补充全局依赖。
  • 层次化融合:结合 HAN、Transformer 架构,提高长依赖捕获能力。

3.补充问题

DPCNN的超参数

  1. total_words = 20000
    只保留训练语料中出现频率最高的 20,000 个词,其余词都映射为 <unk>

    • 作用:控制词表大小,减少稀有词带来的噪声和计算开销。
    • 对长文本的影响:即使文本很长,也只会按最大词表截断——所有低频词统一处理成 <unk>,保证序列长度和词表维度都在可控范围内。
  2. doc_maxlen = 500
    每条文本被截断或填充到 500 个词(token)。

    • 截断:若文本长度 > 500,则只保留前 500 个 token,丢弃后面的部分。
    • 填充:若文本长度 < 500,则在尾部补 <pad> 直至长度为 500。
    • 对长文本的影响:通过固定长度让所有输入张量尺寸统一。500 足以覆盖大多数新闻文章主体,同时截掉过长尾部,兼顾效率与完整性。
  3. net_depth = 20
    网络的总层数(区域嵌入层 + 若干卷积块 ×2 + 池化层),决定模型金字塔的高度。

    • 每两个卷积块后,下采样一次;20 层可以支持约 9~10 次下采样(实际到序列长度变为 1 时停止)。
    • 对长文本的影响:更多深层意味着能对序列进行更多次的半速下采样,把原来 500 长度的序列,逐步缩减到几十、几级、直至 1,从而在最顶层获得整个文本的全局表征。
  4. batch_size = 1024
    每批在显存中同时处理 1024 条文本。

    • 对长文本的影响:虽然每条是 500 长度的张量,但大 batch size 能更高效利用 GPU 并行计算;如果显存不足,可调小。
  5. 其他超参数

    • embedding_dim = 200:词向量维度;影响每个词的表达能力。
    • LR = 5e-4 & EPOCHS = 30:学习率和训练轮数,影响收敛速度与最终效果。

DPCNN如何处理长文本

  • 固定长度截断/填充:先把所有文本统一到 doc_maxlen = 500,保证输入张量尺寸一致。

  • 区域嵌入(3-gram 卷积):在长度为 500 之上先做一次 1D 卷积,提取局部 n-gram 特征。

  • 金字塔式下采样

    • 每经过两个卷积块,就通过 MaxPool1d(kernel=3, stride=2, padding=1) 将序列长度减半。
    • 层层下采样后,从 500 → ~250 → ~125 → … → 1(或很小),最后得到一个定长的特征图,融合了全局信息。
  • 残差连接:每个卷积块前后的输入相加,保证即便文本很长,梯度也能顺畅向底层传递,不会在深层网络中消失。

这种“先定长截断 + 多次半速下采样 + 残差加速”的策略,使 DPCNN 能高效地处理和表征长文本,并在顶层快速聚合全局语义。

DPCNN就像是嵌套多层的漏斗

这个过程就像一个漏斗:

  • 顶部宽大(原始文本长度长、信息多),
  • 每经过一层卷积+池化,就压缩一次长度、升华语义,最终汇聚到底部的“分类表示”。
层级序列长度(示意)特征维度(num_filters)
输入文本500200(embedding_dim)
conv1×1500250
block1500250
pool1250250
block2250250
pool2125250
block3125250
pool362250
blockN1250
FC输出-10(类别数)
http://www.dtcms.com/a/520438.html

相关文章:

  • 兰州网站建设多少钱网页制作和设计实验目的
  • 专门做动漫的网站有哪些网站开发文件结构组成
  • Flexbox
  • `.bat`、`.cmd`、`.ps1`的区别
  • MySQL 安装教程(Windows 版):从入门到配置全流程
  • 网站建设责任分解杭州市建筑业协会官网
  • 【数据库】MySQL数据库基础
  • 四川省建设厅官方培训网站网站顶部
  • 图解Vue3 响应式,手动实现核心原理
  • 压缩与缓存调优实战指南:从0到1根治性能瓶颈(三)
  • 【设计模式】外观模式/门面模式(Facaed)
  • 矽塔 SA8206 36V/2.5A 过压/过流保护芯片
  • 莱州做网站网站建设给客户看的ppt
  • Windows - Maven 安装到 IDEA 配置全流程
  • java填充word模版导出word文件支持导出pdf,支持本地下载和网络下载,使用jar包
  • 网络安全:Apache Druid 安全漏洞
  • 宁波公司建站模板wordpress用户调用
  • 70%的RAG性能与分块有关
  • 足球网站开发外贸网站优化推广
  • Uncertainty-Aware Null Space Networks for Data-Consistent Image Reconstruction
  • 孝感网站seodw做网站的导航栏怎么做
  • LeetCode 每日一题 166. 分数到小数
  • 封面论文丨薄膜铌酸锂平台实现强耦合电光调制,《Light Sci. Appl. 》报道机器学习优化新范式
  • 做外贸找产品上哪个网站好flash素材网站有哪些
  • Rust内存安全:所有权与生命周期的精妙设计
  • 2510rs,稳定裸函数
  • 西安住房建设局网站首页企业网站 设计需求
  • LangChain:让大模型具备思考与行动能力的框架
  • MySQL 及 SQL 注入详细说明
  • 医院移动护理系统源码,JAVA移动护理系统源码,医院移动护士站源码