大语言模型(LLM)训练的教师强制(Teacher Forcing)方法

大语言模型(LLM)在训练时使用一种名为“教师强制(Teacher Forcing)”的方法,而不是它们在推理(生成文本)时使用的“自回归(Autoregressive)”方法 。阐明关于LLM训练的一些常见问题,例如如何控制输出长度,以及为什么训练效率比推理更高。

训练 vs. 推理:Teacher Forcing vs. 自回归

区分大语言模型在两个不同阶段的运作方式:

  • 自回归(推理/生成阶段):这是LLM在生成文本(即推理)时使用的方法 。它以序列化的方式,逐个token地工作 。为了预测下一个token,模型会将它已经生成的token作为输入 。例如,为了写出“The quick brown fox”,模型首先预测出“The”,然后用“The”作为输入来预测“quick”,再用“The quick”来预测“brown”,以此类推。这个过程是天生的序列化过程,因此速度较慢。

  • Teacher Forcing(训练阶段):该方法用于模型的训练阶段 。在训练时,模型不会使用自己先前(可能不正确)的预测作为下一步的输入,而是始终被喂入正确、真实的答案(即“标签”或“ground truth”)。为了预测序列中的每一个token,模型会接收来自训练数据中真实的前序token作为输入 。然后,模型会并行地计算出所有位置的输出,再将其预测的输出(如t2’, t3’, t4’)与真实的后续token(如t2, t3, t4)进行比较,以计算损失(Loss)。

使用Teacher Forcing进行训练的主要优点是:

  • 高效率:因为模型不必等待前一个token生成后才能预测下一个,所有token的预测都可以并行计算 。这使得训练过程比自回归推理快得多,并能带来更高的GPU利用率 。
  • 长度控制:由于模型在训练时是“看着答案”来生成的,它被训练去生成一个与所提供的标签长度完全相同的输出,这直接解决了训练期间输出长度如何控制的问题 。

Teacher Forcing是一种有效的训练方法吗?

Teacher Forcing是一种科学上合理的方法,它并不会影响模型的学习目标 。通过数学推导证明了Teacher Forcing、最大似然估计(Maximum Likelihood Estimation, MLE)和交叉熵损失(Cross-Entropy Loss)这三者的优化目标是等价的 。

  • 最大似然估计(MLE):模型训练的根本目标是最大化模型在给定输入x的条件下,生成正确token序列y的概率 。这可以表示为最大化整个序列的对数似然。

    • 一个序列的概率是其每个token在给定所有前序token的条件下的概率之积:pθ(y1:T∣x)=∏t=1Tpθ(yt∣y<t,x)p_{\theta}(y_{1:T}|x)=\prod_{t=1}^{T}p_{\theta}(y_{t}|y_{<t},x)pθ(y1:Tx)=t=1Tpθ(yty<t,x)
    • MLE的目标是最大化所有训练样本的对数概率之和:LMLE(θ)=∑∑log⁡pθ(yt∣y<t,x)\mathcal{L}_{MLE}(\theta) = \sum \sum \log p_{\theta}(y_{t}|y_{<t},x)LMLE(θ)=∑∑logpθ(yty<t,x)
  • Teacher Forcing损失:在Teacher Forcing中,一个序列的总损失是其每一个token位置上损失的总和 。在每一步t,损失是正确token yty_tyt 在给定真实前序token y<ty_{<t}y<t 条件下的负对数概率。

    • 总损失为:L=−∑t=1Tlog⁡pθ(yt∣y<t,x)L = -\sum_{t=1}^{T}\log p_{\theta}(y_{t}|y_{<t},x)L=t=1Tlogpθ(yty<t,x)
  • 交叉熵损失:此损失函数用于衡量两个概率分布之间的差异。在这里,它比较的是模型预测的下一个token的概率分布与真实的概率分布(一个one-hot向量,其中正确token的概率为1)。在整个序列上累加的交叉熵损失,在数学上与Teacher Forcing的损失是完全相同的 。

因此,得出了以下等价关系:
CrossEntropy=LTeacher−Forcing=−LMLE(θ)CrossEntropy = L_{Teacher-Forcing} = - \mathcal{L}_{MLE}(\theta)CrossEntropy=LTeacherForcing=LMLE(θ)
这表明,使用Teacher Forcing来最小化交叉熵损失,等同于最大化训练数据的似然。

Teacher Forcing在代码中如何实现

使用Hugging Face的transformers库,提供了一个实践层面的代码讲解。

  1. 数据准备DataCollatorForLanguageModeling被用来准备数据 。它通过简单地复制inputs来创建用于计算损失的labels
  2. 前向传播与损失计算:当模型执行其forward方法时,如果传入了labels参数,就会自动触发损失的计算 。
  3. 移位以实现“预测下一个token”:最关键的一步是,在损失函数(例如ForCausalLMLoss)内部,模型的输出(logits)和标签(labels)会被相互错开一位 。标签被移动,使得输入中位置i的token(input_ids)被用来预测标签中位置i+1的token 。这种错位正是“预测下一个token”这一任务的本质。
  4. 计算损失:最终的损失是通过在模型的预测(logits)和移位后的正确标签(shifted labels)之间计算cross_entropy(交叉熵)得出的 。这个代码实现与Teacher Forcing的示意图完全对应,即模型在每个位置的输出都与真实序列中的下一个token进行比较。

我们跟随一个具体的例子,看看一句话是如何在训练流程中被处理的,以及每一步的数据细节是怎样的。

核心目标:教会模型“接话”

首先要理解,LLM训练的核心任务是预测下一个词(Next Token Prediction)
比如我们给模型一句话“天空是”,我们希望它能预测出“蓝色”这个词。训练的本质就是给模型看海量的文本,让它反复练习这个“接话”的游戏,直到它做得非常好。

完整训练流程的详细拆解

让我们以一句话 “大模型爱学习” 为例,看看它在训练中经历了什么。

第1步:数据准备(输入与标签的制作)

在模型开始训练前,我们首先要准备好给它“吃”的数据。

  1. 文本分词 (Tokenization):计算机不认识汉字,只认识数字。所以第一步是把文本切分成最小的单元(Token),然后转换成对应的数字ID。

    • “大模型爱学习” -> อาจจะถูกตัดเป็น -> ["大", "模型", "爱", "学习"]
    • 然后,我们查阅一个预先制作好的词典(Tokenizer),将这些词转换为唯一的数字ID。
    • 假设词典是这样的:{"大": 10, "模型": 25, "爱": 33, "学习": 88}
    • 那么我们的输入数据就变成了 [10, 25, 33, 88]。这个在代码里通常被称为 input_ids
  2. 制作标签 (Labels):这是最关键的一步。在Teacher Forcing训练模式下,标签(labels)就是输入(inputs)的一个完整复制品

    • 所以,我们现在有两份一模一样的数据:
      • inputs (输入): [10, 25, 33, 88]
      • labels (标签): [10, 25, 33, 88]

你可能会问:为什么输入和标签一样?别急,玄机在后面。

第2步:模型进行并行预测

现在我们把 inputs ([10, 25, 33, 88]) 送进大模型。

  • 与推理时一个一个词往外蹦不同,在训练时,模型会并行地处理整个输入序列 。这意味着它会同时计算出每一个位置的“下一个词预测”。
  • 模型的输出是一系列的logitsLogits可以理解为一个超长的列表,代表了模型对词典里每一个词的预测分数。分数越高,代表模型认为这个词是下一个词的可能性越大。
    • 当模型看到 10 (“大”) 时,它会输出一个logits向量,这是对第二个词的预测。
    • 当模型看到 10, 25 (“大”, “模型”) 时,它会输出另一个logits向量,这是对第三个词的预测。
    • …以此类推。

所以,输入是一个长度为4的序列,输出也是4组对应的logits预测。

第3步:关键操作 —“移位”,对齐预测和答案

这是整个流程中最巧妙、最核心的部分。现在我们手上有两样东西:

  1. 模型的预测 (Logits):模型在每个位置上对 下一个 词的预测。
  2. 真实的答案 (Labels):我们知道每个位置后面 应该 跟哪个词。

我们的目标是:用模型在位置 i 的预测,去对比位置 i+1 的真实答案。
例如:用模型看了“大”之后的预测,去和标准答案“模型”做对比。

为了实现这个目标,代码里会执行一个**移位(Shift)**操作 。

让我们把数据可视化:

输入 (Inputs)模型看到的内容模型的预测目标预测输出 (Logits)真实答案 (Labels)
10 (“大”)“大”“模型”Logits_125 (“模型”)
25 (“模型”)“大”, “模型”“爱”Logits_233 (“爱”)
33 (“爱”)“大”, “模型”, “爱”“学习”Logits_388 (“学习”)
88 (“学习”)“大”, “模型”, “爱”, “学习”(无)Logits_4(无)

如上表所示,我们需要比较的是“预测输出”和“真实答案”这两列。代码通过简单的数组切片就实现了这个对齐:

  • 取所有位置的预测Logits
  • 取所有位置的、向左移动一位的标签:即从labels的第二个元素开始取 。
    • labels: [10, 25, 33, 88]
    • shifted_labels: [25, 33, 88]

这样,Logits_1 就会和 25 比较,Logits_2 就会和 33 比较,以此类推。这完美地实现了“预测下一个词”的训练目标。

第4步:计算损失 (Loss)

对齐之后,我们就在每个位置上计算损失。

  • 这个计算是通过交叉熵损失函数 (Cross-Entropy Loss) 完成的 。
  • 你可以把交叉熵理解为衡量“惊讶程度”的指标。
    • 在位置1,模型预测的 Logits_1 如果给正确答案 25 (“模型”) 打了很高的分,那么损失就很小(模型不惊讶)。
    • 反之,如果模型给 25 打了很低的分,那么损失就很大(模型很惊讶,它猜错了)。
  • 最后,我们会把所有位置(位置1, 2, 3)的损失加起来,得到这个句子总的损失值 。
第5步:模型学习与更新

计算出的总损失值是一个数字,它告诉我们模型这次“考试”考得有多差。然后,通过反向传播算法,这个损失值会被用来微调模型内部亿万个参数。目的就是让模型下次再看到类似的输入时,能给出更接近正确答案的预测,从而让损失值变得更小。

这个过程会重复数万亿次,模型最终就学会了语言的规律。

总结一下完整流程:

  1. 准备数据:将一句话“大模型爱学习”转换成数字ID,并复制一份作为标签。
    • inputs: [10, 25, 33, 88]
    • labels: [10, 25, 33, 88]
  2. 并行预测:模型接收inputs,并行为每个位置输出一个对下一个词的预测(logits)。
  3. 移位对齐:将labels向左移一位,使得模型的预测logits[i]与正确答案labels[i+1]对齐。
  4. 计算损失:在每个位置上,使用交叉熵比较模型的预测和正确答案,计算出损失。
  5. 累加损失:将所有位置的损失相加,得到总损失 。
  6. 更新模型:根据总损失,使用优化算法(如梯度下降)更新模型的内部参数,完成一次学习。
import torch
import torch.nn as nn
from torch.optim import AdamW# ==============================================================================
# 1. 初始化设置 (Setup & Initialization)
# ==============================================================================# 假设我们有一个预训练好的大语言模型 (LLM) 和它的分词器 (Tokenizer)
# 在实际应用中,这些通常从Hugging Face加载
# model = AutoModelForCausalLM.from_pretrained("some-llm")
# tokenizer = AutoTokenizer.from_pretrained("some-llm")# 为了演示,我们用模拟的组件代替
class MockTokenizer:def __init__(self):# 词典:将词映射到ID。-100是Hugging Face中常用的一个特殊值,# 用于在计算损失时忽略某些token 。我们后面会用到它。self.vocab = {"[PAD]": 0, "我": 1, "爱": 2, "学": 3, "习": 4, "大": 5, "模": 6, "型": 7}self.pad_token_id = 0self.ignore_index = -100def encode(self, text):return [self.vocab[char] for char in text]class MockLLM(nn.Module):def __init__(self, vocab_size):super().__init__()# 模型的词嵌入层和输出头self.embedding = nn.Embedding(vocab_size, 768) # 假设隐藏层维度是768self.head = nn.Linear(768, vocab_size)def forward(self, input_ids, attention_mask=None):# 1. 输入的token ID通过嵌入层,变成向量表示embedded_vectors = self.embedding(input_ids) # (batch, seq_len) -> (batch, seq_len, hidden_dim)# 2. 经过模型主体(Transformer层),这里简化处理# 在真实模型中,这里会有一系列的Transformer Blocktransformer_output = embedded_vectors # 简化,实际有复杂计算# 3. 通过输出头,将向量表示转换回词典大小的logitslogits = self.head(transformer_output) # (batch, seq_len, hidden_dim) -> (batch, seq_len, vocab_size)return logits# 实例化我们的模拟组件
tokenizer = MockTokenizer()
model = MockLLM(vocab_size=len(tokenizer.vocab))
optimizer = AdamW(model.parameters(), lr=5e-5)# ==============================================================================
# 2. 数据准备 (Data Preparation) - Teacher Forcing的关键起点
# ==============================================================================# 我们的原始训练数据
sample_text = "我爱学习大模型"# (2.1) 分词并将文本转为数字ID (Tokenization)
# input_ids: [1, 2, 3, 4, 5, 6, 7]
input_ids = tokenizer.encode(sample_text)# (2.2) 转换为PyTorch张量(Tensor),并增加一个batch维度(批处理大小为1)
# 形状: [1, 7] (1个样本, 序列长度为7)
input_ids_tensor = torch.tensor([input_ids], dtype=torch.long)# (2.3) 创建标签(labels)。这是核心步骤之一:
# “这个Label仅仅是input的复制” 。
# labels = inputs.clone() 
labels_tensor = input_ids_tensor.clone()print(f"原始输入 (input_ids): {input_ids_tensor}")
print(f"原始标签 (labels):    {labels_tensor}")
print("-" * 30)# ==============================================================================
# 3. 训练步骤 (A Single Training Step)
# ==============================================================================# 清零之前的梯度
optimizer.zero_grad()# (3.1) 前向传播 (Forward Pass)
# 将准备好的input_ids送入模型,得到logits
# logits的形状: [batch_size, sequence_length, vocab_size]
# 也就是 [1, 7, 8] -> (1个样本, 7个token, 每个token都有8个可能的分数,对应词典大小)
logits = model(input_ids=input_ids_tensor)print(f"模型输出Logits的形状: {logits.shape}")
print("-" * 30)# (3.2) 移位操作 (Shift) - Teacher Forcing的核心实现
# 这是反复强调的最关键细节。
# 我们的目标:用位置i的预测(logits),去和位置i+1的答案(labels)做对比。# logits形状:  [1, 7, 8]
# labels形状:  [1, 7]# 截取logits:我们不需要用最后一个token的输出来预测任何东西,所以去掉最后一个。
# 取从第0个到倒数第二个token的预测结果。
# shift_logits形状: [1, 6, 8]
shift_logits = logits[:, :-1, :]# 截取labels:我们预测的目标是从第1个token开始,所以去掉第0个。
# shift_labels形状: [1, 6]
shift_labels = labels_tensor[:, 1:]print("--- 移位操作 ---")
print(f"移位前Logits形状: {logits.shape}  (预测了7次)")
print(f"移位后Logits形状: {shift_logits.shape} (我们只关心前6次的预测)")
print(f"移位前Labels形状: {labels_tensor.shape} (7个真实答案)")
print(f"移位后Labels形状: {shift_labels.shape} (我们只关心后6个真实答案)")
print(f"移位后的标签内容: {shift_labels}")
print("-" * 30)# (3.3) 计算损失 (Loss Calculation)
# 在计算损失前,通常会将数据展平(Flatten) 。
# 将 [batch_size, sequence_length, vocab_size] -> [(batch_size * sequence_length), vocab_size]
# 将 [batch_size, sequence_length] -> [(batch_size * sequence_length)]
# 这样就可以一次性计算所有token的损失。# 展平后的logits形状: [6, 8]
flat_logits = shift_logits.reshape(-1, model.head.out_features)# 展平后的labels形状: [6]
flat_labels = shift_labels.reshape(-1)print("--- 展平操作 ---")
print(f"展平后Logits形状: {flat_logits.shape}")
print(f"展平后Labels形状: {flat_labels.shape}")
print("-" * 30)# 使用交叉熵损失函数 。
# ignore_index告诉损失函数,如果label是-100,就不要计算这个位置的损失。
# 这在处理padding(为了让句子等长而填充的无意义token)时非常有用。
loss_function = nn.CrossEntropyLoss(ignore_index=tokenizer.ignore_index)# loss_function会自动比较flat_logits (模型的预测分布) 和 flat_labels (正确答案的ID)。
# 它会计算出模型预测的“惊讶程度”,即损失值。
loss = loss_function(flat_logits, flat_labels)# (3.4) 反向传播 (Backward Pass)
# 根据计算出的损失值,自动计算模型中每个参数的梯度。
loss.backward()# (3.5) 参数更新 (Optimizer Step)
# 指示优化器根据刚刚计算出的梯度,来更新模型的所有参数。
optimizer.step()print(f"计算出的总损失 (Loss): {loss.item()}")
print("模型参数已更新!完成一次训练迭代。")
  1. Teacher Forcing的起点:训练的inputslabels一开始是完全相同的副本 。
  2. 并行计算:模型一次性处理整个输入序列,并行地为每个输入位置生成一个对“下一个词”的预测(logits)。这解释了为什么训练比推理效率高 。
  3. 核心是移位(Shift):通过对logitslabels进行简单的切片(一个去掉结尾,一个去掉开头),我们就完美地创造出了“用前一个词预测后一个词”的训练任务,这正是Teacher Forcing的精髓 。
  4. 损失函数:最终使用标准的交叉熵损失函数 来衡量预测与真实答案之间的差距,并驱动模型的学习。

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

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

相关文章

归一化与激活函数:深度学习的双引擎

归一化和激活函数区别 归一化和激活函数是深度学习中两个不同但又存在关联的技术,前者聚焦于“数据分布的调整”,后者聚焦于“引入非线性与输出转换”。 Softmax 既可以被视为一种归一化操作,也属于激活函数 因为它同时满足两者的核心特征,只是从不同角度定义:从“输出…

C# --- 单例类错误初始化 + 没有释放资源导致线程泄漏

C# --- 单例类错误初始化 没有释放资源导致线程泄漏Background原因分析问题一&#xff1a; 错误初始化&#xff08;使用了箭头函数&#xff09;问题一&#xff1a; 没有Dispose资源Background 背景: service A的其中一个Api会向mq发送消息问题&#xff1a;线上发现这个服务经常…

MySQL基础学习之DML,DQL(二)

这里写目录标题一、DML1、INSERT语句1)、给指定列添加数据2)、给全部列添加数据3)、批量数据添加数据4)、操作2、UPDATE语句3、DELETE语句二、DQL1、单表查询1&#xff09;查询语法2&#xff09;查询全部3&#xff09;查询部分4&#xff09;条件查询5&#xff09;聚合函数6&…

在 Linux 系统中实现 Spring Boot 程序自动启动的最佳实践

在实际部署 Spring Boot 项目的生产环境中&#xff0c;如何确保服务自动启动&#xff08;如开机自动运行、宕机自动恢复&#xff09;是一项基础而关键的运维能力。本文将系统介绍如何在 Linux 中将 Spring Boot 应用注册为 systemd 服务&#xff0c;实现进程守护与自动启动。&a…

如何建立项目团队的自驱力文化?

建立项目团队的自驱力文化&#xff0c;关键在于赋权机制、目标共创、持续反馈、内在激励、价值认同。 其中&#xff0c;“目标共创”尤其重要。项目成员若未参与目标制定&#xff0c;仅被动接受任务&#xff0c;将很难激发责任感和参与热情。反之&#xff0c;通过共创目标&…

【React Native】布局文件-底部TabBar

布局文件-底部tabBar 内容配置 export default function Layout() {return (<Tabs />); }默认会将布局文件是将与它在同一个目录的所有文件&#xff0c;包括下级目录的文件&#xff0c;全都配置成Tab了。&#xff1a; 这样做显然不对&#xff0c;正确的做法是 在app目…

CompareFace使用

CompareFace 使用 CompareFace 有三种服务&#xff0c;分别是人脸识别&#xff08;RECOGNITION&#xff09;、人脸验证&#xff08;VERIFICATION&#xff09;、人脸检测&#xff08;DETECTION&#xff09;。 人脸识别其实就是人脸身份识别(每张照片只有一个人脸)&#xff0c;…

APP测试之Monkey压力测试

&#xff08;一&#xff09;Monkey简介 Monkey意指猴子&#xff0c;顽皮淘气。所以Monkey测试&#xff0c;顾名思义也就像猴子一样在软件上乱敲按键&#xff0c;猴子什么都不懂&#xff0c;就爱捣乱。 Monkey 是 Android SDK 自带的命令行工具&#xff0c;它通过向系统发送伪…

时序大模型为时序数据库带来的变革与机遇

时序数据&#xff08;Time Series Data&#xff09;作为记录系统状态随时间变化的重要数据类型&#xff0c;在物联网、金融交易、工业监控等领域呈爆炸式增长。传统时序数据库专注于高效存储和查询时序数据&#xff0c;而时序大模型&#xff08;Time Series Foundation Models&…

深入核心:理解Spring Boot的三大基石:起步依赖、自动配置与内嵌容器

深入核心&#xff1a;理解Spring Boot的三大基石&#xff1a;起步依赖、自动配置与内嵌容器 摘要&#xff1a;在上一章&#xff0c;我们领略了Spring Boot带来的革命性开发体验。但魔法的背后&#xff0c;必有其科学的支撑。本章将带你深入Spring Boot的内核&#xff0c;系统性…

达梦数据库配置兼容MySQL

前言 作为一名数据库管理员或开发者&#xff0c;当项目需要从MySQL迁移到达梦数据库时&#xff0c;最关心的莫过于兼容性问题。达梦作为国产数据库的佼佼者&#xff0c;提供了良好的MySQL兼容模式&#xff0c;今天我就来分享一下如何配置达梦数据库以实现对MySQL的兼容。 一、为…

js与vue基础学习

vue创建项目 安装node安装node、npm、cnpm node -v npm -v #npm服务器位置处于国外&#xff0c;下载包的速度会比较缓慢。阿里为国内用户提供的cnpm&#xff0c;他是npm的镜像&#xff0c;下载第三方包时&#xff0c;们完全可以使用cnpm来替代npm。 cnpm -v在node中执行JavaScr…

【开源.NET】一个 .NET 开源美观、灵活易用、功能强大的图表库

文章目录一、项目介绍二、适用场景三、功能模块四、功能特点五、效果展示六、开源地址一、项目介绍 LiveCharts2 是一个开源、简单、灵活、交互式且功能强大的 .NET 图表库。LiveCharts2 现在几乎可以在任何地方运行&#xff1a;Maui、Uno Platform、Blazor-wasm、WPF、WinFor…

使用Whistle自定义接口返回内容:Mock流式JSON数据全解析

一.mock接口返回数据流程 定位目标接口 在Whistle的Network面板中找到需要Mock的接口&#xff0c;右键点击请求信息&#xff0c;选择COPY -> URL复制完整URL&#xff0c;确保URL路径精确到具体接口。准备Mock数据 点击对应接口&#xff0c;在右侧面板切换到response标签页&a…

【前端】富文本编辑器插件 wangEditor 5 基本使用(Vue2)

https://www.wangeditor.com/v5 一、安装 首先安装editor yarn add wangeditor/editor # 或者 npm install wangeditor/editor --save安装Vue2组件 yarn add wangeditor/editor-for-vue # 或者 npm install wangeditor/editor-for-vue --save或者Vue3 yarn add wangeditor/…

自适应哈希索引 和 日志缓冲区

目录 1. 自适应哈希索引在内存中的位置 2. 自适应哈希索引的作用 3. 为什么要创建自适应哈希索引 4. 适应哈希索引的Key -Value如何设置&#xff1f; 5. 日志缓冲区在内存中的位置 6. 日志缓冲区的作用 7. 日志不通过LogBuffer直接写入磁盘不行吗&#xff1f; 1. 自适应哈…

中国旅行社协会在京召开“文旅人工智能应用研讨会”,助力文旅创新发展

7月15日&#xff0c;由中国旅行社协会数字经济专业委员会和在线旅行服务商分会联合主办的“人工智能技术在文旅产业中的应用”研讨会在北京举行。中国旅行社协会副会长、秘书长孙桂珍出席并致辞&#xff0c;中国工程院外籍院士、具身智能机器人专家张建伟、北京第二外国语学院旅…

Linux之Zabbix分布式监控篇(一)

一、概念和特点概念Zabbix是一款开源、免费的监控软件 主要用于7*24*365实时监控网络设置&#xff0c;操作系统&#xff0c;应用程序&#xff0c;网络带宽等资源的运行状态&#xff0c;并且一旦发生异常能够第一时间个SA管理员发送报警信息特点Zabbix是c/s结构&#xff0c;有c…

ZYNQ千兆光通信实战:Tri Mode Ethernet MAC深度解析

—— 从硬件设计到Linux驱动的光通信创新实践** 当ZYNQ遇上光通信 在工业控制、医疗成像和航空航天等领域,抗干扰、长距离传输的光通信技术至关重要。Xilinx ZYNQ-7000系列凭借ARM+FPGA的架构,结合Tri Mode Ethernet MAC (TEMAC) 核心,为千兆光通信提供了完美解决方案。本文…

求不重叠区间总和最大值

例题链接&#xff1a;1051-习题-数学考试_2021秋季算法入门班第一章习题&#xff1a;模拟、枚举、贪心 来源&#xff1a;牛客网 时间限制&#xff1a;C/C/Rust/Pascal 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C/Rust/Pascal 32 M&#xff0c;其他语言64 M 64bit …