250行代码从头搭建Llama 3,GitHub一天4.6k星!Karpathy大赞

Meta最新模型LLaMA细节与代码详解 本文对Facebook Meta AI最新提出的大语言模型LLaMA进行简单的介绍,以及对其开源出的代码和细节进行了详细的说明。 阅读详情

Llama系列作为为数不多的优质开源LLM,一直受到开发者们的追捧。在Hugging Face社区的文本生成模型中,几乎是「霸榜」的存在。

就在520这天,一位名叫Nishant Aklecha的开发者在推特上宣布了自己的一个开源项目,名为「从头开始实现Llama 3」。

这个项目详细到什么程度呢——

矩阵乘法、注意力头、位置编码等模块全部都拆开解释。

而且项目全部用Jupyter Notebook写成,小白都可以直接上手运行。

堪比哈佛NLP小组曾经出品的「The Annotated Transformer」。

https://nlp.seas.harvard.edu/annotated-transformer/

才一天多的时间,小哥发表的这篇推特已经有32万次阅读,甚至被Andrej Karpathy大佬亲自点赞——

「全部拆开解释之后,通过模块的嵌套以及互相调用,可以更清楚地看到模型到底做了什么。」

项目也在GitHub上获得了4.6k星。

项目地址:https://github.com/naklecha/llama3-from-scratch

那就让我们来看看作者是如何深入拆解Llama 3的。

下载并读取模型权重

首先需要从Meta官网下载模型权重文件,以便后续运行时使用。

https://github.com/meta-llama/llama3/blob/main/README.md

下载后需要先读取权重文件中的变量名:

model = torch.load("Meta-Llama-3-8B/consolidated.00.pth")  
print(json.dumps(list(model.keys())[:20], indent=4))
[  
    "tok_embeddings.weight",  
    "layers.0.attention.wq.weight",  
    "layers.0.attention.wk.weight",  
    "layers.0.attention.wv.weight",  
    "layers.0.attention.wo.weight",  
    "layers.0.feed_forward.w1.weight",  
    "layers.0.feed_forward.w3.weight",  
    "layers.0.feed_forward.w2.weight",  
    "layers.0.attention_norm.weight",  
    "layers.0.ffn_norm.weight",  
    "layers.1.attention.wq.weight",  
    "layers.1.attention.wk.weight",  
    "layers.1.attention.wv.weight",  
    "layers.1.attention.wo.weight",  
    "layers.1.feed_forward.w1.weight",  
    "layers.1.feed_forward.w3.weight",  
    "layers.1.feed_forward.w2.weight",  
    "layers.1.attention_norm.weight",  
    "layers.1.ffn_norm.weight",  
    "layers.2.attention.wq.weight"  
]

以及模型的配置信息:

with open("Meta-Llama-3-8B/params.json", "r") as f:  
    config = json.load(f)  
config
{'dim': 4096,  
 'n_layers': 32,  
 'n_heads': 32,  
 'n_kv_heads': 8,  
 'vocab_size': 128256,  
 'multiple_of': 1024,  
 'ffn_dim_multiplier': 1.3,  
 'norm_eps': 1e-05,  
 'rope_theta': 500000.0}

根据以上输出,可以推断出模型架构的信息——

  • 32个transformer层

  • 每个多头注意力模块有32个注意力头

  • 分词器的词汇量为128256

直接将模型配置信息存储到变量中,方便使用。

dim = config["dim"]``n_layers = config["n_layers"]``n_heads = config["n_heads"]``n_kv_heads = config["n_kv_heads"]``vocab_size = config["vocab_size"]``multiple_of = config["multiple_of"]``ffn_dim_multiplier = config["ffn_dim_multiplier"]``norm_eps = config["norm_eps"]``rope_theta = torch.tensor(config["rope_theta"])

分词器与编码

那么就从语言模型的第一步——分词器开始,但是这一步并不需要我们自己手写。

Llama 3使用了GPT等大模型常用的BPE分词器,karpathy大佬之前就复现过一个最简版。

https://github.com/karpathy/minbpe

除了Karapthy大佬复现的版本,OpenAI也开源了一个运行速度很快的分词器tiktoken。这两个随便挑,估计都比自己从头训练的要强。

https://github.com/openai/tiktoken

有了分词器,下一步就是要把输入的文本切分为token。

prompt = "the answer to the ultimate question of life, the universe, and everything is "``tokens = [128000] + tokenizer.encode(prompt)``print(tokens)``tokens = torch.tensor(tokens)``prompt_split_as_tokens = [tokenizer.decode([token.item()]) for token in tokens]``print(prompt_split_as_tokens)
[128000, 1820, 4320, 311, 279, 17139, 3488, 315, 2324, 11, 279, 15861, 11, 323, 4395, 374, 220]``['<|begin_of_text|>', 'the', ' answer', ' to', ' the', ' ultimate', ' question', ' of', ' life', ',', ' the', ' universe', ',', ' and', ' everything', ' is', ' ']

再使用PyTorch内置的神经网络模块(torch.nn)将token转换为embedding,[17x1]的token维度变为[17x4096]。

embedding_layer = torch.nn.Embedding(vocab_size, dim)``embedding_layer.weight.data.copy_(model["tok_embeddings.weight"])``token_embeddings_unnormalized = embedding_layer(tokens).to(torch.bfloat16)``token_embeddings_unnormalized.shape
torch.Size([17, 4096])

此处应该是整个项目中唯一使用PyTorch内置模块的地方。而且,作者给出了温馨提示——记得经常打印一下张量维度,更容易理解。

之后再使用RMS对embedding进行归一化处理。这一步不会改变张量形状,只是归一化其中的数值,公式如下:

模型配置中的norm_eps变量设置为1e-5,就是用在此处,防止rms值意外设置为0。

# def rms_norm(tensor, norm_weights):``#     rms = (tensor.pow(2).mean(-1, keepdim=True) + norm_eps)**0.5``#     return tensor * (norm_weights / rms)``def rms_norm(tensor, norm_weights):`    `return (tensor * torch.rsqrt(tensor.pow(2).mean(-1, keepdim=True) + norm_eps)) * norm_weights

构建Transformer层

每一个Transformer层都需要经过如下步骤:

由于是从头构建,我们只需要访问模型字典中第一层(layer.0)的权重。

先用刚才定义的rms_norm函数,结合模型权重,进行embedding的归一化处理。

token_embeddings = rms_norm(token_embeddings_unnormalized, model["layers.0.attention_norm.weight"])``token_embeddings.shape
torch.Size([17, 4096])

多头注意力

查询向量

让我们先用一张图复习注意力机制的计算过程:

如果从模型直接加载查询、键、值和输出的权重,我们会得到四个二维矩阵,形状分别为 [4096x4096]、[1024x4096]、[1024x4096]、[4096x4096]。

print(`    `model["layers.0.attention.wq.weight"].shape,`    `model["layers.0.attention.wk.weight"].shape,`    `model["layers.0.attention.wv.weight"].shape,`    `model["layers.0.attention.wo.weight"].shape``)
torch.Size([4096, 4096]) torch.Size([1024, 4096]) torch.Size([1024, 4096]) torch.Size([4096, 4096])

因为大模型考虑了注意力中乘法并行化的需求,压缩了矩阵维度。但是为了更清楚地展示机制,作者决定将这些矩阵都展开。

模型有32个注意力头,因此查询权重矩阵应该展开为[32x128x4096],其中128是查询向量的长度,4096是embedding的维度。

q_layer0 = model["layers.0.attention.wq.weight"]``head_dim = q_layer0.shape[0] // n_heads``q_layer0 = q_layer0.view(n_heads, head_dim, dim)``q_layer0.shape
torch.Size([32, 128, 4096])

于是可以访问第一个注意力头的查询权重,维度是[128x4096]。

q_layer0_head0 = q_layer0[0]``q_layer0_head0.shape
torch.Size([128, 4096])

现在将查询权重与embedding相乘,就得到了查询矩阵,维度为[17x128],表示长度为17的句子,其中每个token都有维度为128的查询向量。

q_per_token = torch.matmul(token_embeddings, q_layer0_head0.T)``q_per_token.shape
torch.Size([17, 128])
位置编码

由于注意力机制中对每个token没有序列「位置」的概念,第一个词和最后一个词在Q、K、V矩阵看来都是一样的,因此需要在查询向量中嵌入维度为[1x128]的位置编码。

位置编码有多种方法,Llama模型采用的是旋转位置编码(RoPE)。

首先将查询向量两两分为一对,共有64对。

q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)``q_per_token_split_into_pairs.shape
torch.Size([17, 64, 2])

句子中在m位置的一对查询向量,旋转角度为m*(rope_theta),其中rope_theta也在模型的配置信息中。

zero_to_one_split_into_64_parts = torch.tensor(range(64))/64``zero_to_one_split_into_64_parts
tensor([0.0000, 0.0156, 0.0312, 0.0469, 0.0625, 0.0781, 0.0938, 0.1094, 0.1250,`        `0.1406, 0.1562, 0.1719, 0.1875, 0.2031, 0.2188, 0.2344, 0.2500, 0.2656,`        `0.2812, 0.2969, 0.3125, 0.3281, 0.3438, 0.3594, 0.3750, 0.3906, 0.4062,`        `0.4219, 0.4375, 0.4531, 0.4688, 0.4844, 0.5000, 0.5156, 0.5312, 0.5469,`        `0.5625, 0.5781, 0.5938, 0.6094, 0.6250, 0.6406, 0.6562, 0.6719, 0.6875,`        `0.7031, 0.7188, 0.7344, 0.7500, 0.7656, 0.7812, 0.7969, 0.8125, 0.8281,`        `0.8438, 0.8594, 0.8750, 0.8906, 0.9062, 0.9219, 0.9375, 0.9531, 0.9688,`        `0.9844])
freqs = 1.0 / (rope_theta ** zero_to_one_split_into_64_parts)``freqs
tensor([1.0000e+00, 8.1462e-01, 6.6360e-01, 5.4058e-01, 4.4037e-01, 3.5873e-01,`        `2.9223e-01, 2.3805e-01, 1.9392e-01, 1.5797e-01, 1.2869e-01, 1.0483e-01,`        `8.5397e-02, 6.9566e-02, 5.6670e-02, 4.6164e-02, 3.7606e-02, 3.0635e-02,`        `2.4955e-02, 2.0329e-02, 1.6560e-02, 1.3490e-02, 1.0990e-02, 8.9523e-03,`        `7.2927e-03, 5.9407e-03, 4.8394e-03, 3.9423e-03, 3.2114e-03, 2.6161e-03,`        `2.1311e-03, 1.7360e-03, 1.4142e-03, 1.1520e-03, 9.3847e-04, 7.6450e-04,`        `6.2277e-04, 5.0732e-04, 4.1327e-04, 3.3666e-04, 2.7425e-04, 2.2341e-04,`        `1.8199e-04, 1.4825e-04, 1.2077e-04, 9.8381e-05, 8.0143e-05, 6.5286e-05,`        `5.3183e-05, 4.3324e-05, 3.5292e-05, 2.8750e-05, 2.3420e-05, 1.9078e-05,`        `1.5542e-05, 1.2660e-05, 1.0313e-05, 8.4015e-06, 6.8440e-06, 5.5752e-06,`        `4.5417e-06, 3.6997e-06, 3.0139e-06, 2.4551e-06])
freqs_for_each_token = torch.outer(torch.arange(17), freqs)``freqs_cis = torch.polar(torch.ones_like(freqs_for_each_token), freqs_for_each_token)

经过以上操作后,我们构建了freq_cis矩阵,存储句子中每个位置的、对查询向量每个值的旋转角度。

将每对查询向量转换为复数,之后进行与旋转角度进行点积操作。

q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)``q_per_token_as_complex_numbers.shape
torch.Size([17, 64])
q_per_token_as_complex_numbers_rotated = q_per_token_as_complex_numbers * freqs_cis``q_per_token_as_complex_numbers_rotated.shape
torch.Size([17, 64])

这样我们就得到了旋转后的查询向量,需要再转换回实数形式。

q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers_rotated)``q_per_token_split_into_pairs_rotated.shape
torch.Size([17, 64, 2])
q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)``q_per_token_rotated.shape
torch.Size([17, 128])

旋转后的查询向量,维度依旧是 [17x128]。

键向量

键向量的计算与查询向量非常类似,也需要进行旋转位置编码,只是维度有所差异。

键的权重数量仅为查询的1/4,因为需要减少模型计算量,每个权重值被4个注意力头共享。

k_layer0 = model["layers.0.attention.wk.weight"]``k_layer0 = k_layer0.view(n_kv_heads, k_layer0.shape[0] // n_kv_heads, dim)``k_layer0.shape
torch.Size([8, 128, 4096])

因此这里第一个维度的值为8,而不是我们在查询权重中看到的32。

k_layer0_head0 = k_layer0[0]``k_per_token = torch.matmul(token_embeddings, k_layer0_head0.T)``k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)``k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)``k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis)``k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)``k_per_token_rotated.shape
torch.Size([17, 128])

照着前面查询向量部分的计算流程,就可以得到句子中每个token的键向量了。

查询和键相乘

对句子进行「自注意力」的过程,就是将查询向量和键向量相乘,得到的QK矩阵中的每个值描述了对应位置token查询值和键值的相关程度。

相乘后,我们会得到一个维度为[17x17]自注意力矩阵。

qk_per_token = torch.matmul(q_per_token_rotated, k_per_token_rotated.T)/(head_dim)**0.5``qk_per_token.shape
torch.Size([17, 17])
掩码

语言模型的学习目标,是根据句子之前的内容预测下一个token,因此训练和推理时需要将token位置之后的QK分数屏蔽。

值向量

值权重数量和键权重一样,都是在4个注意力头之间共享(以节省计算量)。

v_layer0 = model["layers.0.attention.wv.weight"]``v_layer0 = v_layer0.view(n_kv_heads, v_layer0.shape[0] // n_kv_heads, dim)``v_layer0.shape
torch.Size([8, 128, 4096])

之后我们获取第一层第一个注意力头的值权重,与句子embedding相乘,获取值向量。

v_layer0_head0 = v_layer0[0]``v_per_token = torch.matmul(token_embeddings, v_layer0_head0.T)``v_per_token.shape
torch.Size([17, 128])
注意力向量

将进行过掩码的QK矩阵和句子的值向量相乘,就得到了注意力矩阵,维度为[17x128]。

qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)``qkv_attention.shape
torch.Size([17, 128])
多头注意力

以上得到的注意力矩阵,是第一层第一个注意力头的计算结果。

接下来需要运行一个循环,对第一层中所有32个注意力头进行上述运算过程。

qkv_attention_store = []``   ``for head in range(n_heads):`    `q_layer0_head = q_layer0[head]`    `k_layer0_head = k_layer0[head//4] # key weights are shared across 4 heads`    `v_layer0_head = v_layer0[head//4] # value weights are shared across 4 heads`    `q_per_token = torch.matmul(token_embeddings, q_layer0_head.T)`    `k_per_token = torch.matmul(token_embeddings, k_layer0_head.T)`    `v_per_token = torch.matmul(token_embeddings, v_layer0_head.T)``   `    `q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)`    `q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)`    `q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers * freqs_cis[:len(tokens)])`    `q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)``   `    `k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)`    `k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)`    `k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis[:len(tokens)])`    `k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)``   `    `qk_per_token = torch.matmul(q_per_token_rotated, k_per_token_rotated.T)/(128)**0.5`    `mask = torch.full((len(tokens), len(tokens)), float("-inf"), device=tokens.device)`    `mask = torch.triu(mask, diagonal=1)`    `qk_per_token_after_masking = qk_per_token + mask`    `qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax(qk_per_token_after_masking, dim=1).to(torch.bfloat16)`    `qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)`    `qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)`    `qkv_attention_store.append(qkv_attention)``   ``len(qkv_attention_store)
32

为了并行计算的方便,我们需要把上面展开的矩阵压缩回去。

也就是将32个维度为[17x128]的注意力矩阵,压缩成一个维度为[17x4096]的大矩阵。

stacked_qkv_attention = torch.cat(qkv_attention_store, dim=-1)``stacked_qkv_attention.shape
torch.Size([17, 4096])

最后,别忘了乘以输出权重矩阵。

w_layer0 = model["layers.0.attention.wo.weight"]``w_layer0.shape``# torch.Size([4096, 4096])``embedding_delta = torch.matmul(stacked_qkv_attention, w_layer0.T)``embedding_delta.shape
torch.Size([17, 4096])

至此,注意力模块的计算就结束了。

相加与归一化

对照这张Transformer层的架构图,在多头自注意力模块之后还需要完成一些运算。

首先将注意力模块的输出与原始的embedding相加。

embedding_after_edit = token_embeddings_unnormalized + embedding_delta``embedding_after_edit.shape
torch.Size([17, 4096])

之后进行RMS归一化。

embedding_after_edit_normalized = rms_norm(embedding_after_edit, model["layers.0.ffn_norm.weight"])``embedding_after_edit_normalized.shape
torch.Size([17, 4096])

前馈神经网络层

Llama 3的Transformer层中使用了SwiGLU前馈网络,这种架构非常擅长在必要情况下为模型添加非线性,这也是当今LLM中的常见操作。

SwiGLU与Vanilla两种前馈神经网络架构的对比

于是我们从模型中加载前馈网络的权重,并按照公式计算:

w1 = model["layers.0.feed_forward.w1.weight"]``w2 = model["layers.0.feed_forward.w2.weight"]``w3 = model["layers.0.feed_forward.w3.weight"]``output_after_feedforward = torch.matmul(torch.functional.F.silu(torch.matmul(embedding_after_edit_normalized, w1.T)) * torch.matmul(embedding_after_edit_normalized, w3.T), w2.T)``output_after_feedforward.shape
torch.Size([17, 4096])

别忘了前馈层之后还有一次相加。

layer_0_embedding = embedding_after_edit+output_after_feedforward``layer_0_embedding.shape
torch.Size([17, 4096])

以上就是一个完整Transformer层的实现,最终输出的向量维度为[17x4096],相当于为句子中每个token重新计算了一个长度为4096的embedding向量。

预测下一个输出

之后的每一个Transformer层都会编码出越来越复杂的查询,直到最后一层的输出的embedding可以预测句子下一个token。

因此需要再嵌套一个外层循环,将Transformer层的流程重复32次。

final_embedding = token_embeddings_unnormalized``for layer in range(n_layers):`    `qkv_attention_store = []`    `layer_embedding_norm = rms_norm(final_embedding, model[f"layers.{layer}.attention_norm.weight"])`    `q_layer = model[f"layers.{layer}.attention.wq.weight"]`    `q_layer = q_layer.view(n_heads, q_layer.shape[0] // n_heads, dim)`    `k_layer = model[f"layers.{layer}.attention.wk.weight"]`    `k_layer = k_layer.view(n_kv_heads, k_layer.shape[0] // n_kv_heads, dim)`    `v_layer = model[f"layers.{layer}.attention.wv.weight"]`    `v_layer = v_layer.view(n_kv_heads, v_layer.shape[0] // n_kv_heads, dim)`    `w_layer = model[f"layers.{layer}.attention.wo.weight"]`    `for head in range(n_heads):`        `q_layer_head = q_layer[head]`        `k_layer_head = k_layer[head//4]`        `v_layer_head = v_layer[head//4]`        `q_per_token = torch.matmul(layer_embedding_norm, q_layer_head.T)`        `k_per_token = torch.matmul(layer_embedding_norm, k_layer_head.T)`        `v_per_token = torch.matmul(layer_embedding_norm, v_layer_head.T)`        `q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)`        `q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)`        `q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers * freqs_cis)`        `q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)`        `k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)`        `k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)`        `k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis)`        `k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)`        `qk_per_token = torch.matmul(q_per_token_rotated, k_per_token_rotated.T)/(128)**0.5`        `mask = torch.full((len(token_embeddings_unnormalized), len(token_embeddings_unnormalized)), float("-inf"))`        `mask = torch.triu(mask, diagonal=1)`        `qk_per_token_after_masking = qk_per_token + mask`        `qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax(qk_per_token_after_masking, dim=1).to(torch.bfloat16)`        `qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)`        `qkv_attention_store.append(qkv_attention)``   `    `stacked_qkv_attention = torch.cat(qkv_attention_store, dim=-1)`    `w_layer = model[f"layers.{layer}.attention.wo.weight"]`    `embedding_delta = torch.matmul(stacked_qkv_attention, w_layer.T)`    `embedding_after_edit = final_embedding + embedding_delta`    `embedding_after_edit_normalized = rms_norm(embedding_after_edit, model[f"layers.{layer}.ffn_norm.weight"])`    `w1 = model[f"layers.{layer}.feed_forward.w1.weight"]`    `w2 = model[f"layers.{layer}.feed_forward.w2.weight"]`    `w3 = model[f"layers.{layer}.feed_forward.w3.weight"]`    `output_after_feedforward = torch.matmul(torch.functional.F.silu(torch.matmul(embedding_after_edit_normalized, w1.T)) * torch.matmul(embedding_after_edit_normalized, w3.T), w2.T)`    `final_embedding = embedding_after_edit+output_after_feedforward

最后一个Transformer层的输出维度与第一层相同,依旧是[17x4096]。

final_embedding = rms_norm(final_embedding, model["norm.weight"])``final_embedding.shape
torch.Size([17, 4096])

此时需要利用输出解码器,将最后一层输出的embedding先进行归一化处理,再转换为token。

final_embedding = rms_norm(final_embedding, model["norm.weight"])``final_embedding.shape``# torch.Size([17, 4096])
model["output.weight"].shape``# torch.Size([128256, 4096])
logits = torch.matmul(final_embedding[-1], model["output.weight"].T)``logits.shape
torch.Size([128256])

输出的向量维度与分词器中词汇数量相同,每个值代表了下一个token的预测概率。

模型预测下一个词是42?

和《银河系漫游指南》的梦幻联动(不知道是不是作者故意设置成这样的)

next_token = torch.argmax(logits, dim=-1)``next_token
tensor(2983)
tokenizer.decode([next_token.item()])
'42'

至此,我们就完成了Llama 3对输入句子进行下一个token预测的全过程。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范
  • …

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署
  • …

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建
  • …

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案
  • …

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

在这里插入图片描述

Llama 架构分析 Meta 开发并公开发布了 Llama系列大型语言模型 (LLM),这是一组经过预训练和微调的生成文本模型,参数规模从 70 亿到 700 亿不等。在大多数任务中,LLaMA-13B要比GPT-3(175B)的性能要好,LLaMA-65B和组好的模型Chinchilla-70B以及PaLM-540B的实力相当。 阅读详情

相关推荐

GPT-4稀疏激活原理:2%激活率背后的MoE架构与硬件协同

大语言模型中的‘稀疏激活’指模型在单次推理中仅动态调用部分参数子集,而非全量计算——这是区别于传统稠密模型的核心范式。其技术原理根植于Mixture of Experts(MoE)架构,通过路由机制(Router)实现输入Token到专家子集的选择性分发,从而在保持超大规模参数容量(如1.8万亿)的同时,将实际计算量压缩至极低水平(如2%)。这一设计显著降低FLOPs与延迟,支撑毫秒级响应,但对显存占用、负载均衡、NVLink通信和Tensor Core硬件适配提出严苛要求。典型应用场景包括高并发API服务

weixin_30443731的博客 439

【大模型】基于 LlaMA2 的高 star 的 GitHub 开源项目汇总

基于 LlaMA2 的高 star 的 GitHub 开源项目汇总

Zack的博客 5771

视觉特征-自监督-掩码特征预测【2024-11】:D-JEPA·T2I(通过下一词元预测实现高分辨率图像合成)【相对于D-JEPA的优化:文本条件、流匹配损失、VoPE】

近年来,自回归模型在类别条件图像生成方面展现了卓越的性能。然而,将下一词元预测应用于高分辨率文本到图像生成仍未得到充分探索。在本文中,我们提出了基于连续词元的自回归模型D-JEPA·T2I,该模型在架构和训练策略上均进行了创新,能够在高达4K的任意分辨率下生成高质量、照片级真实感的图像。在架构方面,我们采用去噪联合嵌入预测架构(D-JEPA),同时利用多模态视觉Transformer有效融合文本和视觉特征。此外,我们引入流匹配损失以及所提出的视觉旋转位置编码(VoPE),以实现连续分辨率学习。

u013250861的博客 174

Meta版ChatGPT惨遭“开源”?最新大模型LLaMA被泄露,已在GitHub收获7k+星

与 OpenAI 的 GPT-3 相比,Meta 在一开始就将 LLaMA 定位成一个“开源的研究工具”,该模型所使用的是各类公开可用的数据集(例如 Common Crawl、维基百科以及 C4)。这里测试的是所谓 5-shot 准确率,也就是对于任何特定问题,源材料都至少对其提及 5 次,(随着每次提及,答案的确定性水平都会提高,这与人类推理的过程非常相似。事实上,无论此事是否是 Meta 有意为之,在部分网友看来,LLaMA 原本的设定就是申请之后即可下载,“被公开是迟早的事情”。

IT界那些事儿 3390

llama 2 github官方文档

完成此操作后,您可以请求访问 Hugging Face 上的任何模型,并在 1-2 天内您的帐户将被授予访问所有版本的权限。我们最新版本的 Llama 现在可供个人、创作者、研究人员和各种规模的企业使用,以便他们能够负责任地实验、创新和扩展他们的想法。请参阅 llama-recipes 存储库,了解如何向推理代码的输入和输出添加安全检查器的。我们的使命是通过这个机会为个人和行业赋能,同时营造一个发现和道德人工智能进步的环境。一旦您的请求获得批准,您将通过电子邮件收到签名的 URL。开头,则您复制正确。

具身机器人和通用AI 1324

【十万字拆解】从零开始实现GPT-2(完整版)

本文是一篇 14 万字、从零硬核实现 GPT 的保姆级指南。内容全面覆盖四个阶段:①从最基础的 Bigram 语言模型切入,跑通数据处理与训练闭环;②仿照 Transformer 架构,深度研究 Multi-Head Attention、残差网络、LayerNorm 及 Dropout 的底层数学与代码实现;③从零构建BPE 分词器,对齐 GPT-2 规范;④从头搭建 GPT-1/2 工业级预训练流程,包含混合精度、梯度累积等十余项硬件级工程调优,并在 AutoDL 算力平台上从0开始训练!适合所有层次!

Pi_Nick的博客 1228

Software 3.0 实战指南:用自然语言驱动可验证代码生成

Software 3.0 是继手工编码(1.0)和框架配置(2.0)之后的软件范式演进,其核心是将自然语言指令作为系统意图的直接表达载体。它依托大语言模型(LLM)的代码生成能力,通过结构化 Prompt 设计、本地化推理部署与四层验证闭环(静态检查、动态测试、沙箱执行、人工审查),实现从需求到可上线服务的工程化落地。该范式并非取代开发者,而是将角色从‘代码编写者’升维为‘意图架构师’与‘验证设计者’,显著压缩重复性脚本开发周期,已在自动化报表、API 校验、知识库问答等场景验证实效。本文聚焦真实业务中的

weixin_33709590的博客 425

【速通版!语义通信基础与前沿学习计划】

🧠语义通信基础与前沿学习计划

dally2的博客 1412

大模型时代程序员能力重构与面试指南

大语言模型(LLM)正在重塑程序员的技术栈和工作方式,从基础编码到系统设计都发生了范式转移。理解LLM的核心原理,如提示词工程、模型微调和性能优化,已成为现代开发者的必备技能。这些技术不仅能提升3-5倍的开发效率,还能在金融、电商等场景中实现智能审批、合同审核等实际应用。掌握LLM工具链(如LangChain、GitHub Copilot)和集成架构设计,尤其是处理高并发、成本控制等工程实践,已成为高级程序员的核心竞争力。在技术面试中,企业越来越注重候选人的LLM实战能力,包括生产级Prompt设计、模型评

weixin_33860553的博客 389

使用buildroot系统的qmake编译QT出现Unknown module(s) in QT: xxxx 的错误解决方法

可以看到,我这里使用的是 qt5base-5.15.2 目录下的qmake,这个qmake只包含了基础的qt模块,而额外添加的qt模块没有包含进去,需要使用。可以看到我这里是有的,如果你跟我一样,模块存在,但是还是报找不到对应模块的错误的话,大概率是跟我一样,用错qmake了,看第二点。在包含 qt5base 目录下查看,是否有对应模块的目录,如果没有的话,需要通过make menuconfig 添加一下。目录下的qmake才可以。

T541132的博客 2490

告别ROS1思维:在ROS2 Humble上,用Python搞定MoveIt2机械臂控制的完整流程

本文详细介绍了在ROS2 Humble环境下使用Python控制MoveIt2机械臂的完整流程。从环境配置、架构变革到实战操作,涵盖URDF适配、Action接口编程及性能优化技巧,帮助开发者高效迁移ROS1项目至ROS2平台,实现工业级机械臂控制。

weixin_30352645的博客 449

Karpathy大神点赞,从零实现LLaMa3项目爆火,已获1.5k star

一个月前,Meta 发布了开源大模型 llama3 系列,在多个关键基准测试中优于业界 SOTA 模型,并在代码生成任务上全面领先。此后,开发者们便开始了本地部署和实现,比如 llama3 的中文实现、llama3 的纯 NumPy 实现等。十几个小时前,有位名为「Nishant Aklecha」的开发者发布了一个从零开始实现 llama3 的存储库,包括跨多个头的注意力矩阵乘法、位置编码和每个层...

深度学习技术前沿 421

AI编程实战:用Spec Coding与Codex半小时重构全栈项目

这次我们来看一个能显著提升全栈开发效率的实战方法:利用 AI 编程工具 Codex 和 Spec Coding 工作流,将原本需要数周甚至一个月的全栈项目重构工期,压缩到半小时级别。这不是概念探讨,而是基于现有工具链的、可立即上手的工程实践。 对于前端开发者或全栈工程师而言,面对老旧项目重构、技术栈升级或从零搭建新项目时,最大的痛点往往是重复性、模式化的代码编写工作。手动编写 CRUD 接口、页面组件、状态管理和联调测试,耗时费力且容易出错。而 AI 辅助编程的核心价值,正是在于将开发者从这些“体力活”中解

weixin_33525298的博客 290

AI大模型时代,新手和程序员如何转型入局AI行业?

在人工智能(AI)的浪潮中,大模型技术正以前所未有的速度发展,并在各个领域展现出其强大的应用潜力。

老皮的博客 684

CTP-API开发系列之三:柜台系统简介

综合交易平台(Comprehensive Transaction Platform,CTP)是专门为期货公司开发的一套期货经纪业务管理系统,由交易、风险控制和结算三大系统组成。接下来分享的内容,对于期货公司的负责交易、运维同事会比较熟悉,针对CTP-API接口对接的朋友可以了解一下,在接口之上的系统是怎样的。

码上助君的专栏 6198

prplOS组件流程梳理

本文梳理了prplOS系统中设备信息管理模块(deviceinfo-manager)的工作流程。该模块启动时通过/etc/init.d/deviceinfo-manager调用核心框架amxrt执行,主要功能包括收集设备信息、管理数据模型、初始化子系统等。系统采用ODL文件定义数据模型,通过解析器将配置文件转换为内存中的对象树。流程涉及命令行参数解析、ODL文件加载、后端模块扫描等核心步骤,最终构建出完整的数据模型供上层应用访问。整个架构体现了模块化设计思想,通过动态加载插件实现功能扩展。

四儿家的小祖宗的博客 1268

LLaMA及其子孙模型概述

Alpaca是Stanford用52k指令数据微调LLaMA 7B后得到的预训练模型,作者声称在单轮指令执行的效果上,Alpaca的回复质量和openai的text-davinci-003相当,但是Alpaca的参数非常少(微调一个7B的llama需要在8张A100 80G上训练3个小时,花费至少100美元)。为了更好的评估效果,我们使用了一个包含一千个样本和九个真实场景的评估集来测试各种模型,同时通过量化分析来提供有价值的见解,以便更好地促进开源聊天模型的发展。白泽提出的训练方法。

qq_44193969的博客 2328

贝叶斯地理统计模型R-INLA-1

贝叶斯地理统计模型R-INLA-1

学习中 2426

LLaMA细节与代码解析

也就是说,假如当前输入的序列长度是512,那么截取出来的这个新的freqs_cis,形状就是(512, 64),reshape之后,形状就变成了(1, 512, 1, 32),也就是在每一个位置上,都对应有32个角度,根据刚刚torch.polar的介绍,当我们固定绝对值(也就是向量的模长)时,角度就可以在笛卡尔坐标系下唯一确定一个复数,这样一来也就是32个复数,即64个特征维度,所以就可以对应的将它融合到每个attention head的64个特征中去了。接下来是transformer模型的构建。

AI生成式技术曾小健 2073

2026华为OD机试 新系统真题题库目录|机考题库 + 算法考点详解

华为OD机试 新系统真题题库目录|机考题库 + 算法考点详解华为od机试,华为od机试真题,华为od机试E卷,华为odE卷,华为od机试真题E卷,华为OD,华为OD机试,华为OD机试真题,华为od机考,华为od机试D卷,华为od机试真题D卷,华为od手撕代码,华为od,华为od机试C卷,华为od e卷,华为2026e卷,od机试,2026E卷,华为OD机试E卷,什么是华为od,华为od介绍,全面了解华为od,2026华为od,如何备战华为od,华为od算法,华为od手撕代码,华为OD机试2024年最新题库,

KJ.JK 4699

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

LLaMa系列模型详解(原理介绍、代码解读):LLaMa

下图很直观的展示了旋转变换的过程:旋转编码 RoPE 可以有效地保持位置信息的相对关系,

qq_51957239的博客 2万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Meta开源的LLaMa到底好不好用?最全测评结果来了

源|机器之心Meta 开源的大模型系列 LLaMA 评测出炉,对比结果显示,和 ChatGPT 还是有差距的。ChatGPT 的持续爆火,早已让各大科技公司坐不住了。就在刚刚过去的一周,Meta「开源」了一个新的大模型系列 ——LLaMA(Large Language Model Meta AI),参数量从 70 亿到 650 亿不等。因为 LLaMA 比之前发布的很多大模型参数更少,但性能更好,...

夕小瑶科技说 1万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Llama-GitHub 项目教程

Llama-GitHub 项目教程 1. 项目目录结构及介绍 Llama-GitHub 项目的目录结构如下: llama-github/ ├── docs/ ├── llama_github/ ├── tests/ ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── M...

gitblog_01012的博客 1331

LLaMA系列 | LLaMA和LLaMA-2精简总结

LLaMA系列 | LLaMA和LLaMA-2精简总结

weixin_43646592的博客 9137

LLaMA(大规模机器学习和分析)

LLaMA(大规模机器学习和分析)是一个先进的软件平台,是Meta 推出 AI 语言模型 LLaMA,一个有着 上百亿数量级参数的大语言模型用于大规模部署和管理机器学习模型。

chen7ang的博客 5641

Meta LLaMA 2实操:从零到一搭建顶尖开源大语言模型【超详篇】

●您可以用自己的特定数据集训练模型,这可以使模型更好地适应您的特定用例和业务需求。●可以调整模型架构和训练过程,以优化模型的表现。

yue85832982的博客 3154
上一篇: 零成本无部署,一个免费使用40余种LLM大模型的方法
下一篇: 本地安装llama-3大模型,无需联网即可跟AI大模型聊天
Python_金钱豹
博客等级 码龄5年 1万+粉丝 2835原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值