Browse Source

fix some bugs in chapter3

thankuyou 8 tháng trước cách đây
mục cha
commit
bcbfff9593
1 tập tin đã thay đổi với 25 bổ sung25 xóa
  1. 25 25
      docs/chapter3/第三章 大语言模型基础.md

+ 25 - 25
docs/chapter3/第三章 大语言模型基础.md

@@ -14,7 +14,7 @@
 
 $$P(S)=P(w_1,w_2,…,w_m)=P(w_1)⋅P(w_2∣w_1)⋅P(w_3∣w_1,w_2)⋯P(w_m∣w_1,…,w_{m−1})$$
 
-这个公式被称为概率的链式法则。然而,直接计算这个公式几乎是不可能的,因为像 $P(w_m∣w_1,dots,w_{m−1})$ 这样的条件概率太难从语料库中估计了,词序列 $w_1,dots,w_{m−1}$ 可能从未在训练数据中出现过。
+这个公式被称为概率的链式法则。然而,直接计算这个公式几乎是不可能的,因为像 $P(w_m∣w_1,\cdots,w_{m−1})$ 这样的条件概率太难从语料库中估计了,词序列 $w_1,\cdots,w_{m−1}$ 可能从未在训练数据中出现过。
 
 <div align="center">
   <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/3-figures/1757249275674-0.png" alt="图片描述" width="90%"/>
@@ -23,7 +23,7 @@ $$P(S)=P(w_1,w_2,…,w_m)=P(w_1)⋅P(w_2∣w_1)⋅P(w_3∣w_1,w_2)⋯P(w_m∣w_1
 
 为了解决这个问题,研究者引入了<strong>马尔可夫假设 (Markov Assumption)</strong> 。其核心思想是:我们不必回溯一个词的全部历史,可以近似地认为,一个词的出现概率只与它前面有限的 $n−1$ 个词有关,如图3.1所示。基于这个假设建立的语言模型,我们称之为 <strong>N-gram模型</strong>。这里的 "N" 代表我们考虑的上下文窗口大小。让我们来看几个最常见的例子来理解这个概念:
 
-- <strong>Bigram (当 N=2 时)</strong> :这是最简单的情况,我们假设一个词的出现只与它前面的一个词有关。因此,链式法则中复杂的条件概率 $P(w_i∣w_1,dots,w_{i−1})$ 就可以被近似为更容易计算的形式:
+- <strong>Bigram (当 N=2 时)</strong> :这是最简单的情况,我们假设一个词的出现只与它前面的一个词有关。因此,链式法则中复杂的条件概率 $P(w_i∣w_1,\cdots,w_{i−1})$ 就可以被近似为更容易计算的形式:
 
 $$P(w_{i}∣w_{1},…,w_{i−1})≈P(w_{i}∣w_{i−1})$$
 
@@ -242,17 +242,17 @@ class EncoderLayer(nn.Module):
         self.norm1 = nn.LayerNorm(d_model)
         self.norm2 = nn.LayerNorm(d_model)
         self.dropout = nn.Dropout(dropout)
-    
+
     def forward(self, x, mask):
         # 残差连接与层归一化将在 3.1.2.4 节中详细解释
         # 1. 多头自注意力
         attn_output = self.self_attn(x, x, x, mask)
         x = self.norm1(x + self.dropout(attn_output))
-        
+
         # 2. 前馈网络
         ff_output = self.feed_forward(x)
         x = self.norm2(x + self.dropout(ff_output))
-        
+
         return x
 
 # --- 解码器核心层 ---
@@ -267,20 +267,20 @@ class DecoderLayer(nn.Module):
         self.norm2 = nn.LayerNorm(d_model)
         self.norm3 = nn.LayerNorm(d_model)
         self.dropout = nn.Dropout(dropout)
-        
+
     def forward(self, x, encoder_output, src_mask, tgt_mask):
         # 1. 掩码多头自注意力 (对自己)
         attn_output = self.self_attn(x, x, x, tgt_mask)
         x = self.norm1(x + self.dropout(attn_output))
-        
+
         # 2. 交叉注意力 (对编码器输出)
         cross_attn_output = self.cross_attn(x, encoder_output, encoder_output, src_mask)
         x = self.norm2(x + self.dropout(cross_attn_output))
-        
+
         # 3. 前馈网络
         ff_output = self.feed_forward(x)
         x = self.norm3(x + self.dropout(ff_output))
-        
+
         return x
 ```
 
@@ -327,54 +327,54 @@ class MultiHeadAttention(nn.Module):
     def __init__(self, d_model, num_heads):
         super(MultiHeadAttention, self).__init__()
         assert d_model % num_heads == 0, "d_model 必须能被 num_heads 整除"
-        
+
         self.d_model = d_model
         self.num_heads = num_heads
         self.d_k = d_model // num_heads
-        
+
         # 定义 Q, K, V 和输出的线性变换层
         self.W_q = nn.Linear(d_model, d_model)
         self.W_k = nn.Linear(d_model, d_model)
         self.W_v = nn.Linear(d_model, d_model)
         self.W_o = nn.Linear(d_model, d_model)
-        
+
     def scaled_dot_product_attention(self, Q, K, V, mask=None):
         # 1. 计算注意力得分 (QK^T)
         attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
-        
+
         # 2. 应用掩码 (如果提供)
         if mask is not None:
             # 将掩码中为 0 的位置设置为一个非常小的负数,这样 softmax 后会接近 0
             attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
-        
+
         # 3. 计算注意力权重 (Softmax)
         attn_probs = torch.softmax(attn_scores, dim=-1)
-        
+
         # 4. 加权求和 (权重 * V)
         output = torch.matmul(attn_probs, V)
         return output
-        
+
     def split_heads(self, x):
         # 将输入 x 的形状从 (batch_size, seq_length, d_model)
         # 变换为 (batch_size, num_heads, seq_length, d_k)
         batch_size, seq_length, d_model = x.size()
         return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
-        
+
     def combine_heads(self, x):
         # 将输入 x 的形状从 (batch_size, num_heads, seq_length, d_k)
         # 变回 (batch_size, seq_length, d_model)
         batch_size, num_heads, seq_length, d_k = x.size()
         return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
-        
+
     def forward(self, Q, K, V, mask=None):
         # 1. 对 Q, K, V 进行线性变换
         Q = self.split_heads(self.W_q(Q))
         K = self.split_heads(self.W_k(K))
         V = self.split_heads(self.W_v(V))
-        
+
         # 2. 计算缩放点积注意力
         attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
-        
+
         # 3. 合并多头输出并进行最终的线性变换
         output = self.W_o(self.combine_heads(attn_output))
         return output
@@ -453,14 +453,14 @@ class PositionalEncoding(nn.Module):
         # 创建一个足够长的位置编码矩阵
         position = torch.arange(max_len).unsqueeze(1)
         div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))
-        
+
         # pe (positional encoding) 的大小为 (max_len, d_model)
         pe = torch.zeros(max_len, 1, d_model)
-        
+
         # 偶数维度使用 sin, 奇数维度使用 cos
         pe[:, 0, 0::2] = torch.sin(position * div_term)
         pe[:, 0, 1::2] = torch.cos(position * div_term)
-        
+
         # 将 pe 注册为 buffer,这样它就不会被视为模型参数,但会随模型移动(例如 to(device))
         self.register_buffer('pe', pe)
 
@@ -648,7 +648,7 @@ How are you?
 一个篮球队在一个赛季的80场比赛中赢了60%。在接下来的赛季中,他们打了15场比赛,赢了12场。两个赛季的总胜率是多少?
 请一步一步地思考并解答。
 
->>> 
+>>>
 (模型可能会输出)
 好的,我们来一步步计算。
 第一步:计算第一个赛季赢得的比赛数。
@@ -849,7 +849,7 @@ print("\n模型的回答:")
 print(response)
 
 >>>
-我叫通义千问,是由阿里云研发的预训练语言模型,可以回答问题、创作文字,还能表达观点、撰写代码。我主要的功能是在多个领域提 
+我叫通义千问,是由阿里云研发的预训练语言模型,可以回答问题、创作文字,还能表达观点、撰写代码。我主要的功能是在多个领域提
 供帮助,包括但不限于:语言理解、文本生成、机器翻译、问答系统等。有什么我可以帮到你的吗?
 ```