《大模型项目实战》- GitHub项目笔记(一)
自注意力允许序列中的每个元素(如单词)通过加权聚合其他元素的信息,权重由元素之间的相关性动态决定。例如,在句子中,"it"需要关联到"cat"而非"fish",自注意力通过计算相关性权重实现这一点。详细的自注意机制和多头注意力机制见链接代码如下:self.W_q = torch.nn.Linear(input_dim, hidden_dim)# Query 线性变换。
第一章
自注意机制,自注意力允许序列中的每个元素(如单词)通过加权聚合其他元素的信息,权重由元素之间的相关性动态决定。例如,在句子 "The cat ate the fish because it was hungry" 中,"it" 需要关联到 "cat" 而非 "fish",自注意力通过计算相关性权重实现这一点。
详细的自注意机制和多头注意力机制见链接注意力机制(Attention)、自注意力机制(Self Attention)和多头注意力(Multi-head Self Attention)机制详解
代码如下:
import torch
import torch.nn.functional as Fclass SelfAttention(torch.nn.Module):
def __init__(self, input_dim, hidden_dim):
super(SelfAttention, self).__init__()
self.W_q = torch.nn.Linear(input_dim, hidden_dim) # Query 线性变换
self.W_k = torch.nn.Linear(input_dim, hidden_dim) # Key 线性变换
self.W_v = torch.nn.Linear(input_dim, hidden_dim) # Value 线性变换
self.hidden_dim = hidden_dim # 存储 hidden_dim 以便后续计算def forward(self, x):
q = self.W_q(x) # 计算 Q
k = self.W_k(x) # 计算 K
v = self.W_v(x) # 计算 V# 计算注意力分数(QK^T / sqrt(d_k))
attention_scores = torch.matmul(q, k.transpose(1, 2)) / torch.sqrt(torch.tensor(self.hidden_dim, dtype=torch.float32))
# 计算注意力权重(Softmax 归一化)
attention_weights = F.softmax(attention_scores, dim=-1)# 计算最终输出(加权求和 Value)
output = torch.matmul(attention_weights, v)
return output
通过以上自注意机制的代码,输入一个自定义矩阵,做一个示例输出,代码如下
# 创建一个示例输入(batch_size=1, seq_len=3, input_dim=4)
X_sample = torch.tensor([
[[0.1, 0.2, 0.3, 0.4], # "I"
[0.5, 0.6, 0.7, 0.8], # "love"
[0.9, 1.0, 1.1, 1.2]] # "NLP"
])# 定义 SelfAttention 层
attention_layer = SelfAttention(input_dim=4, hidden_dim=4)# 计算注意力输出
output_sample = attention_layer(X_sample)# 打印结果
print("Self-Attention Output:\n", output_sample)
多头注意机制,通过并行运行多个独立的注意力头(Attention Head),每个头关注不同的子空间特征,最后合并结果以增强模型的表达能力。
自注意机制和多头注意机制原理类比对比
代码如下(Tensorflow框架下)
import tensorflow as tf
def multihead_attention(Q, K, V, num_heads, head_size):
# 分别计算Q、K、V的维度
d_model = Q.shape[-1]
# 将Q、K、V分别线性变换为多头
Q = tf.keras.layers.Dense(d_model)(Q)
K = tf.keras.layers.Dense(d_model)(K)
V = tf.keras.layers.Dense(d_model)(V)
# 将Q、K、V分别拆分为多个头
Q = tf.reshape(Q, (-1, num_heads, head_size, d_model // num_heads))
K = tf.reshape(K, (-1, num_heads, head_size, d_model // num_heads))
V = tf.reshape(V, (-1, num_heads, head_size, d_model // num_heads))
# 计算注意力分数
attention_scores = tf.matmul(Q, K, transpose_b=True) / tf.math.sqrt(tf.cast(d_model // num_heads, tf.float32))
attention_weights = tf.nn.softmax(attention_scores, axis=-1)
# 注意力加权求和
attention_output = tf.matmul(attention_weights, V)
attention_output = tf.reshape(attention_output, (-1, head_size, d_model))
return attention_output
# 示例用法
Q = tf.random.normal((32, 10, 64)) # (batch_size, sequence_length, d_model)
K = tf.random.normal((32, 10, 64)) # (batch_size, sequence_length, d_model)
V = tf.random.normal((32, 10, 64)) # (batch_size, sequence_length, d_model)
num_heads = 4
head_size = 16
output = multihead_attention(Q, K, V, num_heads, head_size)
print(output.shape)
代码如下(pytorch库下)
import torch
import torch.nn.functional as F
class MultiheadAttention(torch.nn.Module):
def __init__(self, d_model, num_heads):
super(MultiheadAttention, self).__init__()
self.num_heads = num_heads
self.d_model = d_model
self.head_size = d_model // num_heads
self.W_q = torch.nn.Linear(d_model, d_model)
self.W_k = torch.nn.Linear(d_model, d_model)
self.W_v = torch.nn.Linear(d_model, d_model)
def forward(self, Q, K, V):
batch_size = Q.size(0)
Q = self.W_q(Q).view(batch_size, -1, self.num_heads, self.head_size)
K = self.W_k(K).view(batch_size, -1, self.num_heads, self.head_size)
V = self.W_v(V).view(batch_size, -1, self.num_heads, self.head_size)
attention_scores = torch.matmul(Q, K.transpose(2, 3)) / (self.head_size ** 0.5)
attention_weights = F.softmax(attention_scores, dim=-1)
attention_output = torch.matmul(attention_weights, V)
attention_output = attention_output.view(batch_size, -1, self.d_model)
return attention_output
# 示例用法
Q = torch.randn(32, 10, 64) # (batch_size, sequence_length, d_model)
K = torch.randn(32, 10, 64) # (batch_size, sequence_length, d_model)
V = torch.randn(32, 10, 64) # (batch_size, sequence_length, d_model)
num_heads = 4
multihead_attention = MultiheadAttention(d_model=64, num_heads=num_heads)
output = multihead_attention(Q, K, V)
print(output.shape)
第二章
这章的内容主要是整个大模型的架构,下面这张图概括的很详细,实际上,第三章3-3图也是对这张图的扩展

以下是我看书时的做的重点笔记
- 硬件部分主要包括服务器和推理卡。AI推理卡与消费级显卡有一定的区别。AI推理卡是专门为人工智能应用程序设计的硬件,具有更强大的计算能力和更高的并行处理能力,可以支持深度学习、神经网络等复杂的AI算法,而消费级显卡则更多用于图形处理、游戏等日常应用,两者在计算能力上也有一定的区别。推理卡没有图像输出接口,不能当成显卡使用,一般不内置风扇,需要服务器靠自身硬件配置来解决散热的问题。有代表性的推理卡如A100、A800、A10、P100、V100、T4等,高性能的消费级显卡如RTX4090、RTX3090、RTX2080等。推理卡和显卡都可以用于支撑大语言模型的运算,可根据具体的需求和性价比来选型。
- 通过PyTorch的k位量化访问大语言模型的bitsandbytes库,在Windows上运行就会遇到一些问题,而在Linux上问题较少,所以如果长期训练和使用大语言模型,则建议采用Linux系统,如Ubuntu22.04发行版等
- Transformers库基本统一了大语言模型的调用API。不管是哪一个模型,只要是Hugging Face格式,都统一采用Model.from_pretrained方式进行装载。虽然有的模型使用AutoModel,有的采用诸如LlamaForCausalLM的专用model类,但总体上它们的编程方法是类似的。
- 在Chat应用方面,OpenAI提供的API主要有三个,分别是models、completions和embeddings,其请求路径(path)及主要作用如下图

对于这章,GitHub上面给出了一个基于hugging face格式的transformers库加载大模型的代码示例
from transformers import AutoTokenizer, AutoModel
# 装载tokenizer
tokenizer = AutoTokenizer.from_pretrained("Tokenizer路径")
# 装载model
model = AutoModel.from_pretrained("模型路径", device='cuda')
# 将模型设置成评估模式
model = model.eval()
# 推理
response, history = model.chat(tokenizer, "你好", history=[])
print(response)
第三章
这章主要介绍了硬件和软件部署,以及大模型运用的运行模式,以下是我笔记的重点归纳:


将模型实例设置为评估模式后,其权重将不再更新,这与其在训练模式下不同。尽管在评估模式下,模型会进行梯度计算并存储梯度信息,但不会执行反向传播。换句话说,评估模式下模型处于锁定状态,不会因推理过程而导致参数发生变化。
大语言模型的推理是一个分步预测的过程,模型一次生成一定量的token,逐步构建完整答案。只要将这个生成过程反映到客户端,就可避免用户长时间的等待。为此,OpenAI兼容接口引入了SSE技术。SSE是一种HTML5技术,允许服务器向客户端推送数据,不需要客户端主动请求,当服务端有新消息时,会实时将消息推送到前端,从而实现动态的聊天效果(也就是流式输出)。从客户端来看,结果是一段一段生成的(也就是一段一段的token),不但生成过程无卡顿,而且能使用户体验打字的视觉效果,就像人工智能在不断地打字回答用户的问题。这样既减少了用户对大语言模型的性能焦虑,又提高了用户体验,还减轻了API服务的并发压力。

在前端实现流式输出,以React.js开发场景中使用的openai-node组件为例,其接口调用过程如下:
async function chat_stream(prompt) {
//将用户的问题加到会话历史中
message_history.push({ role: 'user', content: prompt });
const stream = openai.beta.chat.completions.stream({
model: '模型名称',
messages: message_history,
stream: true, //流方式(服务器使用SSE响应)
});
var snapshot = "";
for await (const chunk of stream) {
//content是SSE推送的增量内容
var content = chunk.choices[0]?.delta?.content;
snapshot = snapshot + content;
//更新界面显示
}
//将LLM的回答加到会话历史中
message_history.push({ "role": "assistant", "content": snapshot });
}
第四章
讲了基础硬件(很简约,但是我们学习过程中确实也接触不到多少需要手动自己组装机箱),软件安装,GitHub上面写了重要的几个基础软件和其他软件的安装命令(第4章 应用环境搭建),很详细,这本书好就好在老师真的当小白是小白,书上面这章介绍更详细,完全可以当安装指导手册。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)