基于ChatGLM-6B第一版,要注意还有ChatGLM2-6B以及ChatGLM3-6B

转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/

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的参数并调用了该类?

转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/

激活函数与位置编码

代码简单明了,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对上下文表示做线性计算,返回输出。

转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/

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....

转载请备注出处:https://www.cnblogs.com/zhiyong-ITNote/

聊聊ChatGLM-6B的源码分析的更多相关文章

  1. 【小家Spring】聊聊Spring中的数据绑定 --- DataBinder本尊(源码分析)

    每篇一句 唯有热爱和坚持,才能让你在程序人生中屹立不倒,切忌跟风什么语言或就学什么去~ 相关阅读 [小家Spring]聊聊Spring中的数据绑定 --- 属性访问器PropertyAccessor和 ...

  2. HashMap实现原理及源码分析

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...

  3. TextView 的新特性,Autosizing 到底是如何实现的? | 源码分析

    一.前言 Hi,大家好,我是承香墨影! 前两天聊了一下 Autosizing 的使用,反映还不错.毕竟是这种能解决实际问题的新 Api,确实在需要的时候,用起来会很顺手. 简单回顾一下,Autosiz ...

  4. HashMap和ConcurrentHashMap实现原理及源码分析

    HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...

  5. HashMap实现原理及源码分析(JDK1.7)

    转载:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技 ...

  6. Dubbo 源码分析 - SPI 机制

    1.简介 SPI 全称为 Service Provider Interface,是 Java 提供的一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加 ...

  7. 转载-HashMap1.7源码分析

    原文地址-https://www.cnblogs.com/chengxiao/p/6059914.html HashMap实现原理及源码分析   哈希表(hash table)也叫散列表,是一种非常重 ...

  8. MyBatis 源码分析系列文章导读

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  9. EasyUI学习总结(三)——easyloader源码分析(转载)

    声明:这一篇文章是转载过来的,转载地址忘记了,原作者如果看到了,希望能够告知一声,我好加上去! easyloader模块是用来加载jquery easyui的js和css文件的,而且它可以分析模块的依 ...

  10. HashMap实现原理及源码分析之JDK7

    攻克集合第一关!! 转载 http://www.cnblogs.com/chengxiao/ 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如m ...

随机推荐

  1. LeetCode 周赛上分之旅 #47 前后缀分解结合单调栈的贡献问题

    ️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越 ...

  2. Jenkins 命令执行 -- jetty 敏感信息泄露 --(CVE-2021-2816)&&(CVE-2017-1000353)&&(CVE-2018-1000861)

    Jenkins 命令执行 -- jetty 敏感信息泄露 --(CVE-2021-2816)&&(CVE-2017-1000353)&&(CVE-2018-100086 ...

  3. 浅析依赖属性(DependencyProperty)

    在WPF中,引入了依赖属性这个概念,提到依赖属性时通常都会说依赖属性能节省实例对内存的开销.此外依赖属性还有两大优势. 支持多属性值,依赖属性系统可以储存多个值,配合Expression.Style. ...

  4. 2023 ICPC 网络赛 II

    开场顺着读了 AC 不会,B 是 KDT 优化建图板子,让 zsy 确认了一下并制止他现在做.把 D 转化转化成了经典问题·,当时以为是网络流,所以 zsy 签完 M 就上去写了,写一半发现假了,问了 ...

  5. 其它——Siege压力测试工具使用

    文章目录 Siege压力测试工具使用 一 Siege介绍 二 windows 下使用 三 mac和linux使用 四 使用 五 参数详解 六 结果详解 七 修改系统的文件描述符限制 Siege压力测试 ...

  6. Redis系列之——持久化

    一 持久化的作用 1.1 什么是持久化 redis的所有数据保存在内存中,对数据的更新将异步的保存到硬盘上 1.2 持久化的实现方式 快照:某时某刻数据的一个完成备份, -mysql的Dump -re ...

  7. Go with Protobuf

    原文在这里. 本教程为 Go 程序员提供了使用Protocol buffer的基本介绍. 本教程使用proto3向 Go 程序员介绍如何使用 protobuf.通过创建一个简单的示例应用程序,它向你展 ...

  8. React项目中webpack的配置过程

    初始化一个web项目 使用npm init -y 初始化一个项目 在项目目录下创建src, dist文件夹,创建webpack.config.js配置文件 然后在src文件夹下创建index.js, ...

  9. Python 环境迁移

    平时用python环境会装一堆依赖,也包括自己的模块,要迁移到陌生环境,得好好处理才行. 下面介绍个方法,实践过还可以: 总结下步骤: miniconda或conda安装一个python环境,pyth ...

  10. jenkins原理篇——成员权限管理

    大家好,我是蓝胖子,前面几节我讲述了jenkins的语法以及我是如何使用jenkins对测试和正式环境进行发布的.但正式环境使用jenkins还有一点很重要,那就是权限管理.正式环境的权限往往不能对所 ...