Day07 【手动实现bert网络结构】

目标

今天旨在通过手动实现一个简化版的 BERT 模型 (DiyBert 类),并与 Hugging Face 提供的 BERT 模型进行对比,验证自定义实现是否正确。代码的核心内容涉及矩阵运算来实现 BERT 的各个部分,包括 embeddingself-attentionfeed-forward 网络、LayerNormpooler 层等。
实现过程

1. 导入所需的库

import torch
import math
import numpy as np
from transformers import BertModel
  • torch:PyTorch库,用于深度学习相关操作。
  • math:提供数学函数,如平方根、幂运算等。
  • np:NumPy库,用于处理矩阵运算和向量化操作。
  • BertModel:从Hugging Face的transformers库中导入BERT预训练模型。

2. softmax函数

def softmax(x):
    return np.exp(x) / np.sum(np.exp(x), axis=-1, keepdims=True)
  • 该函数对输入进行归一化处理,返回每个元素相对其总和的概率分布。用于 self-attention 计算时,对注意力权重进行规范化。

3. GELU激活函数

def gelu(x):
    return 0.5 * x * (1 + np.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * np.power(x, 3))))
  • GELU(Gaussian Error Linear Unit)激活函数是BERT模型中常用的激活函数,基于高斯误差线性单元。

4. 自定义DiyBert 类

该类构造了一个自定义的 BERT 模型,试图通过手动矩阵运算实现 BERT 模型的各个部分。

__init__初始化
def __init__(self, state_dict):
    self.num_attention_heads = 12
    self.hidden_size = 768
    self.num_layers = 1  # 模型的层数,通常是12
    self.load_weights(state_dict)
  • 初始化时,定义了 BERT 模型的结构,如注意力头的数量、隐藏层的维度、Transformer层的数量等。
  • load_weights 方法将从预训练模型加载的权重存储到相应的变量中。
权重参数加载
def load_weights(self, state_dict):
    self.word_embeddings = state_dict["embeddings.word_embeddings.weight"].numpy()
    ...
    self.pooler_dense_weight = state_dict["pooler.dense.weight"].numpy()
    self.pooler_dense_bias = state_dict["pooler.dense.bias"].numpy()
  • 该方法从预训练的模型中加载词嵌入层、位置编码、Transformer的权重等。
embedding编码层
def embedding_forward(self, x):
    we = self.get_embedding(self.word_embeddings, x)
    pe = self.get_embedding(self.position_embeddings, np.array(list(range(len(x)))))
    te = self.get_embedding(self.token_type_embeddings, np.array([0] * len(x)))
    embedding = we + pe + te
    embedding = self.layer_norm(embedding, self.embeddings_layer_norm_weight, self.embeddings_layer_norm_bias)
    return embedding
  • 该方法计算输入的 word_embeddingsposition_embeddingstoken_type_embeddings 的加和,并对结果应用 LayerNorm 层。
get_embedding解码
def get_embedding(self, embedding_matrix, x):
    return np.array([embedding_matrix[index] for index in x])
  • 该方法用于根据输入索引从词嵌入矩阵中获取对应的嵌入。
多层注意力
def all_transformer_layer_forward(self, x):
    for i in range(self.num_layers):
        x = self.single_transformer_layer_forward(x, i)
    return x
  • all_transformer_layer_forward 会遍历所有 Transformer 层并对输入进行处理。
  • single_transformer_layer_forward 处理单层 Transformer 层,包括计算 self-attentionfeed-forward 网络,并使用 LayerNorm 层进行残差连接。
自注意力层
def self_attention(self, x, q_w, q_b, k_w, k_b, v_w, v_b, attention_output_weight, attention_output_bias, num_attention_heads, hidden_size):
    q = np.dot(x, q_w.T) + q_b
    k = np.dot(x, k_w.T) + k_b
    v = np.dot(x, v_w.T) + v_b
    ...
    qk = np.matmul(q, k.swapaxes(1, 2))
    qk /= np.sqrt(attention_head_size)
    qk = softmax(qk)
    qkv = np.matmul(qk, v)
    qkv = qk
### BERT Neural Network Architecture Diagram BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer架构的预训练语言模型。其核心在于利用双向编码器来捕捉上下文信息,从而实现更深层次的语言理解能力[^4]。 以下是有关 BERT 网络结构的关键点: #### 1. **整体架构** BERT 的主要组成部分是一个堆叠的 Transformer 编码器层。标准版本的 BERT 使用了 12 层或 24 层 Transformer 结构,每层都由自注意力机制(Self-Attention Mechanism)和前馈神经网络(Feedforward Neural Networks)组成[^5]。 #### 2. **输入表示** BERT 将输入序列转换为词嵌入、位置嵌入以及分段嵌入三部分之和作为初始输入向量。这种设计允许模型同时考虑单词本身的意义及其在句子中的相对位置关系[^6]。 #### 3. **双向性** 与其他单向语言模型不同的是,BERT 利用了 Masked Language Model (MLM) 技术实现了真正的双向建模方式。这种方式使得模型能够更好地理解和预测给定语境下的词语含义[^7]。 #### 可视化图示 虽然无法直接在此处展示图片文件,但可以描述一张典型的 BERT 架构图应包含的内容: - 输入层展示了如何将原始文本转化为 tokenized tokens 并附加特殊标记 `[CLS]` 和 `[SEP]`; - 中间部分显示多个连续排列的 Transformer Blocks; - 输出端则分别对应于下游任务所需的 logits 值或者用于 NSP (Next Sentence Prediction) 训练目标的概率分布. 如果希望获取具体的图表资源,建议访问以下链接寻找高质量的相关资料: - Google AI Blog 上发布的官方介绍文章. - Hugging Face 提供的各种教程文档中也常配有清晰易懂的概念图解说明. ```python import transformers from transformers import BertTokenizer, BertModel tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') model = BertModel.from_pretrained("bert-base-uncased") text = "Replace me by any text you'd like." encoded_input = tokenizer(text, return_tensors='pt') output = model(**encoded_input) print(output.last_hidden_state.shape) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值