日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

聊聊ChatGLM-6B的源码分析

發(fā)布時間:2024/1/11 windows 39 coder
生活随笔 收集整理的這篇文章主要介紹了 聊聊ChatGLM-6B的源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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

轉載請備注出處:https://www.cnblogs.com/zhiyong-ITNote/

PrefixEncoder

作用:在微調(diào)時(以P-Tuning V2為例),方法訓練時凍結模型的全部參數(shù),只激活PrefixEncoder的參數(shù)。
其源碼如下,整體來看是比較簡單的。

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,這個函數(shù)的作用與直接調(diào)用類構造函數(shù)相同,但它提供了一種更靈活的方式來創(chuàng)建類的實例,因為它可以接受任意數(shù)量的位置參數(shù)和關鍵字參數(shù)。在Pytorch中,用于模塊化的構造函數(shù)。從源碼分析來看,GLU/MLP類就是構造了兩個線性層與gelu激活函數(shù),其結構可簡化如下:

PrefixEncoder類的初始化方法來看,其就是embedding層與MLP的組合。其結構可簡化如下:

詳細解讀可參考 ChatGLM的模型架構

Q:在這里還有一個問題,從哪里可以定位溯源到微調(diào)時禁用了全部的參數(shù),只激活PrefixEncoder的參數(shù)并調(diào)用了該類?

轉載請備注出處:https://www.cnblogs.com/zhiyong-ITNote/

激活函數(shù)與位置編碼

代碼簡單明了,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

標準的注意力機制計算公式如下:




多頭注意力就是將多個單頭注意力的結果拼接起來,再點乘一個新的權重參數(shù)。


attention_fn函數(shù)實現(xiàn)了注意力的核心計算過程(即上述數(shù)學表達式),包括計算注意力分數(shù)、注意力概率和上下文層。這些計算對于實現(xiàn)許多自然語言處理任務,如語言建模、命名實體識別等,都是非常重要的。

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函數(shù)為注入了RoPE位置信息,然后調(diào)用attention_fn計算注意力概率、上下文層表示,并得到返回值。這些都是在forward函數(shù)中調(diào)用處理的。

最后還調(diào)用了dense對上下文表示做線性計算,返回輸出。

轉載請備注出處:https://www.cnblogs.com/zhiyong-ITNote/

GLU

GLU也可以理解為是MLP,在后面版本的ChatGLM中,去掉了GLU類的定義聲明,直接換成了MLP。在上面已經(jīng)寫過不再贅述。

GLMBlock

一般都會把GLMBlock對應為transformer結構的實現(xiàn)。從其構造函數(shù)來看,主要是拼接各個層到一起。

從代碼來看,中間有兩次的殘差連接,如下所示

# 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的源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。