SimCSE如何实现两次独立dropout?BERT两次dropout输出相同如何解决
SimCSE两次独立dropout原理及代码问题修复
代码输出完全相同的根因
- 从
transformers库加载的预训练模型默认处于评估模式(eval mode),该模式下dropout层、BN层等仅训练阶段生效的组件会被完全关闭,相同输入多次调用模型必然得到完全一致的输出。 - 你当前的代码没有手动开启模型训练模式,因此无法触发两次独立dropout计算。
正确实现代码
只需在调用模型前开启训练模式即可激活dropout层,修改后代码如下:
from transformers import AutoModel, AutoTokenizer import torch bert = AutoModel.from_pretrained('bert-base-cased') tokenizer = AutoTokenizer.from_pretrained('bert-base-cased') sent_dict = tokenizer('Some weights of the model checkpoint at bert-base-cased were not used when initializing BertModel', return_tensors='pt') # 关键:手动开启训练模式,激活dropout bert.train() out1 = bert(**sent_dict).pooler_output out2 = bert(**sent_dict).pooler_output print(torch.allclose(out1, out2)) # 输出为False,代表两次输出存在差异
SimCSE两次独立dropout的核心原理
SimCSE的无监督训练逻辑完全依托BERT原生的dropout实现,核心逻辑如下:
- 把BERT自带的dropout(包括embedding层dropout、transformer块内的attention dropout、全连接层dropout)作为天然的无监督数据增强方式,不需要额外构造正样本。
- 同一句子输入模型两次,每次前向传播走独立的随机dropout掩码,得到两个存在轻微差异的表征,训练时让这两个表征的相似度尽可能高,和同批次其他句子的表征相似度尽可能低,从而让模型学到更鲁棒的语义向量。
- 全程不需要修改BERT内部结构,仅需要保持模型在训练模式即可实现。
注意事项
- 如果你的训练代码固定了全局随机种子,两次调用模型前需要重置随机种子才会得到不同的dropout结果,否则固定种子下两次dropout掩码完全一致,输出也会相同。
- 推理阶段需要切换回
bert.eval()模式关闭dropout,保证相同输入的输出稳定。
内容的提问来源于stack exchange,提问作者user17377708
相关产品推荐
相关产品推荐

