You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

置换BERT位置编码未达预期效果,是否存在其他位置相关机制?

BERT模型中除位置编码外是否存在其他位置相关机制?

我正在开发一个Transformer相关的Jupyter Notebook,目的是演示Transformer完全依赖位置编码来理解序列顺序。之前了解到这个概念仅适用于无掩码注意力的模型(比如GPT-2),但用BERT模型(带交叉注意力)预测[MASK] token时,得到了意外结果。

预期结果

  • 不做任何置换时,模型预测的token分布(分布A)保持一致
  • 仅置换输入ID得到分布B
  • 仅置换位置嵌入得到分布B
  • 同时置换输入ID和位置嵌入得到分布A

实际结果

有时结果符合预期,但有时仅置换输入ID或位置嵌入会产生不同结果,偶尔二者结果又相同。

核心问题

Hugging Face的BERT模型中,除位置编码外,是否存在其他受位置影响的机制?

复现代码

import torch
import ipywidgets as widgets
from IPython.display import display
from transformers import BertForMaskedLM, AutoTokenizer
import matplotlib.pyplot as plt
import torch.nn.functional as F
import logging
import warnings

# surpress renaming warnings
logging.getLogger("transformers.modeling_utils").setLevel(logging.ERROR)
warnings.simplefilter("ignore", FutureWarning)

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

input_ids = torch.Tensor([[]])
tokens = []
permutation = []

output = widgets.Output()

def permute_columns(matrix, permutation=None):
    n = len(permutation)
    first_n_columns = matrix[:, :n]
    permuted_columns = first_n_columns[:, permutation]
    remaining_columns = matrix[:, n:]
    new_matrix = torch.hstack((permuted_columns, remaining_columns))
    return new_matrix

def update_permutation(ordered_tags):
    global permutation
    fixed_tokens = [tokens[0]] + ordered_tags + [tokens[-1]]
    
    permutation = [tokens.index(tag) for tag in fixed_tokens]
    

def tokenize(text):
    global input_ids, tokens
    input_ids = tokenizer(text, return_tensors="pt").input_ids
    tokens = [tokenizer.decode([token_id]).strip() for token_id in input_ids[0]]
    
    if len(tokens) > 2:
        reorderable_tokens = tokens[1:-1]
    else:
        reorderable_tokens = []
    
    with output:
        output.clear_output(wait=True)
        tags_input.allowed_tags = reorderable_tokens
        tags_input.value = reorderable_tokens
        update_permutation(tags_input.value)

def on_tags_change(change):
    if len(change['new']) != len(tags_input.allowed_tags):
        tags_input.value = tags_input.allowed_tags  # Restore original value


def masked_prediction(input_ids, permutation, permute_input, permute_encoding):
    
    with output:
        output.clear_output(wait=True)  # Clear previous outputs
        
        if input_ids.numel() == 0:
            print("You can't use an empty sequence for prediction")
            return
        
        model = BertForMaskedLM.from_pretrained("bert-base-uncased")
        
        if permute_encoding:
            model.bert.embeddings.position_embeddings.weight.data = permute_columns(model.bert.embeddings.position_embeddings.weight.T, permutation).T
        if permute_input:
            input_ids = permute_columns(input_ids, permutation)
            
        decoded_text = tokenizer.decode(input_ids[0], skip_special_tokens=False)
            
        with torch.no_grad():
            outputs = model(input_ids)
            
        logits = outputs.logits

        top_k = 5

        mask_token_indices = torch.where(input_ids == tokenizer.mask_token_id)[1]
        print(decoded_text, mask_token_indices, permutation)
        num_masks = len(mask_token_indices)
        if num_masks == 0:
            print("You need to include a [MASK] token for prediction")
            return

        fig, axs = plt.subplots(1, num_masks, figsize=(15, 6))
        
        if num_masks == 1:
            axs = [axs]

        for i, idx in enumerate(mask_token_indices):
            mask_token_logits = logits[0, idx, :]

            softmax_probs = F.softmax(mask_token_logits, dim=0)

            top_token_probs, top_token_ids = torch.topk(softmax_probs, top_k, dim=0)

            predicted_tokens = [tokenizer.decode([token_id]).strip() for token_id in top_token_ids]
            predicted_confidences = top_token_probs.tolist()

            axs[i].bar(predicted_tokens, predicted_confidences, color='blue')
            axs[i].set_xlabel('Predicted Tokens')
            axs[i].set_ylabel('Confidence')
            axs[i].set_title(f'Masked Token at Position {idx.item()}')
            axs[i].set_ylim(0, 1)

        plt.show()

def on_predict_button_click(b):
    masked_prediction(input_ids, permutation, permute_input_checkbox.value, permute_encoding_checkbox.value)

text_input = widgets.Text(placeholder='Write text here to encode.', description='Input:')
text_input.observe(lambda change: tokenize(change['new']), names='value')
tags_input = widgets.TagsInput(value=[], allowed_tags=[], allow_duplicates=False)

# Observe changes in tags order to update the permutation and prevent deletion
tags_input.observe(on_tags_change, names='value')
tags_input.observe(lambda change: update_permutation(change['new']), names='value')

# Create checkboxes for permute_input and permute_encoding
permute_input_checkbox = widgets.Checkbox(value=False, description='Permute Inputs')
permute_encoding_checkbox = widgets.Checkbox(value=False, description='Permute Encodings')

# Create a button to trigger the prediction
predict_button = widgets.Button(description="Run Prediction")
predict_button.on_click(on_predict_button_click)

# Display the widgets
display(text_input)
display(tags_input)
display(permute_input_checkbox)
display(permute_encoding_checkbox)
display(predict_button)
display(output)

内容的提问来源于stack exchange,提问作者Lukas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:12:35