天天看點

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

作者:極市平台

作者丨科技猛獸

編輯丨極市平台

本文首發于極市平台,轉載須經授權并注明來源

本文目錄

1 LLaMa:開源高效的大語言模型

(來自 Meta AI)

1.1 背景:模型參數量級的積累,或者訓練資料的增加,哪個對性能提升幫助更大?

1.2 LLaMa 做到了什麼

1.3 LLaMa 預訓練資料

1.4 LLaMa 模型架構

1.5 LLaMa 的優化

1.6 LLaMa 的高效實作

1.7 LLaMa 實驗結果

1.8 訓練期間的性能變化

太長不看版

本文介紹來自 Meta AI 的 LLaMa 模型,類似于 OPT,也是一種完全開源的大語言模型。LLaMa 的參數量級從 7B 到 65B 大小不等,是在數萬億個 token 上面訓練得到。值得一提的是,LLaMa 雖然隻使用公共的資料集,依然取得了強悍的性能。LLaMA-13B 在大多數基準測試中都優于 GPT-3 (175B),LLaMA65B 與最佳模型 Chinchilla-70B 和 PaLM-540B 相比具有競争力。

1 LLaMa:開源高效的大語言模型

論文名稱:LLaMA: Open and Efficient Foundation Language Models

論文位址:

https://arxiv.org/pdf/2302.13971.pdf

代碼連結:

https://github.com/facebookresearch/llama

1.1 背景:模型參數量級的積累,或者訓練資料的增加,哪個對性能提升幫助更大?

以 GPT-3 為代表的大語言模型 (Large language models, LLMs) 在海量文本集合上訓練,展示出了驚人的湧現能力以及零樣本遷移和少樣本學習能力。GPT-3 把模型的量級縮放到了 175B,也使得後面的研究工作繼續去放大語言模型的量級。大家好像有一個共識,就是:模型參數量級的增加就會帶來同樣的性能提升。

但是事實确實如此嗎?

最近的 "Training Compute-Optimal Large Language Models[1]" 這篇論文提出一種縮放定律 (Scaling Law):

訓練大語言模型時,在計算成本達到最優情況下,模型大小和訓練資料 (token) 的數量應該比例相等地縮放,即:如果模型的大小加倍,那麼訓練資料的數量也應該加倍。

翻譯過來就是:當我們給定特定的計算成本預算的前提下,語言模型的最佳性能不僅僅可以通過設計較大的模型搭配小一點的資料集得到,也可以通過設計較小的模型配合大量的資料集得到。

那麼,相似成本訓練 LLM,是大 LLM 配小資料訓練,還是小 LLM 配大資料訓練更好?

縮放定律 (Scaling Law) 告訴我們對于給定的特定的計算成本預算,如何去比對最優的模型和資料的大小。但是本文作者團隊認為,這個功能隻考慮了總體的計算成本,忽略了推理時候的成本。因為大部分社群使用者其實沒有訓練 LLM 的資源,他們更多的是拿着訓好的 LLM 來推理。在這種情況下,我們首選的模型應該不是訓練最快的,而應該是推理最快的 LLM。呼應上題,本文認為答案就是:小 LLM 配大資料訓練更好,因為小 LLM 推理更友好。

1.2 LLaMa 做到了什麼

LLaMa 沿着小 LLM 配大資料訓練的指導思想,訓練了一系列性能強悍的語言模型,參數量從 7B 到 65B。例如,LLaMA-13B 比 GPT-3 小10倍,但是在大多數基準測試中都優于 GPT-3。大一點的 65B 的 LLaMa 模型也和 Chinchilla 或者 PaLM-540B 的性能相當。

同時,LLaMa 模型隻使用了公開資料集,開源之後可以複現。但是大多數現有的模型都依賴于不公開或未記錄的資料完成訓練。

1.3 LLaMa 預訓練資料

LLaMa 預訓練資料大約包含 1.4T tokens,對于絕大部分的訓練資料,在訓練期間模型隻見到過1次,Wikipedia 和 Books 這兩個資料集見過2次。

如下圖1所示是 LLaMa 預訓練資料的含量和分布,其中包含了 CommonCrawl 和 Books 等不同域的資料。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖1:LLaMa 預訓練資料的含量和分布

CommonCrawl (占 67%): 包含 2017 到 2020 的5個版本,預處理部分包含:删除重複資料,去除掉非英文的資料,并通過一個 n-gram 語言模型過濾掉低品質内容。

C4 (占 15%): 在探索性實驗中,作者觀察到使用不同的預處理 CommonCrawl 資料集可以提高性能,是以在預訓練資料集中加了 C4。預處理部分包含:删除重複資料,過濾的方法有一些不同,主要依賴于啟發式方法,例如标點符号的存在或網頁中的單詞和句子的數量。

Github (占 4.5%): 在 Github 中,作者隻保留在 Apache、BSD 和 MIT 許可下的項目。此外,作者使用基于行長或字母數字字元比例的啟發式方法過濾低品質檔案,并使用正規表達式删除标題。最後使用重複資料删除。

Wikipedia (占 4.5%): 作者添加了 2022 年 6-8 月的 Wikipedia 資料集,包括 20 種語言,作者處理資料以删除超連結、評論和其他格式樣闆。

Gutenberg and Books3 (占 4.5%): 作者添加了兩個書的資料集,分别是 Gutenberg 以及 ThePile (訓練 LLM 的常用公開資料集) 中的 Book3 部分。處理資料時作者執行重複資料删除,删除内容重疊超過 90% 的書籍。

ArXiv (占 2.5%): 為了添加一些科學資料集,作者處理了 arXiv Latex 檔案。作者删除了第一部分之前的所有内容,以及參考文獻。還删除了 .tex 檔案的評論,以及使用者編寫的内聯擴充定義和宏,以增加論文之間的一緻性。

Stack Exchange (占 2%): 作者添加了 Stack Exchange,這是一個涵蓋各種領域的高品質問題和答案網站,範圍從計算機科學到化學。作者從 28 個最大的網站保留資料,從文本中删除 HTML 标簽并按分數對答案進行排序。

Tokenizer 的做法基于 SentencePieceProcessor[2],使用 bytepair encoding (BPE) 算法。

LLaMa 的 PyTorch 代碼如下,用到了 sentencepiece 這個庫。

class Tokenizer:
    def __init__(self, model_path: str):
        # reload tokenizer
        assert os.path.isfile(model_path), model_path
        self.sp_model = SentencePieceProcessor(model_file=model_path)
        logger.info(f"Reloaded SentencePiece model from {model_path}")

        # BOS / EOS token IDs
        self.n_words: int = self.sp_model.vocab_size()
        self.bos_id: int = self.sp_model.bos_id()
        self.eos_id: int = self.sp_model.eos_id()
        self.pad_id: int = self.sp_model.pad_id()
        logger.info(
            f"#words: {self.n_words} - BOS ID: {self.bos_id} - EOS ID: {self.eos_id}"
        )
        assert self.sp_model.vocab_size() == self.sp_model.get_piece_size()

    def encode(self, s: str, bos: bool, eos: bool) -> List[int]:
        assert type(s) is str
        t = self.sp_model.encode(s)
        if bos:
            t = [self.bos_id] + t
        if eos:
            t = t + [self.eos_id]
        return t

    def decode(self, t: List[int]) -> str:
        return self.sp_model.decode(t)
           

1.4 LLaMa 模型架構

Pre-normalization [受 GPT3 的啟發]:

為了提高訓練穩定性,LLaMa 對每個 Transformer 的子層的輸入進行歸一化,而不是對輸出進行歸一化。使用 RMSNorm[3] 歸一化函數。

class RMSNorm(torch.nn.Module):
    def __init__(self, dim: int, eps: float = 1e-6):
        super().__init__()
        self.eps = eps
        self.weight = nn.Parameter(torch.ones(dim))

    def _norm(self, x):
        return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)

    def forward(self, x):
        output = self._norm(x.float()).type_as(x)
        return output * self.weight
           
詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

SwiGLU 激活函數 [受 PaLM 的啟發]:

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

Rotary Embeddings [受 GPTNeo 的啟發]:

LLaMa 去掉了絕對位置編碼,使用旋轉位置編碼 (Rotary Positional Embeddings, RoPE)[5],這裡的 RoPE 來自蘇劍林老師,其原理略微複雜,感興趣的讀者可以參考蘇神的原始論文和官方部落格介紹:

https://spaces.ac.cn/archives/8265

Self-Attention 的 PyTorch 代碼:

class Attention(nn.Module):
    def __init__(self, args: ModelArgs):
        super().__init__()

        self.n_local_heads = args.n_heads // fs_init.get_model_parallel_world_size()
        self.head_dim = args.dim // args.n_heads

        self.wq = ColumnParallelLinear(
            args.dim,
            args.n_heads * self.head_dim,
            bias=False,
            gather_output=False,
            init_method=lambda x: x,
        )
        self.wk = ColumnParallelLinear(
            args.dim,
            args.n_heads * self.head_dim,
            bias=False,
            gather_output=False,
            init_method=lambda x: x,
        )
        self.wv = ColumnParallelLinear(
            args.dim,
            args.n_heads * self.head_dim,
            bias=False,
            gather_output=False,
            init_method=lambda x: x,
        )
        self.wo = RowParallelLinear(
            args.n_heads * self.head_dim,
            args.dim,
            bias=False,
            input_is_parallel=True,
            init_method=lambda x: x,
        )

        self.cache_k = torch.zeros(
            (args.max_batch_size, args.max_seq_len, self.n_local_heads, self.head_dim)
        ).cuda()
        self.cache_v = torch.zeros(
            (args.max_batch_size, args.max_seq_len, self.n_local_heads, self.head_dim)
        ).cuda()

    def forward(self, x: torch.Tensor, start_pos: int, freqs_cis: torch.Tensor, mask: Optional[torch.Tensor]):
        bsz, seqlen, _ = x.shape
        xq, xk, xv = self.wq(x), self.wk(x), self.wv(x)

        xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim)
        xk = xk.view(bsz, seqlen, self.n_local_heads, self.head_dim)
        xv = xv.view(bsz, seqlen, self.n_local_heads, self.head_dim)

        xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)

        self.cache_k = self.cache_k.to(xq)
        self.cache_v = self.cache_v.to(xq)

        self.cache_k[:bsz, start_pos : start_pos + seqlen] = xk
        self.cache_v[:bsz, start_pos : start_pos + seqlen] = xv

        keys = self.cache_k[:bsz, : start_pos + seqlen]
        values = self.cache_v[:bsz, : start_pos + seqlen]

        xq = xq.transpose(1, 2)
        keys = keys.transpose(1, 2)
        values = values.transpose(1, 2)
        scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim)
        if mask is not None:
            scores = scores + mask  # (bs, n_local_heads, slen, cache_len + slen)
        scores = F.softmax(scores.float(), dim=-1).type_as(xq)
        output = torch.matmul(scores, values)  # (bs, n_local_heads, slen, head_dim)
        output = output.transpose(
            1, 2
        ).contiguous().view(bsz, seqlen, -1)

        return self.wo(output)
           

這裡有幾個地方值得注意一下:

首先是 model.py 檔案裡面從 fairscale 中 import 了3個類,分别是:ParallelEmbedding,RowParallelLinear,和 ColumnParallelLinear。

Fairscale 連結如下,是一個用于高性能大規模預訓練的庫,LLaMa 使用了其 ParallelEmbedding 去替換 Embedding, 使用了其 RowParallelLinear 和 ColumnParallelLinear 去替換 nn.Linear,猜測可能是為了加速吧。

https://github.com/facebookresearch/fairscale

另一個需要注意的點是:cache 的緩存機制,可以看到在構造函數裡面定義了下面兩個東西:

self.cache_k = torch.zeros((args.max_batch_size, args.max_seq_len, self.n_local_heads, self.head_dim)).cuda()

self.cache_v = torch.zeros((args.max_batch_size, args.max_seq_len, self.n_local_heads, self.head_dim)).cuda()

關鍵其實就是這幾行代碼:

self.cache_k[:bsz, start_pos : start_pos + seqlen] = xk

self.cache_v[:bsz, start_pos : start_pos + seqlen] = xv

keys = self.cache_k[:bsz, : start_pos + seqlen]

values = self.cache_v[:bsz, : start_pos + seqlen]

在訓練的時候,因為每次都是輸入完整的一句話,是以 cache 機制其實是不發揮作用的。

在推理的時候,比如要生成 "I have a cat",過程是:

1 輸入 <s>,生成 <s> I。

2 輸入 <s> I,生成 <s> I have。

3 輸入 <s> I have,生成 <s> I have a。

4 輸入 <s> I have a,生成 <s> I have a cat。

在執行3這一步時,計算 "a" 的資訊時,還要計算 <s> I have 的 Attention 資訊,比較複雜。是以,cache 的作用就是在執行2這一步時,提前把 <s> I have 的 keys 和 values 算好,并儲存在 self.cache_k 和 self.cache_v 中。在執行3這一步時,計算 Attention 所需的 keys 和 values 是直接從這裡面取出來的:

keys = self.cache_k[:bsz, : start_pos + seqlen]

values = self.cache_v[:bsz, : start_pos + seqlen]

隻需要額外地計算 "a" 的 keys 和 values 即可,這對模型的快速推理是至關重要的。

還有一個值得注意的點:self.cache_k = self.cache_k.to(xq)

這裡使用的是 to() 函數的一種不太常見的用法:torch.to(other, non_blocking=False, copy=False)→Tensor

Returns a Tensor with same torch.dtype and torch.device as the Tensor other.

FFN 的 PyTorch 代碼:

class FeedForward(nn.Module):
    def __init__(
        self,
        dim: int,
        hidden_dim: int,
        multiple_of: int,
    ):
        super().__init__()
        hidden_dim = int(2 * hidden_dim / 3)
        hidden_dim = multiple_of * ((hidden_dim + multiple_of - 1) // multiple_of)

        self.w1 = ColumnParallelLinear(
            dim, hidden_dim, bias=False, gather_output=False, init_method=lambda x: x
        )
        self.w2 = RowParallelLinear(
            hidden_dim, dim, bias=False, input_is_parallel=True, init_method=lambda x: x
        )
        self.w3 = ColumnParallelLinear(
            dim, hidden_dim, bias=False, gather_output=False, init_method=lambda x: x
        )

    def forward(self, x):
        return self.w2(F.silu(self.w1(x)) * self.w3(x))

           

這裡需要注意的點是:

激活函數用的是 F.silu(),也就是 Swish 激活函數。

self.w2(F.silu(self.w1(x)) * self.w3(x)) 的實作也就是 SwiGLU 激活函數。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖2:silu 激活函數

Transformer Block 的 PyTorch 代碼:

class TransformerBlock(nn.Module):
    def __init__(self, layer_id: int, args: ModelArgs):
        super().__init__()
        self.n_heads = args.n_heads
        self.dim = args.dim
        self.head_dim = args.dim // args.n_heads
        self.attention = Attention(args)
        self.feed_forward = FeedForward(
            dim=args.dim, hidden_dim=4 * args.dim, multiple_of=args.multiple_of
        )
        self.layer_id = layer_id
        self.attention_norm = RMSNorm(args.dim, eps=args.norm_eps)
        self.ffn_norm = RMSNorm(args.dim, eps=args.norm_eps)

    def forward(self, x: torch.Tensor, start_pos: int, freqs_cis: torch.Tensor, mask: Optional[torch.Tensor]):
        h = x + self.attention.forward(self.attention_norm(x), start_pos, freqs_cis, mask)
        out = h + self.feed_forward.forward(self.ffn_norm(h))
        return out
           

Transformer 的 PyTorch 代碼:

class Transformer(nn.Module):
    def __init__(self, params: ModelArgs):
        super().__init__()
        self.params = params
        self.vocab_size = params.vocab_size
        self.n_layers = params.n_layers

        self.tok_embeddings = ParallelEmbedding(
            params.vocab_size, params.dim, init_method=lambda x: x
        )

        self.layers = torch.nn.ModuleList()
        for layer_id in range(params.n_layers):
            self.layers.append(TransformerBlock(layer_id, params))

        self.norm = RMSNorm(params.dim, eps=params.norm_eps)
        self.output = ColumnParallelLinear(
            params.dim, params.vocab_size, bias=False, init_method=lambda x: x
        )

        self.freqs_cis = precompute_freqs_cis(
            self.params.dim // self.params.n_heads, self.params.max_seq_len * 2
        )

    @torch.inference_mode()
    def forward(self, tokens: torch.Tensor, start_pos: int):
        _bsz, seqlen = tokens.shape
        h = self.tok_embeddings(tokens)
        self.freqs_cis = self.freqs_cis.to(h.device)
        freqs_cis = self.freqs_cis[start_pos : start_pos + seqlen]

        mask = None
        if seqlen > 1:
            mask = torch.full((1, 1, seqlen, seqlen), float("-inf"), device=tokens.device)
            mask = torch.triu(mask, diagonal=start_pos + 1).type_as(h)

        for layer in self.layers:
            h = layer(h, start_pos, freqs_cis, mask)
        h = self.norm(h)
        output = self.output(h[:, -1, :])  # only compute last logits
        return output.float()
           

self.tok_embeddings 用的是 ParallelEmbedding 這個函數,把 ids 變為詞向量。

mask 部分通過 torch.full() 函數和 torch.triu() 函數得到一個上三角矩陣,用于注意力的計算。

通過 torch.nn.ModuleList() 函數定義所有的 Transformer Block。

所有的 norm 函數都使用 RMSNorm 去定義。

生成過程的 PyTorch 代碼:

class LLaMA:
    def __init__(self, model: Transformer, tokenizer: Tokenizer):
        self.model = model
        self.tokenizer = tokenizer

    def generate(
        self,
        prompts: List[str],
        max_gen_len: int,
        temperature: float = 0.8,
        top_p: float = 0.95,
    ) -> List[str]:
        bsz = len(prompts)
        params = self.model.params
        assert bsz <= params.max_batch_size, (bsz, params.max_batch_size)

        prompt_tokens = [self.tokenizer.encode(x, bos=True, eos=False) for x in prompts]

        min_prompt_size = min([len(t) for t in prompt_tokens])
        max_prompt_size = max([len(t) for t in prompt_tokens])

        total_len = min(params.max_seq_len, max_gen_len + max_prompt_size)

        tokens = torch.full((bsz, total_len), self.tokenizer.pad_id).cuda().long()
        for k, t in enumerate(prompt_tokens):
            tokens[k, : len(t)] = torch.tensor(t).long()
        input_text_mask = tokens != self.tokenizer.pad_id
        start_pos = min_prompt_size
        prev_pos = 0
        for cur_pos in range(start_pos, total_len):
            logits = self.model.forward(tokens[:, prev_pos:cur_pos], prev_pos)
            if temperature > 0:
                probs = torch.softmax(logits / temperature, dim=-1)
                next_token = sample_top_p(probs, top_p)
            else:
                next_token = torch.argmax(logits, dim=-1)
            next_token = next_token.reshape(-1)
            # only replace token if prompt has already been generated
            next_token = torch.where(
                input_text_mask[:, cur_pos], tokens[:, cur_pos], next_token
            )
            tokens[:, cur_pos] = next_token
            prev_pos = cur_pos

        decoded = []
        for i, t in enumerate(tokens.tolist()):
            # cut to max gen len
            t = t[: len(prompt_tokens[i]) + max_gen_len]
            # cut to eos tok if any
            try:
                t = t[: t.index(self.tokenizer.eos_id)]
            except ValueError:
                pass
            decoded.append(self.tokenizer.decode(t))
        return decoded


def sample_top_p(probs, p):
    probs_sort, probs_idx = torch.sort(probs, dim=-1, descending=True)
    probs_sum = torch.cumsum(probs_sort, dim=-1)
    mask = probs_sum - probs_sort > p
    probs_sort[mask] = 0.0
    probs_sort.div_(probs_sort.sum(dim=-1, keepdim=True))
    next_token = torch.multinomial(probs_sort, num_samples=1)
    next_token = torch.gather(probs_idx, -1, next_token)
    return next_token
           

這裡需要注意的是:

torch.multinomial() 函數用于按照一定的機率 (probs_sort) 采樣一定數量 (num_samples) 的 Tensor。

torch.gather() 函數是一個抽資料的函數,按照 probs_idx 的索引和 dim=-1 的次元。

1.5 LLaMa 的優化

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

1.6 LLaMa 的高效實作

快速的注意力機制: LLaMa 采用了高效的 causal multi-head attention (基于 xformers[6]),不存儲注意力權重,且不計算 mask 掉的 query 和 key 的值。

手動實作反向傳播過程,不使用 PyTorch autograd: 使用 checkpointing 技術減少反向傳播中的激活值的計算,更準确地說,LLaMa 儲存計算代價較高的激活值,例如線性層的輸出。

通過使用模型和序列并行減少模型的記憶體使用。此外,LLaMa 還盡可能多地重疊激活的計算和網絡上的 GPU 之間的通信。

LLaMa-65B 的模型使用 2048 塊 80G 的 A100 GPU,在 1.4T token 的資料集上訓練 21 天。

1.7 LLaMa 實驗結果

LLaMa 在 20 個标準的 Zero-Shot 和 Few-Shot 任務上面做了評測。在評測時的任務包括自由形式的生成任務和多項選擇任務。多項選擇任務的目标是根據提供的上下文在一組給定選項中選擇最合适的答案。

Zero-Shot 在評測時,作者提供了任務和測試示例的文本描述。LLaMa 要麼使用開放式生成提供答案,要麼對給定的答案進行排名。Few-Shot 在評測時,作者提供了任務的幾個示例 (在 1 到 64 之間) 和一個測試示例。LLaMa 将此文本作為輸入并生成答案或者排名不同的選項。

1.7.1 常識推理實驗結果

作者考慮了8個标準的常識推理基準:BoolQ, PIQA, SIQA, WinoGrande 等,采用标準的 Zero-Shot 的設定進行評估。結果如圖3所示,LLaMA-65B 在除了 BoolQ 的所有基準測試中都優于 Chinchilla-70B,在除了 BoolQ 和 WinoGrande 的任何地方都超過了 PaLM540B。LLAMA-13B 模型在大多數基準測試中也優于 GPT-3。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖3:常識推理實驗結果

1.7.2 封閉式問答實驗結果

如下圖3和4所示是封閉式問答實驗結果,圖4是 Natural Questions 資料集,圖5是 TriviaQA 資料集,報告的是報告精确比對性能,即:模型無法通路包含回答問題證據的文檔。在這兩個基準測試中,LLaMA-65B 在零樣本和少樣本設定中實作了最先進的性能,而且 LLaMa-13B 的性能也同樣具備競争力。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖4:Natural Questions 封閉式問答實驗結果

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖5:TriviaQA 封閉式問答實驗結果

1.7.3 閱讀了解實驗結果

閱讀了解任務在 RACE 資料集上做評測,結果如圖6所示。LLaMA-65B 與 PaLM-540B 具有競争力,LLaMA-13B 的性能比 GPT-3 好幾個百分點。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖6:閱讀了解實驗結果

1.7.4 數學推理實驗結果

作者在 MATH 和 GSM8k 兩個任務上面做數學推理任務,MATH 是一個 12K 中學和高中數學問題的資料集,用 LaTeX 編寫。GSM8k 是一組中學數學問題。在 GSM8k 上,盡管 LLaMA-65B 從沒在數學資料上進行微調,但可以觀察到 LLaMA-65B 優于 Minerva-62B。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖7:數學推理實驗結果

1.7.5 代碼生成實驗結果

作者在 HumanEval 和 MBPP 兩個任務上面做代碼生成任務,對于這兩個任務,模型接收幾個句子中的程式描述,以及一些輸入輸出示例。模型需要生成一個符合描述并滿足測試用例的 Python 程式。圖7将 LLaMa 與尚未在代碼上微調的現有語言模型 (PaLM 和 LaMDA) 進行比較,PaLM 和 LLAMA 在包含相似數量代碼标記的資料集上進行訓練。對于相似數量的參數,LLaMa 優于其他通用模型,例如 LaMDA 和 PaLM,這些模型沒有專門針對代碼進行訓練或微調。具有 13B 參數的 LLAMA,在 HumanEval 和 MBPP 上都優于 LaMDA 137B。LLaMA 65B 也超過了訓練時間更長的 PaLM 62B。

1.7.6 大規模多任務語言了解實驗結果

MMLU 大規模多任務語言了解基準由涵蓋各種知識領域的多項選擇題組成,包括人文、STEM 和社會科學。作者使用基準提供的示例在 5-shot 設定中評估我們的模型,結果如圖7所示。可以觀察到 LLaMa-65B 在大多數領域平均落後于 Chinchilla70B 和 PaLM-540B 幾個百分點。一個潛在的解釋是,LLaMa 在預訓練資料中隻使用了有限數量的書籍和學術論文,即 ArXiv、Gutenberg 和 Books3,總計隻有 177GB,而其他的模型訓練了多達 2TB 的書籍。

作者還發現加入一些微調指令也能夠提升 大規模多任務語言了解的性能。盡管 LLaMA-65B 的非微調版本已經能夠遵循基本指令,但可以觀察到非常少量的微調提高了 MMLU 的性能,并進一步提高了模型遵循指令的能力。

如下圖8所示,盡管這裡使用的指令微調方法很簡單,但在 MMLU 上達到了 68.9%。LLAMA-I (65B) 優于 MMLU 現有中等大小的指令微調模型,但仍遠未達到最先進的水準。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖8:大規模多任務語言了解實驗結果

1.8 訓練期間的性能變化

如下圖9所示是 7B、13B、33B 和 65B 這幾個模型在一些問答和常識基準的表現随着 training token 的變化,圖10是 7B、13B、33B 和 65B 這幾個模型的 training loss 随着 training token 的變化。在大多數基準測試中,性能穩步提高,并且與模型的訓練困惑度相關。

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖9:7B、13B、33B 和 65B 這幾個模型在一些問答和常識基準的表現随着 training token 的變化

詳聊LLaMa技術細節:LLaMA大模型是如何煉成的?

圖10:7B、13B、33B 和 65B 這幾個模型的 training loss 随着 training token 的變化

參考

https://blog.csdn.net/weixin_44826203/article/details/129255185

  1. ^https://arxiv.org/abs/2203.15556
  2. ^Neural machine translation of rare words with subword units
  3. ^Root Mean Square Layer Normalization
  4. ^Glu variants improve transformer
  5. ^RoFormer: Enhanced Transformer with Rotary Position Embedding
  6. ^https://github.com/facebookresearch/xformers

繼續閱讀