Transformer系列-1丨基础Transformer模型和代码详解

1 前言

笔者在深度学习入门期间自学过Transformer,但是那时碍于急于求成,并未对其进行深度归纳与分享。

近期,笔者观察到不论是自然语言处理模型还是视觉模型,已经几乎从传统的CNN、RNN的网络结构设计全面转向基于Transformer的结构设计了。

如下图1所示,在ImageNet数据集上,基于Transformer的网络的精度几乎已经全面领先基于纯CNN设计的网络了。

图1

另外,最近大火的chatGPT,其核心也是基于Transformer构建的。这不禁重新燃起了我来做一期对于基础Transformer解析类文章的兴趣,便于新手入门老手复习

关于对Transformer的解析,网上已经有很多不错的相关教程了,这里推荐几个笔者认为写的不错的。

  1. 知乎文章《详解_Transformer_ (Attention Is All You Need)》,点赞7000+

  2. 知乎文章《Transformer模型详解(图解最完整版)》,点赞4000+

  3. 非常有名的英文教程《The Illustrated Transformer》,知乎文章(1)就是借鉴该教程的

  4. B站李宏毅视频《第5讲-Transformer-1_哔哩哔哩_bilibili》

  5. 本文

与现有文章不同的是,本文我们打算结合相关的代码,从理论结合实践的角度加深读者对Transformer的理解。本文采用的代码是:

https://github.com/hyunwoongko/transformer

2 提出动机

Transformer提出的具体动机在现有文章中已经被阐明的很清楚了,总结而言就是:

(1)递归神经网络(RNN)或卷积神经网络(CNN)来处理序列数据时,在长序列上的表现不佳,因为它们难以捕捉长期依赖关系

(2)递归神经网络(RNN),包括LSTM/GRU及其变体,只能从左向右依次计算或者从右向左依次计算,也就是当前时刻的计算依赖上一步计算的输入,严重限制了模型的并行能力

所以,Transformer另辟蹊径,仅用自注意力(self-Attenion)和前馈网络/全连接层(Feed Forward Neural Network)就作为其主体框架,便获得对输入数据(文本、图像)较好的并行处理能力。另外,自注意力的使用使得模型对较长序列输入的处理能力也大大提升。

3 方法与代码详解

3.1 整体模型预览

本文我们以自顶而下的步骤来逐步解析Transformer中各个模块。为了更好地说明,这里我们借鉴了《The Illustrated Transformer》的原理图,没办法,这位老哥写的太好了,这里强烈建议大家去看一下原版。

假设我们要做一个语言翻译任务,如下图2所示,那么需要构建一个翻译模型,这里不妨这个模型就是基于Transformer构建的。该模型输入一段原始语言(看图片中可能是印度文),输出英文翻译。

图2

具体地,该基于Transformer构建的翻译模型由两部分构成,分别是编码器(encoder)解码器(decoder),如下图3所示。

图3

编码器的输出作为解码器的输入。这里的编码器是将输入映射为特征表征(可视为待翻译句子的含义),而解码器根据特征表征实现**“含义—>目标语言”**的转换。具体代码实现如下:

class Transformer(nn.Module):

    def __init__(self, src_pad_idx, trg_pad_idx, trg_sos_idx, enc_voc_size, dec_voc_size, d_model, n_head, max_len,
                 ffn_hidden, n_layers, drop_prob, device):
        super().__init__()
        self.src_pad_idx = src_pad_idx
        self.trg_pad_idx = trg_pad_idx
        self.trg_sos_idx = trg_sos_idx
        self.device = device
        self.encoder = Encoder(d_model=d_model,
                               n_head=n_head,
                               max_len=max_len,
                               ffn_hidden=ffn_hidden,
                               enc_voc_size=enc_voc_size,
                               drop_prob=drop_prob,
                               n_layers=n_layers,
                               device=device)

        self.decoder = Decoder(d_model=d_model,
                               n_head=n_head,
                               max_len=max_len,
                               ffn_hidden=ffn_hidden,
                               dec_voc_size=dec_voc_size,
                               drop_prob=drop_prob,
                               n_layers=n_layers,
                               device=device)

    def forward(self, src, trg):
        src_mask = self.make_pad_mask(src, src, self.src_pad_idx, self.src_pad_idx)

        src_trg_mask = self.make_pad_mask(trg, src, self.trg_pad_idx, self.src_pad_idx)

        trg_mask = self.make_pad_mask(trg, trg, self.trg_pad_idx, self.trg_pad_idx) * \
                   self.make_no_peak_mask(trg, trg)

        enc_src = self.encoder(src, src_mask) # 编码器
        output = self.decoder(trg, enc_src, trg_mask, src_trg_mask) # 解码器
        return output

从代码的forward函数可以看出,作者先对模型的输入(src,trg)进行了预处理,获取到一些诸如掩码等信息。接着,将这些先喂给编码器(self.encoder)来获取特征表征(enc_src),该特征表征和一些掩码被馈入解码器(self.decoder)中,输出张量翻译信息(output)。

图4

如上图4所示,这个编码器解码器的结构可以总结如下:

(1)编码器

编码器由一个嵌入层+六个编码层构成,每个编码层由一个自注意力(self-Attenion)和一层前馈网络(Feed Forward Neural Network)组成,如下图5所示。需要注意的是,自注意力前馈网络中均包含残差连接(目的是为了防止梯度消失,提高训练稳定性);

图5

编码器的代码实现如下所示:

class Encoder(nn.Module):

    def __init__(self, enc_voc_size, max_len, d_model, ffn_hidden, n_head, n_layers, drop_prob, device):
        super().__init__()
        self.emb = TransformerEmbedding(d_model=d_model,
                                        max_len=max_len,
                                        vocab_size=enc_voc_size,
                                        drop_prob=drop_prob,
                                        device=device)

        self.layers = nn.ModuleList([EncoderLayer(d_model=d_model,
                                                  ffn_hidden=ffn_hidden,
                                                  n_head=n_head,
                                                  drop_prob=drop_prob)
                                     for _ in range(n_layers)])

    def forward(self, x, s_mask):
        x = self.emb(x)

        for layer in self.layers:
            x = layer(x, s_mask)

        return x

上述代码中的self.emb就是嵌入层,n_layers被设定为6,表示该编码器由6层解码层(EncoderLayer)构成。我们再进入EncoderLayer的定义,可见:

class EncoderLayer(nn.Module):

    def __init__(self, d_model, ffn_hidden, n_head, drop_prob):
        super(EncoderLayer, self).__init__()
        self.attention = MultiHeadAttention(d_model=d_model, n_head=n_head)
        self.norm1 = LayerNorm(d_model=d_model)
        self.dropout1 = nn.Dropout(p=drop_prob)

        self.ffn = PositionwiseFeedForward(d_model=d_model, hidden=ffn_hidden, drop_prob=drop_prob)
        self.norm2 = LayerNorm(d_model=d_model)
        self.dropout2 = nn.Dropout(p=drop_prob)

    def forward(self, x, s_mask):
        # 1. compute self attention
        _x = x
        x = self.attention(q=x, k=x, v=x, mask=s_mask)
        
        # 2. add and norm
        x = self.dropout1(x)
        x = self.norm1(x + _x)
        
        # 3. positionwise feed forward network
        _x = x
        x = self.ffn(x)
      
        # 4. add and norm
        x = self.dropout2(x)
        x = self.norm2(x + _x)
        return x

通过查看上述代码的forward函数,可见在每个编码层中执行了如下操作:

  • (1)自注意力操作( self.attention)

  • (2)相加和归一化(也就是残差连接)

  • (3)前馈网络运算(self.ffn,本质就是全连接层)

  • (4)相加和归一化(残差连接)

(2)解码器

解码器由一个嵌入层+六个解码层+一个输出层构成,每个解码层由一个自注意力(self-Attenion),一个编码-解码注意力(Encoder- decoder Attention)和一层前馈网络(Feed Forward Neural Network)组成,如下图6所示;

图6

解码器的代码实现如下所示:

class Decoder(nn.Module):
    def __init__(self, dec_voc_size, max_len, d_model, ffn_hidden, n_head, n_layers, drop_prob, device):
        super().__init__()
        self.emb = TransformerEmbedding(d_model=d_model,
                                        drop_prob=drop_prob,
                                        max_len=max_len,
                                        vocab_size=dec_voc_size,
                                        device=device)

        self.layers = nn.ModuleList([DecoderLayer(d_model=d_model,
                                                  ffn_hidden=ffn_hidden,
                                                  n_head=n_head,
                                                  drop_prob=drop_prob)
                                     for _ in range(n_layers)])

        self.linear = nn.Linear(d_model, dec_voc_size)

    def forward(self, trg, enc_src, trg_mask, src_mask):
        trg = self.emb(trg)

        for layer in self.layers:
            trg = layer(trg, enc_src, trg_mask, src_mask)

        # pass to LM head
        output = self.linear(trg)
        return output

其中,self.emb为嵌入层;n_layers=6,这表明解码器由6个解码层(DecoderLayer)构成;最后,使用输出层(self.linear)将解码特征映射为字向量输出。这里,我们就解码层(DecoderLayer)展开,其具体实现代码如下:

class DecoderLayer(nn.Module):

    def __init__(self, d_model, ffn_hidden, n_head, drop_prob):
        super(DecoderLayer, self).__init__()
        self.self_attention = MultiHeadAttention(d_model=d_model, n_head=n_head)
        self.norm1 = LayerNorm(d_model=d_model)
        self.dropout1 = nn.Dropout(p=drop_prob)

        self.enc_dec_attention = MultiHeadAttention(d_model=d_model, n_head=n_head)
        self.norm2 = LayerNorm(d_model=d_model)
        self.dropout2 = nn.Dropout(p=drop_prob)

        self.ffn = PositionwiseFeedForward(d_model=d_model, hidden=ffn_hidden, drop_prob=drop_prob)
        self.norm3 = LayerNorm(d_model=d_model)
        self.dropout3 = nn.Dropout(p=drop_prob)

    def forward(self, dec, enc, t_mask, s_mask):
        # 1. compute self attention
        _x = dec
        x = self.self_attention(q=dec, k=dec, v=dec, mask=t_mask)
        
        # 2. add and norm
        x = self.dropout1(x)
        x = self.norm1(x + _x)

        if enc is not None:
            # 3. compute encoder - decoder attention
            _x = x
            x = self.enc_dec_attention(q=x, k=enc, v=enc, mask=s_mask)
            
            # 4. add and norm
            x = self.dropout2(x)
            x = self.norm2(x + _x)

        # 5. positionwise feed forward network
        _x = x
        x = self.ffn(x)
        
        # 6. add and norm
        x = self.dropout3(x)
        x = self.norm3(x + _x)
        return x

从上述代码可以看出,每个解码层比编码层多了一个模块运算,即编码-解码注意力及其残差连接。

再仔细一看,这个编码-解码注意力的k和v值为enc,其实也就是编码器的输出。也就是说,每层解码层的输入不光有上一解码层的输出(dec),还有编码器的最终输出(enc),和图4中展示的一致。

写到这里,Transformer的大致结构大家应该就有了初步的印象了。这里需要提一嘴的是,编码-解码注意力(Encoder- decoder Attention)的本质也是个自注意力,其唯一区别仅在输入的来源上。而前馈网络(Feed Forward Neural Network)其实就是全连接层与激活函数的组合,并不需要进行重点解析。

那么这样一来,我们只需要理解自注意力的具体实现,也就掌握了Transformer的核心了。
针对所有自学遇到困难的同学们,我帮大家系统梳理大模型学习脉络,将这份 LLM大模型资料 分享出来:包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程等, 😝有需要的小伙伴,可以 扫描下方二维码领取🆓↓↓↓

👉[CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)]()👈

3.2 自注意力

自注意力模块,笔者最先接触的时候是在做视觉任务遇到了一个叫做Non-local注意力模块,其结构如下图7所示(具体见我之前写的知乎文章)。事实上,该模块就是借鉴自注意力进行设计的。

图7

在Transformer中,每个单词向量(embeddings)被映射成三个不同的向量,分别叫做Query向量(Q)、Key向量(K)和Value向量(V),如下图8所示。具体是怎么个映射法呢,就是输入到三个不同的全连接层(内参分别为、和)中即可。

图8

在每个单词向量都获取了其对应的三个Q、K、V向量后。对于任意单词,用它的Query向量(Q)去探索自身和其他单词的Key向量(K),如下图9所示。具体探索方法就是两者进行点积,某种意义上就是求解余弦相似度,如果两者相似度较高,则赋予较大的值(下图中的Score)来反应两者的关系。

图9

上述计算可以大致把握两个单词之间的相似度(或者称为关联性,即图中的Score)。之后,需要利用该相似度来衡量各单词相对于所关注单词(上图9中受关注的单词为thinking)的重要性,进而对各个单词所占权重进行调整。

具体地,作者先是对每个计算的相似度进行了标准化,然后使用softmax函数将标准化的相似度转换成了注意力,如下图10所示。

图10

接着,如图11所示,作者利用获取的注意力来调整各单词Value向量(V)所占的权重。最后,对加权后的各单词Value向量(V)进行按位相加融合,获取自注意力模块的输出(就是图10中的)。

图11

为了便于大家理解,上面的讲解是拆分进行的。在实际计算过程中,采用了基于矩阵的计算方法来提升运算效率,具体如下图12所示。

假设有2个单词,每个单词维度为4(当然这只是假设),那么输入的维度就是。然后通过三个不同权重的全连接层(权重维度为)将输入映射为三个维度为的向量,即Query向量(Q)、Key向量(K)和Value向量(V)。

那么上述关于自注意力的运算步骤可以用下面公式表示,即

更形象地,其图示为:

图12

其代码实现如下所示:

class MultiHeadAttention(nn.Module):

    def __init__(self, d_model, n_head):
        super(MultiHeadAttention, self).__init__()
        self.n_head = n_head
        self.attention = ScaleDotProductAttention()
        self.w_q = nn.Linear(d_model, d_model)
        self.w_k = nn.Linear(d_model, d_model)
        self.w_v = nn.Linear(d_model, d_model)
        self.w_concat = nn.Linear(d_model, d_model)

    def forward(self, q, k, v, mask=None):
        # 1. dot product with weight matrices
        q, k, v = self.w_q(q), self.w_k(k), self.w_v(v)

        # 2. split tensor by number of heads
        q, k, v = self.split(q), self.split(k), self.split(v)

        # 3. do scale dot product to compute similarity
        out, attention = self.attention(q, k, v, mask=mask)

        # 4. concat and pass to linear layer
        out = self.concat(out)
        out = self.w_concat(out)

        # 5. visualize attention map
        # TODO : we should implement visualization

        return out

    def split(self, tensor):
        """
        split tensor by number of head

        :param tensor: [batch_size, length, d_model]
        :return: [batch_size, head, length, d_tensor]
        """
        batch_size, length, d_model = tensor.size()

        d_tensor = d_model // self.n_head
        tensor = tensor.view(batch_size, length, self.n_head, d_tensor).transpose(1, 2)
        # it is similar with group convolution (split by number of heads)

        return tensor

    def concat(self, tensor):
        """
        inverse function of self.split(tensor : torch.Tensor)

        :param tensor: [batch_size, head, length, d_tensor]
        :return: [batch_size, length, d_model]
        """
        batch_size, head, length, d_tensor = tensor.size()
        d_model = head * d_tensor

        tensor = tensor.transpose(1, 2).contiguous().view(batch_size, length, d_model)
        return tensor

其中self.attention(自注意力)定义为:

class ScaleDotProductAttention(nn.Module):
    """
    compute scale dot product attention

    Query : given sentence that we focused on (decoder)
    Key : every sentence to check relationship with Qeury(encoder)
    Value : every sentence same with Key (encoder)
    """

    def __init__(self):
        super(ScaleDotProductAttention, self).__init__()
        self.softmax = nn.Softmax(dim=-1)

    def forward(self, q, k, v, mask=None, e=1e-12):
        # input is 4 dimension tensor
        # [batch_size, head, length, d_tensor]
        batch_size, head, length, d_tensor = k.size()

        # 1. dot product Query with Key^T to compute similarity
        k_t = k.transpose(2, 3)  # transpose
        score = (q @ k_t) / math.sqrt(d_tensor)  # scaled dot product

        # 2. apply masking (opt)
        if mask is not None:
            score = score.masked_fill(mask == 0, -10000)

        # 3. pass them softmax to make [0, 1] range
        score = self.softmax(score)

        # 4. multiply with Value
        v = score @ v

        return v, score

需要注意的是,上面文字部分我们讲了那么多,其实是在讲解单头自注意力。然而,细心的小伙伴应该发现了上述代码定义的是多头自注意力。我们可以认为,当self.n_head=1时,就是上面我们讲解的单头自注意力了。当然,在Transformer中,作者默认采用的是多头自注意力,这是为什么呢?

因为,相比单头自注意力,多头的优势主要体现在:

  • 更好的建模能力:利用多个注意力头可以捕获序列中更多的信息和特征,从而提升模型的建模能力。

  • 更好的泛化能力:多头自注意力可以提高模型对新数据的泛化能力,因为它可以将不同方面的特征编码到不同的注意力头中,从而使模型更加全面地理解输入序列。那么多头是如何实现的呢?

如图13所示,假设self.n_head=8,即八头注意力,对于每个头(序号为)都执行一次单头注意力运算,获得相应的输出。最后,对所有头所处的进行堆叠融合后,利用全连接层将其映射成与单一注意力输出相同的尺寸即可。

图13

至此,关于Transformer的核心部分(即自注意力)就讲解完毕了。这里顺嘴提一下,从上述代码中可以看出,解码层中的编码-解码注意力(self.enc_dec_attention)的定义也是一个多头自注意力(MultiHeadAttention类),唯一区别在于其输入的Query向量(q)为前面解码器的输出(x),而Key向量(k)和Value向量(v)输入为编码器的输出(enc)。

下面我们就Transformer另外两个重要的创新进行解析,分别为:

  • 位置编码

  • 输入掩码

3.3 位置编码

从上面的解析可以看出,自注意力对输入序列中各单词的位置/顺序不敏感,因为通过Query向量Key向量的交互,每个单词的距离被缩小为一个常量。这样会导致一个很严重的问题,比如“我吃牛肉”这句话,在Transformer看来和“牛吃我肉”是没什么区别的。

为了缓解该问题,作者提出了位置编码。简而言之,就是在词向量输入到注意力模块之前,与该词向量等长的位置向量进行了按位相加,进而赋予了词向量相应的位置信息。

那么,如何获取该位置编码呢?作者给出了位置编码的定义公式,具体如下:

乍一看,变量有三,公式还有两个,着实不太好懂。这里需要注意,为位置向量的维度,前面提到该维度与词向量维度一致。变量为单词在句子中的位置,比如“我吃牛肉”,那么这个牛的。那么这个又是什么东西呢?其实,这个和分别表示位置向量的偶数位置和奇数位置,自然而然地,。

作者这样定义位置编码的原因在于:

  • 使得Transformer可以更容易掌握单词间的相对位置,因为Sin(A+B)=Sin(A)Cos(B)+ Cos(A)Sin(B), Cos(A+B)= Cos(A)Cos(B)- Sin(A)Sin(B)。那么知道某单词的位置编码后(如),其相对距离为的单词的位置编码()可以根据函数和函数的性质快速计算出。

  • 即使在测试的时候遇到比训练集中所有句子都长的句子,上述公式也可以给出一个合适的位置编码。

位置代码获取的代码实现如下:

class PositionalEncoding(nn.Module):
   """
   compute sinusoid encoding.
   """
   def __init__(self, d_model, max_len, device):
       """
       constructor of sinusoid encoding class

       :param d_model: dimension of model
       :param max_len: max sequence length
       :param device: hardware device setting
       """
       super(PositionalEncoding, self).__init__()

       # same size with input matrix (for adding with input matrix)
       self.encoding = torch.zeros(max_len, d_model, device=device)
       self.encoding.requires_grad = False  # we don't need to compute gradient

       pos = torch.arange(0, max_len, device=device)
       pos = pos.float().unsqueeze(dim=1)
       # 1D => 2D unsqueeze to represent word's position

       _2i = torch.arange(0, d_model, step=2, device=device).float()
       # 'i' means index of d_model (e.g. embedding size = 50, 'i' = [0,50])
       # "step=2" means 'i' multiplied with two (same with 2 * i)

       self.encoding[:, 0::2] = torch.sin(pos / (10000 ** (_2i / d_model)))
       self.encoding[:, 1::2] = torch.cos(pos / (10000 ** (_2i / d_model)))
       # compute positional encoding to consider positional information of words

   def forward(self, x):
       # self.encoding
       # [max_len = 512, d_model = 512]

       batch_size, seq_len = x.size()
       # [batch_size = 128, seq_len = 30]

       return self.encoding[:seq_len, :]
       # [seq_len = 30, d_model = 512]
       # it will add with tok_emb : [128, 30, 512]   

这里也提供一个图例加深读者理解,如图14所示。图中每一行对应于一个词向量的位置编码,可见该句子共有20个词(0-19),其中第一行是输入序列中第一个单词向量的位置编码。每一行包含512个值(即),每个值都是按照上述计算公式计算而来,介于1和 -1之间。左半部分的值由正弦函数计算获得,而右半部分的值由余弦函数计算获得。在实现中,将这两部分计算出来的值穿插拼接起来,就可以形成每个单词对应的位置编码了。

图14

至此,关于位置编码的解析就结束了,相信大家在仔细看完上述解释和代码后,应当能够理解位置编码的含义了。

3.4 输入掩码

输入掩码是笔者认为比较重要的一部分了。在深度学习中,掩码的作用一般是让模型自动忽略一些内容

正常的翻译逻辑应该是,模型在接收原始语言的语句输入后(利用编码器进行编码),会利用解码器一个词一个词地逐个翻译。也就是,时刻翻译的单词会考虑之前时刻(如,)已经翻译好的所有单词。在Transformer的测试阶段,这是这样执行的。

那么可能会有人会问,前面不是提到Transformer的一大亮点在于其并行能力吗?这不还是在等待前面翻译的内容作为后续的输入吗?

这里需要解释一下,这种情况只发生在测试阶段。在训练阶段,作者利用将监督信息(即目标翻译)右移一位作为解码器的输入(加上了一个起始符),并设置掩码使得解码器在时刻的翻译只能考虑输入目标翻译时刻之前(如,)的内容,这是为了防止翻译信息的提前泄露。如图15所示,我举了个例子,

图15

从上图15可以看到,翻译第个单词时,都会用到目标翻译第1个到第个单词作为输入。需要注意的是,这里的训练方式叫做Teacher Forcing,也就是不管你模型最后的输出是啥,你的输入都得是目标翻译的一部分,给你强行扭过来。当然,在测试/应用阶段,解码器前一时刻的输出将作为后面的输入,因为我们是无法在测试阶段提前获取目标翻译的。

为了实现这种“翻译第个单词时用到目标翻译第1个到第个单词作为输入”,作者引入了输入掩码,具体实现也很简单。这里借鉴《知乎文章:Transformer模型详解(图解最完整版)》的图来更好的说明,具体如下:

图16

假设输入到Transformer解码器的矩阵维度为(也就是包含在内有5个单词,每个单词视作6维度),那么在翻译第一个单词时,只会用到起始符,而翻译第二个单词时只会用到起始符和第一个单词,后续类推,那么设置的掩码矩阵应该如上图16右边的Mask矩阵所示。

该Mask矩阵用在哪儿呢?这里通过查看自注意力的代码实现,如下:

class ScaleDotProductAttention(nn.Module):
    """
    compute scale dot product attention

    Query : given sentence that we focused on (decoder)
    Key : every sentence to check relationship with Qeury(encoder)
    Value : every sentence same with Key (encoder)
    """

    def __init__(self):
        super(ScaleDotProductAttention, self).__init__()
        self.softmax = nn.Softmax(dim=-1)

    def forward(self, q, k, v, mask=None, e=1e-12):
        # input is 4 dimension tensor
        # [batch_size, head, length, d_tensor]
        batch_size, head, length, d_tensor = k.size()

        # 1. dot product Query with Key^T to compute similarity
        k_t = k.transpose(2, 3)  # transpose
        score = (q @ k_t) / math.sqrt(d_tensor)  # scaled dot product

        # 2. apply masking (opt)
        if mask is not None:
            score = score.masked_fill(mask == 0, -10000)

        # 3. pass them softmax to make [0, 1] range
        score = self.softmax(score)

        # 4. multiply with Value
        v = score @ v

        return v, score

可以发现,Mask 操作是在自注意力模块计算Score后,以及使用 Softmax 之前使用的

4 总结

写到这里,关于Transformer比较重要的点基本都讲解完毕了。如果大家一路看过来,能够理解我的所言所语,我相信应该会有所收获的。本期内容还是侧重于对基础Transformer的讲解,未来我打算多去分享一些基于Transformer设计的网络模型以及实际应用。欢迎大家关注!

图17 Transformer总结构图

在大模型时代,我们如何有效的去学习大模型?

现如今大模型岗位需求越来越大,但是相关岗位人才难求,薪资持续走高,AI运营薪资平均值约18457元,AI工程师薪资平均值约37336元,大模型算法薪资平均值约39607元。
在这里插入图片描述

掌握大模型技术你还能拥有更多可能性

• 成为一名全栈大模型工程师,包括Prompt,LangChain,LoRA等技术开发、运营、产品等方向全栈工程;

• 能够拥有模型二次训练和微调能力,带领大家完成智能对话、文生图等热门应用;

• 薪资上浮10%-20%,覆盖更多高薪岗位,这是一个高需求、高待遇的热门方向和领域;

• 更优质的项目可以为未来创新创业提供基石。

可能大家都想学习AI大模型技术,也_想通过这项技能真正达到升职加薪,就业或是副业的目的,但是不知道该如何开始学习,因为网上的资料太多太杂乱了,如果不能系统的学习就相当于是白学。为了让大家少走弯路,少碰壁,这里我直接把都打包整理好,希望能够真正帮助到大家_。

一、AGI大模型系统学习路线

很多人学习大模型的时候没有方向,东学一点西学一点,像只无头苍蝇乱撞,下面是我整理好的一套完整的学习路线,希望能够帮助到你们学习AI大模型。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

在这里插入图片描述

三、AI大模型经典PDF书籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四、AI大模型各大场景实战案例

在这里插入图片描述

结语

【一一AGI大模型学习 所有资源获取处(无偿领取)一一】
所有资料 ⚡️ ,朋友们如果有需要全套 《LLM大模型入门+进阶学习资源包》,扫码获取~

👉[CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)]()👈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值