当前位置: 首页 > news >正文

多模态大模型MLLM基础训练范式 Pre-train + Instruction FineTuning

多模态大模型Pre-train

为了在图文嵌入空间中更好地对齐视觉和文本信息。为此,使用图像-文本对(image-caption style data),表示为 ( X , Y a ) (\mathbf{X}, Y_a) (X,Ya),其中:

  • X \mathbf{X} X:图像(Image)。
  • Y a = { y i } i = 1 N a Y_a = \{y_i\}_{i=1}^{N_a} Ya={yi}i=1Na:是图像的描述(response,描述或文本回应),包含 N a N_a Na 个token(词元)。

下面两个公式是图文对齐预训练中核心的 语言建模概率函数损失函数定义。它们共同描述了:如何让模型学会根据一张图像生成对应的文字描述,以实现图文信息在嵌入空间的对齐。

公式(1):生成概率公式

p ( Y a ∣ X ) = ∏ i = 1 N a F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) (1) p(Y_a|\mathbf{X}) = \prod_{i=1}^{N_a} F_\theta(y_i | P_\phi \circ V_\varphi(\mathbf{X})) \quad \text{(1)} p(YaX)=i=1NaFθ(yiPϕVφ(X))(1)

🔍 解释:

这是一个 条件语言建模公式(Conditional Language Modeling)。该公式定义了生成文本 Y a Y_a Ya 在图像 X \mathbf{X} X 条件下的概率,是一个自回归语言建模形式(Autoregressive Language Modeling):

  • ∏ i = 1 N a \prod_{i=1}^{N_a} i=1Na:表示对所有token做乘积,相当于整体生成序列的联合概率。
  • F θ F_\theta Fθ:是语言模型(如 LLM)中的解码器函数,参数为 θ \theta θ
  • y i y_i yi:目标文本序列的第 i i i 个token。
  • P ϕ P_\phi Pϕ:是将视觉特征投影到语言模型空间的投影器(如一个MLP或线性变换)。
  • V φ ( X ) V_\varphi(\mathbf{X}) Vφ(X):是视觉编码器(Vision Encoder),将图像 X \mathbf{X} X 编码为视觉特征。
  • ∘ \circ :表示函数复合, P ϕ ∘ V φ ( X ) P_\phi \circ V_\varphi(\mathbf{X}) PϕVφ(X) 就是“先编码图像再投影”。

  • 给定图像 X \mathbf{X} X,目标是根据图像生成一段文字 Y a = { y 1 , y 2 , … , y N a } Y_a = \{y_1, y_2, \dots, y_{N_a}\} Ya={y1,y2,,yNa}
  • 每个词 y i y_i yi 的生成概率,依赖于图像特征经过视觉编码器 V φ V_\varphi Vφ 和投影模块 P ϕ P_\phi Pϕ 得到的特征。
  • F θ F_\theta Fθ 是 LLM 的解码器部分,根据图像特征一步步生成句子。

公式(2):训练目标(最大似然)

这个是对应的训练目标——最大化似然(Maximum Likelihood Estimation, MLE)。通过这种损失训练,视觉特征(来自图像)和语言特征(来自文本)被映射到同一个语义空间中,实现图文特征的对齐。
max ⁡ ϕ , θ ′ , φ ′ ∑ i = 1 N a log ⁡ F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) (2) \max_{\phi, \theta', \varphi'} \sum_{i=1}^{N_a} \log F_\theta(y_i | P_\phi \circ V_\varphi(\mathbf{X})) \quad \text{(2)} ϕ,θ,φmaxi=1NalogFθ(yiPϕVφ(X))(2)

🔍 解释:
  • log ⁡ F θ ( ⋅ ) \log F_\theta(\cdot) logFθ():表示的是每个token的对数概率(log-likelihood)。
  • 对所有token求和即为整个序列的log-likelihood。
  • max ⁡ ϕ , θ ′ , φ ′ \max_{\phi, \theta', \varphi'} maxϕ,θ,φ:表示对这三个部分的参数进行优化:
    • ϕ \phi ϕ:投影器的参数。
    • θ ′ \theta' θ:语言模型中允许学习的部分参数(不是全部)。
    • φ ′ \varphi' φ:视觉编码器中允许学习的部分参数(不是全部)。

损失函数定义(Loss Function):

损失函数是上面最大化目标的对立面——我们在训练中实际上是最小化负对数似然(Negative Log-Likelihood Loss,NLL)

L NLL = − ∑ i = 1 N a log ⁡ F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) \mathcal{L}_{\text{NLL}} = - \sum_{i=1}^{N_a} \log F_\theta(y_i | P_\phi \circ V_\varphi(\mathbf{X})) LNLL=i=1NalogFθ(yiPϕVφ(X))

这个损失函数的核心思想就是:

  • 如果模型对某个正确token的预测概率高(接近1),它的log值就是负的很小;
  • 如果模型预测错了,log值就是负的很大,总损失就会变大;
  • 所以,通过最小化负log概率,我们可以让模型学会尽量准确地生成目标描述文本。

  • 用的是自回归语言模型的训练方式:一个词一个词预测。
  • 每预测一个token y i y_i yi,我们就计算它的对数概率 log ⁡ F θ ( y i ∣ ⋅ ) \log F_\theta(y_i | \cdot) logFθ(yi)
  • 然后将所有token的log概率加起来。
  • 最后最大化这个和(就是最小化负的log-likelihood)。目标是让正确的文本描述在图像条件下的生成概率越高越好。
⚠️ 说明:
  • 只对部分参数进行训练,是因为使用的是小型语言模型(small-scale LLM),为了效率和防止过拟合,作者只更新关键连接器部分参数。这被称为Partial Parameter Tuning(部分参数可学习)。
  • 仅仅训练连接器(如 P ϕ P_\phi Pϕ)可能不足以实现图文对齐,因此本方法允许在小模型上微调部分 LLM 和视觉模型的参数。

Pre-train案例代码

import os
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from transformers import GPT2LMHeadModel, GPT2Tokenizer, ViTModel, ViTImageProcessor
import requests
import zipfile
from tqdm import tqdm
from PIL import Image
import json# ==================== 配置参数 ====================
class Config:# 数据配置coco_path = "./coco"image_size = 224       # ViT标准输入尺寸batch_size = 8         # 根据GPU显存调整max_seq_len = 64       # 文本序列最大长度# 模型配置vision_model = "google/vit-base-patch16-224-in21k"language_model = "gpt2"projection_dim = 768   # 投影层维度需与语言模型匹配# 训练配置lr = 1e-4epochs = 2           # 训练轮数,根据数据集大小和GPU显存调整device = torch.device("cuda" if torch.cuda.is_available() else "cpu")grad_clip = 1.0        # 梯度裁剪阈值num_workers = 4        # 数据加载线程数# ==================== 数据下载 ====================
def download_with_progress(url: str, save_path: str):"""带进度条的文件下载函数"""response = requests.get(url, stream=True)total_size = int(response.headers.get('content-length', 0))with open(save_path, 'wb') as f, tqdm(desc=f"Downloading {os.path.basename(save_path)}",total=total_size,unit='iB',unit_scale=True,unit_divisor=1024,) as bar:for data in response.iter_content(chunk_size=1024):f.write(data)bar.update(len(data))def prepare_coco_data():"""准备COCO数据集"""os.makedirs(Config.coco_path, exist_ok=True)# 下载训练图像image_zip = os.path.join(Config.coco_path, "train2017.zip")if not os.path.exists(os.path.join(Config.coco_path, "train2017")):print("下载COCO训练集...")download_with_progress("http://images.cocodataset.org/zips/train2017.zip",image_zip)with zipfile.ZipFile(image_zip, 'r') as zip_ref:zip_ref.extractall(Config.coco_path)os.remove(image_zip)# 下载标注文件ann_zip = os.path.join(Config.coco_path, "annotations.zip")if not os.path.exists(os.path.join(Config.coco_path, "annotations")):print("下载COCO标注...")download_with_progress("http://images.cocodataset.org/annotations/annotations_trainval2017.zip",ann_zip)with zipfile.ZipFile(ann_zip, 'r') as zip_ref:zip_ref.extractall(Config.coco_path)os.remove(ann_zip)# ==================== 数据集类 ====================
class CocoCaptionDataset(Dataset):"""COCO图像描述数据集"""def __init__(self, image_dir: str, annotation_path: str):self.image_dir = image_dir# 初始化图像处理器try:self.image_processor = ViTImageProcessor.from_pretrained(Config.vision_model)except Exception as e:raise RuntimeError(f"无法加载图像处理器: {str(e)}")# 加载标注数据try:with open(annotation_path) as f:annotations = json.load(f)except FileNotFoundError:raise FileNotFoundError(f"标注文件 {annotation_path} 不存在")# 构建数据映射self.id_to_filename = {img["id"]: img["file_name"] for img in annotations["images"]}self.annotations = [(ann["image_id"], ann["caption"]) for ann in annotations["annotations"]]# 初始化文本处理器try:self.tokenizer = GPT2Tokenizer.from_pretrained(Config.language_model)# 使用EOS作为填充符,确保模型正确处理填充if self.tokenizer.pad_token is None:self.tokenizer.pad_token = self.tokenizer.eos_tokenexcept Exception as e:raise RuntimeError(f"无法加载文本处理器: {str(e)}")def __len__(self):return len(self.annotations)def __getitem__(self, idx):image_id, caption = self.annotations[idx]# 加载并处理图像image_path = os.path.join(self.image_dir, self.id_to_filename[image_id])try:image = Image.open(image_path).convert("RGB")pixel_values = self.image_processor(images=image, return_tensors="pt").pixel_values.squeeze(0)  # (3, 224, 224)except Exception as e:raise RuntimeError(f"图像处理失败: {image_path} - {str(e)}")# 处理文本tokens = self.tokenizer(caption,max_length=Config.max_seq_len,padding="max_length",truncation=True,return_tensors="pt")return pixel_values, tokens.input_ids.squeeze(0), tokens.attention_mask.squeeze(0)# ==================== 多模态模型 ====================
class VisionLanguageModel(nn.Module):"""视觉-语言多模态模型"""def __init__(self):super().__init__()# 视觉编码器(冻结)try:self.vision_encoder = ViTModel.from_pretrained(Config.vision_model)for param in self.vision_encoder.parameters():param.requires_grad = Falseexcept Exception as e:raise RuntimeError(f"无法加载视觉模型: {str(e)}")# 视觉特征投影层self.visual_projection = nn.Sequential(nn.Linear(self.vision_encoder.config.hidden_size, Config.projection_dim),nn.GELU(),nn.LayerNorm(Config.projection_dim))# 语言模型(部分微调)try:self.language_model = GPT2LMHeadModel.from_pretrained(Config.language_model)# 冻结除最后两层外的所有参数for param in self.language_model.parameters():param.requires_grad = Falsefor param in self.language_model.transformer.h[-2:].parameters():param.requires_grad = True# 获取GPT2分词器以保持一致性self.tokenizer = GPT2Tokenizer.from_pretrained(Config.language_model)if self.tokenizer.pad_token is None:self.tokenizer.pad_token = self.tokenizer.eos_tokenself.language_model.config.pad_token_id = self.language_model.config.eos_token_idexcept Exception as e:raise RuntimeError(f"无法加载语言模型: {str(e)}")def forward(self, images, input_ids, attention_mask):batch_size = images.size(0)# 视觉特征提取vision_outputs = self.vision_encoder(images)visual_features = vision_outputs.last_hidden_state[:, 0, :]  # [CLS] token# 特征投影projected_visual = self.visual_projection(visual_features).unsqueeze(1)  # [B, 1, dim]# 修改标签以匹配维度# 将输入的后移一位作为标签,并忽略视觉标记的位置labels = input_ids.clone()  # 复制输入作为标签# 将标签中所有视觉标记的位置设为-100,使损失函数忽略这些位置labels_attention_mask = torch.cat([torch.zeros(batch_size, 1, device=Config.device),  # 视觉标记部分attention_mask  # 文本部分], dim=1)# 文本嵌入text_embeddings = self.language_model.transformer.wte(input_ids)# 合并视觉和文本特征combined_embeddings = torch.cat([projected_visual, text_embeddings], dim=1)# 调整注意力掩码visual_attention = torch.ones(batch_size, 1, device=Config.device)combined_attention = torch.cat([visual_attention, attention_mask], dim=1)# 使用自定义标签进行损失计算outputs = self.language_model(inputs_embeds=combined_embeddings,attention_mask=combined_attention,labels=None  # 不使用内部标签处理)# 手动计算损失logits = outputs.logits  # [B, seq_len+1, vocab_size]# 移除视觉标记的logits,只保留文本部分shift_logits = logits[:, :-1, :]  # [B, seq_len, vocab_size]# 为了计算损失,我们将输入向右移动一位,这样每个token都是预测下一个token的shift_labels = torch.cat([input_ids[:, 1:],  # 将输入向右移动一位torch.full((batch_size, 1), self.tokenizer.eos_token_id, device=Config.device)  # 添加EOS作为最后一个标签], dim=1)# 忽略填充标记的损失loss_mask = attention_mask.float()# 计算交叉熵损失loss_fct = nn.CrossEntropyLoss(reduction='none')loss = loss_fct(shift_logits.reshape(-1, shift_logits.size(-1)), shift_labels.reshape(-1))# 应用掩码并计算平均值masked_loss = (loss.view(batch_size, -1) * loss_mask).sum() / loss_mask.sum()return masked_loss# ==================== 训练流程 ====================
def train():# 准备数据prepare_coco_data()# 初始化数据集try:train_dataset = CocoCaptionDataset(image_dir=os.path.join(Config.coco_path, "train2017"),annotation_path=os.path.join(Config.coco_path, "annotations/captions_train2017.json"))except Exception as e:print(f"数据集初始化失败: {str(e)}")return# 数据加载器train_loader = DataLoader(train_dataset,batch_size=Config.batch_size,shuffle=True,num_workers=Config.num_workers,pin_memory=True)# 初始化模型try:model = VisionLanguageModel().to(Config.device)except Exception as e:print(f"模型初始化失败: {str(e)}")return# 优化器配置optimizer = torch.optim.AdamW([{'params': model.visual_projection.parameters()},{'params': model.language_model.transformer.h[-2:].parameters()}], lr=Config.lr)# 学习率调度scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=Config.epochs)# 混合精度训练# scaler = torch.amp.GradScaler()scaler = torch.cuda.amp.GradScaler()  # 启用混合精度训练# 训练循环for epoch in range(Config.epochs):model.train()total_loss = 0.0progress_bar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{Config.epochs}")for batch_idx, (images, input_ids, attention_mask) in enumerate(progress_bar):# 数据转移到设备images = images.to(Config.device, non_blocking=True)input_ids = input_ids.to(Config.device, non_blocking=True)attention_mask = attention_mask.to(Config.device, non_blocking=True)# 梯度清零optimizer.zero_grad(set_to_none=True)# 混合精度前向with torch.amp.autocast(device_type='cuda', dtype=torch.float16):loss = model(images, input_ids, attention_mask)# 反向传播scaler.scale(loss).backward()# 梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), Config.grad_clip)# 参数更新scaler.step(optimizer)scaler.update()# 统计损失total_loss += loss.item()progress_bar.set_postfix({"batch_loss": loss.item()})# # 添加定期检查点(每1000个批次保存一次)# if (batch_idx + 1) % 1000 == 0:#     torch.save({#         'epoch': epoch,#         'iteration': batch_idx,#         'model_state_dict': model.state_dict(),#         'optimizer_state_dict': optimizer.state_dict(),#         'loss': loss.item(),#     }, f"coco_caption_epoch_{epoch}_iter_{batch_idx}.pt")# 更新学习率scheduler.step()# 保存检查点torch.save({'epoch': epoch,'model_state_dict': model.state_dict(),'optimizer_state_dict': optimizer.state_dict(),'loss': total_loss / len(train_loader),}, f"coco_caption_epoch_{epoch}.pt")# 打印统计信息avg_loss = total_loss / len(train_loader)print(f"\nEpoch {epoch+1} | Avg Loss: {avg_loss:.4f} | last_LR: {scheduler.get_last_lr()[0]:.2e}")if __name__ == "__main__":train()

多模态大模型Instruction FineTuning

监督式微调。我们使用图像-文本对 ( X , Y ) (X,Y) (X,Y) 作为多轮对话的原始形式。令 A \mathcal{A} A表示属于助手回应的所有标记的集合,即 A = { y ∣ y ∈ Y t a , ∀ t = 1 , … , T } \mathcal{A} = \{y \mid y \in Y_t^a, \, \forall t =1, \dots, T\} A={yyYta,t=1,,T},其中 Y t a Y_t^a Yta 是第 t t t轮对话中的助手回应。我们通过最大化助手回应的对数似然,逐步地将其作为训练目标进行监督式微调(最大化模型回应的对数似然)
max ⁡ ϕ , θ ′ , φ ∑ i = 1 N I ( y i ∈ A ) log ⁡ F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) \max_{\phi, \theta',\varphi} \sum_{i=1}^{N} \mathbb{I}(y_i \in \mathcal{A}) \log F_{\theta}(y_i | P_{\phi} \circ V_{\varphi}(X)) ϕ,θ,φmaxi=1NI(yiA)logFθ(yiPϕVφ(X))其中 N N N 是文本序列 Y Y Y的长度, I ( y i ∈ A ) \mathbb{I}(y_i \in \mathcal{A}) I(yiA) 是指示函数,当 y i ∈ A y_i \in \mathcal{A} yiA 时为1,否则为 0。我们还允许在监督式微调阶段对语言模型和视觉编码器的部分可学习参数进行调整。


公式(1)有选择的语言建模目标

max ⁡ ϕ , θ , φ ∑ i = 1 N I ( y i ∈ A ) log ⁡ F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) (1) \max_{\phi, \theta, \varphi} \sum_{i=1}^{N} \mathbb{I}(y_i \in \mathcal{A}) \log F_{\theta}(y_i | P_{\phi} \circ V_{\varphi}(X)) \quad\text{(1)} ϕ,θ,φmaxi=1NI(yiA)logFθ(yiPϕVφ(X))(1)

其中包含以下几个重要部分:

  • max ⁡ ϕ , θ , φ \max_{\phi, \theta, \varphi} maxϕ,θ,φ:表示我们正在优化(最大化)目标函数的参数,具体来说,优化的是模型的三个参数: ϕ \phi ϕ(连接器参数)、 θ \theta θ(语言模型参数)和 φ \varphi φ(视觉编码器参数)。
  • ∑ i = 1 N \sum_{i=1}^{N} i=1N:对整个输出文本序列 Y Y Y(长度为 N N N)的每一个元素进行求和,其中 N N N 是文本序列的长度。
  • I ( y i ∈ A ) \mathbb{I}(y_i \in \mathcal{A}) I(yiA):这是指示函数(indicator function),当 y i ∈ A y_i \in \mathcal{A} yiA 时,其值为 1,否则为 0。 A \mathcal{A} A 表示属于助手回应的标记集合,用于确认每个 y i y_i yi 是否是来自助手的回应。
  • F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) F_{\theta}(y_i | P_{\phi} \circ V_{\varphi}(X)) Fθ(yiPϕVφ(X)):这是生成模型的输出,表示给定图像 X X X,通过视觉编码器 V φ ( X ) V_{\varphi}(X) Vφ(X) 和连接器 P ϕ P_{\phi} Pϕ,由语言模型 F θ F_{\theta} Fθ 生成文本 y i y_i yi 的概率。这个概率依赖于图像 X X X 以及模型参数 θ \theta θ ϕ \phi ϕ φ \varphi φ
    • F θ F_{\theta} Fθ:小型语言模型(LLM),其参数为 θ \theta θ
    • P ϕ P_{\phi} Pϕ:连接器,用于连接视觉编码器和语言模型,其参数为 ϕ \phi ϕ
    • V φ V_{\varphi} Vφ:视觉编码器,用于处理图像数据,其参数为 φ \varphi φ
    • ∘ \circ :表示视觉编码器 V φ V_{\varphi} Vφ 和连接器 P ϕ P_{\phi} Pϕ 之间的组合操作。

这是一个 有选择的语言建模目标(Selective Language Modeling Objective)
和普通的语言建模一样,我们最大化目标 token 的对数概率(log-likelihood),但它有两点关键不同

  1. 选择性训练(Selective Training)

    • 并不是对整个文本序列都训练,而是只训练那些属于助手回应的部分 A \mathcal{A} A的 token。
    • 通过 I ( y i ∈ A ) \mathbb{I}(y_i \in \mathcal{A}) I(yiA)这个指示函数实现。
  2. 多模态条件语言建模(Conditioned on Image)

    • 文本生成不仅依赖前面的文本,还要依赖图像 X X X 的表示
    • 图像通过视觉编码器 V φ V_\varphi Vφ 和连接器 P ϕ P_\phi Pϕ 映射为适合语言模型输入形式。
条件语言建模

F θ ( y i ∣ y < i , Z ) F_{\theta}(y_i \mid y_{<i}, Z) Fθ(yiy<i,Z)这是语言模型预测 token y i y_i yi 的概率,前提是:

  • 已知图像表示 Z Z Z
  • 已知之前已生成的 token 序列 y < i y_{<i} y<i
  • 实际上,它可以表示为: log ⁡ P ( y 1 , y 2 , … , y N ∣ Z ) = ∑ i = 1 N log ⁡ P ( y i ∣ y < i , Z ) \log P(y_1, y_2, \ldots, y_N \mid Z) = \sum_{i=1}^{N} \log P(y_i \mid y_{<i}, Z) logP(y1,y2,,yNZ)=i=1NlogP(yiy<i,Z)
加入掩码(只训练助手回应的 token)

我们不对所有 token 求损失,而是只计算: y i ∈ A y_i \in \mathcal{A} yiA,即属于助手回应的那部分的 token。这通过乘以一个指示函数实现:
I ( y i ∈ A ) = { 1 如果  y i 是助手回应的 token 0 否则 \mathbb{I}(y_i \in \mathcal{A}) = \begin{cases} 1 & \text{如果 } y_i \text{ 是助手回应的 token} \\ 0 & \text{否则} \end{cases} I(yiA)={10如果 yi 是助手回应的 token否则

公式(2)损失函数

最终的训练目标是:

L = − ∑ i = 1 N I ( y i ∈ A ) ⋅ log ⁡ P ( y i ∣ y < i , Z ) (2) \mathcal{L} = - \sum_{i=1}^{N} \mathbb{I}(y_i \in \mathcal{A}) \cdot \log P(y_i \mid y_{<i}, Z) \quad\text{(2)} L=i=1NI(yiA)logP(yiy<i,Z)(2)

  • 模型需要在给定图像表示 Z Z Z 和之前生成的 token 序列 y < i y_{<i} y<i 的条件下,生成下一个 token y i y_i yi。因此,我们采用负对数似然损失(negative log-likelihood)来衡量生成正确 token 的概率,即 − log ⁡ P ( y i ∣ y < i , Z ) -\log P(y_i \mid y_{<i}, Z) logP(yiy<i,Z)
  • 在训练对话模型时,输入通常包含了用户的提示和系统的回答。我们只希望模型针对“助手回应”的部分(记作集合 A \mathcal{A} A)进行学习,而不希望对那些已存在的提示部分产生损失。通过使用指示函数 I ( y i ∈ A ) \mathbb{I}(y_i \in \mathcal{A}) I(yiA),我们只对回答部分的 token 计算损失,从而防止模型“记住”提示内容,而专注于生成高质量的回复。
  • 整个训练过程的核心是让模型学会如何根据图像信息 Z Z Z 和上下文生成恰当的回答。通过仅在助手生成部分计算损失,我们确保训练信号只来自模型需要生成的内容,从而更好地实现视觉与语言之间的对齐和有效指令跟随。

分析指令微调公式(1)和公式(2)的联系和区别

这两个公式从本质上都在优化多模态大模型在“助手回答”部分生成正确文本的概率,通过对这些 token 的对数概率求和,可以鼓励模型输出高概率的(即正确的)回答。但它们表达方式和细节略有不同。

公式1:
max ⁡ ϕ , θ , φ ∑ i = 1 N I ( y i ∈ A ) log ⁡ F θ ( y i ∣ P ϕ ∘ V φ ( X ) ) \max_{\phi, \theta, \varphi} \sum_{i=1}^{N} \mathbb{I}(y_i \in \mathcal{A}) \log F_{\theta}(y_i \mid P_{\phi} \circ V_{\varphi}(X)) ϕ,θ,φmaxi=1NI(yiA)logFθ(yiPϕVφ(X))
这个公式以最大化形式出现,直接表达了“最大化对数似然”的目标。其中:

  • V φ ( X ) V_{\varphi}(X) Vφ(X) 表示将图像 X X X 编码为视觉特征;
  • P ϕ P_{\phi} Pϕ 将视觉特征投影到语言模型的嵌入空间;
  • F θ F_{\theta} Fθ 则是整个语言生成模型,它隐式地包含了自回归结构(即内部考虑了上下文 y < i y_{<i} y<i),因此公式中没有显式写出 y < i y_{<i} y<i

公式2:
L = − ∑ i = 1 N I ( y i ∈ A ) ⋅ log ⁡ P ( y i ∣ y < i , Z ) \mathcal{L} = - \sum_{i=1}^{N} \mathbb{I}(y_i \in \mathcal{A}) \cdot \log P(y_i \mid y_{<i}, Z) L=i=1NI(yiA)logP(yiy<i,Z)
这个公式以损失函数的形式给出,采用了负对数似然(negative log-likelihood, NLL)的定义,目标是最小化这个损失。这里:

  • Z Z Z 通常代表经过投影后的视觉特征,即 Z = P ϕ ∘ V φ ( X ) Z = P_{\phi} \circ V_{\varphi}(X) Z=PϕVφ(X)
  • 显式地包含了自回归条件 y < i y_{<i} y<i,说明在生成每个 token 时,模型会考虑之前已经生成的 token。
优化目标
  • 公式1是一个最大化问题,直接追求对数似然的最大化。
  • 公式2则是一个最小化问题,即最小化负对数似然损失。从数学上讲,这两种表述在目标上是等价的(最大化对数似然等价于最小化负对数似然)。
伪代码
def LLaVA_Forward(image, input_ids):# 将图像通过视觉编码器得到视觉特征visual_features = VisualEncoder(image)# 通过投影层将视觉特征转换为语言模型相同的维度projected_features = ProjectionLayer(visual_features)# 将投影后的特征作为记忆传入语言模型(扩展成合适的维度)memory = ExpandDim(projected_features)# 语言模型接收文本输入和视觉记忆,输出各 token 的 logitslogits = LanguageModel(input_ids, memory)return logitsdef Compute_Loss(logits, target_ids, answer_mask):# 对 logits、target_ids 和 answer_mask 进行扁平化处理logits_flat = Flatten(logits)targets_flat = Flatten(target_ids)mask_flat = Flatten(answer_mask)  # 1 表示属于助手回答的 token# 仅对 mask 为1的 token 计算交叉熵损失selected_logits = logits_flat[mask_flat == 1]selected_targets = targets_flat[mask_flat == 1]loss = CrossEntropyLoss(selected_logits, selected_targets)return loss# 训练过程伪代码
for each batch in training_data:image, input_ids, target_ids, answer_mask = GetBatch()logits = LLaVA_Forward(image, input_ids)loss = Compute_Loss(logits, target_ids, answer_mask)loss.backward()optimizer.step()optimizer.zero_grad()

Instruction FineTuning案例代码

# 环境 torch transformers datasets Pillow sentencepiece accelerate
import torch
from torch.utils.data import Dataset, DataLoader
from transformers import AutoTokenizer, AutoModelForCausalLM, ViTModel, ViTImageProcessor
from torch.optim import AdamW
from datasets import load_dataset
from PIL import Image# --------------------
# 配置参数
# --------------------
class Config:dataset_name = "nlphuji/flickr30k"max_length = 128  # 总序列长度(图像+文本)image_size = 224text_model = "distilgpt2"vision_model = "google/vit-base-patch16-224"projector_hidden_size = 768batch_size = 8lr = 1e-5epochs = 3device = "cuda" if torch.cuda.is_available() else "cpu"# --------------------
# 数据集构建
# --------------------
class Flickr30kDataset(Dataset):def __init__(self, dataset, processor, tokenizer):self.dataset = datasetself.processor = processorself.tokenizer = tokenizerself.prompt_template = "[用户] 请描述这张图片。\n[助手] "self.text_max_length = Config.max_length - 1  # 为图像特征预留位置def __len__(self):return len(self.dataset)def __getitem__(self, idx):item = self.dataset[idx]image = item["image"].convert("RGB")text = item["caption"][0]# 图像处理pixel_values = self.processor(image, return_tensors="pt",size={"height": Config.image_size, "width": Config.image_size}).pixel_values[0]# 文本处理(预留图像位置)full_text = self.prompt_template + texttokens = self.tokenizer(full_text, max_length=self.text_max_length,truncation=True,padding="max_length",return_tensors="pt",return_attention_mask=True)# 构建助手标签掩码input_ids = tokens["input_ids"][0]prompt_ids = self.tokenizer.encode(self.prompt_template, add_special_tokens=False,max_length=self.text_max_length,truncation=True)prompt_len = len(prompt_ids)# 扩展标签到总长度(图像+文本)labels = torch.full((Config.max_length,), -100, dtype=torch.long)labels[1:1+len(input_ids)] = input_ids.clone()labels[1:1+prompt_len+1] = -100  # +1覆盖[助手]标记return {"pixel_values": pixel_values,"input_ids": input_ids,"labels": labels}# --------------------
# 多模态模型
# --------------------
class MultimodalModel(torch.nn.Module):def __init__(self):super().__init__()self.vision_encoder = ViTModel.from_pretrained(Config.vision_model)for param in self.vision_encoder.parameters():param.requires_grad = Falseself.projector = torch.nn.Linear(self.vision_encoder.config.hidden_size,Config.projector_hidden_size)self.language_model = AutoModelForCausalLM.from_pretrained(Config.text_model)self.language_model.transformer.wte.weight.requires_grad = Falsedef forward(self, pixel_values, input_ids, labels):# 视觉特征提取vision_outputs = self.vision_encoder(pixel_values)image_embeds = vision_outputs.last_hidden_state[:, 0, :]image_embeds = self.projector(image_embeds)# 文本嵌入text_embeds = self.language_model.transformer.wte(input_ids)# 拼接图像特征(维度对齐)inputs_embeds = torch.cat([image_embeds.unsqueeze(1),  # [batch, 1, hidden]text_embeds                 # [batch, seq-1, hidden]], dim=1)  # 最终维度 [batch, seq, hidden]# 语言模型前向outputs = self.language_model(inputs_embeds=inputs_embeds,labels=labels)return outputs# --------------------
# 训练流程
# --------------------
def train():processor = ViTImageProcessor.from_pretrained(Config.vision_model)tokenizer = AutoTokenizer.from_pretrained(Config.text_model)tokenizer.pad_token = tokenizer.eos_token# 加载数据集dataset = load_dataset(Config.dataset_name)["test"].shuffle(seed=42).select(range(100))train_dataset = Flickr30kDataset(dataset, processor, tokenizer)# 维度验证sample = train_dataset[0]assert sample["pixel_values"].shape == (3, Config.image_size, Config.image_size)assert sample["input_ids"].shape == (Config.max_length-1,)assert sample["labels"].shape == (Config.max_length,)train_loader = DataLoader(train_dataset,batch_size=Config.batch_size,shuffle=True,collate_fn=lambda batch: {'pixel_values': torch.stack([x['pixel_values'] for x in batch]),'input_ids': torch.stack([x['input_ids'] for x in batch]),'labels': torch.stack([x['labels'] for x in batch])})model = MultimodalModel().to(Config.device)optimizer = AdamW(filter(lambda p: p.requires_grad, model.parameters()), lr=Config.lr)model.train()for epoch in range(Config.epochs):total_loss = 0for batch in train_loader:pixel_values = batch["pixel_values"].to(Config.device)input_ids = batch["input_ids"].to(Config.device)labels = batch["labels"].to(Config.device)outputs = model(pixel_values, input_ids, labels)loss = outputs.lossoptimizer.zero_grad()loss.backward()optimizer.step()total_loss += loss.item()print(f"Epoch: {epoch+1}, Step Loss: {loss.item():.4f}")print(f"Epoch {epoch+1} Average Loss: {total_loss/len(train_loader):.4f}")return model# --------------------
# 推理模块
# --------------------
def inference(model, image_path):processor = ViTImageProcessor.from_pretrained(Config.vision_model)tokenizer = AutoTokenizer.from_pretrained(Config.text_model)image = Image.open(image_path).convert("RGB")pixel_values = processor(image,return_tensors="pt",size={"height": Config.image_size, "width": Config.image_size}).pixel_values.to(Config.device)# 生成输入序列(适配维度)prompt = "[用户] 请描述这张图片。\n[助手] "input_ids = tokenizer.encode(prompt,max_length=Config.max_length-1,truncation=True,padding="max_length",return_tensors="pt").to(Config.device)model.eval()with torch.no_grad():vision_outputs = model.vision_encoder(pixel_values)image_embeds = model.projector(vision_outputs.last_hidden_state[:, 0, :])text_embeds = model.language_model.transformer.wte(input_ids)inputs_embeds = torch.cat([image_embeds.unsqueeze(1), text_embeds], dim=1)generated = model.language_model.generate(inputs_embeds=inputs_embeds,max_length=Config.max_length,temperature=0.9)print("生成结果:", tokenizer.decode(generated[0], skip_special_tokens=True))if __name__ == "__main__":trained_model = train()# torch.save(trained_model.state_dict(), "multimodal_model.pth")# inference(trained_model, "test_image.jpg")  # 替换为真实图片路径

相关文章:

多模态大模型MLLM基础训练范式 Pre-train + Instruction FineTuning

多模态大模型Pre-train 为了在图文嵌入空间中更好地对齐视觉和文本信息。为此&#xff0c;使用图像-文本对&#xff08;image-caption style data&#xff09;&#xff0c;表示为 ( X , Y a ) (\mathbf{X}, Y_a) (X,Ya​)&#xff0c;其中&#xff1a; X \mathbf{X} X&#x…...

2025.4.15六年之约day11

六年之约已经断更好几个月了&#xff0c;当初六年之约是当做日记来写的&#xff0c;然后被同事刷到了&#xff0c;被谈及的时候挺尴尬的&#xff0c;毕竟里面记录的是我的所思所想。在互联网下&#xff0c;是不适合发布日记的&#xff0c;但我又爱记录所思所想所做。 不知道距…...

Rust学习之实现命令行小工具minigrep(二)

Rust学习之实现命令行小工具minigrep&#xff08;二&#xff09; Rust学习之实现命令行小工具minigrep&#xff08;一&#xff09; 前言 继续记录一下Rust 语言学习过程&#xff0c;上次写了一个命令行查找字符串的小项目minigrep。学习完了闭包&#xff08;Closures&#x…...

Access Token 和 Refresh Token 的双令牌机制,维持登陆状态

目录 1. 双令牌机制2. 工作流程3. 客户端实现4. 服务器端实现5. 注意事项拓展&#xff1a;Token在客户端安全存储的几种方式 为了实现客户端在 JWT Token 过期后自动更新 Token&#xff0c;通常会采用 Access Token 和 Refresh Token 的双令牌机制。以下是实现自动更新 Token 的…...

前端 -- uni-app 的 splitChunks 分包详解与实战!

全文目录: 开篇语📝 前言📖 目录🌟 什么是 splitChunks?🛠 splitChunks 的核心原理📂 文件拆分的机制⚙️ 配置选项✨ splitChunks 实战案例1️⃣ 项目初始化2️⃣ 编写页面逻辑3️⃣ 配置 splitChunks4️⃣ 查看效果🧩 splitChunks 的高级用法与优化🔍 优化一…...

【教程】检查RDMA网卡状态和测试带宽 | 附测试脚本

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 检查硬件和驱动状态 测试RDMA通信 报错修复 对于交换机的配置&#xff0c;可以看这篇&#xff1a; 【教程】详解配置多台主机通过交换机实现互…...

OSPF的拓展配置

OSPF的拓展配置 1&#xff0c;ospf的手工认证 1&#xff0c;接口认证 r1: display ospf peer brief &#xff08;查看邻居关系&#xff09; int g 0/0/0 ospf authentication-mode md5 1 cipher 123456 display this r2: ospf authentication-mode md5 1 plain 12345…...

http、https、TLS、证书原理理解,对称加密到非对称加密问题,以及对应的大致流程

http 超文本传输协议 存在问题&#xff1a; 安全性、隐私性、数据完整性 易被中间人&#xff08;黑客之类的&#xff09;对数据进行劫持、篡改、隐私泄露 引出了 https &#xff08;source&#xff09; http 在网络模型中的应用层 Application > transport > inter…...

vscode格式化为什么失效?自动保存和格式化(Prettier - Code formatter,vue-format)

vscode自动格式化保存最终配置 博主找了好多的插件&#xff0c;也跟着教程配置了很多&#xff0c;结果还是没有办法格式化&#xff0c;最终发现了一个隐藏的小齿轮&#xff0c;配置完后就生效了 关键步骤 关键配置 一定要点小齿轮&#xff01;&#xff01;&#xff01; 这个小…...

两类中断控制器处理流程_链式和层级

今天呢&#xff0c;我们来用一种新的视角去看中断子系统&#xff0c;然后仿照人家的方法去写一个虚拟的中断子系统&#xff0c;我们先来讲讲链式和层级&#xff1a; 链式中断控制器(chained)&#xff1a; 上图中&#xff0c;左边的"chained intc"就是链式中断控制器…...

软件测试之接口测试用例设计

1.接口测试用例设计简介 我们对系统的需求分析完成之后&#xff0c;即可设计对应的接口测试用例&#xff0c;然后用接口测试用例进行接口测试。接口测试用例的设计也需要用到黑盒测试方法&#xff0c;其与功能测试用例设计的方法类似&#xff0c;接口测试用例设计中还需要增加…...

猫咪如厕检测与分类识别系统系列【九】视频检测区域在线绘制+支持摄像头+网络摄像头+整体构建【上】

前情提要 家里养了三只猫咪&#xff0c;其中一只布偶猫经常出入厕所。但因为平时忙于学业&#xff0c;没法时刻关注牠的行为。我知道猫咪的如厕频率和时长与健康状况密切相关&#xff0c;频繁如厕可能是泌尿问题&#xff0c;停留过久也可能是便秘或不适。为了更科学地了解牠的如…...

MySQL-运维篇

日志主从复制分库分表读写分离 日志 在任何一种数据库当中都会有各种各样的日志&#xff0c;这些日志记录着数据库运行的各个方面 错误日志 这个命令可以查看文件尾部的50行日志&#x1f446; 这个命令是实时输出&#x1f446; 二进制日志 第三个是索引文件&#xff0c;里面…...

mysql关联查询语句

假设存在以下三张表&#xff1a; orders 表&#xff1a;记录订单信息&#xff0c;包含 order_id&#xff08;订单编号&#xff09;、customer_id&#xff08;客户编号&#xff09;、order_date&#xff08;订单日期&#xff09;等字段。customers 表&#xff1a;记录客户信息&…...

Uniapp权限申请优化方案

获取权限前给用户提示&#xff0c;并在用户拒绝后48小时内不再弹窗请求授权。 优化方案分析 您的代码已经实现了基本的权限申请逻辑&#xff0c;但可以进一步优化以满足应用商店的审核要求。 1. 权限申请前的用户提示优化 当前代码中已经包含了权限申请前的提示功能&#x…...

案例驱动的 IT 团队管理:创新与突破之路:第四章 危机应对:从风险预见到创新破局-4.2 人才流失危机-4.2.3梯队建设的“洋葱模型“

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 梯队建设的"洋葱模型"&#xff1a;破解IT团队人才流失危机的创新实践1. 人才流失危机的现实挑战1.1 行业现状与数据警示1.2 传统应对策略的失效 2. 洋葱模型的理论…...

双目视觉中矩阵等参数说明及矫正

以下是标定文件中各个参数的详细解释&#xff1a; 1. 图像尺寸 (imageSize) 参数值: [1280, 1024]含义: 相机的图像分辨率&#xff0c;宽度为1280像素&#xff0c;高度为1024像素。 2. 相机内参矩阵 (leftCameraMatrix / rightCameraMatrix) 结构: yaml data: [fx, 0, cx, 0,…...

烽火ai场控接入deepseek自动回复话术软件

要将烽火AI场控软件与DeepSeek自动回复话术软件进行对接&#xff0c;实现直播间自动互动功能&#xff0c;需通过API接口或脚本工具完成数据互通。以下是具体操作步骤及注意事项&#xff1a; 确认兼容性与准备工作 软件支持检查 确认烽火AI场控是否开放API接口&#xff08;一般需…...

CSS 美化页面(三)

一、盒模型 盒模型本质上是一个盒子&#xff0c;封装周围的HTML元素 。包含&#xff1a; 外边距&#xff0c;边框&#xff0c;填充&#xff0c;和实际内容 一个盒子由四个区域组成&#xff1a;内容&#xff08;Content&#xff09;、内边距&#xff08;Padding&#xff09;、外…...

面试题之数据库-mysql高阶及业务场景设计

最近开始面试了&#xff0c;410面试了一家公司 针对自己薄弱的面试题库&#xff0c;深入了解下&#xff0c;也应付下面试。在这里先祝愿大家在现有公司好好沉淀&#xff0c;定位好自己的目标&#xff0c;在自己的领域上发光发热&#xff0c;在自己想要的领域上&#xff08;技术…...

STM32F407实现SD卡的读写功能

文章目录 前言一、SDIO简介二、SD卡操作1.读操作2.写数据3.擦除操作4.最终效果5.完整工程 前言 在STM32中存储空间是有限的&#xff0c;对于需要存储大量数据的项目就需要外扩存储空间&#xff0c;一般会选择FLASH、EEPROM或者SD卡。SD是这三种中可达空间最大的&#xff0c;所…...

Vue 3中的setup【与Vue 2的区别】

一、前言 在Vue 3中&#xff0c;setup是组合式API&#xff08;Composition API&#xff09;的核心入口函数。其核心作用是为组件提供灵活的逻辑组织方式&#xff0c;解决复杂组件中逻辑碎片化的问题。 二、核心作用 1.初始化响应式数据 通过ref和reactive等API声明响应式状态…...

基于PySide6的YOLOv8/11目标检测GUI界面——智能安全帽检测系统

&#x1f4d6; 前言 在工业安全领域&#xff0c;智能安全帽检测是保障工人生命安全的重要技术手段。本文将介绍如何利用YOLOv8/YOLOv11目标检测算法与PySide6 GUI框架&#xff0c;开发一套功能完整的智能安全帽检测系统。系统支持&#xff1a; 动态切换检测模型&#xff08;Y…...

AF3 generate_chain_data_cache脚本解读

AlphaFold3 generate_chain_data_cache 脚本在源代码的scripts文件夹下。该脚本从指定目录中批量解析 mmCIF/PDB 文件的工具,并将每个链的基本信息(序列、分辨率、是否属于聚类等)提取并写入 JSON 文件,主要用于后续蛋白质建模、过滤或训练数据准备。 源代码: import ar…...

C/C++不透明指针

今天在ESP32编程中又看到了这个词&#xff0c;这个词出现在cursor回答中。回答如下&#xff1a; struct esp_netif_obj; typedef struct esp_netif_obj esp_netif_t;esp_netif_obj的具体实现细节被隐藏了用户代码只能通过esp_netif_t类型指针来操作网络接口这种封装方式被称为…...

电力实习中需要注意哪些安全用电问题

电力实习中需要注意哪些安全用电问题 在电工实习中&#xff0c;由于涉及到电力设备和电气设施&#xff0c;安全问题尤为重要。 以下是电工实习中需要注意的安全问题&#xff1a; 一、电气设备及线路安全 使用电气设备前&#xff0c;应确保设备具有良好的电气绝缘&#xff0c…...

【版本控制】git命令使用大全

大家好&#xff0c;我是jstart千语。今天来总结一下git的使用命令&#xff0c;上文会先将git命令都列出来&#xff0c;便于快速寻找&#xff0c;然后还会对部分常用命令图文讲解&#xff0c;适合新手&#xff0c;让你快速地理解。最后还会总结在idea中使用git。如果有缺失的&am…...

Day09【基于Tripletloss实现的简单意图识别对话系统】

基于Tripletloss实现的表示型文本匹配 目标数据准备参数配置数据处理Triplet Loss目标Triplet Loss计算公式公式说明 模型构建网络结构设计网络训练目标损失函数设计 主程序推理预测类初始化加载问答知识库文本向量化知识库查询主程序main测试测试效果 参考博客 目标 在此之前…...

什么是HIGG验厂,HIGG验厂有什么要求?HIGG验厂有什么作用

什么是Higg验厂&#xff1f; Higg验厂&#xff08;Higg Facility Environmental Module, FEM & Higg Facility Social & Labor Module, FSLM&#xff09;是由可持续服装联盟&#xff08;SAC, Sustainable Apparel Coalition&#xff09;开发的一套评估工具&#xff0c…...

SmolVLM新模型技术解读笔记

原文地址&#xff1a;https://huggingface.co/blog/zh/smolervlm 一、核心发布概要 新成员亮相&#xff1a;推出256M&#xff08;2.56亿参数&#xff09;与500M&#xff08;5亿参数&#xff09;视觉语言模型关键定位&#xff1a;目前全球最小VLM&#xff08;256M&#xff09;…...

解决USG5150防火墙web无法连接问题

参考 防火墙usg5500&#xff08;V300R001C00SPC700&#xff09;WEB界面无法登陆 现象 Web防火墙突然无法web登录&#xff0c;Ping通&#xff0c;但是Tcpping端口不通。无论是从外网、还是内网都一样。 Probing 192.168.100.1:1234/tcp - No response - time2047.528ms Prob…...

Resilience4j与Spring Cloud Gateway整合指南:构建弹性的API网关

什么是Resilience4j&#xff1f; Resilience4j是一个轻量级的容错库&#xff0c;专为Java 8和函数式编程设计。它借鉴了Netflix Hystrix的设计理念&#xff0c;但更加轻量且专注于Java 8的函数式编程风格。Resilience4j提供了多种容错机制&#xff0c;帮助开发者构建弹性强健的…...

Quipus,LightRag的Go版本的实现

1 项目简介 奇谱系统当前版本以知识库为核心&#xff0c;基于知识库可以快构建自己的问答系统。知识库的Rag模块的构建算法是参考了LightRag的算法流程的Go版本优化实现&#xff0c;它可以帮助你快速、准确地构建自己的知识库&#xff0c;搭建属于自己的AI智能助手。与当前LLM…...

怎样完成本地模型知识库检索问答RAG

怎样完成本地模型知识库检索问答RAG 目录 怎样完成本地模型知识库检索问答RAG使用密集检索器和系数检索器混合方式完成知识库相似检索1. 导入必要的库2. 加载文档3. 文本分割4. 初始化嵌入模型5. 创建向量数据库6. 初始化大语言模型7. 构建问答链8. 提出问题并检索相关文档9. 合…...

研发效率破局之道阅读总结(2)流程优化

研发效率破局之道阅读总结(2)流程优化 Author: Once Day Date: 2025年4月15日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 程序的艺术_Once-Day…...

解决PIP 安装出错ERROR: cp310-cp310-manylinux_2_28_x86_64.whl is not a supported wheel

ERROR: torch-2.8.0.dev20250325cu128-cp310-cp310-manylinux_2_28_x86_64.whl is not a supported wheel on this platform. 可以 pip debug --verbose | grep manylinux | grep cp310 WARNING: This command is only meant for debugging. Do not use this with automation f…...

b站golang后端开发一面

go和其他语言的对比 Golang&#xff08;也称为Go语言&#xff09;是一种静态类型、编译型语言&#xff0c;由Google开发&#xff0c;以其简洁、高效和强大的并发处理能力著称。 Golang的设计哲学强调简洁明了。与Python类似&#xff0c;Go语法简洁&#xff0c;易于学习和编写。…...

Vue3 SSR Serverless架构革命:弹性计算与量子加速

一、全维度Serverless SSR架构 1.1 蜂巢式弹性调度系统 1.2 冷启动时间优化表 优化策略Node.js冷启(ms)Deno冷启(ms)Bun冷启(ms)裸启动1800960420预编译二进制650380210内存快照预热22016090WASM实例池15011075量子状态预载453832 二、边缘渲染协议升级 2.1 流式SSR响应协议…...

深度大脑:AI大模型的设计与运行原理

AI大模型的设计与运行原理涉及多个复杂环节&#xff0c;以下是系统化的总结&#xff0c;结合核心要点与补充细节&#xff1a; 一、AI大模型的设计 1. 深度神经网络架构 Transformer&#xff1a;取代RNN/CNN&#xff0c;解决长程依赖问题。核心组件&#xff1a; 自注意力机制…...

Python网络编程从入门到精通:Socket核心技术+TCP/UDP实战详解

引言 网络编程是构建现代分布式系统的核心能力&#xff0c;而Socket作为通信的基石&#xff0c;其重要性不言而喻。本文将从零开始&#xff0c;通过清晰的代码示例、原理剖析和对比分析&#xff0c;带你彻底掌握Python中的Socket编程技术&#xff0c;涵盖TCP可靠连接、UDP高效…...

使用CMake生成Opencv对应库文件

opencv环境配置&#xff1a;版本3.4/3.2(OpenCV-3.4.3) CMake&#xff1a;3.12.1 D:\OpenCv\opencv\build\x64\vc16\bin路径添加至环境变量中 CMake环境配置&#xff1a; D:\Install_QT\bin路径添加至环境变量中&#xff08;path中即可&#xff09; QT5环境变量配置&#xff1a…...

MySQL 数据库备份和恢复全指南

MySQL 是一款常用的开源数据库系统&#xff0c;在日常运维中&#xff0c;数据备份和恢复是系统管理的重要一环。本文将细致介绍 MySQL 两大备份方案—— mysqldump 和 XtraBackup&#xff0c;包括备份方式、恢复步骤、定时脚本、远程备份和常见问题处理方案。 一、mysqldump 备…...

关于我的服务器

最近我买了台腾讯云服务器&#xff0c;然后新手小白只会用宝塔。。。 安装完之后默认的端口是8888&#xff0c;打开面板就会提示我有风险。然后 我改了端口之后&#xff0c;怎么都打不开。 于是 学到了几句命令可以使用&#xff1a; //查看端口是否已经修改成功 cat www/se…...

spring面试题

1&#xff0c;如何理解spring boot中的starter Starter是一种简化依赖管理和自动配置的核心机制&#xff0c;能快速集成特定功能模块&#xff0c;无需手动配置复杂依赖和xml文件。 依赖简化&#xff1a;将某个功能模块所需的所有依赖打包成一个“一站式”依赖&#xff0c;开发…...

python setup.py学习

Python-setup进阶打包命令 Python-setup进阶打包命令_python setup-CSDN博客 packages 需要处理的包目录&#xff08;包含__init__.py的文件夹&#xff09;&#xff0c;这里通常使用 find_packages()&#xff0c;它默认在和setup.py同一目录下搜索各个含有 __init__.py的包。…...

最简单的使用SDL2 播放原始音频数据程序

author: hjjdebug date: 2025年 04月 15日 星期二 14:02:05 CST description: 最简单的使用SDL2 播放原始音频数据程序 文章目录 1.最简单的播放音频的程序是什么样子的?2. 怎样用SDL 来编写音频播放器代码?2.1 SDL播放音频核心代码:混音函数2.2 先看看音频播放的可能的两种框…...

利用IDEA开发Spark-SQL

创建子模块Spark-SQL&#xff0c;并添加依赖 创建Spark-SQL的测试代码&#xff1a; 运行结果&#xff1a; 自定义函数&#xff1a; UDF&#xff1a; UDAF&#xff08;自定义聚合函数&#xff09; 强类型的 Dataset 和弱类型的 DataFrame 都提供了相关的聚合函数&#xff0c; …...

随身Wi-Fi能跑PCDN?

随身WiFi可以用于运行PCDN&#xff08;点对点内容分发网络&#xff09;&#xff0c;但存在技术限制和潜在风险&#xff0c;需谨慎操作。 可行性分析 技术基础 随身WiFi本质是便携式无线路由器&#xff0c;具备网络接入和分发能力&#xff0c;理论上可配置为PCDN节点。 部分用户…...

Google-A2A协议全面解析:一文掌握Agent-to-Agent协议的核心与应用

前言&#xff1a; 在当今人工智能技术飞速发展的时代&#xff0c;智能体&#xff08;Agent&#xff09;已悄然融入我们生活的各个角落。无论是个人智能助手&#xff0c;还是企业的自动化工具&#xff0c;各类AI代理的应用愈发广泛。但目前这些智能体之间大多处于孤立状态&…...

jmeter压测工具出现乱码

然后 prev.setDataEncoding(“utf-8”)...