聊聊 从源码来看ChatGLM-6B的模型结构
基于ChatGLM-6B第一版,要注意还有ChatGLM2-6B以及ChatGLM3-6B
概述
ChatGLM是transformer架构的神经网络模型,因此从transformer结构入手,分析其源码结构。
transformer结构:

位置编码
ChatGLM-6B的位置编码采用的旋转位置编码(RoPB)实现。其源码:
class RotaryEmbedding(torch.nn.Module):
def __init__(self, dim, base=10000, precision=torch.half, learnable=False):
super().__init__()
inv_freq = 1. / (base ** (torch.arange(0, dim, 2).float() / dim))
inv_freq = inv_freq.half()
self.learnable = learnable
if learnable:
self.inv_freq = torch.nn.Parameter(inv_freq)
self.max_seq_len_cached = None
else:
self.register_buffer('inv_freq', inv_freq)
self.max_seq_len_cached = None
self.cos_cached = None
self.sin_cached = None
self.precision = precision
def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys,
error_msgs):
pass
def forward(self, x, seq_dim=1, seq_len=None):
if seq_len is None:
seq_len = x.shape[seq_dim]
if self.max_seq_len_cached is None or (seq_len > self.max_seq_len_cached):
self.max_seq_len_cached = None if self.learnable else seq_len
t = torch.arange(seq_len, device=x.device, dtype=self.inv_freq.dtype)
freqs = torch.einsum('i,j->ij', t, self.inv_freq)
# Different from paper, but it uses a different permutation in order to obtain the same calculation
emb = torch.cat((freqs, freqs), dim=-1).to(x.device)
if self.precision == torch.bfloat16:
emb = emb.float()
# [sx, 1 (b * np), hn]
cos_cached = emb.cos()[:, None, :]
sin_cached = emb.sin()[:, None, :]
if self.precision == torch.bfloat16:
cos_cached = cos_cached.bfloat16()
sin_cached = sin_cached.bfloat16()
if self.learnable:
return cos_cached, sin_cached
self.cos_cached, self.sin_cached = cos_cached, sin_cached
return self.cos_cached[:seq_len, ...], self.sin_cached[:seq_len, ...]
def _apply(self, fn):
if self.cos_cached is not None:
self.cos_cached = fn(self.cos_cached)
if self.sin_cached is not None:
self.sin_cached = fn(self.sin_cached)
return super()._apply(fn)
## 转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/
激活函数
ChatGLM-6B采用的激活函数是GeLU(高斯误差线性单元),其源码:
@torch.jit.script
def gelu_impl(x):
"""OpenAI's gelu implementation."""
return 0.5 * x * (1.0 + torch.tanh(0.7978845608028654 * x *
(1.0 + 0.044715 * x * x)))
def gelu(x):
return gelu_impl(x)
编码器-解码器(encoder-decoder)
接下来就是编码器解码器结构,如何抓住模型源头来分析?可以从transformers的API入手:
from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).half().to("cuda:1").eval()
print(mode)
## 转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/
输出:
ChatGLMForConditionalGeneration(
(transformer): ChatGLMModel(
(word_embeddings): Embedding(130528, 4096)
(layers): ModuleList(
(0-27): 28 x GLMBlock(
(input_layernorm): LayerNorm((4096,), eps=1e-05, elementwise_affine=True)
(attention): SelfAttention(
(rotary_emb): RotaryEmbedding()
(query_key_value): Linear(in_features=4096, out_features=12288, bias=True)
(dense): Linear(in_features=4096, out_features=4096, bias=True)
)
(post_attention_layernorm): LayerNorm((4096,), eps=1e-05, elementwise_affine=True)
(mlp): GLU(
(dense_h_to_4h): Linear(in_features=4096, out_features=16384, bias=True)
(dense_4h_to_h): Linear(in_features=16384, out_features=4096, bias=True)
)
)
)
(final_layernorm): LayerNorm((4096,), eps=1e-05, elementwise_affine=True)
)
(lm_head): Linear(in_features=4096, out_features=130528, bias=False)
)
从脑图的角度来梳理下其结构

其结构图表示如下:

将结构图与最开始的transformer结构图对比来看,两者还是比较符合的。
官方源码中标注了编码器与解码器是一体的,只需要配置参数即可切换为解码器。如下:

聊聊 从源码来看ChatGLM-6B的模型结构的更多相关文章
- 死磕Java之聊聊HashSet源码(基于JDK1.8)
HashSet的UML图 HashSet的成员变量及其含义 public class HashSet<E> extends AbstractSet<E> implements ...
- 从源码来看ReentrantLock和ReentrantReadWriteLock
上一篇花了点时间将同步器看了一下,心中对锁的概念更加明确了一点,知道我们所使用到的锁是怎么样获取同步状态的,我们也写了一个自定义同步组件Mutex,讲到了它其实就是一个简版的ReentrantLock ...
- 死磕Java之聊聊ThreadLocal源码(基于JDK1.8)
记得在一次面试中被问到ThreadLocal,答得马马虎虎,所以打算研究一下ThreadLocal的源码 面试官 : 用过ThreadLocal吗? 楼主答 : 用过,当时使用ThreadLocal的 ...
- 聊聊ThreadLocal源码(基于JDK1.8)
原文:https://cloud.tencent.com/developer/article/1333298 聊聊JDK源码中ThreadLocal的实现 主要方法: ThreadLocal的get方 ...
- 死磕Java之聊聊HashMap源码(基于JDK1.8)
死磕Java之聊聊HashMap源码(基于JDK1.8) http://cmsblogs.com/?p=4731 为什么面试要问hashmap 的原理
- Spring5源码分析(1)设计思想与结构
1 源码地址(带有中文注解)git@github.com:yakax/spring-framework-5.0.2.RELEASE--.git Spring 的设计初衷其实就是为了简化我们的开发 基于 ...
- Redis 源码简洁剖析 09 - Reactor 模型
Reactor 模型 事件驱动框架 Redis 如何实现 Reactor 模型 事件的数据结构:aeFileEvent 主循环:aeMain 函数 事件捕获与分发:aeProcessEvents 函数 ...
- 死磕Java之聊聊ArrayList源码(基于JDK1.8)
工作快一年了,近期打算研究一下JDK的源码,也就因此有了死磕java系列 ArrayList 是一个数组队列,相当于动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractLis ...
- 死磕Java之聊聊LinkedList源码(基于JDK1.8)
工作快一年了,近期打算研究一下JDK的源码,也就因此有了死磕java系列 LinkedList 是一个继承于AbstractSequentialList的双向链表,链表不需要capacity的设定,它 ...
- 从OkHttp的源码来看 HTTP
先来了解一下OkHttp的历史,最早是square公司觉得Android给的HttpClient这块的库不太好用,于是乎做了一层包装,再后来他们包装的这个库被Android官方给收回去了,而Andro ...
随机推荐
- 「loj - 6179」Pyh 的求和
link. 我们想要求出 \(\varphi(ij)=\varphi(i)\varphi(j)C\) 中的常数.先研究 \(i=p^a\),\(j=p^b\) 的情况,即 \(\varphi(p^{a ...
- MongoDB慢日志
MongoDB慢日志 熟悉 Mysql 的人应该知道,Mysql 是有个慢查询日志的,它可以帮助我们进行优化我们的 sql,并提高我们系统的稳定性和流畅性.那么 MongoDB 中是否也有类似的功 ...
- Oracle CloudWorld 2023:Safra Catz主题演讲——把客户的成功放在首要位置
Safra Catz在Oracle CloudWorld 2023的开场演讲主题是"把客户的成功放在首要位置".她强调了客户的重要性,并说大家通过合作和技术可以实现几乎一切.她感谢 ...
- 【Mac2021版Intel芯片下载】 - Intel芯片推荐安装
[Mac2021版Intel芯片下载] - Intel芯片推荐安装 往下拉有安装图文教程一.下载提示1请点击图标进行下载 ●每个软件下方均标注了该软件的用途,请注意查看: ●如果点击无反应,请换一个浏 ...
- C静态库的创建与使用--为什么要引入静态库?
C源程序需要经过预处理.编译.汇编几个阶段,得到各自源文件对应的可重定位目标文件,可重定位目标文件就是各个源文件的二进制机器代码,一般是.o格式.比如:util1.c.util2.c及main.c三个 ...
- King's Tour 题解
King's Tour 题面大意 在 \(n\times m\) 的网格中构造一种从 \((1,1)\) 走到 \((a,b)\) 的方案,要求经过所有格子恰好一次,格子之间八联通. 思路分析 模拟赛 ...
- sqlserver在设计表结构时,如何选择字段的数据类型
在设计表结构时,选择适当的字段数据类型是非常重要的,它会直接影响数据库的性能.存储空间和数据的完整性.以下是在 SQL Server 中选择字段数据类型时的一些建议和理由: 1. 整数类型:在 SQL ...
- openwrt ping: sendto: Network unreachable解决办法
root@OpenWrt:/# ping zhihu.com PING zhihu.com (103.41.167.234): 56 data bytes ping: sendto: Network ...
- 研读Java代码必须掌握的Eclipse快捷键
1. Ctrl+左键 和F3 这个是大多数人经常用到的,用来查看变量.方法.类的定义 跳到光标所在标识符的定义代码.当按执行流程阅读时,F3实现了大部分导航动作. 2 Ctrl+Shift+G 在工作 ...
- C# 压缩PDF文件
PDF 文件可以包含文本.图片及各种媒体元素,但如果文件太大则会影响传输效果同时也会占用过多磁盘空间.通过压缩PDF文件,能够有效减小文件大小,从而提高传输效率并节省存储空间.想要通过C#代码快速有效 ...