LLaMa系列模型详解(原理介绍、代码解读):LLaMA 3

news2024/10/6 14:35:14

LLaMA 3

2024年4月18日,Meta 重磅推出了Meta Llama 3,Llama 3是Meta最先进开源大型语言模型的下一代,包括具有80亿和700亿参数的预训练和指令微调的语言模型,能够支持广泛的应用场景。这一代Llama在一系列行业标准基准测试中展示了最先进的性能,并提供了新的功能,包括改进的推理能力。

image.png

版本和性能

新的 8B 和 70B 参数 Llama 3 模型是 Llama 2 的重大飞跃,并为这些规模的 LLM 模型建立了新的最先进技术。由于预训练和训练后的改进,模型是当今 8B 和 70B 参数规模的最佳模型。我训练后程序的改进大大降低了错误拒绝率,改善了一致性并增加了模型响应的多样性。我们还看到了推理、代码生成和指令跟踪等功能的极大改进,使 Llama 3 更加易于操控。

image.png

模型架构

从模型架构上看,LLaMA 3和LLaMA 2基本没有区别,同样使用了Transformer的Decoder-only架构,加入RMSNorm预归一化,使用 SwiGLU 激活函数和旋转位置嵌入,使用了改进的注意力机制GQA,增加了上下文长度。故本文不具体解释。

上述具体的技术和方法可以查看LLaMA 2的博客:点击此处

模型代码如下,代码来自LLaMA 3:https://github.com/meta-llama/llama3

# Copyright (c) Meta Platforms, Inc. and affiliates.  
# This software may be used and distributed in accordance with the terms of the Llama 3 Community License Agreement.  
  
import math  
from dataclasses import dataclass  
from typing import Optional, Tuple  
  
import fairscale.nn.model_parallel.initialize as fs_init  
import torch  
import torch.nn.functional as F  
from fairscale.nn.model_parallel.layers import (  
    ColumnParallelLinear,  
    RowParallelLinear,  
    VocabParallelEmbedding,  
)  
from torch import nn  
  
  
@dataclass  
class ModelArgs:  
    dim: int = 4096  
    n_layers: int = 32  
    n_heads: int = 32  
    n_kv_heads: Optional[int] = None  
    vocab_size: int = -1  
    multiple_of: int = 256  # make SwiGLU hidden layer size multiple of large power of 2  
    ffn_dim_multiplier: Optional[float] = None  
    norm_eps: float = 1e-5  
    rope_theta: float = 500000  
  
    max_batch_size: int = 32  
    max_seq_len: int = 2048  
  
  
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  
  
  
def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0):  
    freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))  
    t = torch.arange(end, device=freqs.device, dtype=torch.float32)  
    freqs = torch.outer(t, freqs)  
    freqs_cis = torch.polar(torch.ones_like(freqs), freqs)  # complex64  
    return freqs_cis  
  
  
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):  
    ndim = x.ndim  
    assert 0 <= 1 < ndim  
    assert freqs_cis.shape == (x.shape[1], x.shape[-1])  
    shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]  
    return freqs_cis.view(*shape)  
  
  
def apply_rotary_emb(  
    xq: torch.Tensor,  
    xk: torch.Tensor,  
    freqs_cis: torch.Tensor,  
) -> Tuple[torch.Tensor, torch.Tensor]:  
    xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))  
    xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))  
    freqs_cis = reshape_for_broadcast(freqs_cis, xq_)  
    xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3)  
    xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)  
    return xq_out.type_as(xq), xk_out.type_as(xk)  
  
  
def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor:  
    """torch.repeat_interleave(x, dim=2, repeats=n_rep)"""  
    bs, slen, n_kv_heads, head_dim = x.shape  
    if n_rep == 1:  
        return x  
    return (  
        x[:, :, :, None, :]  
        .expand(bs, slen, n_kv_heads, n_rep, head_dim)  
        .reshape(bs, slen, n_kv_heads * n_rep, head_dim)  
    )  
  
  
class Attention(nn.Module):  
    def __init__(self, args: ModelArgs):  
        super().__init__()  
        self.n_kv_heads = args.n_heads if args.n_kv_heads is None else args.n_kv_heads  
        model_parallel_size = fs_init.get_model_parallel_world_size()  
        self.n_local_heads = args.n_heads // model_parallel_size  
        self.n_local_kv_heads = self.n_kv_heads // model_parallel_size  
        self.n_rep = self.n_local_heads // self.n_local_kv_heads  
        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,  
            self.n_kv_heads * self.head_dim,  
            bias=False,  
            gather_output=False,  
            init_method=lambda x: x,  
        )  
        self.wv = ColumnParallelLinear(  
            args.dim,  
            self.n_kv_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_kv_heads,  
                self.head_dim,  
            )  
        ).cuda()  
        self.cache_v = torch.zeros(  
            (  
                args.max_batch_size,  
                args.max_seq_len,  
                self.n_local_kv_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_kv_heads, self.head_dim)  
        xv = xv.view(bsz, seqlen, self.n_local_kv_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]  
  
        # repeat k/v heads if n_kv_heads < n_heads  
        keys = repeat_kv(  
            keys, self.n_rep  
        )  # (bs, cache_len + seqlen, n_local_heads, head_dim)  
        values = repeat_kv(  
            values, self.n_rep  
        )  # (bs, cache_len + seqlen, n_local_heads, head_dim)  
  
        xq = xq.transpose(1, 2)  # (bs, n_local_heads, seqlen, head_dim)  
        keys = keys.transpose(1, 2)  # (bs, n_local_heads, cache_len + seqlen, head_dim)  
        values = values.transpose(  
            1, 2  
        )  # (bs, n_local_heads, cache_len + seqlen, head_dim)  
        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, seqlen, cache_len + seqlen)  
        scores = F.softmax(scores.float(), dim=-1).type_as(xq)  
        output = torch.matmul(scores, values)  # (bs, n_local_heads, seqlen, head_dim)  
        output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1)  
        return self.wo(output)  
  
  
class FeedForward(nn.Module):  
    def __init__(  
        self,  
        dim: int,  
        hidden_dim: int,  
        multiple_of: int,  
        ffn_dim_multiplier: Optional[float],  
    ):  
        super().__init__()  
        hidden_dim = int(2 * hidden_dim / 3)  
        # custom dim factor multiplier  
        if ffn_dim_multiplier is not None:  
            hidden_dim = int(ffn_dim_multiplier * hidden_dim)  
        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))  
  
  
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,  
            ffn_dim_multiplier=args.ffn_dim_multiplier,  
        )  
        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(self.attention_norm(x), start_pos, freqs_cis, mask)  
        out = h + self.feed_forward(self.ffn_norm(h))  
        return out  
  
  
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 = VocabParallelEmbedding(  
            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(  
            params.dim // params.n_heads,  
            params.max_seq_len * 2,  
            params.rope_theta,  
        )  
  
    @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((seqlen, seqlen), float("-inf"), device=tokens.device)  
  
            mask = torch.triu(mask, diagonal=1)  
  
            # When performing key-value caching, we compute the attention scores  
            # only for the new sequence. Thus, the matrix of scores is of size            # (seqlen, cache_len + seqlen), and the only masked entries are (i, j) for            # j > cache_len + i, since row i corresponds to token cache_len + i.            mask = torch.hstack(  
                [torch.zeros((seqlen, start_pos), device=tokens.device), mask]  
            ).type_as(h)  
  
        for layer in self.layers:  
            h = layer(h, start_pos, freqs_cis, mask)  
        h = self.norm(h)  
        output = self.output(h).float()  
        return output

Tokenizer

LLaMA3 改进了Tokenizer,使得对长文本的处理更快。

# Copyright (c) Meta Platforms, Inc. and affiliates.  
# This software may be used and distributed in accordance with the terms of the Llama 3 Community License Agreement.  
  
import os  
from logging import getLogger  
from pathlib import Path  
from typing import (  
    AbstractSet,  
    cast,  
    Collection,  
    Dict,  
    Iterator,  
    List,  
    Literal,  
    Sequence,  
    TypedDict,  
    Union,  
)  
  
import tiktoken  
from tiktoken.load import load_tiktoken_bpe  
  
  
logger = getLogger(__name__)  
  
  
Role = Literal["system", "user", "assistant"]  
  
  
class Message(TypedDict):  
    role: Role  
    content: str  
  
  
Dialog = Sequence[Message]  
  
  
class Tokenizer:  
    """  
    Tokenizing and encoding/decoding text using the Tiktoken tokenizer.    """  
    special_tokens: Dict[str, int]  
  
    num_reserved_special_tokens = 256  
  
    pat_str = r"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+"  # noqa: E501  
  
    def __init__(self, model_path: str):  
        """  
        Initializes the Tokenizer with a Tiktoken model.  
        Args:            model_path (str): The path to the Tiktoken model file.        """        assert os.path.isfile(model_path), model_path  
  
        mergeable_ranks = load_tiktoken_bpe(model_path)  
        num_base_tokens = len(mergeable_ranks)  
        special_tokens = [  
            "<|begin_of_text|>",  
            "<|end_of_text|>",  
            "<|reserved_special_token_0|>",  
            "<|reserved_special_token_1|>",  
            "<|reserved_special_token_2|>",  
            "<|reserved_special_token_3|>",  
            "<|start_header_id|>",  
            "<|end_header_id|>",  
            "<|reserved_special_token_4|>",  
            "<|eot_id|>",  # end of turn  
        ] + [  
            f"<|reserved_special_token_{i}|>"  
            for i in range(5, self.num_reserved_special_tokens - 5)  
        ]  
        self.special_tokens = {  
            token: num_base_tokens + i for i, token in enumerate(special_tokens)  
        }  
        self.model = tiktoken.Encoding(  
            name=Path(model_path).name,  
            pat_str=self.pat_str,  
            mergeable_ranks=mergeable_ranks,  
            special_tokens=self.special_tokens,  
        )  
        logger.info(f"Reloaded tiktoken model from {model_path}")  
  
        self.n_words: int = self.model.n_vocab  
        # BOS / EOS token IDs  
        self.bos_id: int = self.special_tokens["<|begin_of_text|>"]  
        self.eos_id: int = self.special_tokens["<|end_of_text|>"]  
        self.pad_id: int = -1  
        self.stop_tokens = {  
            self.special_tokens["<|end_of_text|>"],  
            self.special_tokens["<|eot_id|>"],  
        }  
        logger.info(  
            f"#words: {self.n_words} - BOS ID: {self.bos_id} - EOS ID: {self.eos_id}"  
        )  
  
    def encode(  
        self,  
        s: str,  
        *,  
        bos: bool,  
        eos: bool,  
        allowed_special: Union[Literal["all"], AbstractSet[str]] = set(),  
        disallowed_special: Union[Literal["all"], Collection[str]] = (),  
    ) -> List[int]:  
        """  
        Encodes a string into a list of token IDs.  
        Args:            s (str): The input string to be encoded.            bos (bool): Whether to prepend the beginning-of-sequence token.            eos (bool): Whether to append the end-of-sequence token.            allowed_tokens ("all"|set[str]): allowed special tokens in string            disallowed_tokens ("all"|set[str]): special tokens that raise an error when in string  
        Returns:            list[int]: A list of token IDs.  
        By default, setting disallowed_special=() encodes a string by ignoring        special tokens. Specifically:        - Setting `disallowed_special` to () will cause all text corresponding          to special tokens to be encoded as natural text (insteading of raising          an error).        - Setting `allowed_special` to "all" will treat all text corresponding          to special tokens to be encoded as special tokens.        """        assert type(s) is str  
  
        # The tiktoken tokenizer can handle <=400k chars without  
        # pyo3_runtime.PanicException.        TIKTOKEN_MAX_ENCODE_CHARS = 400_000  
  
        # https://github.com/openai/tiktoken/issues/195  
        # Here we iterate over subsequences and split if we exceed the limit        # of max consecutive non-whitespace or whitespace characters.        MAX_NO_WHITESPACES_CHARS = 25_000  
  
        substrs = (  
            substr  
            for i in range(0, len(s), TIKTOKEN_MAX_ENCODE_CHARS)  
            for substr in self._split_whitespaces_or_nonwhitespaces(  
                s[i : i + TIKTOKEN_MAX_ENCODE_CHARS], MAX_NO_WHITESPACES_CHARS  
            )  
        )  
        t: List[int] = []  
        for substr in substrs:  
            t.extend(  
                self.model.encode(  
                    substr,  
                    allowed_special=allowed_special,  
                    disallowed_special=disallowed_special,  
                )  
            )  
        if bos:  
            t.insert(0, self.bos_id)  
        if eos:  
            t.append(self.eos_id)  
        return t  
  
    def decode(self, t: Sequence[int]) -> str:  
        """  
        Decodes a list of token IDs into a string.  
        Args:            t (List[int]): The list of token IDs to be decoded.  
        Returns:            str: The decoded string.        """        # Typecast is safe here. Tiktoken doesn't do anything list-related with the sequence.  
        return self.model.decode(cast(List[int], t))  
  
    @staticmethod  
    def _split_whitespaces_or_nonwhitespaces(  
        s: str, max_consecutive_slice_len: int  
    ) -> Iterator[str]:  
        """  
        Splits the string `s` so that each substring contains no more than `max_consecutive_slice_len`        consecutive whitespaces or consecutive non-whitespaces.        """        current_slice_len = 0  
        current_slice_is_space = s[0].isspace() if len(s) > 0 else False  
        slice_start = 0  
  
        for i in range(len(s)):  
            is_now_space = s[i].isspace()  
  
            if current_slice_is_space ^ is_now_space:  
                current_slice_len = 1  
                current_slice_is_space = is_now_space  
            else:  
                current_slice_len += 1  
                if current_slice_len > max_consecutive_slice_len:  
                    yield s[slice_start:i]  
                    slice_start = i  
                    current_slice_len = 1  
        yield s[slice_start:]  
  
  
class ChatFormat:  
    def __init__(self, tokenizer: Tokenizer):  
        self.tokenizer = tokenizer  
  
    def encode_header(self, message: Message) -> List[int]:  
        tokens = []  
        tokens.append(self.tokenizer.special_tokens["<|start_header_id|>"])  
        tokens.extend(self.tokenizer.encode(message["role"], bos=False, eos=False))  
        tokens.append(self.tokenizer.special_tokens["<|end_header_id|>"])  
        tokens.extend(self.tokenizer.encode("\n\n", bos=False, eos=False))  
        return tokens  
  
    def encode_message(self, message: Message) -> List[int]:  
        tokens = self.encode_header(message)  
        tokens.extend(  
            self.tokenizer.encode(message["content"].strip(), bos=False, eos=False)  
        )  
        tokens.append(self.tokenizer.special_tokens["<|eot_id|>"])  
        return tokens  
  
    def encode_dialog_prompt(self, dialog: Dialog) -> List[int]:  
        tokens = []  
        tokens.append(self.tokenizer.special_tokens["<|begin_of_text|>"])  
        for message in dialog:  
            tokens.extend(self.encode_message(message))  
        # Add the start of an assistant message for the model to complete.  
        tokens.extend(self.encode_header({"role": "assistant", "content": ""}))  
        return tokens
  • 为了防止因字符串过长而产生的性能问题,encode 方法使用一个循环来处理不超过 400,000 字符的子字符串。这种方法可以避免运行时错误,例如在 Python 的外部库(如 C 或 Rust 写的库)中可能发生的内存错误。
  • 使用 _split_whitespaces_or_nonwhitespaces 方法来处理可能的大量连续空格或非空格字符,限制每个片段的最大长度为 25,000 字符。这样做既保证了处理的灵活性,也避免了处理过长片段可能带来的问题。

训练数据

为了训练最佳的语言模型,收集一个大规模、高质量的训练数据集至关重要。Meta AI在预训练数据上投入了大量资金。Llama 3在超过15T的token上进行预训练,所有数据都来自公开可用的来源。我们的训练数据集比用于Llama 2的数据集大了七倍,并且包括了四倍的代码。为了准备即将到来的多语言用例,超过5%的Llama 3预训练数据集由高质量的非英语数据组成,覆盖了超过30种语言。然而,我们不期望在这些语言中达到与英语相同的性能水平。

为了确保Llama 3训练的数据质量最高,我们开发了一系列数据过滤管道。这些管道包括使用启发式过滤器、NSFW过滤器、语义去重方法和文本分类器来预测数据质量。我们发现,Llama的前几代在识别高质量数据方面出奇地好,因此我们使用Llama 2生成了为Llama 3提供动力的文本质量分类器的训练数据。

为了在Llama 3模型中有效利用我们的预训练数据,我们投入了大量精力来扩大预训练规模。具体来说,我们为下游基准评估开发了一系列详细的扩展法则。这些扩展法则使我们能够选择最佳数据混合方案,并就如何最佳利用我们的训练计算资源做出明智的决策。重要的是,扩展法则允许我们在实际训练模型之前预测我们最大模型在关键任务上的性能。这帮助我们确保最终模型在各种使用场景和能力上的强劲性能。

在Llama 3的开发过程中,我们对扩展行为做出了几项新的观察。例如,虽然对于80亿参数模型来说,Chinchilla最优的训练计算量对应于约2000亿个token,但我们发现即使模型在数据量增加两个数量级后,模型性能仍然在持续提升。在我们的80亿和700亿参数模型经过高达15T个token的训练后,它们的性能继续以对数线性方式提升。大型模型可以在较少的训练计算量下匹配这些小型模型的性能,但通常更倾向于使用小型模型,因为它们在推理过程中效率更高。

为了训练我们最大的Llama 3模型,我们结合了三种类型的并行化:数据并行化、模型并行化和流水线并行化。我们最有效的实现方式在同时训练16K个GPU时,每个GPU的计算利用率超过400 TFLOPS。我们在两个定制构建的24K GPU集群上执行了训练运行。为了最大化GPU的运行时间,我们开发了一个新的高级训练堆栈,自动化了错误检测、处理和维护。我们还大大提高了硬件的可靠性和检测机制,用于静默数据损坏,并开发了新的可扩展存储系统,减少了检查点和回滚的开销。这些改进使得整体有效训练时间超过了95%。综合来看,这些改进将Llama 3的训练效率提高了约三倍,与Llama 2相比。

指令微调

为了充分释放我们预训练模型在聊天用例中的潜力,我们对指令调整方法也进行了创新。我们的后训练方法是监督式微调(SFT)、拒绝采样、近端策略优化(PPO)和直接策略优化(DPO)的组合。用于SFT的提示质量和用于PPO和DPO的偏好排名对对齐模型的性能有巨大影响。我们在模型质量上的一些最大改进来自于仔细筛选这些数据,并对人类标注者提供的多轮质量保证进行多次审查。

通过PPO和DPO从偏好排名中学习也大大提高了Llama 3在推理和编码任务上的性能。我们发现,如果你问一个模型一个它难以回答的推理问题,模型有时会产生正确的推理轨迹:模型知道如何产生正确的答案,但它不知道如何选择它。在偏好排名上进行训练使模型学会了如何选择它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1684821.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UI问题 --- CardView和其它的控件在同一布局中时,始终覆盖其它控件

原本代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"40dp"android:layout_height"wrap_content"andr…

【Vue3】env环境变量的配置和使用(区分cli和vite)

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、env文件二、vue3cli加载env1..env配置2..dev配置&#xff08;其他环境参考&#xff09;3.package.json文件4.使用 三、vue3vite加载e…

MobaXterm使用私钥远程登陆linux

秘钥的形式使用MobaXterm 远程连接 linux 服务器 MobaXterm使用私钥远程登陆linux just填写远程主机 不指定用户 勾选使用私钥 选择私钥即可 1.使用秘钥连接 远程linux 服务器的好处 只需要第一次添加秘钥&#xff0c;并输入密码后&#xff0c;以后再连接就不需要再输入密码…

5款网页表白代码5(附带源码)

5款网页表白代码5 前言效果图及部分源码1.博客式表白2.故事式表白3.信封式表白4.信封式表白&#xff08;简洁版&#xff09;5.高级UI表白页 领取源码下期更新预报 前言 大部分人都有喜欢的人&#xff0c;学会这些表白代码&#xff0c;下次表白你肯定会成功。希望你有个女朋友 …

二叉树遍历操作详解

目录 一、思路详解 1.1 递归思路 1.2 递归分支图 1.3 递归栈帧图 二、C语言实现 2.1 前序遍历 2.2 中序遍历 2.3 后序遍历 三、查找值为x的结点 3.1 递归思路 3.2 C语言代码 一、思路详解 采用递归的思想解决问题&#xff0c;以高度为3的满二叉树为例。 1.1 递归思…

vscode更改语言,记录一下

首先打开安装好的Vscode软件&#xff0c;可以看到页面上显示的是英文效果。 同时按键ctrlshiftp&#xff0c;接着在输入框中输入 configure Display language如图&#xff1a; 选择中文简体就ok了&#xff0c;如果没有则安装 chinese Language pack

Qt QString详细用法

一.基础用法 1.创建QString对象 QString str1 "Hello, World!"; QString str2("This is a QString object."); //一个是等号的重载&#xff0c;一个是拷贝构造&#xff0c;本质上是等价的 2.获取字符串长度 int length str1.length(); // 返回字符串…

UBUNTU22.04无法安装nvidia-driver-550 依赖于 nvidia-dkms-550 (<= 550.54.15-1)

类似的报错信息&#xff0c;就是卡在了nvidia-dkms-550无法安装 Loading new nvidia-550.40.07 DKMS files… Building for 6.5.0-15-generic Building for architecture x86_64 Building initial module for 6.5.0-15-generic ERROR: Cannot create report: [Errno 17] File e…

项目启动失败,【consul】

如题&#xff0c;启动时项目未能正常启动&#xff0c;但上次都一切正常&#xff0c;日志提示&#xff1a; Consul service ids must not be empty, must start with a letter 经过排查是因为consul的consulconfigservice服务假死&#xff0c;导致无法正常获取到配置文件&am…

【全开源】JAVA人力资源招聘社会校招类型招聘系统校园招聘PC端

塑造企业高效招聘新体验 一、源码简介 招聘PC端源码&#xff0c;一款面向企业的招聘管理系统解决方案。它拥有完整的招聘流程管理功能&#xff0c;从职位发布到候选人管理&#xff0c;再到面试安排与结果反馈&#xff0c;所有环节都通过直观易用的界面进行展现&#xff0c;大…

tinyrenderer-移动镜头

同一个点的坐标在不同基坐标系中转换 设 (O, i,j,k)坐标系中点P坐标为 假设基坐标(i,j,k)与(i’,j’,k’)的转换关系为 如图&#xff0c;可以看出 其中(x’,y’,z’)为点P在基坐标(i’,j’,k’)下的坐标&#xff0c;(Ox’,Oy’,Oz’)为(i’,j’,k’)坐标系原点O’在(i,j,k…

【关键字】——register在C语言中的使用

register——寄存器 了解register之前&#xff0c;应该先认识认识寄存器&#xff0c;何为寄存器&#xff1f; 在计算机中&#xff0c;数据可以存储在远程二级存储&#xff08;网盘&#xff0c;服务器&#xff09;&#xff0c;本地二级存储&#xff08;本地磁盘&#xff09;&am…

DOS学习-目录与文件应用操作经典案例-move

欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 一.前言 move命令不仅能够对文件或目录进行重命名&#xff0c;还可以将文件转移到用户指定的位置。 二.使用 命令格式1&#xff08;重命名&#xff09;:move …

VR直播:改变我们的直播方式,让现场触手可及

VR直播是近期比较火爆的一种直播方式&#xff0c;相信在抖音上我们都刷到过转动手机、变换视角的VR直播&#xff0c;因为形式比较新颖&#xff0c;用户的参与度比较高&#xff0c;一场直播下来用户的打赏也是较为可观的。 不仅仅在直播行业&#xff0c;在众多应用领域中&#…

ARTS Week 29

Algorithm 本周的算法题为 2413. 最小偶倍数 给你一个正整数 n &#xff0c;返回 2 和 n 的最小公倍数&#xff08;正整数&#xff09;。 示例 1&#xff1a;输入&#xff1a;n 5输出&#xff1a;10解释&#xff1a;5 和 2 的最小公倍数是 10 。 实现代码如下&#xff1a; con…

压摆率SR、增益带宽积GBP、开环增益Aol

运放的选型对运放电路的实际效果非常关键&#xff0c;一定要理解运放重要参数的概念。下面几天将对运放的选型进行系统学习并做实验 运放的压摆率&#xff08;Slew Rate&#xff0c;简称SR&#xff09;是指闭环放大器在输入为阶跃信号时&#xff0c;输出电压时间变化率的平均值…

BEVFusion的相机工作流中,图像编码之后FPN+ADP网络的作用

在BEVFusion的相机工作流中&#xff0c;图像编码之后会经过一个FPNADP的网络,那么这个结构的作用是什么呢 FPN大家都很熟悉&#xff0c;就是特征金字塔。但是这里还是贴一些来自GPT的废话 在Bird’s Eye View (BEV) 算法中使用的特征金字塔网络&#xff08;FPN, Feature Pyrami…

鸿蒙OS开发:【一次开发,多端部署】(分栏控件)

一多分栏控件 介绍 本示例分别展示了多场景下&#xff0c;一多分栏控件的响应式变化效果。 本示例分别用到了[SideBarContainer]组件与[Navigation]组件&#xff0c;对应使用场景如下&#xff1a; ABC&#xff1a;即SideBarContainer组件组合Navigation组件AC&#xff1a;S…

SSRF攻击技术

1、SSRF形成原因 SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF是要目标网站的内部系统。&#xff08;因为他是从内部系统访问的&#xff0c;所有可以通过它攻击外网无法访问的内部系…

03-01-Vue组件的定义和注册

前言 我们接着上一篇文章02-Vue实例的生命周期函数 来讲。 下一篇文章 03-02-Vue组件之间的传值 什么是组件 组件&#xff1a; 组件的出现&#xff0c;就是为了拆分Vue实例的代码量的&#xff0c;能够让我们以不同的组件&#xff0c;来划分不同的功能模块&#xff0c;将来我们…