MiniMind:3块钱成本 + 2小时!训练自己的0.02B的大模型。minimind源码解读、MOE架构

大家好,我是此林。

目录

1. 前言

2. minimind模型源码解读

1. MiniMind Config部分

1.1. 基础参数

1.2. MOE配置

 

2.  MiniMind Model 部分 

2.1. MiniMindForCausalLM: 用于语言建模任务

2.2. 主干模型 MiniMindModel

2.3. MiniMindBlock: 模型的基本构建块

2.4. class Attention(nn.Module)

2.5. MOEFeedForward

2.6. FeedForward

2.7. 其他

3. 写在最后


 

1. 前言

大模型在这个时代可以说无处不在了,但是LLM动辄数百亿参数的庞大规模。对于我们个人开发者而言不仅难以训练,甚至连部署都显得遥不可及。

那 github 上 20k Star+ 的开源项目 minimind,声称仅用3块钱成本 + 2小时!即可训练出仅为25.8M的超小语言模型 MiniMind。 

这不是谣言,此林已经帮你们试过了,AutoDL租用的 GPU 上训练(Pretrain + SFT有监督微调)差不多2个小时半。Pretain 和 SFT 的数据集总共才 2.5G 左右。部分源码也解读了一下。

这是 Pretain 之后的:模型复读机现象有点明显,只会词语接龙。

这是 SFT 微调后的:幻觉现象还是有点严重的,不过句子很流畅,可以接话了。

当然也用 react 快速搭了一个聊天框架,适配 http stream,看着还不错。

链接文末自取。

2. minimind模型源码解读

1. MiniMind Config部分

1.1. 基础参数

from transformers import PretrainedConfig

PretrainedConfig 是所有 Transformer 模型配置类的基类,用于:

 • 存储模型的结构参数(如隐藏层大小、注意力头数、层数等)

 • 记录预训练模型的元信息(如 model_type、tokenizer_class)

 • 支持从预训练模型自动加载配置

在 Transformers 中,每个模型都有一个对应的 Config 类,比如:

    •    BertModel — BertConfig

    •    GPT2Model — GPT2Config

    •    LlamaModel — LlamaConfig

这些都继承自 PretrainedConfig,主要是构建模型前先配置参数。

使用场景举例:查看 bert 隐藏层维度

from transformers import PretrainedConfigconfig = PretrainedConfig.from_pretrained("bert-base-uncased")print(config.hidden_size) # 查看隐藏层维度

那在这里的场景,是自定义配置用于训练或推理,下面会说到。

这里就是定义了 MiniMindConfig,继承自 PretrainedConfig。

class MiniMindConfig(PretrainedConfig):model_type = "minimind"def __init__(self,dropout: float = 0.0,bos_token_id: int = 1,# 省略...**kwargs):super().__init__(**kwargs)self.dropout = dropoutself.bos_token_id = bos_token_idself.eos_token_id = eos_token_idself.hidden_act = hidden_actself.hidden_size = hidden_size# 省略...# 和MoE相关的参数,如果use_moe=false,就忽略下边的self.use_moe = use_moeself.num_experts_per_tok = num_experts_per_tok  # 每个token选择的专家数量self.n_routed_experts = n_routed_experts  # 总的专家数量self.n_shared_experts = n_shared_experts  # 共享专家self.scoring_func = scoring_func  # 评分函数,默认为'softmax'self.aux_loss_alpha = aux_loss_alpha  # 辅助损失的alpha参数self.seq_aux = seq_aux  # 是否在序列级别上计算辅助损失self.norm_topk_prob = norm_topk_prob  # 是否标准化top-k概率

下面就一行一行来看里面的参数。

dropout: float = 0.0

Dropout 是一种防止过拟合的正则化技术,在每次前向传播时,随机丢弃一部分神经元的输出,防止模型过度依赖某些神经元,从而提高泛化能力。

比如:dropout = 0.1,那么:

 • 模型每层中有 10% 的神经元在训练时会被“屏蔽”(不参与计算)。

 • 在推理时(即模型使用阶段),Dropout 是自动关闭的。

dropout: float = 0.0 就是关闭dropout。

bos_token_id: int = 1, # 开始 token 的 ID(Begin of Sentence)
eos_token_id: int = 2, # 结束 token 的 ID(End of Sentence)

在推理中的作用:

 • bos_token_id:模型知道“从这里开始生成”。

 • eos_token_id:模型在生成过程中,一旦预测出这个 token,就认为输出完毕,停止生成。

这两个 token 也经常用于 Hugging Face 的 generate() 方法

model.generate(
    input_ids,
    bos_token_id=1,
    eos_token_id=2,
    max_length=50
)

hidden_act: str = 'silu'

激活函数类型(如 silu、relu、gelu),用SwiGLU激活函数替代了ReLU,这样做是为了提高性能。

 hidden_size: int = 512

Transformer 每层的隐藏状态维度 

intermediate_size: int = None

前馈层中间维度,如果为None,即用户没设置,后面代码里会设置成 hidden_size * 8 / 3,这是在FeedForward里做的事情。

num_attention_heads: int = 8, # 每层中注意力头的数量
num_hidden_layers: int = 8, # Transformer 层的数量
num_key_value_heads: int = 2, # KV heads 的数量(用于多头注意力键值共享/分离)

每个 Transformer 层由多头注意力层(Multi-Head Attention)和 前馈网络(FFN)组成。

上面的参数表示:模型有 8 层 Transformer 层,每个 Transformer 层中有 8 个注意力头,并且使用 2 个专门的头来处理键(Key)和值(Value),相当于在多头注意力的计算中,键和值部分的处理是分开的。

vocab_size: int = 6400

模型词表大小(tokenizer 中的 token 总数) ,minimind是自己训练了个tokenizer。        

rms_norm_eps: float = 1e-05, # RMSNorm 的 epsilon 值(防止除以0)rope_theta: int = 1000000.0, # RoPE 中的位置旋转频率(控制编码的尺度)

采用了GPT-3的预标准化方法,也就是在每个Transformer子层的输入上进行归一化,而不是在输出上。具体来说,使用的是RMSNorm归一化函数。

像GPT-Neo一样,去掉了绝对位置嵌入,改用了旋转位置嵌入(RoPE),这样在处理超出训练长度的推理时效果更好。 

flash_attn: bool = True

Transformer 架构中,注意力机制 是关键的计算部分。传统的注意力计算涉及较大的矩阵乘法,内存消耗大且计算速度较慢,尤其是在处理长序列时。FlashAttention 是一种基于 GPU 的优化算法,专门为 Transformer 模型中的自注意力计算(Self-Attention)进行加速。

1.2. MOE配置

下面的为MOE 配置:仅当 use_moe=True 时有效

它的结构基于Llama3和Deepseek-V2/3中的MixFFN混合专家模块。

DeepSeek-V2在前馈网络(FFN)方面,采用了更细粒度的专家分割和共享的专家隔离技术,以提高Experts的效果。

            use_moe: bool = False, # 是否启用 MOE(专家混合)机制

            num_experts_per_tok: int = 2, # 每个 token 选择的专家数量(Top-K)

            n_routed_experts: int = 4, # 可路由的专家总数(不包含共享专家)

            n_shared_experts: int = 1, # 所有 token 共享的专家数量(共享路径)

            scoring_func: str = 'softmax', # 路由函数类型(如 softmax、top-k-gumbel)

            aux_loss_alpha: float = 0.1, # MOE 的辅助损失系数(平衡 load balance)

            seq_aux: bool = True, # 是否在序列级别计算辅助损失,而非 token 级别

            norm_topk_prob: bool = True, # 是否对 Top-K 路由概率归一化(影响路由输出

num_experts_per_tok: int = 2

在 MoE 中,我们通常有很多个前馈网络(专家),比如 n_routed_experts = 8。但我们并不希望每个 token 都经过所有 8 个专家计算,这样计算成本太高。所以我们使用一个门控网络(gate)来为每个 token 选择得分Top-K的专家处理。

这里等于 num_experts_per_tok = 2 就是选择得分前 2 的专家,输出结果是这两个专家的加权和(按照 gate 输出的概率加权)。

n_routed_experts: int = 4

n_routed_experts 表示有多少个普通专家(非共享专家)可以被 gate 路由(选择)使用。

共享专家是指在所有层中都可以使用的专家,在token前向路径自动经过,不用 gate 选。

结合刚才的 num_experts_per_tok = 2

对于每个 token:

  1. gate 只会在这 4 个专家中计算得分(不是在全部 MoE 中的专家)。

  2. 从中选择得分最高的 2 个来执行前馈计算。

  3. gate 输出加权这些专家的结果。

 scoring_func: str = 'softmax' # 路由函数类型(如 softmax、top-k-gumbel)

这个就是门控网络(gate)对专家打分的机制,用了softmax,通常配合负载平衡机制使用,下面这个参数就是。

aux_loss_alpha: float = 0.1

在 MoE 模型中,每个 token 会通过路由选择若干个专家来处理,这些专家的计算量通常是不均衡的,某些专家可能会频繁被选中,而其他专家可能很少或几乎不被选择。这种不均衡的负载分配会导致一些专家被过度使用,而其他专家则被闲置,进而影响训练效率和最终模型的泛化能力。

为了解决这个问题,辅助损失会通过在模型训练中加上一个额外的损失项,强制使各个专家的使用频率更均衡,从而改善负载平衡。

seq_aux: bool = True, # 是否在序列级别计算辅助损失,而非 token 级别

表示在序列级别计算辅助损失,而不是每个 token 单独的负载。也就是模型会保证整个输入序列的专家负载是均衡的,而不单单是某个具体的 token。在 token 级别计算辅助损失会导致较高的计算成本。

norm_topk_prob: bool = True

是否对 Top-K 路由概率归一化(影响路由输出),归一化简单来说就是让概率总和为 1。

看到这里,相信你对MoE已经有了一定了解。

所以总的来说,MoE 模型的核心思想是:在每次前向传播的过程中,通过门控网络(gate) 只挑选得分Top-N个专家 参与计算,避免了全局计算的高成本。MoE 的最大优势在于它的 稀疏性

传统的神经网络是 Dense(密集)网络,也叫 全连接网络。对于每一个输入样本,网络中的每个神经元都会参与计算,也就是每一层都会进行全量计算。每然后进行加权和计算。

 

2.  MiniMind Model 部分 

主要架构分为几个部分,逐个来介绍。

2.1. MiniMindForCausalLM: 用于语言建模任务

包含:

1. 主干模型 MiniMindModel
2. 输出层 lm_head(共享词嵌入权重)
输出:包含 logits(预测)、past_key_values(KV缓存)和 aux_loss(MOE专用)

 

2.2. 主干模型 MiniMindModel

包含:

1. 词嵌入(embed_tokens)+ Dropout
2. 位置编码(RoPE)预计算并注册为 buffer
3. 堆叠多个 MiniMindBlock 层(用 nn.ModuleList)
输出:最后的隐藏状态、present key values、辅助损失(如果用了 MOE)

 

2.3. MiniMindBlock: 模型的基本构建块

包含:
1. 自注意力层(self_attn)
2. 两个 RMSNorm 层(输入 & Attention 之后)
3. 一个前馈层(MLP 或 MOE)
4. 前向传播:LayerNorm → Attention → 残差 → LayerNorm → MLP 或 MOE→ 残差

self.mlp = FeedForward(config) if not config.use_moe else MOEFeedForward(config)

具体看这行代码,如果use_moe == true,那么使用MOEFeedForward,否则使用FeedForward

 

2.4. class Attention(nn.Module)

GQA(Grouped Query Attention)+ Rotary Positional Embedding + FlashAttention(可选)+ KV Cache(可选) 。优化过的高效自注意力实现,类似 LLaMA3 / DeepSeek-V2/3 模型结构。

 

2.5. MOEFeedForward

1. __init__():初始化函数,定义层结构(线性层、注意力层、专家列表等)

self.experts = nn.ModuleList([
        FeedForward(config) for _ in range(config.n_routed_experts)
    ])

比如这里定义了一组专家 FFN 层,供后续调用。

2.forward():前向传播逻辑,

  • token 被送入路由器 gate

  • 决定用哪些专家处理这些 token

  • 聚合专家输出

3. moe_infer():推理专用的稀疏处理方法(只在 MoE 中),MiniMind 的这个模块为了高效推理自己实现的一个工具方法,只在 self.training == False 时被调用,它属于性能优化路径。

不重复计算专家,将所有 token 排序,根据分配给专家的结果批处理执行,最后用 scatter_add_ 聚合输出,避免内存浪费。

 

2.6. FeedForward

这个其实是是 MoE 和非 MoE 都能用的通用 FFN 单元,在 MoE 中,FeedForward 被封装为专家模块。(可以看下之前 MOEFeedForward 里标红的部分)

多数情况下是 transformer 块中的 MLP 部分。

1. __init__():初始化函数

2.forward():前向传播逻辑。

 

2.7. 其他

1. class RMSNorm(torch.nn.Module)

RMSNorm,和 LayerNorm 类似,归一化技术。但它 只依赖于特征的均方根(RMS),而不是标准差。这种方法更快、更稳定,尤其适用于大模型。

2. def precompute_freqs_cis()

用于实现 旋转位置编码(RoPE)。RoPE 的目标是将位置信息以旋转方式注入到 query 和 key 中,替代传统的绝对位置嵌入。这个之前介绍参数里说过。

3. def apply_rotary_pos_emb()

应用旋转位置编码,每个 token 的向量分成前半和后半部分,将其旋转(换顺序并取反),保留位置信息并增强长期依赖能力。

4. def repeat_kv()

支持GQA,用于 将较少的 Key/Value head 扩展重复以适配更多的 Query heads。例如 Q=8 头,KV=2 头,那么每个 KV 会被复制 4 次。

 

3. 写在最后

GitHub - jingyaogong/minimind: 🚀🚀 「大模型」2小时完全从0训练26M的小参数GPT!🌏 Train a 26M-parameter GPT from scratch in just 2h!

关注我吧,我是此林,带你看不一样的世界! 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/80379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

引言:Client Hello 为何是 HTTPS 安全的核心?

当用户在浏览器中输入 https:// 时,看似简单的操作背后,隐藏着一场加密通信的“暗战”。Client Hello 作为 TLS 握手的首个消息,不仅决定了后续通信的加密强度,还可能成为攻击者的突破口。据统计,超过 35% 的网站因 TL…

Dockerfile 完全指南:从入门到最佳实践

Dockerfile 完全指南:从入门到最佳实践 1. Dockerfile 简介与作用 Dockerfile 是一个文本文件,包含了一系列用于构建 Docker 镜像的指令。它允许开发者通过简单的指令定义镜像的构建过程,实现自动化、可重复的镜像构建。 主要作用&#xf…

Python httpx库终极指南

一、发展历程与技术定位 1.1 历史演进 起源:httpx 由 Encode 团队开发,于 2019 年首次发布,目标是提供一个现代化的 HTTP 客户端,支持同步和异步操作,并兼容 HTTP/1.1 和 HTTP/2。背景: requests 库虽然功…

app加固

1、什么是加固? 我们之前讲的逆向,大多数都是用加密算法去加密一些明文字符串,然后把得到的结果用 Base64、Hex等进行编码后提交。加固其实也一样,只不过他通常加密的是 dex文件而已。但是 dex 文件加密以后,安卓系统是没法直接运行的。所以加固的核心&…

Win全兼容!五五 Excel Word 转 PDF 工具解决多场景转换难题

各位办公小能手们!今天给你们介绍一款超牛的工具——五五Excel Word批量转PDF工具V5.5版。这玩意儿专注搞批量格式转换,能把Excel(.xls/.xlsx)和Word(.doc/.docx)文档唰唰地变成PDF格式。 先说说它的核心功…

springCloud/Alibaba常用中间件之Nacos服务注册与发现

文章目录 SpringCloud Alibaba:依赖版本补充六、Nacos:服务注册与发现1、下载安装Nacos2、服务注册1. 导入依赖(这里以服务提供者为例)2. 修改配置文件和主启动类3. 创建业务类4. 测试 3.服务映射1. 导入依赖2. 修改配置文件和主启动类3. 创建业务类和RestTemplate配置类用来提…

uniapp中score-view中的文字无法换行问题。

项目场景: 今天遇到一个很恶心的问题,uniapp中的文字突然无法换行了。得..就介样 原因分析: 提示:经过一fan研究后发现 scroll-view为了能够横向滚动设置了white-space: nowrap; 强制不换行 解决起来最先想到的是,父…

【STM32 学习笔记】I2C通信协议

注:通信协议的设计背景 3:00~10:13 I2C 通讯协议(Inter-Integrated Circuit)是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强, 不需要USART、CAN等通讯协议的外部收发设备,现在被广…

【网络原理】数据链路层

目录 一. 以太网 二. 以太网数据帧 三. MAC地址 四. MTU 五. ARP协议 六. DNS 一. 以太网 以太网是一种基于有线或无线介质的计算机网络技术,定义了物理层和数据链路层的协议,用于在局域网中传输数据帧。 二. 以太网数据帧 1)目标地址 …

控制台打印带格式内容

1. 场景 很多软件会在控制台打印带颜色和格式的文字,需要使用转义符实现这个功能。 2. 详细说明 2.1.转义符说明 样式开始:\033[参数1;参数2;参数3m 可以多个参数叠加,若同一类型的参数(如字体颜色)设置了多个&…

[6-2] 定时器定时中断定时器外部时钟 江协科技学习笔记(41个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 V 30 31 32 33 34 35 36 37 38 39 40 41

数据库的脱敏策略

数据库的脱敏策略:就是屏蔽敏感的数据 脱敏策略三要求: (1)表对象 (2)生效条件(脱敏列、脱敏函数) (3)二元组 常见的脱敏策略规则: 替换、重排、…

Python序列化的学习笔记

1. Npy&Numpy O4-mini-Cursor:如果.npy文件里包含了「Python对象」而非纯数值数组时,就必须在加载时加上allow_pickleTrue。

[思维模式-27]:《本质思考力》-7- 逆向思考的原理与应用

目录 一、什么是逆向思考 1.1、逆向思考的六大核心思维模式 1.2、逆向思考的四大实践方法 1. 假设倒置法 2. 缺陷重构法 3. 用户反推法 4. 规则解构法 1.3、逆向思考的经典案例库 1. 商业创新:从“卖产品”到“卖服务” 2. 用户体验:从“功能满…

在python中,为什么要引入事件循环这个概念?

在Python中,事件循环(Event Loop)是异步编程的核心机制,它的引入解决了传统同步编程模型在高并发场景下的效率瓶颈问题。以下从技术演进、性能优化和编程范式三个角度,探讨这一概念的必要性及其价值。 一、同步模型的局…

Taccel:一个高性能的GPU加速视触觉机器人模拟平台

触觉感知对于实现人类水平的机器人操作能力至关重要。而视觉触觉传感器(VBTS)作为一种有前景的解决方案,通过相机捕捉弹性凝胶垫的形变模式来感知接触的方式,为视触觉机器人提供了高空间分辨率和成本效益。然而,这些传…

oracle 会话管理

会话管理 1:查看当前所有用户的会话(SESSION): SELECT * FROM V S E S S I O N W H E R E U S E R N A M E I S N O T N U L L O R D E R B Y L O G O N T I M E , S I D ; 其中 O r a c l e 内部进程的 U S E R N A M E 为空 2 :查看当前…

Python开发后端InfluxDB数据库测试接口

1、使用PyCharm创建一个Python项目wzClear 2、新建package包wzInfluxdb和wzConfig包,如上图所示,新建一个DB.json配置文件并添加influxdb配置信息,DB.json为统一配置文件 {"influxdbV1": {"url": "http://192.168.0…

采用LLaMa-Factory对QWen大模型实现微调(效果很好)

前言 LLaMA-factory是一个非常有用的开源框架。关于利用llama-factory实现大模型的微调,研究了有一个多月了,终于相对成功的微调了一个QWen的大模型。其中的曲折愿和大家分享! 一、源码的下载 在github上的网址: GitHub - hiyou…

深入理解深度Q网络DQN:基于python从零实现

DQN是什么玩意儿? 深度Q网络(DQN)是深度强化学习领域里一个超厉害的算法。它把Q学习和深度神经网络巧妙地结合在了一起,专门用来搞定那些状态空间维度特别高、特别复杂的难题。它展示了用函数近似来学习价值函数的超能力&#xf…