如何识别句子中影响特定情感类别的词汇?附Transformer模型代码
找出Transformer情感分析中驱动情感类别的词汇实现思路
你当前使用nlptown/bert-base-multilingual-uncased-sentiment完成情感分类,要定位导致最终情感类别的关键词汇,以下是三种实用的实现思路,可直接结合你的现有代码调整:
1. 基于注意力权重的分析
Transformer的注意力机制天然能反映每个token对最终输出的贡献度,通过提取对应情感类别的注意力权重,就能定位关键词汇:
- 实现步骤:
- 修改模型前向传播,让模型返回注意力权重;
- 对最后一层(或多层)的注意力权重取平均,映射到每个输入token;
- 按权重排序,筛选出权重最高的若干token。
- 代码示例:
import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification MODEL = "nlptown/bert-base-multilingual-uncased-sentiment" tokenizer = AutoTokenizer.from_pretrained(MODEL) model = AutoModelForSequenceClassification.from_pretrained(MODEL) txt = "你的测试文本" # 编码文本并获取注意力权重 tokens = tokenizer.encode_plus(txt, add_special_tokens=True, return_tensors='pt') outputs = model(**tokens, output_attentions=True) # 提取最后一层注意力权重,取多头注意力的平均值 last_layer_attn = outputs.attentions[-1] # shape: (1, num_heads, seq_len, seq_len) avg_attn = last_layer_attn.mean(dim=1).squeeze(0) # shape: (seq_len, seq_len) # 取<CLS> token对其他token的注意力(因为<CLS>对应最终分类输出) cls_attn = avg_attn[0][1:-1] # 去掉<CLS>和<SEP>对应的权重 # 映射token和权重 input_tokens = tokenizer.convert_ids_to_tokens(tokens['input_ids'][0])[1:-1] token_attn_pairs = list(zip(input_tokens, cls_attn.tolist())) # 按权重降序排序 token_attn_pairs.sort(key=lambda x: x[1], reverse=True) print("按注意力权重排序的关键词汇:") for token, attn in token_attn_pairs[:5]: # 取top5 print(f"{token}: {attn:.4f}")
2. 基于梯度的特征重要性(Integrated Gradients)
通过计算每个token嵌入对目标情感类别概率的梯度,梯度绝对值越大,说明该token对结果的影响越强:
- 实现步骤:
- 将token输入设置为可求导;
- 计算目标类别概率对token嵌入的梯度;
- 对梯度取绝对值并平均,映射到token后排序。
- 代码示例:
import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification MODEL = "nlptown/bert-base-multilingual-uncased-sentiment" tokenizer = AutoTokenizer.from_pretrained(MODEL) model = AutoModelForSequenceClassification.from_pretrained(MODEL) txt = "你的测试文本" sen_dict= {1:'Highly-negative',2:'Negative',3:'Neutral',4:'Positive',5:'Highly-positive'} # 编码文本,保留token嵌入并设置可求导 tokens = tokenizer.encode_plus(txt, add_special_tokens=True, return_tensors='pt') input_ids = tokens['input_ids'] embeddings = model.get_input_embeddings()(input_ids) embeddings.requires_grad = True # 前向传播获取输出 outputs = model(inputs_embeds=embeddings, attention_mask=tokens['attention_mask']) probs = torch.nn.functional.softmax(outputs.logits, dim=-1) sen_idx = probs.argmax(dim=1).item() + 1 # 对应1-5的情感类别 target_prob = probs[0, sen_idx-1] # 目标类别概率 # 计算梯度 target_prob.backward() gradients = embeddings.grad.squeeze(0) # 对梯度取绝对值,按token维度平均(因为每个token嵌入是多维的) token_importance = gradients.abs().mean(dim=1).tolist()[1:-1] # 去掉<CLS>和<SEP> # 映射token和重要性 input_tokens = tokenizer.convert_ids_to_tokens(input_ids[0])[1:-1] token_importance_pairs = list(zip(input_tokens, token_importance)) token_importance_pairs.sort(key=lambda x: x[1], reverse=True) print(f"驱动{sen_dict[sen_idx]}的关键词汇:") for token, importance in token_importance_pairs[:5]: print(f"{token}: {importance:.4f}")
3. 基于遮挡的分析(Occlusion Testing)
逐个遮挡输入中的每个token(替换为[MASK]或删除),观察目标情感类别概率的变化,下降越多说明该token越关键:
- 实现步骤:
- 计算原文本的目标类别概率;
- 遍历每个token,生成遮挡后的文本并计算对应概率;
- 计算概率差值,差值大的token即为关键词汇。
- 代码示例:
import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification MODEL = "nlptown/bert-base-multilingual-uncased-sentiment" tokenizer = AutoTokenizer.from_pretrained(MODEL) model = AutoModelForSequenceClassification.from_pretrained(MODEL) txt = "你的测试文本" sen_dict= {1:'Highly-negative',2:'Negative',3:'Neutral',4:'Positive',5:'Highly-positive'} # 计算原文本的情感概率和类别 tokens = tokenizer.encode_plus(txt, add_special_tokens=True, return_tensors='pt') outputs = model(**tokens) probs = torch.nn.functional.softmax(outputs.logits, dim=-1) sen_idx = probs.argmax(dim=1).item() + 1 original_prob = probs[0, sen_idx-1].item() # 遍历每个token(排除<CLS>和<SEP>) input_ids = tokens['input_ids'][0].tolist() input_tokens = tokenizer.convert_ids_to_tokens(input_ids) token_importance = [] for i in range(1, len(input_ids)-1): # 替换当前token为[MASK] occluded_ids = input_ids.copy() occluded_ids[i] = tokenizer.mask_token_id occluded_tokens = {'input_ids': torch.tensor([occluded_ids]), 'attention_mask': tokens['attention_mask']} # 计算遮挡后的概率 with torch.no_grad(): occluded_outputs = model(**occluded_tokens) occluded_probs = torch.nn.functional.softmax(occluded_outputs.logits, dim=-1) occluded_prob = occluded_probs[0, sen_idx-1].item() # 概率下降值越大,token越关键 importance = original_prob - occluded_prob token_importance.append((input_tokens[i], importance)) # 按重要性降序排序 token_importance.sort(key=lambda x: x[1], reverse=True) print(f"驱动{sen_dict[sen_idx]}的关键词汇:") for token, importance in token_importance[:5]: print(f"{token}: {importance:.4f}")
内容的提问来源于stack exchange,提问作者help_180399
相关产品推荐
相关产品推荐

