NOAI 2025 复赛题解|第1题:9万个德语词,10分钟,拆得完吗?
NOAI复赛 自然语言处理
需要真题、资料,请拉到文末添加艾斯老师微信。
题目回顾
德语有大量组合词,由多个短词拼在一起。给一份数据集,每个样本是一个组合词和一个 0-1 数组:1 表示该字符是某个短词的最后一个字母。
"Sprachbereich": [0,0,0,0,0,1,0,0,0,0,0,0,1] → "Sprach" + "bereich"
训练集 94,306 条,验证集 11,788 条,测试集 11,789 条。GPU 训练+测试不超过 10 分钟。评分 = 平均 F1-score。
这是一个序列标注问题
不要被"德语"吓到 😂 你不需要懂德语。
本质是:给一个字符序列,预测每个位置是 0 还是 1。跟中文分词、命名实体识别是同一类问题。
思路一:字符级 BiLSTM
每个字符当作一个 token,Embedding + BiLSTM + Linear 逐位置预测。
class CharSegmenter(nn.Module): def __init__(self, vocab_size, embed_dim, hidden_dim): super().__init__() self.embedding = nn.Embedding(vocab_size, embed_dim) self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True, bidirectional=True) self.fc = nn.Linear(hidden_dim * 2, 1) def forward(self, x): x = self.embedding(x) out, _ = self.lstm(x) return self.fc(out).squeeze(-1)
字符词表只有几十个(a-z + ä/ö/ü/ß),Embedding 维度 32~64 够了。双向是因为判断词尾需要同时看前后文。
思路二:CNN + LSTM
在 LSTM 前加一层 1D 卷积,先提取局部 n-gram 特征。德语中 "ung"、"heit"、"keit" 都是常见词尾后缀——CNN 擅长捕捉这种固定长度模式,LSTM 擅长捕捉长距离依赖。两者互补。
思路三:纯 CNN
叠几层不同 kernel_size(3、5、7)的 1D 卷积。纯 CNN 比 LSTM 快很多,10 分钟内可以跑更多 epoch。F1 可能略低,但如果 BiLSTM 只能跑 5 个 epoch,纯 CNN 能跑 20 个——epoch 不够模型就没训好。
数据处理的关键
• 类别不均衡:大部分位置是 0,分割点(1)很少。用加权 BCEWithLogitsLoss,给正样本更高权重
• 最后一个字符永远是 1:每个词的末尾一定是分割点。预测时直接把最后一位设成 1,免费多对一个位置
• 统一转小写:德语名词首字母大写,转小写可以减少词表、让模型更容易学到规律
容易踩的坑
坑 1F1 是逐分词算的,不是逐字符
预测的分词起止位置必须和真实完全一致才算正确。错一个字符,整个分词就判错。"差一点"和"差很多"的惩罚一样。
坑 210 分钟 GPU 限时
9 万条训练数据不算小。先跑 1 个 epoch 看耗时,推算能跑几个 epoch,留 1~2 分钟给测试。选模型时要把时间成本算进去。
区分度在哪
• 认清这是序列标注问题,选对模型架构
• BiLSTM 和纯 CNN 的取舍——取决于对 10 分钟限制的把握
• 类别不均衡处理 + F1 评分规则的精确理解
• 最后一位一定是 1 这个先验——用了就多对一个位置 🎯
这道题的难度不在 NLP 知识,在时间管理和对评分规则的精确理解。