聊聊ChatGLM-6B的源码分析
基于ChatGLM-6B第一版,要注意还有ChatGLM2-6B以及ChatGLM3-6B
PrefixEncoder
作用:在微调时(以P-Tuning V2为例),方法训练时冻结模型的全部参数,只激活PrefixEncoder的参数。
其源码如下,整体来看是比较简单的。
class PrefixEncoder(torch.nn.Module):
def __init__(self, config):
super().__init__()
self.prefix_projection = config.prefix_projection
if self.prefix_projection:
# 使用一个两层(线性层)的MLP编码prefix
self.embedding = torch.nn.Embedding(config.pre_seq_len, config.hidden_size)
self.trans = torch.nn.Sequential(
torch.nn.Linear(config.hidden_size, config.hidden_size),
torch.nn.Tanh(),
torch.nn.Linear(config.hidden_size, config.num_layers * config.hidden_size * 2)
)
else:
self.embedding = torch.nn.Embedding(config.pre_seq_len, config.num_layers * config.hidden_size * 2)
def forward(self, prefix: torch.Tensor):
if self.prefix_projection:
prefix_tokens = self.embedding(prefix)
past_key_values = self.trans(prefix_tokens)
else:
past_key_values = self.embedding(prefix)
return past_key_values
为什么源码注释中会说到MLP?定位追溯:
self.mlp = GLU(
hidden_size,
inner_hidden_size=inner_hidden_size,
bias=use_bias,
layer_id=layer_id,
params_dtype=params_dtype,
empty_init=empty_init
)
def default_init(cls, *args, **kwargs):
return cls(*args, **kwargs)
class GLU(torch.nn.Module):
def __init__(self, hidden_size, inner_hidden_size=None,
layer_id=None, bias=True, activation_func=gelu, params_dtype=torch.float, empty_init=True):
super(GLU, self).__init__()
if empty_init:
init_method = skip_init
else:
init_method = default_init
self.layer_id = layer_id
self.activation_func = activation_func
# Project to 4h.
self.hidden_size = hidden_size
if inner_hidden_size is None:
inner_hidden_size = 4 * hidden_size
self.inner_hidden_size = inner_hidden_size
self.dense_h_to_4h = init_method(
torch.nn.Linear,
self.hidden_size,
self.inner_hidden_size,
bias=bias,
dtype=params_dtype,
)
# Project back to h.
self.dense_4h_to_h = init_method(
torch.nn.Linear,
self.inner_hidden_size,
self.hidden_size,
bias=bias,
dtype=params_dtype,
)
def forward(self, hidden_states):
"""
hidden_states: [seq_len, batch, hidden_size]
"""
# [seq_len, batch, inner_hidden_size]
intermediate_parallel = self.dense_h_to_4h(hidden_states)
intermediate_parallel = self.activation_func(intermediate_parallel)
output = self.dense_4h_to_h(intermediate_parallel)
return output
# 转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/
init_method
对应到default_init
,这个函数的作用与直接调用类构造函数相同,但它提供了一种更灵活的方式来创建类的实例,因为它可以接受任意数量的位置参数和关键字参数。在Pytorch中,用于模块化的构造函数。从源码分析来看,GLU/MLP类就是构造了两个线性层与gelu激活函数,其结构可简化如下:
从PrefixEncoder
类的初始化方法来看,其就是embedding层与MLP的组合。其结构可简化如下:
详细解读可参考 ChatGLM的模型架构
Q:在这里还有一个问题,从哪里可以定位溯源到微调时禁用了全部的参数,只激活PrefixEncoder的参数并调用了该类?
激活函数与位置编码
代码简单明了,RoPE的理论知识可以多了解。
attention_fn
伪代码表示为:
def attention_fn(
self,
query_layer,
key_layer,
value_layer,
attention_mask,
hidden_size_per_partition,
layer_id,
layer_past=None,
scaling_attention_score=True,
use_cache=False,
):
xxxx
标准的注意力机制计算公式如下:
多头注意力就是将多个单头注意力的结果拼接起来,再点乘一个新的权重参数。
attention_fn
函数实现了注意力的核心计算过程(即上述数学表达式),包括计算注意力分数、注意力概率和上下文层。这些计算对于实现许多自然语言处理任务,如语言建模、命名实体识别等,都是非常重要的。
SelfAttention
伪代码表示为:
class SelfAttention(torch.nn.Module):
xxxx
attention_mask_func
将注意力掩码应用于Transformer模型中的注意力得分中。
@staticmethod
def attention_mask_func(attention_scores, attention_mask):
attention_scores.masked_fill_(attention_mask, -10000.0)
return attention_scores
apply_rotary_pos_emb_index
函数为注入了RoPE位置信息,然后调用attention_fn
计算注意力概率、上下文层表示,并得到返回值。这些都是在forward
函数中调用处理的。
最后还调用了dense对上下文表示做线性计算,返回输出。
GLU
GLU也可以理解为是MLP,在后面版本的ChatGLM中,去掉了GLU类的定义声明,直接换成了MLP。在上面已经写过不再赘述。
GLMBlock
一般都会把GLMBlock
对应为transformer结构的实现。从其构造函数来看,主要是拼接各个层到一起。
从代码来看,中间有两次的残差连接,如下所示
# Residual connection.
alpha = (2 * self.num_layers) ** 0.5
hidden_states = attention_input * alpha + attention_output
mlp_input = self.post_attention_layernorm(hidden_states)
# MLP.
mlp_output = self.mlp(mlp_input)
# Second residual connection.
output = mlp_input * alpha + mlp_output
ChatGLMPreTrainedModel
TODO....
ChatGLMModel
TODO....
聊聊ChatGLM-6B的源码分析的更多相关文章
- 【小家Spring】聊聊Spring中的数据绑定 --- DataBinder本尊(源码分析)
每篇一句 唯有热爱和坚持,才能让你在程序人生中屹立不倒,切忌跟风什么语言或就学什么去~ 相关阅读 [小家Spring]聊聊Spring中的数据绑定 --- 属性访问器PropertyAccessor和 ...
- HashMap实现原理及源码分析
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...
- TextView 的新特性,Autosizing 到底是如何实现的? | 源码分析
一.前言 Hi,大家好,我是承香墨影! 前两天聊了一下 Autosizing 的使用,反映还不错.毕竟是这种能解决实际问题的新 Api,确实在需要的时候,用起来会很顺手. 简单回顾一下,Autosiz ...
- HashMap和ConcurrentHashMap实现原理及源码分析
HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...
- HashMap实现原理及源码分析(JDK1.7)
转载:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技 ...
- Dubbo 源码分析 - SPI 机制
1.简介 SPI 全称为 Service Provider Interface,是 Java 提供的一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加 ...
- 转载-HashMap1.7源码分析
原文地址-https://www.cnblogs.com/chengxiao/p/6059914.html HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重 ...
- MyBatis 源码分析系列文章导读
1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...
- EasyUI学习总结(三)——easyloader源码分析(转载)
声明:这一篇文章是转载过来的,转载地址忘记了,原作者如果看到了,希望能够告知一声,我好加上去! easyloader模块是用来加载jquery easyui的js和css文件的,而且它可以分析模块的依 ...
- HashMap实现原理及源码分析之JDK7
攻克集合第一关!! 转载 http://www.cnblogs.com/chengxiao/ 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如m ...
随机推荐
- 真·Redis缓存优化—97%的优化率你见过嘛?
本文通过一封618前的R2M(公司内部缓存组件,可以认为等同于Redis)告警,由浅入深的分析了该告警的直接原因与根本原因,并根据原因提出相应的解决方法,希望能够给大家在排查类似问题时提供相应的思路. ...
- stat函数详解
Linux系统函数之文件系统管理 stat函数 作用:获取文件信息 include <sys/types.h> #include <sys/stat.h> #include & ...
- 期中考试成绩出来了。分数在70~80是等级B。
#多输入 空格分割a = input()b = a.split()c = list(map(int, b))print(c) 等级B 描述 期中考试成绩出来了.分数在70-80是等级B. 输入 请 ...
- Python 提取PDF文本和图片
从PDF中提取内容能帮助我们获取文件中的信息,以便进行进一步的分析和处理.此外,在遇到类似项目时,提取出来的文本或图片也能再次利用.要在Python中通过代码提取PDF文件中的文本和图片,可以使用 S ...
- ChatGPT 是如何产生心智的?
一.前言 - ChatGPT真的产生心智了吗? 来自斯坦福大学的最新研究结论,一经发出就造成了学术圈的轰动,"原本认为是人类独有的心智理论(Theory of Mind,ToM),已经出现在 ...
- idea修改默认maven配置
idea修改默认maven配置 方法一 (不推荐) 打开project.default.xml文件,在其中加入如下几行配置. 代码如下 保存修改之后新建一个maven项目查看效果 方法二 新增Proj ...
- 3.MongoDB-备份恢复
备份工具 (1)** mongoexport/mongoimport (2)***** mongodump/mongorestore 备份工具区别在那里? 应用场景总结: mongoexport/mo ...
- .Net中的内存泄露
.Net中的内存泄露 说明: 虽然已经有GC垃圾回收器在工作,但是还是会出现内存泄露. 内存碎片 费托管内存泄露比托管内存泄露更加严重.GC可以移动托管内存,为其他对象腾空间.但是非托管内存将永远的卡 ...
- [C++]二叉链-二叉树存储
二叉链存二叉树 预备知识 指针的熟练掌握 Bolg template模板的知识 Bolg 二叉树的基本知识 感谢: 代码参考:CSDN博主「云雨澄枫」的原创文章 链接 代码解析 结构体 BiNode ...
- 线上SQL超时场景分析-MySQL超时之间隙锁
前言 之前遇到过一个由MySQL间隙锁引发线上sql执行超时的场景,记录一下. 背景说明 分布式事务消息表:业务上使用消息表的方式,依赖本地事务,实现了一套分布式事务方案 消息表名:mq_messag ...