• [技术干货] 损失函数:AI的“错题本”如何指导它进步
    损失函数:AI的“错题本”如何指导它进步考试后,老师会让我们整理错题本,分析每道题的错误原因,避免下次再犯。在AI训练中,也有一个类似的“错题本”——损失函数(Loss Function)。它不仅记录模型的“错误”,还通过量化错误程度,指导模型调整参数、逐步优化。本文将用生活化案例拆解损失函数的作用机制,并介绍几种常见类型。一、损失函数:AI的“错误评分系统”什么是损失函数?损失函数是AI模型训练的核心工具,它的作用是:计算预测值与真实值的差距(即“错误程度”);将错误转化为可优化的数值(损失值);通过最小化损失值,驱动模型参数更新。类比错题本:错题记录:模型每次预测错误的数据点(如把猫误判为狗);错误分析:损失函数计算错误的严重性(如“猫狗误判”比“猫虎误判”损失更小);改进方向:根据损失值调整模型参数,减少同类错误。二、损失函数如何指导AI进步?1. 量化错误:从“差不多”到“精确打击”假设训练一个图像分类模型,输入一张猫的图片,模型输出预测概率:真实标签:猫(概率应为100%)模型预测:猫(80%)、狗(15%)、老虎(5%)损失函数的作用:计算预测与真实的差距(如交叉熵损失会惩罚低概率的正确类别);生成一个具体的损失值(如0.5),数值越小表示模型越准确。类比学习:学生答题后,老师不会只说“错了”,而是会扣分(如选择题错一题扣2分);损失函数通过数值量化错误,让模型明确“改进空间有多大”。2. 反向传播:根据错误调整参数模型通过反向传播算法(Backpropagation)利用损失函数更新参数:计算损失值对每个参数的梯度(即“参数调整方向”);沿梯度反方向调整参数(如减少导致错误增大的权重);重复迭代,逐步降低损失值。类比纠错:学生根据错题本分析错误原因(如“公式记错”);针对性复习公式(调整参数),避免下次再犯。三、常见损失函数类型与适用场景1. 均方误差(MSE,Mean Squared Error)公式:MSE=1n∑i=1n(yi−y^i)2MSE = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 MSE=n1​i=1∑n​(yi​−y^​i​)2特点:对大错误惩罚更重(误差平方后放大);适用于回归问题(如预测房价、温度)。案例:预测房价时,若真实值为300万,模型预测为200万,误差为100万,MSE会将其放大为1亿,迫使模型重点关注大误差。2. 交叉熵损失(Cross-Entropy Loss)公式(二分类):L=−[ylog⁡(y^)+(1−y)log⁡(1−y^)]L = -[y \log(\hat{y}) + (1-y)\log(1-\hat{y})] L=−[ylog(y^​)+(1−y)log(1−y^​)]特点:惩罚预测概率与真实标签的偏离(如真实为猫,但模型预测概率低);适用于分类问题(如图像分类、文本情感分析)。案例:将猫误判为狗时,若模型对猫的预测概率仅为0.3(真实应为1),交叉熵损失会生成一个较大的值(约1.2),驱动模型提高猫类别的概率。3. 平均绝对误差(MAE,Mean Absolute Error)公式:MAE=1n∑i=1n∣yi−y^i∣MAE = \frac{1}{n}\sum_{i=1}^{n}|y_i - \hat{y}_i| MAE=n1​i=1∑n​∣yi​−y^​i​∣特点:对所有错误一视同仁(误差线性计算);适用于对异常值不敏感的场景(如预测销量,偶尔的极端值不影响整体)。对比MSE:MSE对异常值更敏感(误差平方后放大);MAE更鲁棒,但梯度恒定(可能导致收敛变慢)。4. Hinge Loss(合页损失)公式(支持向量机SVM):L=max⁡(0,1−y⋅y^)L = \max(0, 1 - y \cdot \hat{y}) L=max(0,1−y⋅y^​)特点:关注分类边界的“安全距离”(希望正确类别的预测值远大于其他类);适用于二分类问题(如垃圾邮件检测)。案例:若真实标签为1(正类),模型预测值为0.8,Hinge Loss为0(满足安全距离);若预测值为0.5,损失为0.5,驱动模型提高预测值。四、如何选择损失函数?任务类型推荐损失函数选择理由回归(预测连续值)MSE、MAE直接量化数值差异分类(多类别)交叉熵损失惩罚概率分布偏离二分类交叉熵、Hinge Loss交叉熵通用,Hinge Loss适合SVM异常检测MAE或自定义损失减少异常值干扰实战技巧:从任务目标出发:若需严格惩罚大错误(如医疗诊断),选MSE;若需鲁棒性(如金融风控),选MAE。尝试组合损失:如目标检测中同时使用分类损失和定位损失(如Smooth L1 Loss)。监控损失曲线:若训练集损失下降但验证集损失上升,可能过拟合,需调整模型或正则化。五、结语:损失函数——AI的“纠错老师”损失函数是AI模型的“错题本”和“评分系统”,它通过量化错误、指导参数更新,让模型从“懵懂无知”逐步成长为“精准预测”。理解不同损失函数的特性,能帮助我们根据任务需求选择合适的工具,就像学生根据科目特点选择复习方法一样。下次训练模型时,不妨想想:如果它是你的学生,你会为它设计怎样的“错题本”?
  • [技术干货] 过拟合与欠拟合:AI模型也会“学过头”和“学不会”
    过拟合与欠拟合:AI模型也会“学过头”和“学不会”?在AI训练过程中,我们常遇到两种尴尬情况:模型在训练数据上表现完美,一到新数据就“翻车”(过拟合);或者连训练数据都学不明白,像极了考试总不及格的学生(欠拟合)。这两种现象就像走钢丝——平衡“学得够”和“学得巧”是模型性能的关键。本文用生活化案例带你轻松理解这两个核心概念。一、过拟合:当AI变成“死记硬背”的学霸现象:模型在训练集上准确率99%,测试集上却只有60%,像极了考试前背熟所有例题,换个问法就答错的学生。为什么会出现过拟合?数据量太少:假设用5张猫狗照片训练模型,它可能记住每张照片的背景颜色(如“绿色背景=猫”),而非真正的猫狗特征。类比:只见过5种水果的孩子,可能认为“圆形+红色=苹果”,但遇到草莓或樱桃就会混淆。模型太复杂:用100层神经网络拟合简单的线性数据(如身高与年龄的关系),模型会“创造”出不必要的复杂曲线来完美穿过每个训练点。类比:用高等数学解小学算术题,反而容易算错。训练时间过长:模型反复“啃”训练数据,连数据中的噪声(如照片模糊、标注错误)都当成了规律。类比:背单词时把例句中的错别字也记了下来。如何解决过拟合?简化模型:减少神经网络层数或决策树深度。增加数据:用更多样化的数据训练(如更多猫狗品种、不同角度的照片)。正则化:给模型“减肥”,限制参数值大小(如L1/L2正则化)。早停法:在验证集性能下降时提前终止训练。交叉验证:用不同数据子集多次训练,避免对特定数据“偏科”。二、欠拟合:当AI变成“一知半解”的学渣现象:模型在训练集和测试集上表现都很差,像极了连课本例题都解不出的学生。为什么会出现欠拟合?模型太简单:用直线拟合“正弦曲线”数据,无论怎么调整参数都无法拟合波动。类比:用算盘计算微积分,工具本身能力不足。特征不足:预测房价时只考虑面积,忽略了楼层、地段等关键因素。类比:判断水果甜度只看颜色,忽略了品种和成熟度。数据问题:数据存在大量缺失值或错误标注,导致模型无法学习有效规律。类比:课本印刷错误百出,学生越学越糊涂。如何解决欠拟合?增加模型复杂度:改用深度神经网络或增加决策树深度。丰富特征:加入更多相关特征(如房价预测中加入学区、交通等维度)。减少正则化:如果使用了正则化,尝试降低其强度。检查数据质量:修复缺失值、修正错误标注、处理异常值。三、过拟合 vs 欠拟合:如何找到平衡点?对比项过拟合欠拟合训练集表现准确率极高(接近100%)准确率低测试集表现准确率显著下降准确率同样低模型复杂度过高(参数过多/层数过深)过低(参数过少/层数过浅)典型场景数据量少、模型复杂、训练时间长数据特征不足、模型过于简单解决方案简化模型、增加数据、正则化增加复杂度、丰富特征、优化数据实战技巧:绘制学习曲线:观察训练集和验证集准确率随训练轮次的变化,若两者差距持续扩大,可能过拟合;若两者同步低迷,可能欠拟合。网格搜索调参:通过交叉验证尝试不同模型复杂度(如决策树深度),找到性能最佳点。结语:AI训练的“中庸之道”过拟合和欠拟合的本质是模型与数据的“匹配度”问题:前者像“过度解读”,后者像“理解不足”。作为开发者,我们需要像调音响音量一样,通过调整模型复杂度、数据量和特征工程,找到那个“刚刚好”的平衡点。记住:好的模型不是完美拟合训练数据,而是能在新场景中稳健预测——这或许就是AI学习的“中庸之道”。
  • 计算机如何理解人类语言
    人类语言是地球上最复杂的符号系统之一,它承载着抽象概念、情感表达和文化传承。然而,计算机作为基于二进制逻辑的机器,如何“理解”这种充满模糊性和语境依赖的自然语言?这一过程经历了从简单规则匹配到深度神经网络的革命性演变,本文将带您揭开自然语言处理(NLP)的技术面纱。一、早期尝试:基于规则的“机械翻译”20世纪50年代,计算机科学家们试图通过硬编码语法规则实现机器翻译。例如,早期的系统会将句子拆解为词性标签(名词、动词等),再根据预设的语法结构重组目标语言。这种方法在简单句子上表现尚可,但面对人类语言的歧义性时迅速崩溃:词汇歧义:英文单词“bank”既可指“银行”也可指“河岸”;句法歧义:“Flying planes can be dangerous”既可理解为“驾驶飞机很危险”,也可指“飞行的飞机本身很危险”;语义依赖:“把书放在桌子上”中的“桌子”是“放”的受事对象,而计算机难以捕捉这种关系。这种“符号主义”方法本质上是将人类语言简化为逻辑推理问题,但自然语言的非形式化特性使其注定失败。二、统计革命:让计算机从数据中学习1990年代,统计方法开始主导NLP领域。核心思想是:语言规律隐藏在海量文本中,计算机可以通过概率统计“发现”模式。典型技术包括:N-gram模型:通过统计连续N个词出现的频率预测下一个词(如“我爱你”后接“吗”的概率高于“你爱我”);词向量(Word Embedding):将单词映射为高维空间中的向量,使语义相似的词在向量空间中距离更近(如“猫”和“狗”的向量夹角小于“猫”和“火箭”);隐马尔可夫模型(HMM):用于分词、词性标注等任务,通过观察序列推断隐藏状态。这一阶段的技术突破使机器翻译质量显著提升,但仍依赖人工特征工程,且无法处理长距离语义依赖(如否定词“不”对句子整体的影响)。三、深度学习时代:神经网络的“语言直觉”2010年后,深度学习彻底改变了NLP格局。其核心优势在于:通过端到端训练自动学习语言特征,无需人工设计规则。关键技术包括:循环神经网络(RNN):通过循环结构处理序列数据,捕捉上下文信息(如理解“他”指代前文的“张三”);注意力机制(Attention):动态聚焦关键信息(如翻译“苹果公司”时重点关注“苹果”而非无关词汇);Transformer架构:通过自注意力机制并行处理整个句子,使模型能够“全局思考”(如GPT系列模型通过预测下一个词学习语言模式)。现代大模型(如GPT-4、文心一言)已能生成连贯文本、回答复杂问题,甚至进行创意写作。其“理解”本质是在海量数据中建立统计关联,但这种“理解”与人类仍有本质差异:模型缺乏真实语义和常识推理能力,更多是“概率押注”。四、未来挑战:从“理解”到“共情”尽管技术进步显著,但计算机理解人类语言仍面临挑战:隐喻与讽刺:如何识别“这天气真暖和”(字面)与“这天气冷得像冰箱”(讽刺)的区别?文化语境:中文“龙”象征吉祥,而西方“dragon”代表邪恶,模型需理解文化符号差异;情感分析:判断“这部电影还行”是褒义还是贬义,需结合语气和上下文。未来的方向可能包括:多模态融合:结合图像、语音等模态增强理解(如通过表情判断讽刺);常识推理:引入知识图谱补充世界知识;可解释性:让模型解释决策过程(如“为什么认为这句话是积极的?”)。
  • [技术干货] 智能体目标冲突解决多目标优化中的权重动态调整策略
    智能体目标冲突解决多目标优化中的权重动态调整策略在真实业务或自主决策型 Agent 系统中,智能体往往并非只追求单一目标。例如:无人机需要兼顾任务收益、能源消耗、安全风险;推荐系统需要平衡用户体验、商业转化、内容多样性;智能客服需要同时满足响应速度、答案准确度、用户情绪稳定性。这些目标之间往往存在天然冲突,导致无法单纯依赖固定的权重体系来求解最优策略。我个人认为,多目标优化的难点不在于目标数量的增加,而在于权衡关系的动态性和上下文依赖性。因此,本篇文章讨论的是一种更贴近实际工程的解决方法:动态权重调整策略(Dynamic Weight Adjustment, DWA)。一、为什么固定权重不可行?传统多目标方法通常采用线性加权方式:总目标 = w1 * A + w2 * B + w3 * C但在真实系统中可能出现以下问题:场景变化快:用户状态、环境信息、风险等级随时变化,固定权重无法适配。目标间存在阶段性主次关系:如节能优先还是性能优先取决于电量是否充足。实时反馈信息必须进入优化循环:策略效果应该影响下一轮权重,而不是独立存在。换句话说,智能体真正需要的不是一个公式,而是动态博弈式权衡机制。二、动态权重调整的常用策略(工程实践视角)我把它总结为以下三类,可独立使用或混合使用:策略类型核心思路适用场景性能变化驱动根据每轮目标达成率调整权重训练/迭代型智能体(RL、AutoML)环境与状态驱动根据上下文环境动态切换权重真实物理环境或实时系统用户或业务策略驱动根据 KPI 和 SLA 自动调整企业级平台与推荐系统在实际落地中,我比较推荐状态驱动 + 性能驱动的混合方案,既兼顾系统稳定性,又能具备自适应能力。三、基于性能反馈的动态权重示例思路:每一轮优化后,如果某个目标表现不佳,则适当提升其权重;反之降低。实战代码示例(Python)以下示例使用一个简单任务:智能体需要同时最小化时间消耗和成本支出,并对权重进行动态反馈调整。import random class MultiObjectiveAgent: def __init__(self, w_time=0.5, w_cost=0.5, lr=0.1): self.weights = {"time": w_time, "cost": w_cost} self.lr = lr def evaluate(self): # 模拟性能结果(越小越好) result = { "time": random.uniform(0.1, 1.0), "cost": random.uniform(0.1, 1.0) } return result def adjust_weights(self, result): total = sum(result.values()) normalized = {k: v / total for k, v in result.items()} # 根据表现动态调整(表现越差权重越高) for k in self.weights: adjustment = self.lr * normalized[k] self.weights[k] += adjustment # 归一化 total_w = sum(self.weights.values()) for k in self.weights: self.weights[k] /= total_w def run(self, rounds=10): for step in range(rounds): result = self.evaluate() self.adjust_weights(result) print(f"Step {step+1}") print(f" Performance: {result}") print(f" Adjusted Weights: {self.weights}") print("-"*40) if __name__ == "__main__": agent = MultiObjectiveAgent() agent.run(10) 输出分析思路当某个目标表现持续较差时,其权重会逐渐提高,促使智能体系统在下一轮更倾向于优化此目标,从而形成自适应的目标平衡机制。虽然示例为简化模型,但和企业级调参逻辑一致:用反馈信息驱动资源配置优先级变动。四、工程化落地的思考与建议我在经验中发现,动态权重策略在实际项目部署时需要注意以下几点:不要过度追求实时性权重每次变化过大可能导致智能体策略震荡,可增加滑动平均或模糊逻辑。可以设置硬约束区间一些安全性目标不能被下降到过低,可以设最小阈值。考虑用户感知权重,而非纯数学最优用户体验是非线性的,稍微偏差也可能导致满意度骤降。权重可以成为模型训练的超参数,而非固定参数把它当作学习目标的一部分,而不是外部设定值。五、动态权重策略的系统化设计框架(从策略走向架构)如果把动态权重调整看作一个功能点,往往只停留在代码层面;但如果把它视作智能体核心决策模块之一,我们需要构建更完整的架构。我的经验是,可以将其抽象为四层结构:┌──────────────────────┐ │ 4. 策略执行层 (Policy Layer) │ ← 基于动态权重输出最终策略 ├──────────────────────┤ │ 3. 评估反馈层 (Evaluation Layer) │ ← 收集任务表现、环境状态、风险指数 ├──────────────────────┤ │ 2. 权重调控层 (Weight Adaptation) │ ← 动态调整并归一化权重 ├──────────────────────┤ │ 1. 目标定义层 (Objective Layer) │ ← 明确目标、约束与优先级底线 └──────────────────────┘这个框架能确保系统不是“凭感觉地调权重”,而是有输入、有计算、有反馈、有验证的闭环结构。推荐的工程化实践规则规则含义实践建议R1所有目标必须可指标化转化为可测量、可量化结果值R2权重变化必须可解释保存变更日志用于审计分析R3调整不超过安全区间避免短期波动导致策略漂移R4权重 ≠ 优先级可再引入元优先级做兜底尤其是 R4,这是许多人忽视的 —— 两个目标权重相同,不代表优先级相同,比如安全永远高于收益。六、引入环境驱动的权重切换机制(状态机建模)在许多实时系统中,权重不仅需要动态变化,还要根据状态进行阶段性切换。一种有效方法是将其设计成有限状态机(Finite State Machine, FSM)。示例:无人机任务状态权重模型状态描述主目标次级目标权重策略起飞阶段系统初始上升安全稳定性安全最大化任务巡航执行路径规划能耗 / 时间稳定性反馈驱动动态权重电量告警< 30% 电量能源安全返回能耗权重急速上升紧急状况风险触发安全其他全部放弃强制切换策略这种结合状态机的动态权重策略,本质上是让系统从“自动拟合”进化到自主决策策略切换”。状态驱动代码class WeightManager: def __init__(self): self.weights = {"safety": 0.4, "efficiency": 0.4, "energy": 0.2} def update_state(self, battery, risk): if risk > 0.7: return "emergency" if battery < 0.3: return "low_power" return "normal" def adjust_by_state(self, state): if state == "emergency": self.weights = {"safety": 1.0, "efficiency": 0.0, "energy": 0.0} elif state == "low_power": self.weights = {"safety": 0.3, "efficiency": 0.1, "energy": 0.6} else: # normal pass # 沿用动态调整权重流程 return self.weights核心思想:动态策略 ≠ 全局连续变化,而是分阶段精准控制。七、如何为动态权重引入“学习能力”:元策略思想目前很多动态权重方案依然是手动规则 + 简单反馈,未真正智能化。更进一步的方向是引入Meta-Policy(元策略),让权重不仅影响智能体行为,还能被学习、被优化。可能的学习机制包括:强化学习(RL)驱动的权重自适应基于奖励差异的反向调节机制使用策略梯度更新权重区间利用历史轨迹拟合权重演变模型Python 简易元学习代码history = [] def meta_update(weights, performance): history.append((weights.copy(), performance)) if len(history) > 5: recent = history[-5:] trend = sum([p["reward"] for _, p in recent]) / 5 if trend < benchmark: # 自动提升探索性 for k in weights: weights[k] += random.uniform(-0.05, 0.05) # 归一化 total = sum(weights.values()) for k in weights: weights[k] /= total return weights这段逻辑虽然简化,但体现了核心思想:不仅优化目标,更优化目标之间的关系。八、从单体智能体到协同智能体(Multi-Agent)在分布式智能体系统中,不同Agent之间可能目标不同,甚至互斥,例如:能源调度系统:发电方与调度方目标冲突联盟推荐系统:商业方与用户方指标冲突机器人协同:局部最优与全局最优冲突此时,动态权重不仅作用于单体智能体,还可能上升为群体协商协议,可采用:方法核心思想工程价值博弈论均衡点决策严谨但复杂协同 RL学习群体最优策略自适应性强共识协议限定可接受区间工程成本低总结在智能体从“执行式自动化”向“自主性决策体”演进的过程中,多目标冲突是绕不过的核心挑战。真正的难点并不是目标数量、优化方法或计算能力,而是如何让智能体在动态环境中持续保持合理的目标平衡感,并具备自适应调整能力。本文所讨论的动态权重策略,本质是一种面向现实复杂性的工程思路:不再把目标关系视为静态参数,而是让系统具备“权衡-反馈-再平衡”的智能循环机制。通过性能反馈、环境状态、策略阶段与元学习,将权重从配置项提升为可学习、可解释且可演化的决策变量,让智能体的行为更像一个成熟决策者,而不是被动执行器。我个人认为,这一方向的最终落点不会停留在权重本身,而是指向以下三个未来能力:目标理解能力(Goal Reasoning)智能体不仅知道要做什么,还能判断“什么时候该重视什么”。策略弹性能力(Policy Adaptiveness)面对变化不是“固守”,而是“策略性调整”。价值观一致性(Value Alignment)在复杂目标下坚持底线原则与长期目标,而非短期最优。当智能体能自洽地处理目标冲突,它才真正迈向具备智能性、稳健性与可信度的下一层级。
  • [技术干货] Ascend310部署Qwen-VL-7B实现吸烟动作识别
    Ascend310部署Qwen-VL-7B实现吸烟动作识别OrangePi AI Studio Pro是基于2个昇腾310P处理器的新一代高性能推理解析卡,提供基础通用算力+超强AI算力,整合了训练和推理的全部底层软件栈,实现训推一体。其中AI半精度FP16算力约为176TFLOPS,整数Int8精度可达352TOPS,本文将带领大家在Ascend 310P上部署Qwen2.5-VL-7B多模态理解大模型实现吸烟动作的识别。一、环境配置我们在OrangePi AI Stuido上使用Docker容器部署MindIE:docker pull swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:2.1.RC1-300I-Duo-py311-openeuler24.03-ltsroot@orangepi:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie 2.1.RC1-300I-Duo-py311-openeuler24.03-lts 0574b8d4403f 3 months ago 20.4GB langgenius/dify-web 1.0.1 b2b7363571c2 8 months ago 475MB langgenius/dify-api 1.0.1 3dd892f50a2d 8 months ago 2.14GB langgenius/dify-plugin-daemon 0.0.4-local 3f180f39bfbe 8 months ago 1.35GB ubuntu/squid latest dae40da440fe 8 months ago 243MB postgres 15-alpine afbf3abf6aeb 8 months ago 273MB nginx latest b52e0b094bc0 9 months ago 192MB swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie 1.0.0-300I-Duo-py311-openeuler24.03-lts 74a5b9615370 10 months ago 17.5GB redis 6-alpine 6dd588768b9b 10 months ago 30.2MB langgenius/dify-sandbox 0.2.10 4328059557e8 13 months ago 567MB semitechnologies/weaviate 1.19.0 8ec9f084ab23 2 years ago 52.5MB之后创建一个名为start-docker.sh的启动脚本,内容如下:NAME=$1 if [ $# -ne 1 ]; then echo "warning: need input container name.Use default: mindie" NAME=mindie fi docker run --name ${NAME} -it -d --net=host --shm-size=500g \ --privileged=true \ -w /usr/local/Ascend/atb-models \ --device=/dev/davinci_manager \ --device=/dev/hisi_hdc \ --device=/dev/devmm_svm \ --entrypoint=bash \ -v /models:/models \ -v /data:/data \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ -v /usr/local/dcmi:/usr/local/dcmi \ -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \ -v /usr/local/sbin:/usr/local/sbin \ -v /home:/home \ -v /tmp:/tmp \ -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \ -e http_proxy=$http_proxy \ -e https_proxy=$https_proxy \ -e "PATH=/usr/local/python3.11.6/bin:$PATH" \ swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:2.1.RC1-300I-Duo-py311-openeuler24.03-ltsbash start-docker.sh启动容器后,我们需要替换几个文件并安装Ascend-cann-nnal软件包:root@orangepi:~# docker exec -it mindie bash Welcome to 5.15.0-126-generic System information as of time: Sat Nov 15 22:06:48 CST 2025 System load: 1.87 Memory used: 6.3% Swap used: 0.0% Usage On: 33% Users online: 0 [root@orangepi atb-models]# cd /usr/local/Ascend/ascend-toolkit/8.2.RC1/lib64/ [root@orangepi lib64]# ls /data/fix_openeuler_docker/fixhccl/8.2hccl/ libhccl.so libhccl_alg.so libhccl_heterog.so libhccl_plf.so [root@orangepi lib64]# cp /data/fix_openeuler_docker/fixhccl/8.2hccl/* ./ cp: overwrite './libhccl.so'? cp: overwrite './libhccl_alg.so'? cp: overwrite './libhccl_heterog.so'? cp: overwrite './libhccl_plf.so'? [root@orangepi lib64]# source /usr/local/Ascend/ascend-toolkit/set_env.sh [root@orangepi lib64]# chmod +x /data/fix_openeuler_docker/Ascend-cann-nnal/Ascend-cann-nnal_8.3.RC1_linux-x86_64.run [root@orangepi lib64]# /data/fix_openeuler_docker/Ascend-cann-nnal/Ascend-cann-nnal_8.3.RC1_linux-x86_64.run --install --quiet [NNAL] [20251115-22:41:45] [INFO] LogFile:/var/log/ascend_seclog/ascend_nnal_install.log [NNAL] [20251115-22:41:45] [INFO] Ascend-cann-atb_8.3.RC1_linux-x86_64.run --install --install-path=/usr/local/Ascend/nnal --install-for-all --quiet --nox11 start WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv [NNAL] [20251115-22:41:58] [INFO] Ascend-cann-atb_8.3.RC1_linux-x86_64.run --install --install-path=/usr/local/Ascend/nnal --install-for-all --quiet --nox11 install success [NNAL] [20251115-22:41:58] [INFO] Ascend-cann-SIP_8.3.RC1_linux-x86_64.run --install --install-path=/usr/local/Ascend/nnal --install-for-all --quiet --nox11 start [NNAL] [20251115-22:41:59] [INFO] Ascend-cann-SIP_8.3.RC1_linux-x86_64.run --install --install-path=/usr/local/Ascend/nnal --install-for-all --quiet --nox11 install success [NNAL] [20251115-22:41:59] [INFO] Ascend-cann-nnal_8.3.RC1_linux-x86_64.run install success Warning!!! If the environment variables of atb and asdsip are set at the same time, unexpected consequences will occur. Import the corresponding environment variables based on the usage scenarios: atb for large model scenarios, asdsip for embedded scenarios. Please make sure that the environment variables have been configured. If you want to use atb module: - To take effect for current user, you can exec command below: source /usr/local/Ascend/nnal/atb/set_env.sh or add "source /usr/local/Ascend/nnal/atb/set_env.sh" to ~/.bashrc. If you want to use asdsip module: - To take effect for current user, you can exec command below: source /usr/local/Ascend/nnal/asdsip/set_env.sh or add "source /usr/local/Ascend/nnal/asdsip/set_env.sh" to ~/.bashrc. [root@orangepi lib64]# cat /usr/local/Ascend/nnal/atb/latest/version.info Ascend-cann-atb : 8.3.RC1 Ascend-cann-atb Version : 8.3.RC1.B106 Platform : x86_64 branch : 8.3.rc1-0702 commit id : 16004f23040e0dcdd3cf0c64ecf36622487038ba修改推理使用的逻辑NPU核心为0,1,测试多模态理解大模型:Qwen2.5-VL-7B-Instruct:运行结果表明,Qwen2.5-VL-7B-Instruct在2 x Ascned 310P上推理平均每秒可以输出20个tokens,同时准确理解画面中的人物信息和行为动作。[root@orangepi atb-models]# bash examples/models/qwen2_vl/run_pa.sh --model_path /models/Qwen2.5-VL-7B-Instruct/ --input_image /root/pic/test.jpg [2025-11-15 22:12:49,663] torch.distributed.run: [WARNING] [2025-11-15 22:12:49,663] torch.distributed.run: [WARNING] ***************************************** [2025-11-15 22:12:49,663] torch.distributed.run: [WARNING] Setting OMP_NUM_THREADS environment variable for each process to be 1 in default, to avoid your system being overloaded, please further tune the variable for optimal performance in your application as needed. [2025-11-15 22:12:49,663] torch.distributed.run: [WARNING] ***************************************** /usr/local/lib64/python3.11/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: 'libc10_cuda.so: cannot open shared object file: No such file or directory'If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source? warn( /usr/local/lib64/python3.11/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: 'libc10_cuda.so: cannot open shared object file: No such file or directory'If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source? warn( 2025-11-15 22:12:53.250 7934 LLM log default format: [yyyy-mm-dd hh:mm:ss.uuuuuu] [processid] [threadid] [llmmodels] [loglevel] [file:line] [status code] msg 2025-11-15 22:12:53.250 7933 LLM log default format: [yyyy-mm-dd hh:mm:ss.uuuuuu] [processid] [threadid] [llmmodels] [loglevel] [file:line] [status code] msg [2025-11-15 22:12:53.250] [7934] [139886327420160] [llmmodels] [WARN] [model_factory.cpp:28] deepseekV2_DecoderModel model already exists, but the duplication doesn't matter. [2025-11-15 22:12:53.250] [7933] [139649439929600] [llmmodels] [WARN] [model_factory.cpp:28] deepseekV2_DecoderModel model already exists, but the duplication doesn't matter. [2025-11-15 22:12:53.250] [7934] [139886327420160] [llmmodels] [WARN] [model_factory.cpp:28] deepseekV2_DecoderModel model already exists, but the duplication doesn't matter. [2025-11-15 22:12:53.250] [7933] [139649439929600] [llmmodels] [WARN] [model_factory.cpp:28] deepseekV2_DecoderModel model already exists, but the duplication doesn't matter. [2025-11-15 22:12:53.250] [7934] [139886327420160] [llmmodels] [WARN] [model_factory.cpp:28] llama_LlamaDecoderModel model already exists, but the duplication doesn't matter. [2025-11-15 22:12:53.250] [7933] [139649439929600] [llmmodels] [WARN] [model_factory.cpp:28] llama_LlamaDecoderModel model already exists, but the duplication doesn't matter. [2025-11-15 22:12:55,335] [7934] [139886327420160] [llmmodels] [INFO] [cpu_binding.py-254] : rank_id: 1, device_id: 1, numa_id: 0, shard_devices: [0, 1], cpus: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] [2025-11-15 22:12:55,336] [7934] [139886327420160] [llmmodels] [INFO] [cpu_binding.py-280] : process 7934, new_affinity is [8, 9, 10, 11, 12, 13, 14, 15], cpu count 8 [2025-11-15 22:12:55,356] [7933] [139649439929600] [llmmodels] [INFO] [cpu_binding.py-254] : rank_id: 0, device_id: 0, numa_id: 0, shard_devices: [0, 1], cpus: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] [2025-11-15 22:12:55,357] [7933] [139649439929600] [llmmodels] [INFO] [cpu_binding.py-280] : process 7933, new_affinity is [0, 1, 2, 3, 4, 5, 6, 7], cpu count 8 [2025-11-15 22:12:56,032] [7933] [139649439929600] [llmmodels] [INFO] [model_runner.py-156] : model_runner.quantize: None, model_runner.kv_quant_type: None, model_runner.fa_quant_type: None, model_runner.dtype: torch.float16 [2025-11-15 22:13:01,826] [7933] [139649439929600] [llmmodels] [INFO] [dist.py-81] : initialize_distributed has been Set [2025-11-15 22:13:01,827] [7933] [139649439929600] [llmmodels] [INFO] [model_runner.py-187] : init tokenizer done Using a slow image processor as `use_fast` is unset and a slow processor was saved with this model. `use_fast=True` will be the default behavior in v4.48, even if the model was saved with a slow processor. This will result in minor differences in outputs. You'll still be able to use a slow processor with `use_fast=False`. [2025-11-15 22:13:02,070] [7934] [139886327420160] [llmmodels] [INFO] [dist.py-81] : initialize_distributed has been Set Using a slow image processor as `use_fast` is unset and a slow processor was saved with this model. `use_fast=True` will be the default behavior in v4.48, even if the model was saved with a slow processor. This will result in minor differences in outputs. You'll still be able to use a slow processor with `use_fast=False`. [W InferFormat.cpp:62] Warning: Cannot create tensor with NZ format while dim < 2, tensor will be created with ND format. (function operator()) [W InferFormat.cpp:62] Warning: Cannot create tensor with NZ format while dim < 2, tensor will be created with ND format. (function operator()) [2025-11-15 22:13:08,435] [7933] [139649439929600] [llmmodels] [INFO] [flash_causal_qwen2.py-153] : >>>> qwen_QwenDecoderModel is called. [2025-11-15 22:13:08,526] [7934] [139886327420160] [llmmodels] [INFO] [flash_causal_qwen2.py-153] : >>>> qwen_QwenDecoderModel is called. [2025-11-15 22:13:16.666] [7933] [139649439929600] [llmmodels] [WARN] [operation_factory.cpp:42] OperationName: TransdataOperation not find in operation factory map [2025-11-15 22:13:16.698] [7934] [139886327420160] [llmmodels] [WARN] [operation_factory.cpp:42] OperationName: TransdataOperation not find in operation factory map [2025-11-15 22:13:22,379] [7933] [139649439929600] [llmmodels] [INFO] [model_runner.py-282] : model: FlashQwen2vlForCausalLM( (rotary_embedding): PositionRotaryEmbedding() (attn_mask): AttentionMask() (vision_tower): Qwen25VisionTransformerPretrainedModelATB( (encoder): Qwen25VLVisionEncoderATB( (layers): ModuleList( (0-31): 32 x Qwen25VLVisionLayerATB( (attn): VisionAttention( (qkv): TensorParallelColumnLinear( (linear): FastLinear() ) (proj): TensorParallelRowLinear( (linear): FastLinear() ) ) (mlp): VisionMlp( (gate_up_proj): TensorParallelColumnLinear( (linear): FastLinear() ) (down_proj): TensorParallelRowLinear( (linear): FastLinear() ) ) (norm1): BaseRMSNorm() (norm2): BaseRMSNorm() ) ) (patch_embed): FastPatchEmbed( (proj): TensorReplicatedLinear( (linear): FastLinear() ) ) (patch_merger): PatchMerger( (patch_merger_mlp_0): TensorParallelColumnLinear( (linear): FastLinear() ) (patch_merger_mlp_2): TensorParallelRowLinear( (linear): FastLinear() ) (patch_merger_ln_q): BaseRMSNorm() ) ) (rotary_pos_emb): VisionRotaryEmbedding() ) (language_model): FlashQwen2UsingMROPEForCausalLM( (rotary_embedding): PositionRotaryEmbedding() (attn_mask): AttentionMask() (transformer): FlashQwenModel( (wte): TensorEmbeddingWithoutChecking() (h): ModuleList( (0-27): 28 x FlashQwenLayer( (attn): FlashQwenAttention( (rotary_emb): PositionRotaryEmbedding() (c_attn): TensorParallelColumnLinear( (linear): FastLinear() ) (c_proj): TensorParallelRowLinear( (linear): FastLinear() ) ) (mlp): QwenMLP( (act): SiLU() (w2_w1): TensorParallelColumnLinear( (linear): FastLinear() ) (c_proj): TensorParallelRowLinear( (linear): FastLinear() ) ) (ln_1): QwenRMSNorm() (ln_2): QwenRMSNorm() ) ) (ln_f): QwenRMSNorm() ) (lm_head): TensorParallelHead( (linear): FastLinear() ) ) ) [2025-11-15 22:13:24,268] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-134] : hbm_capacity(GB): 87.5078125, init_memory(GB): 11.376015624962747 [2025-11-15 22:13:24,789] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-342] : pa_runner: PARunner(model_path=/models/Qwen2.5-VL-7B-Instruct/, input_text=请用超过500个字详细说明图片的内容,并仔细判断画面中的人物是否有吸烟动作。, max_position_embeddings=None, max_input_length=16384, max_output_length=1024, max_prefill_tokens=-1, load_tokenizer=True, enable_atb_torch=False, max_prefill_batch_size=None, max_batch_size=1, dtype=torch.float16, block_size=128, model_config=ModelConfig(num_heads=14, num_kv_heads=2, num_kv_heads_origin=4, head_size=128, k_head_size=128, v_head_size=128, num_layers=28, device=npu:0, dtype=torch.float16, soc_info=NPUSocInfo(soc_name='', soc_version=200, need_nz=True, matmul_nd_nz=False), kv_quant_type=None, fa_quant_type=None, mapping=Mapping(world_size=2, rank=0, num_nodes=1,pp_rank=0, pp_groups=[[0], [1]], micro_batch_size=1, attn_dp_groups=[[0], [1]], attn_tp_groups=[[0, 1]], attn_inner_sp_groups=[[0], [1]], attn_cp_groups=[[0], [1]], attn_o_proj_tp_groups=[[0], [1]], mlp_tp_groups=[[0, 1]], moe_ep_groups=[[0], [1]], moe_tp_groups=[[0, 1]]), cla_share_factor=1, model_type=qwen2_5_vl, enable_nz=False), max_memory=93960798208, [2025-11-15 22:13:24,794] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-122] : ---------------Begin warm_up--------------- [2025-11-15 22:13:24,794] [7933] [139649439929600] [llmmodels] [INFO] [cache.py-154] : kv cache will allocate 0.46484375GB memory [2025-11-15 22:13:24,821] [7934] [139886327420160] [llmmodels] [INFO] [cache.py-154] : kv cache will allocate 0.46484375GB memory [2025-11-15 22:13:24,827] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1139] : ------total req num: 1, infer start-------- [2025-11-15 22:13:26,002] [7934] [139886327420160] [llmmodels] [INFO] [flash_causal_qwen2.py-680] : <<<<<<<after transdata k_caches[0].shape=torch.Size([136, 16, 128, 16]) [2025-11-15 22:13:26,023] [7933] [139649439929600] [llmmodels] [INFO] [flash_causal_qwen2.py-676] : <<<<<<< ori k_caches[0].shape=torch.Size([136, 16, 128, 16]) [2025-11-15 22:13:26,023] [7933] [139649439929600] [llmmodels] [INFO] [flash_causal_qwen2.py-680] : <<<<<<<after transdata k_caches[0].shape=torch.Size([136, 16, 128, 16]) [2025-11-15 22:13:26,024] [7933] [139649439929600] [llmmodels] [INFO] [flash_causal_qwen2.py-705] : >>>>>>id of kcache is 139645634198608 id of vcache is 139645634198320 [2025-11-15 22:13:34,363] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1294] : Prefill time: 9476.590633392334ms, Prefill average time: 9476.590633392334ms, Decode token time: 54.94809150695801ms, E2E time: 9531.538724899292ms [2025-11-15 22:13:34,363] [7934] [139886327420160] [llmmodels] [INFO] [generate.py-1294] : Prefill time: 9452.020645141602ms, Prefill average time: 9452.020645141602ms, Decode token time: 54.654598236083984ms, E2E time: 9506.675243377686ms [2025-11-15 22:13:34,366] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1326] : -------------------performance dumped------------------------ [2025-11-15 22:13:34,371] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1329] : | batch_size | input_seq_len | output_seq_len | e2e_time(ms) | prefill_time(ms) | decoder_token_time(ms) | prefill_count | prefill_average_time(ms) | |-------------:|----------------:|-----------------:|---------------:|-------------------:|-------------------------:|----------------:|---------------------------:| | 1 | 16384 | 2 | 9531.54 | 9476.59 | 54.95 | 1 | 9476.59 | /usr/local/lib64/python3.11/site-packages/torchvision/transforms/functional.py:1603: UserWarning: The default value of the antialias parameter of all the resizing transforms (Resize(), RandomResizedCrop(), etc.) will change from None to True in v0.17, in order to be consistent across the PIL and Tensor backends. To suppress this warning, directly pass antialias=True (recommended, future default), antialias=None (current default, which means False for Tensors and True for PIL), or antialias=False (only works on Tensors - PIL will still use antialiasing). This also applies if you are using the inference transforms from the models weights: update the call to weights.transforms(antialias=True). warnings.warn( [2025-11-15 22:13:35,307] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-148] : warmup_memory(GB): 15.75 [2025-11-15 22:13:35,307] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-153] : ---------------End warm_up--------------- /usr/local/lib64/python3.11/site-packages/torchvision/transforms/functional.py:1603: UserWarning: The default value of the antialias parameter of all the resizing transforms (Resize(), RandomResizedCrop(), etc.) will change from None to True in v0.17, in order to be consistent across the PIL and Tensor backends. To suppress this warning, directly pass antialias=True (recommended, future default), antialias=None (current default, which means False for Tensors and True for PIL), or antialias=False (only works on Tensors - PIL will still use antialiasing). This also applies if you are using the inference transforms from the models weights: update the call to weights.transforms(antialias=True). warnings.warn( [2025-11-15 22:13:35,363] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1139] : ------total req num: 1, infer start-------- [2025-11-15 22:13:50,021] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1294] : Prefill time: 1004.0028095245361ms, Prefill average time: 1004.0028095245361ms, Decode token time: 13.301290491575836ms, E2E time: 14611.222982406616ms [2025-11-15 22:13:50,021] [7934] [139886327420160] [llmmodels] [INFO] [generate.py-1294] : Prefill time: 1067.9974555969238ms, Prefill average time: 1067.9974555969238ms, Decode token time: 13.300292536193908ms, E2E time: 14674.196720123291ms [2025-11-15 22:13:50,025] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1326] : -------------------performance dumped------------------------ [2025-11-15 22:13:50,028] [7933] [139649439929600] [llmmodels] [INFO] [generate.py-1329] : | batch_size | input_seq_len | output_seq_len | e2e_time(ms) | prefill_time(ms) | decoder_token_time(ms) | prefill_count | prefill_average_time(ms) | |-------------:|----------------:|-----------------:|---------------:|-------------------:|-------------------------:|----------------:|---------------------------:| | 1 | 1675 | 1024 | 14611.2 | 1004 | 13.3 | 1 | 1004 | [2025-11-15 22:13:50,035] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-385] : Question[0]: [{'image': '/root/pic/test.jpg'}, {'text': '请用超过500个字详细说明图片的内容,并仔细判断画面中的人物是否有吸烟动作。'}] [2025-11-15 22:13:50,035] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-386] : Answer[0]: 这张图片展示了一个无人机航拍的场景,画面中可以看到两名工人站在一个雪地或冰面上。他们穿着橙色的安全背心和红色的安全帽,显得非常醒目。背景中可以看到一些雪地和一些金属结构,可能是桥梁或工业设施的一部分。 从图片的细节来看,画面右侧的工人右手放在嘴边,似乎在吸烟。他的姿势和动作与吸烟者的典型姿势相符。然而,由于图片的分辨率和角度限制,无法完全确定这个动作是否真实发生。如果要准确判断,可能需要更多的视频片段或更清晰的图像。 从无人机航拍的角度来看,这个场景可能是在进行某种工业或建筑项目的检查或监控。两名工人可能正在进行现场检查或讨论工作事宜。雪地和金属结构表明这可能是一个寒冷的冬季,或者是一个寒冷的气候区域。 无人机航拍技术在工业和建筑领域中非常常见,因为它可以提供高空视角,帮助工程师和管理人员更好地了解现场情况。这种技术不仅可以节省时间和成本,还可以提高工作效率和安全性。在进行航拍时,确保遵守当地的法律法规和安全规定是非常重要的。 总的来说,这张图片展示了一个无人机航拍的场景,画面中两名工人站在雪地上,其中一人似乎在吸烟。虽然无法完全确定这个动作是否真实发生,但根据他们的姿势和动作,可以合理推测这个动作的存在。 [2025-11-15 22:13:50,035] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-387] : Generate[0] token num: 282 [2025-11-15 22:13:50,035] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-389] : Latency(s): 14.721353530883789 [2025-11-15 22:13:50,035] [7933] [139649439929600] [llmmodels] [INFO] [run_pa.py-390] : Throughput(tokens/s): 19.15584728050956 本文详细介绍了在OrangePi AI Studio上使用Docker容器部署MindIE环境并运行Qwen2.5-VL-7B-Instruct多模态大模型实现吸烟动作识别的完整过程,验证了在Ascned 310p设备上运行多模态理解大模型的可靠性。
  • 【话题交流】光学压缩(Contexts Optical Compression)是解决长上下文和模拟人类记忆的可行之路吗?
    《DeepSeek-OCR: Contexts Optical Compression》提出用“光学压缩”思路,就是说,我们不让AI‘阅读’文字,我们让它‘看’文字。不再一个一个地把“文字token”(可以理解为单词或字符)喂给AI了,而是先把整页文档“拍一张照片”,然后把这张高分辨率图片喂给AI。效果怎么样呢?论文的数据给出的答案:* 10倍压缩,97%的精度!实验显示,当“文字token”的数量是“视觉token”的10倍以内时(比如把1000个单词压缩成100个视觉单位),模型“解压”还原文字的精度高达97%。* 20倍压缩,依然可用!即便是在接近20倍的极限压缩下(比如把1200多个单词硬塞进64个视觉单位),模型的准确率竟然还能保持在60%左右。这就像你只看一眼超级模糊的缩略图,就能猜出原图的大部分内容。这个有点颠覆当前的AI处理的思路,但是有点像人类的学习的路径,因为人类学习的方式,获取信息的方式,绝大部分是通过视觉,也就是通过眼睛看来获取的。所以这篇论文提出的思路,你怎么看呢?觉得它有发展前途,还是可能不太看好?  
  • [技术干货] 松材线虫病边缘模型训练与推理部署
    松材线虫病边缘模型训练与推理部署本文详细介绍了松材线虫病检测的边缘模型训练与推理部署全流程。首先,针对无人机拍摄的4032×3024原始图像进行预处理,缩放到1024×1024避免内存溢出,并定义了9个类别(包括麻栎、罩网、疑似、早期、轻度、中度、重度、死亡和逾年)。随后采用20%重叠率对图像进行切分,生成训练集60000张、验证集6495张的sahi数据集。模型训练基于yolo11s.yaml配置,在pwd数据集上进行10个Epoch的训练,虽然实际应用建议至少100个Epoch。评估结果显示,模型在pwd(重度)类别上表现最佳(mAP50达0.707),而pwd_early(早期)类别表现较差。为提升推理效率,将模型导出为TensorRT FP16引擎,GPU推理速度提升高达5倍,单张图片推理耗时约20ms。最后,通过Gradio构建了用户友好的检测应用,实现了松材线虫病的实时检测功能,为林业病害监测提供了有效的技术解决方案,具有较强的实用价值和推广前景。1. 原始数据无人机拍摄原始图像大小是4032 x 3024,这里缩放到1024 x 1024,避免在模型训练时内存溢出:%%writefile pwd.yaml # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] path: /home/jetson/ultralytics/dataset/pwd # dataset root dir (absolute path) train: train/images # train images (relative to 'path') val: val/images # val images (relative to 'path') test: # test images (optional) # Classes,类别 names: 0: hardwood # 麻栎 1: net # 罩网 2: abnormal # 疑似 3: pwd_pre_early # 早期 4: pwd_early # 轻度 5: pwd_moderate # 中度 6: pwd # 重度 7: dead_recent # 死亡 8: dead # 逾年 Overwriting pwd.yaml训练集3000张图像,验证集529张图像,查看验证集标注情况:import os import cv2 import yaml import random import numpy as np from matplotlib import pyplot as plt %matplotlib inline with open('pwd.yaml', 'r', encoding='utf-8') as f: data = yaml.load(f.read(), Loader=yaml.FullLoader) classes = data['names'] file_path = os.path.join(data['path'], 'val/images') file_list = os.listdir(file_path) img_paths = random.sample(file_list, 4) img_lists = [] for img_path in img_paths: img_path = os.path.join(file_path, img_path) img = cv2.imread(img_path) h, w, _ = img.shape tl = round(0.002 * (h + w) / 2) + 1 color = (0, 255, 255) if img_path.endswith('.png'): with open(img_path.replace("images", "labels").replace(".png", ".txt")) as f: labels = f.readlines() if img_path.endswith('.jpg'): with open(img_path.replace("images", "labels").replace(".jpg", ".txt")) as f: labels = f.readlines() if img_path.endswith('.jpeg'): with open(img_path.replace("images", "labels").replace(".jpeg", ".txt")) as f: labels = f.readlines() for label in labels: l, x, y, wc, hc = [float(x) for x in label.strip().split()] x1 = int((x - wc / 2) * w) y1 = int((y - hc / 2) * h) x2 = int((x + wc / 2) * w) y2 = int((y + hc / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), color, thickness=tl, lineType=cv2.LINE_AA) cv2.putText(img,classes[int(l)],(x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2, cv2.LINE_AA) img_lists.append(cv2.resize(img, (1024, 1024))) image = np.concatenate([np.concatenate(img_lists[:2], axis=1), np.concatenate(img_lists[2:], axis=1)], axis=0) cv2.imwrite("sample-pwd.png", image) plt.rcParams["figure.figsize"] = (16, 16) plt.imshow(image[:,:,::-1]) plt.axis('off') plt.show() 2. 切分数据对dataset/pwd数据集进行图像切分,切分大小为1024 x 1024,重叠率是20%,生成新的数据集dataset/pwd-sahi:%%writefile pwd-sahi.yaml # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] path: /home/jetson/ultralytics/dataset/pwd-sahi # dataset root dir (absolute path) train: train/images # train images (relative to 'path') val: val/images # val images (relative to 'path') test: # test images (optional) # Classes,类别 names: 0: hardwood # 麻栎 1: net # 罩网 2: abnormal # 疑似 3: pwd_pre_early # 早期 4: pwd_early # 轻度 5: pwd_moderate # 中度 6: pwd # 重度 7: dead_recent # 死亡 8: dead # 逾年 Overwriting pwd-sahi.yaml其中训练集60000张图像(部分为背景图),验证集6495张图像(不含背景图),查看验证集的标注情况:import os import cv2 import yaml import random import numpy as np from matplotlib import pyplot as plt %matplotlib inline with open('pwd-sahi.yaml', 'r', encoding='utf-8') as f: data = yaml.load(f.read(), Loader=yaml.FullLoader) classes = data['names'] file_path = os.path.join(data['path'], 'val/images') file_list = os.listdir(file_path) img_paths = random.sample(file_list, 4) img_lists = [] for img_path in img_paths: img_path = os.path.join(file_path, img_path) img = cv2.imread(img_path) h, w, _ = img.shape tl = round(0.002 * (h + w) / 2) + 1 color = (0, 255, 255) if img_path.endswith('.png'): with open(img_path.replace("images", "labels").replace(".png", ".txt")) as f: labels = f.readlines() if img_path.endswith('.jpg'): with open(img_path.replace("images", "labels").replace(".jpg", ".txt")) as f: labels = f.readlines() if img_path.endswith('.jpeg'): with open(img_path.replace("images", "labels").replace(".jpeg", ".txt")) as f: labels = f.readlines() for label in labels: l, x, y, wc, hc = [float(x) for x in label.strip().split()] x1 = int((x - wc / 2) * w) y1 = int((y - hc / 2) * h) x2 = int((x + wc / 2) * w) y2 = int((y + hc / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), color, thickness=tl, lineType=cv2.LINE_AA) cv2.putText(img,classes[int(l)],(x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2, cv2.LINE_AA) img_lists.append(cv2.resize(img, (1024, 1024))) image = np.concatenate([np.concatenate(img_lists[:2], axis=1), np.concatenate(img_lists[2:], axis=1)], axis=0) cv2.imwrite("sample-pwd-sahi.png", image) plt.rcParams["figure.figsize"] = (16, 16) plt.imshow(image[:,:,::-1]) plt.axis('off') plt.show() 3. 模型训练我们加载yolo11s.yaml模型的配置文件在dataset/pwd数据集上训练10个Epoch,模型的训练结果保存在pine_wilt_disease/yolo11s_10目录下:%%writefile train.py from ultralytics import YOLO # Load a model model = YOLO('yolo11s.yaml') # load yaml model # Train the model results = model.train(data='pwd.yaml', epochs=10, imgsz=640, workers=4, batch=8, project="pine_wilt_disease", name="yolo11s_10") Overwriting train.py在终端中运行:/home/jetson/ultralytics/train.sh在另一个终端中运行/home/jetson/ultralytics/tensorboard.sh可以监控模型的训练情况:4. 模型评估加载训练好的模型,这里我们仅训练了10个Epoch,实际训练至少100个Epoch才能取得较好的效果:from ultralytics import YOLO # Load a model model = YOLO('pine_wilt_disease/yolo11s_10/weights/best.pt') # load the best model # Evaluate the model metrics = model.val( data='pwd.yaml', # 数据集配置 imgsz=640, # 模型输入大小 workers=4, # 数据加载线程 batch=8, # 验证批次大小 plots=True, # 生成验证结果图 split='val' # 指定使用验证集 ) Ultralytics 8.3.55 🚀 Python-3.10.12 torch-2.5.0a0+872d972e41.nv24.08 CUDA:0 (Orin, 7620MiB) YOLO11s summary (fused): 238 layers, 9,416,283 parameters, 0 gradients, 21.3 GFLOPs val: Scanning /home/jetson/ultralytics/dataset/pwd/val/labels.cache... 529 images, 0 backgrounds, 0 corrupt: 100%|██████████| 529/529 [00:00<?, ?it/s] Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 67/67 [00:22<00:00, 2.92it/s] all 529 8612 0.602 0.445 0.442 0.261 net 383 4210 0.681 0.625 0.683 0.401 pwd_early 167 375 1 0 0.0362 0.0168 pwd_moderate 253 503 0.4 0.225 0.224 0.108 pwd 383 1141 0.582 0.765 0.707 0.462 dead_recent 376 1456 0.503 0.443 0.444 0.26 dead 229 927 0.444 0.613 0.557 0.318 Speed: 0.9ms preprocess, 24.5ms inference, 0.0ms loss, 4.1ms postprocess per image Results saved to runs/detect/val注意,图片实际标注的类别只有6类,不包含麻栎和疑似。5. 模型导出导出到TensorRT,GPU推理速度提升高达5倍:https://docs.ultralytics.com/zh/integrations/tensorrt/from ultralytics import YOLO model = YOLO("pine_wilt_disease/yolo11s_10/weights/best.pt") # TensorRT FP16 model.export(format="engine", imgsz=640, batch=1, half=True) WARNING ⚠️ TensorRT requires GPU export, automatically assigning device=0 Ultralytics 8.3.55 🚀 Python-3.10.12 torch-2.5.0a0+872d972e41.nv24.08 CUDA:0 (Orin, 7620MiB) YOLO11s summary (fused): 238 layers, 9,416,283 parameters, 0 gradients, 21.3 GFLOPs PyTorch: starting from 'pine_wilt_disease/yolo11s_10/weights/best.pt' with input shape (1, 3, 640, 640) BCHW and output shape(s) (1, 13, 8400) (18.3 MB) ONNX: starting export with onnx 1.17.0 opset 19... ONNX: slimming with onnxslim 0.1.47... ONNX: export success ✅ 3.2s, saved as 'pine_wilt_disease/yolo11s_10/weights/best.onnx' (36.2 MB) TensorRT: starting export with TensorRT 10.7.0... [11/15/2025-16:23:19] [TRT] [I] [MemUsageChange] Init CUDA: CPU -2, GPU +0, now: CPU 1395, GPU 7158 (MiB) [11/15/2025-16:23:25] [TRT] [I] [MemUsageChange] Init builder kernel library: CPU +970, GPU +258, now: CPU 2322, GPU 7418 (MiB) [11/15/2025-16:23:26] [TRT] [I] ---------------------------------------------------------------- [11/15/2025-16:23:26] [TRT] [I] Input filename: pine_wilt_disease/yolo11s_10/weights/best.onnx [11/15/2025-16:23:26] [TRT] [I] ONNX IR version: 0.0.9 [11/15/2025-16:23:26] [TRT] [I] Opset version: 19 [11/15/2025-16:23:26] [TRT] [I] Producer name: pytorch [11/15/2025-16:23:26] [TRT] [I] Producer version: 2.5.0 [11/15/2025-16:23:26] [TRT] [I] Domain: [11/15/2025-16:23:26] [TRT] [I] Model version: 0 [11/15/2025-16:23:26] [TRT] [I] Doc string: [11/15/2025-16:23:26] [TRT] [I] ---------------------------------------------------------------- TensorRT: input "images" with shape(1, 3, 640, 640) DataType.FLOAT TensorRT: output "output0" with shape(1, 13, 8400) DataType.FLOAT TensorRT: building FP16 engine as pine_wilt_disease/yolo11s_10/weights/best.engine [11/15/2025-16:23:26] [TRT] [I] Local timing cache in use. Profiling results in this builder pass will not be stored. [11/15/2025-16:28:08] [TRT] [I] Compiler backend is used during engine build. [11/15/2025-16:31:48] [TRT] [I] Detected 1 inputs and 1 output network tensors. [11/15/2025-16:31:53] [TRT] [I] Total Host Persistent Memory: 543184 bytes [11/15/2025-16:31:53] [TRT] [I] Total Device Persistent Memory: 0 bytes [11/15/2025-16:31:53] [TRT] [I] Max Scratch Memory: 2764800 bytes [11/15/2025-16:31:53] [TRT] [I] [BlockAssignment] Started assigning block shifts. This will take 162 steps to complete. [11/15/2025-16:31:53] [TRT] [I] [BlockAssignment] Algorithm ShiftNTopDown took 19.653ms to assign 10 blocks to 162 nodes requiring 19046912 bytes. [11/15/2025-16:31:53] [TRT] [I] Total Activation Memory: 19046400 bytes [11/15/2025-16:31:53] [TRT] [I] Total Weights Memory: 18914082 bytes [11/15/2025-16:31:53] [TRT] [I] Compiler backend is used during engine execution. [11/15/2025-16:31:53] [TRT] [I] Engine generation completed in 506.948 seconds. [11/15/2025-16:31:53] [TRT] [I] [MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 2 MiB, GPU 140 MiB TensorRT: export success ✅ 519.0s, saved as 'pine_wilt_disease/yolo11s_10/weights/best.engine' (21.6 MB) Export complete (519.7s) Results saved to /home/jetson/ultralytics/pine_wilt_disease/yolo11s_10/weights Predict: yolo predict task=detect model=pine_wilt_disease/yolo11s_10/weights/best.engine imgsz=640 half Validate: yolo val task=detect model=pine_wilt_disease/yolo11s_10/weights/best.engine imgsz=640 data=pwd.yaml half Visualize: https://netron.app导出FP16精度的量化模型大概需要10分钟左右。6. 模型推理使用TensorRT引擎加载模型对验证集的部分图片进行推理,每张图片的推理耗时约20ms:import cv2 import glob from ultralytics import YOLO import matplotlib.pyplot as plt %matplotlib inline # Load the TensorRT engine model model = YOLO("pine_wilt_disease/yolo11s_10/weights/best.engine") # Define the prediction function def predict(image_path): reuslts = model.predict(image_path, conf=0.45, iou=0.55) return reuslts[0].plot() # Load the images for inference images_path = glob.glob("dataset/pwd/val/images/*.jpeg") # Perform inference and display results for image_path in images_path[:10]: result = predict(image_path) result = cv2.cvtColor(result, cv2.COLOR_BGR2RGB) result = cv2.resize(result, (4032 // 4, 3024 // 4)) plt.imshow(result) plt.axis("off") plt.show() WARNING ⚠️ Unable to automatically guess model task, assuming 'task=detect'. Explicitly define task for your model, i.e. 'task=detect', 'segment', 'classify','pose' or 'obb'. Loading pine_wilt_disease/yolo11s_10/weights/best.engine for TensorRT inference... [11/15/2025-16:31:54] [TRT] [I] Loaded engine size: 21 MiB [11/15/2025-16:31:54] [TRT] [I] [MemUsageChange] TensorRT-managed allocation in IExecutionContext creation: CPU +0, GPU +18, now: CPU 0, GPU 36 (MiB) image 1/1 /home/jetson/ultralytics/dataset/pwd/val/images/1d1d160a-ae4f-4fe4-801d-f001d4e7ff6d.jpeg: 640x640 4 nets, 1 pwd, 1 dead_recent, 20.1ms Speed: 45.6ms preprocess, 20.1ms inference, 49.3ms postprocess per image at shape (1, 3, 640, 640) ... 构建Gradio应用程序,上传图片实现松材线虫病检测的功能:至此,本章结束。
  • [技术干货] 基于 LSTM-Transformer 混合架构的跨尺度时间序列预测模型研究
    基于 LSTM-Transformer 混合架构的跨尺度时间序列预测模型研究1. 引言智能体(AI Agent)在应对复杂任务时,通常需要具备环境感知、自主推理及预测能力。对于金融量化、智能调度、设备运维预警等任务领域,时间序列预测是智能体核心推理模块中的关键能力。传统的 RNN/LSTM 模型擅长捕捉时间依赖结构,但对长序列能力有限; Transformer 则具备优秀的全局依赖建模能力,却在小规模数据中表现不稳定。因此,将 LSTM 的局部时序优势 与 Transformer 的长期依赖与注意力机制 相结合,可以构造更强鲁棒性与泛化能力的混合预测模块,使 AI Agent 具备真正的数据感知与智能推理能力。2. 模型设计思路:LSTM + Transformer 的混合结构混合建模主要目标:模块优势适用作用LSTM捕捉连续时间依赖;适用于小数据场景作为前端特征提取器Transformer Encoder学习全局注意力与特征关联作为后端增强预测结构Linear Regression Layer简化输出预测最终预测输出层模型结构示意:输入序列 -> LSTM -> 中间时间特征 -> Transformer Encoder -> 全局特征 -> 输出预测3. 环境准备建议使用 Python + PyTorchpip install torch numpy matplotlib4. 代码实战:构建混合时间序列预测模型4.1 数据构造(模拟时序数据)import numpy as np import torch from torch import nn import matplotlib.pyplot as plt # 创建模拟时间序列数据 (sin 曲线 + 噪声) x = np.linspace(0, 100, 1000) data = np.sin(x) + np.random.normal(scale=0.1, size=len(x)) def create_dataset(series, input_len=30, pred_len=1): X, Y = [], [] for i in range(len(series) - input_len - pred_len): X.append(series[i:i+input_len]) Y.append(series[i+input_len:i+input_len+pred_len]) return np.array(X), np.array(Y) input_len = 30 pred_len = 1 X, Y = create_dataset(data, input_len, pred_len) # 转换为 Tensor X = torch.tensor(X, dtype=torch.float32).unsqueeze(-1) Y = torch.tensor(Y, dtype=torch.float32) 4.2 创建混合模型 LSTM + Transformerclass HybridLSTMTransformer(nn.Module): def __init__(self, input_dim=1, hidden_dim=64, num_layers=1, nhead=4, trans_layers=2): super().__init__() self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first=True) encoder_layer = nn.TransformerEncoderLayer(d_model=hidden_dim, nhead=nhead, batch_first=True) self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=trans_layers) self.fc = nn.Linear(hidden_dim, 1) def forward(self, x): lstm_out, _ = self.lstm(x) # [batch, seq, hidden] trans_out = self.transformer(lstm_out) out = self.fc(trans_out[:, -1, :]) # 取最后时刻结果 return out4.3 模型训练model = HybridLSTMTransformer() criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) epochs = 20 for epoch in range(epochs): model.train() optimizer.zero_grad() output = model(X) loss = criterion(output, Y) loss.backward() optimizer.step() if epoch % 5 == 0: print(f"Epoch {epoch}/{epochs}, Loss: {loss.item():.6f}") 4.4 模型预测与可视化model.eval() preds = model(X).detach().numpy() plt.plot(Y[:300], label="Real") plt.plot(preds[:300], label="Prediction") plt.title("Hybrid Forecast") plt.legend() plt.show() 5. 实际部署到 AI Agent 的应用场景本模块可作为智能体的 “预测 Plug-in”:场景应用方式模块定位智能电网能耗预测多变量预测预测与策略调度子模块金融交易策略K线 + 宏观变量建模风控与决策子模块工业安全设备传感器异常预警监测与告警模块智能运维调度CPU/GPU/网络指标预测负载均衡优化决策可结合 Agent 框架(如 LangChain、Autogen、Janus、LazyLLM)进行封装并创建 predict_tool() 工具函数供自主调用。6. 总结本文构建了适用于 AI Agent 的 LSTM + Transformer 混合预测模块,能够有效提升小样本与长序列场景下的预测鲁棒性。该结构具有良好的泛化能力,适合作为 AI Agent 的可插拔模块,在决策、控制与风险预判中发挥关键作用。本文针对 AI Agent 在复杂环境下需要具备的未来趋势判断能力,提出了一种 融合式时间序列预测模块设计方案,将 LSTM 的局部时序建模能力 与 Transformer 的全局依赖特征获取能力 进行结合,从而在小样本、长依赖、多周期波动的预测任务中取得更优表现。同时通过 PyTorch 给出可直接运行的混合模型实现代码,帮助开发者快速构建可扩展的预测模块。综合来看,该混合结构具有以下优势:兼顾短期与长期依赖,避免 LSTM 的长期衰减与 Transformer 对数据规模的依赖;模型结构通用性强,可轻松嵌入任意 AI Agent 决策系统;适用领域广泛,包括金融量化、设备运维、智能电网、医疗监测及智能运维调度等;可扩展性强,能够与多变量特征融合,并支持与强化学习、AutoML、MLOps 平台结合,实现全流程自治决策。未来可考虑在以下方向进行升级与迭代:引入 Informer、TimesNet、Mamba、Hybrid CNN 等更先进架构;加入 注意力解释性模块 提升可解释性;与 知识图谱+大模型推理 结合,实现数据驱动 + 知识驱动的混合推理;在 生产环境中加入实时反馈与自适应更新机制,实现端到端闭环智能。通过以上技术整合,AI Agent 将不仅能够“看见当前”,还能够 预测未来并主动决策,从而迈向真正意义的自主智能体。
  • [技术干货] 大模型 Agent 体系中的通信协议抽象
    Agent 与外部工具交互接口标准化:RESTful 与 gRPC 的适配实现随着大模型驱动的智能体(Agent)在业务流程自动化、知识检索、数据分析、运维执行等场景中快速落地,如何让 Agent 可靠、高效、可扩展地调用外部工具(Tools) 成为系统架构设计的重要核心问题。在工程实践中,工具的接入形式多种多样:RESTful API、gRPC 服务、本地函数、本地可执行程序、消息队列等。为了实现 可维护性、可扩展性与可迁移性,构建统一的工具交互标准非常关键。本文重点聚焦——RESTful 与 gRPC 的接口标准化适配实现,并给出完整代码示例,帮助你在自己的 Agent 框架中实现通用化外部工具访问层。一、Agent 调用外部工具为什么需要标准化?1. 外部工具接口形式复杂企业内部服务常见的接口类型包括:RESTful:HTTP + JSON,通用性强,但性能一般;gRPC:二进制传输 + HTTP/2,高性能强类型,适合高频调用;Python/Java 本地方法:绑定不同语言环境;数据库/队列/搜索引擎:SQL、消息协议等。若每种接口都由 Agent 的业务逻辑单独适配,会导致:代码重复且难维护接口升级导致 Agent 要整体修改无法统一调用流程与权限管理2. 标准化的收益构建一个 Tool Adapter 层 可以带来:统一调用规范:Agent 调用工具无需关心背后的协议可扩展性强:新增工具只需扩展一个 Adapter 类日志可统一跟踪:便于审计、故障定位降低 Agent 实现复杂度:实现真正的“能力插件化”二、统一接口规范设计(RESTful/gRPC 适配)我们定义一个通用的工具接口协议,让所有外部调用都遵循统一结构。1. 统一接口协议(伪代码){ "tool_name": "string", "action": "string", "params": { "key": "value" } } 工具返回结构统一为:{ "status": "success|error", "data": {}, "message": "" } 这样 Agent 内核只需要处理:传什么工具?工具的输入是什么?工具的输出是什么?不关心 REST/gRPC 或者其他协议。2. Adapter 标准接口(Python)from abc import ABC, abstractmethod class BaseToolAdapter(ABC): @abstractmethod def call(self, action: str, params: dict) -> dict: pass 所有工具的接入只需继承这个基类。三、RESTful 工具适配器实现(代码实战)RESTful API 是企业最常见的服务形式,我们实现一个 RESTfulToolAdapter。1. 实战代码:RESTful Tool 适配器import requests class RESTfulToolAdapter(BaseToolAdapter): def __init__(self, base_url): self.base_url = base_url def call(self, action: str, params: dict) -> dict: url = f"{self.base_url}/{action}" try: resp = requests.post(url, json=params, timeout=5) resp.raise_for_status() return { "status": "success", "data": resp.json(), "message": "" } except Exception as e: return { "status": "error", "data": None, "message": str(e) } 2. RESTful API 示例服务(Flask)这里构建一个简单的 RESTful 工具:做加法计算。# math_tool_rest.py from flask import Flask, request, jsonify app = Flask(__name__) @app.route("/add", methods=["POST"]) def add(): data = request.get_json() a = data.get("a") b = data.get("b") return jsonify({"result": a + b}) if __name__ == "__main__": app.run(port=5001) 3. Agent 调用示例rest_tool = RESTfulToolAdapter("http://localhost:5001") agent_input = {"a": 3, "b": 5} result = rest_tool.call("add", agent_input) print(result) 输出:{ "status": "success", "data": {"result": 8}, "message": "" } 四、gRPC 工具适配器实现(代码实战)gRPC 常用于高性能、强类型、跨语言通信场景。1. gRPC 服务定义(math.proto)syntax = "proto3"; service MathTool { rpc Add (AddRequest) returns (AddReply) {} } message AddRequest { int32 a = 1; int32 b = 2; } message AddReply { int32 result = 1; } 生成 Python 代码:python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. math.proto2. gRPC 服务端实现# math_tool_grpc_server.py import grpc from concurrent import futures import math_pb2 import math_pb2_grpc class MathToolServicer(math_pb2_grpc.MathToolServicer): def Add(self, request, context): return math_pb2.AddReply(result=request.a + request.b) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) math_pb2_grpc.add_MathToolServicer_to_server(MathToolServicer(), server) server.add_insecure_port("[::]:50052") server.start() server.wait_for_termination() 3. gRPC Tool 适配器实现import grpc import math_pb2 import math_pb2_grpc class GRPCToolAdapter(BaseToolAdapter): def __init__(self, host="localhost", port=50052): channel = grpc.insecure_channel(f"{host}:{port}") self.stub = math_pb2_grpc.MathToolStub(channel) def call(self, action: str, params: dict) -> dict: try: if action == "add": req = math_pb2.AddRequest(a=params["a"], b=params["b"]) reply = self.stub.Add(req) return {"status": "success", "data": {"result": reply.result}} else: return {"status": "error", "message": "unknown action", "data": None} except Exception as e: return {"status": "error", "message": str(e), "data": None} 4. Agent 调用示例grpc_tool = GRPCToolAdapter() result = grpc_tool.call("add", {"a": 10, "b": 20}) print(result) 返回:{ "status": "success", "data": {"result": 30} } 五、Agent 层的通用工具调用入口(抽象化)我们最终可以在 Agent 系统中实现工具的统一注册与调用。class ToolRegistry: def __init__(self): self.tools = {} def register(self, name, adapter): self.tools[name] = adapter def call(self, name, action, params): tool = self.tools.get(name) if not tool: return {"status": "error", "message": "tool not found"} return tool.call(action, params) 使用方式:registry = ToolRegistry() registry.register("math_rest", rest_tool) registry.register("math_grpc", grpc_tool) print(registry.call("math_rest", "add", {"a": 1, "b": 2})) print(registry.call("math_grpc", "add", {"a": 5, "b": 6})) 六、RESTful 与 gRPC 的选型对比项目RESTfulgRPC性能中高协议JSON/HTTP1.1ProtoBuf/HTTP2类型安全弱强跨语言优秀优秀调试难度低中等适用场景通用服务高频快速通信、分布式系统推荐:工具响应慢 / 通用服务 → RESTful高频调用 / 数据量大 / 强类型 → gRPC七、总结本文从 Agent 系统视角,介绍了如何构建 统一的工具交互接口标准化体系,并分别给出了:RESTful 实现gRPC 实现Agent 的统一调用入口这种适配层设计能够极大提升 Agent 在复杂生产系统中的接入能力,使其真正成为 可扩展、可插拔、可维护 的智能能力平台。
  • [技术干货] 智能体知识更新机制:增量式知识图谱构建与融合技术
    智能体知识更新机制:增量式知识图谱构建与融合技术一、引言随着大模型驱动的 智能体(Agent) 在企业业务、搜索问答、自动化运营、RPA 流程中广泛应用,知识更新问题变得尤为突出。传统知识库构建方式往往是“全量构建”,一旦知识发生变化,需要重新爬取、处理、训练或重建索引,成本高且不可实时。而智能体需要:识别新知识是否已存在将新知识增量式注入知识图谱自动融合冲突信息实时影响推理过程不中断系统运行因此,“增量式知识图谱构建与融合(Incremental KG Construction & Fusion)”成为智能体落地的核心能力之一。本文系统介绍智能体的增量知识更新体系,并提供一个 Python 版知识图谱增量构建代码实战。二、智能体知识更新机制概述2.1 三类知识更新模式更新模式特点适用场景全量更新(Full Rebuild)一次性重建全部知识小型知识库、结构稳定批次更新(Batch Update)定期增量、按批次更新中型知识库、更新频率适中实时增量更新(Incremental Update)每条知识都实时更新并融合智能体实时问答、监控、自动决策智能体通常需要 实时增量 模式。三、增量式知识图谱构建流程完整流程如下:新数据流入 → 信息抽取 → 知识对齐/消歧 → 图谱增量更新 → 冲突融合 → 推理索引更新3.1 信息抽取(NER / RE)智能体通过 LLM 或规则抽取:实体(Entity)关系(Relation)属性(Attribute)例如从文本 “张三是华为的软件工程师” 中抽取:{ "entity": ["张三", "华为"], "relation": [ ["张三", "就职于", "华为"], ["张三", "职位", "软件工程师"] ] } 3.2 知识对齐与消歧(Entity Alignment)智能体判断新实体是否已存在:文本相似度语义向量距离属性匹配(公司、邮箱、ID)例如“华为技术有限公司” ≈ “华为”。3.3 图谱增量更新(Graph Update)增量更新关键技术:节点重复检测(Duplicate Check)关系冲突解决(Conflict Resolution)时间戳与版本管理(Versioning)3.4 冲突融合(Knowledge Fusion)三类融合方式:融合类型特点优先级融合权重高的知识覆盖低权重证据投票多来源数据投票决定可信度时间序列融合新知识覆盖旧知识四、系统架构设计一个典型的智能体增量知识图谱系统包含: ┌──────────────┐ Data Source → │ 信息抽取模块 │→ 实体/关系 └──────────────┘ ↓ ┌──────────────┐ │ 对齐/消歧模块 │ └──────────────┘ ↓ ┌────────────────┐ │ 图谱增量更新模块│ └────────────────┘ ↓ ┌──────────────┐ │ 冲突融合模块 │ └──────────────┘ ↓ ┌──────────────┐ │ 查询与推理层 │ └──────────────┘五、代码实战:基于 NetworkX 构建简易增量知识图谱系统本示例将展示:如何增量加入实体与关系如何处理重复实体如何自动融合更新属性使用 Python + NetworkX 进行模拟(真实系统可用 Neo4j / ArangoDB / Nebula / RDF)。5.1 安装依赖pip install networkx5.2 基础图谱骨架import networkx as nx class KnowledgeGraph: def __init__(self): self.graph = nx.MultiDiGraph() # 增量添加实体 def add_entity(self, entity_id, attrs): if entity_id not in self.graph: self.graph.add_node(entity_id, **attrs) else: # 属性融合:新属性覆盖旧属性 existing = self.graph.nodes[entity_id] existing.update(attrs) # 增量添加关系 def add_relation(self, src, relation, dst): self.graph.add_edge(src, dst, relation=relation) # 打印图谱 def show(self): for node in self.graph.nodes(data=True): print("Node:", node) for edge in self.graph.edges(data=True): print("Edge:", edge) 5.3 增量知识注入(含消歧与融合)定义:基于相似度判断是否需要复用节点。实战中通常采用 embedding(如 BERT)计算语义相似度,本示例用简单字符串相似度作演示。from difflib import SequenceMatcher def similar(a, b): return SequenceMatcher(None, a, b).ratio() 智能体增量更新逻辑class IncrementalAgent: def __init__(self, kg: KnowledgeGraph, threshold=0.7): self.kg = kg self.threshold = threshold # 简单的实体对齐 def align_entity(self, new_name): for exist in self.kg.graph.nodes: if similar(exist, new_name) > self.threshold: return exist return new_name # 增量注入一条知识 def inject(self, entity, attrs, relation, target): # 实体消歧 entity_id = self.align_entity(entity) target_id = self.align_entity(target) # 写入实体(自动融合属性) self.kg.add_entity(entity_id, attrs) self.kg.add_entity(target_id, {}) # 写入关系 self.kg.add_relation(entity_id, relation, target_id) 5.4 测试增量更新代码kg = KnowledgeGraph() agent = IncrementalAgent(kg) # 第一条知识 agent.inject("华为", {"type": "Company"}, "雇佣", "张三") agent.inject("张三", {"title": "软件工程师"}, "就职于", "华为") # 第二条知识(同实体不同写法,会自动对齐到“华为”) agent.inject("华为技术有限公司", {"location": "深圳"}, "旗下", "荣耀") # 第三条知识(属性融合:覆盖/新增属性) agent.inject("张三", {"title": "高级工程师"}, "参与项目", "Atlas 900") kg.show() 5.5 运行结果示例(示意)Node: ('华为', {'type': 'Company', 'location': '深圳'}) Node: ('张三', {'title': '高级工程师'}) Node: ('荣耀', {}) Node: ('Atlas 900', {}) Edge: ('华为', '张三', {'relation': '雇佣'}) Edge: ('张三', '华为', {'relation': '就职于'}) Edge: ('华为', '荣耀', {'relation': '旗下'}) Edge: ('张三', 'Atlas 900', {'relation': '参与项目'}) 可以看到:“华为技术有限公司” 自动对齐到 华为张三 的 title 属性被融合并更新为 “高级工程师”图谱结构实现增量式扩展六、增量知识融合中的技术难点6.1 消歧精度与误判需结合:文本相似度Embedding 语义距离RDF 属性匹配图结构上下文6.2 知识冲突处理常见冲突:属性冲突时间冲突数据来源可信度冲突6.3 图谱规模增长与性能百万级节点后需考虑:图数据库索引优化分布式图存储流式写入(Streaming Write)七、典型应用场景场景描述企业知识库实时更新文档、FAQ、规范持续变化实时监控智能体新事件即时写入并触发推理金融风控图谱客户/交易/风险节点实时更新RAG Agent 知识补全外部知识动态扩展推荐系统用户画像用户行为增量更新八、总结增量式知识图谱是智能体从“静态问答”迈向“持续进化”的关键能力。本文从架构、流程、关键技术、冲突融合等角度展开,同时提供了一个可运行的 增量图谱构建与融合代码案例。未来方向包括:融合 RAG 与 KG 的混合检索大模型驱动的自动消歧事件图谱(Event Graph)实时流处理图谱 + 大模型联合推理
  • [热门活动] 【获奖名单公示】/// 产品体验官招募 | 体验华为云Versatile智能体平台,玩转AI Agent构建,反馈优化建议,赢取500元开发者大礼包
      【华为云Versatile智能体平台】产品体验官活动 获奖名单如下:一、高价值建议奖:昵称被评为高价值需求 内容展示建议分值礼品码事漫谈增加Agent发布渠道,如微信小程序等7(高价值需求3票、建议采纳需求1票)500元开发者大礼包1份ddhsaVersatile预置base64转图片插件6(高价值需求2票、建议采纳需求2票)500元开发者大礼包1份福州司马懿工作流应用-代码节点优化,去除预处理代码,提升用户使用效率5(高价值需求2票、建议采纳需求1票)500元开发者大礼包1份评分规则:由产品团队组成的评审团对所有参与者提交的建议进行投票,其中高价值需求(2分)、建议采纳需求(1分),TOP3分值的建议获选。 二、建议贡献排名奖:昵称积分排名(被采纳建议,每条得1分)礼品鸢尾离夏7200元开发者大礼包1份小草飞上天6200元开发者大礼包1份yd_2709879825200元开发者大礼包1份HDC-Feng3200元开发者大礼包1份林欣3200元开发者大礼包1份 恭喜以上8名获奖用户,礼品会发到活动报名时填写报名问卷的账号和收货地址(小助手将联系提供),请注意查收。感谢大家对华为云Versatile智能体平台的关注和支持~ 欢迎各位开发者们在云声平台提出更多优化建议帮助Versatile产品的优化迭代共同构建易用、好用、开放的一站式Agent平台   传送门活动帖子(指定评论区):cid:link_2 活动报名页面:cid:link_1 产品体验入口:华为开发者空间--开发平台--Versatile Agent
  • [技术干货] Pi0☁云端推理部署
    Pi0☁云端推理部署Pi0 是一个通用机器人策略基础模型,专为解决机器人学习中的数据稀缺、泛化能力差和鲁棒性不足等核心挑战而设计。借鉴大语言模型的训练方法,Pi0 通过大规模预训练掌握广泛的机器人操作技能,并能通过微调快速适应具体任务需求。该模型支持高效的数据利用与快速部署,在有限数据下也能实现良好性能,为机器人智能化提供了一种可扩展的解决方案。1. 环境配置在之前LeRobot安装及使用教程和Pi0 模型训练的基础上,Pi0的推理也建议使用云端部署的方式运行。a. 我租赁的服务器是H20,在服务端(openpi环境)中运行:cd /root/autodl-tmp/openpi_episode1_student uv run scripts/serve_policy.py policy:checkpoint --policy.config=enpei_robot_demo_move_toy_low_mem_finetune --policy.dir=checkpoints/enpei_robot_demo_move_toy_low_mem_finetune/my_experiment/9999启动服务器后,他会暴露一个服务端口(默认是 6006):warning: The `tool.uv.dev-dependencies` field (used in `packages/openpi-client/pyproject.toml`) is deprecated and will be removed in a future release; use `dependency-groups.dev` instead INFO:root:Loading model... INFO:2025-11-09 14:40:27,523:jax._src.xla_bridge:925: Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig' INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig' INFO:2025-11-09 14:40:27,524:jax._src.xla_bridge:925: Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory INFO:absl:orbax-checkpoint version: 0.11.13 INFO:absl:Created BasePyTreeCheckpointHandler: use_ocdbt=True, use_zarr3=False, pytree_metadata_options=PyTreeMetadataOptions(support_rich_types=False), array_metadata_store=<orbax.checkpoint._src.metadata.array_metadata_store.Store object at 0x7f78fd908250> INFO:absl:Restoring checkpoint from /root/autodl-tmp/openpi_episode1_student/checkpoints/enpei_robot_demo_move_toy_low_mem_finetune/my_experiment/9999/params. INFO:absl:[thread=MainThread] Failed to get flag value for EXPERIMENTAL_ORBAX_USE_DISTRIBUTED_PROCESS_ID. INFO:absl:[process=0] /jax/checkpoint/read/bytes_per_sec: 1.1 GiB/s (total bytes: 6.1 GiB) (time elapsed: 5 seconds) (per-host) INFO:absl:Finished restoring checkpoint in 5.72 seconds from /root/autodl-tmp/openpi_episode1_student/checkpoints/enpei_robot_demo_move_toy_low_mem_finetune/my_experiment/9999/params. INFO:root:Loaded norm stats from /root/autodl-tmp/openpi_episode1_student/assets/enpei_robot_demo_move_toy_low_mem_finetune/hou/demo_move_toy_openpi INFO:root:Loaded norm stats from /root/autodl-tmp/openpi_episode1_student/checkpoints/enpei_robot_demo_move_toy_low_mem_finetune/my_experiment/9999/assets/hou/demo_move_toy_openpi INFO:root:Creating server (host: autodl-container-9af746813b-5ccfe20e, ip: 172.17.0.8) INFO:websockets.server:server listening on 0.0.0.0:6006 INFO:websockets.server:connection open INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 53688) opened INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 53688) closed INFO:websockets.server:connection open INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 56818) opened INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 56818) closed在AutoDL中使用它的端口转发服务(自定义服务):b. 在客户端(lerobot环境)进入Lerobot仓库代码,中安装openpi-client:cd ./packages/openpi-client pip install -e . c. 启动机械臂进行归零,安装腕部相机和夹爪,查看相机ID:(base) hou@hou-Ubuntu:~/workspace/lerobot_single_student$ conda activate lerobot (lerobot) hou@hou-Ubuntu:~/workspace/lerobot_single_student$ python -m lerobot.episode_default_position --ip="localhost" --port=12345 INFO 2025-11-09 14:25:56 _position.py:33 Connected to EnpeiRobot controller at localhost:12345 INFO 2025-11-09 14:26:02 _position.py:46 Moving to default position, estimated time: 1.72s INFO 2025-11-09 14:26:04 _position.py:50 Successfully moved to default position (lerobot) hou@hou-Ubuntu:~/workspace/lerobot_single_student$ python -m lerobot.find_cameras opencv --- Detected Cameras --- Camera #0: Name: OpenCV Camera @ /dev/video0 Type: OpenCV Id: /dev/video0 Backend api: V4L2 Default stream profile: Format: 0.0 Width: 640 Height: 480 Fps: 30.0 -------------------- Camera #1: Name: OpenCV Camera @ /dev/video2 Type: OpenCV Id: /dev/video2 Backend api: V4L2 Default stream profile: Format: 0.0 Width: 640 Height: 480 Fps: 30.0 -------------------- Camera #2: Name: OpenCV Camera @ /dev/video4 Type: OpenCV Id: /dev/video4 Backend api: V4L2 Default stream profile: Format: 0.0 Width: 640 Height: 480 Fps: 30.0 -------------------- Finalizing image saving... Image capture finished. Images saved to outputs/captured_images2. Pi0 推理启动客户端,在终端中运行run.sh:host 服务器地址(这里因为用了 AutoDL 本地转发,所以是 localhost)port 服务器端口instruction 文本指令,保持和采集数据一致enpei_use_radian 需要使用弧度制#!/bin/bash python -m lerobot.test_openpi \ --robot.ip_address="localhost" \ --robot.port=12345 \ --robot.type=enpei_follower \ --robot.id=enpei_follower \ --robot.cameras="{ handeye: {type: opencv, index_or_path: 4, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 0, width: 320, height: 240, fps: 30}}" \ --host=localhost \ --port=6006 \ --instruction="Put the toy to the white box" \ --fps=30 \ --enpei_use_radian=true (lerobot) hou@hou-Ubuntu:~/workspace/lerobot_single_student$ ./run.sh INFO 2025-11-09 14:48:58 nt_policy.py:30 Waiting for server at ws://localhost:6006... Connected to remote policy server at localhost:6006 Server metadata: {} Using instruction: Put the toy to the white box 设置enpei follower机器人角度单位: 弧度 INFO 2025-11-09 14:48:58 follower.py:134 Connected to EnpeiRobot controller INFO 2025-11-09 14:49:03 a_opencv.py:176 OpenCVCamera(4) connected. INFO 2025-11-09 14:49:05 a_opencv.py:176 OpenCVCamera(0) connected. INFO 2025-11-09 14:49:05 follower.py:156 enpei_follower EnpeiFollower connected. Robot connected successfully 运行策略,目标FPS: 30 推理线程启动 等待第一个动作生成... wait for frame: 0.0018558219999249559 wait for frame: 0.0018982179999511573 Loop duration: 1.4765s, Real FPS: 0.68, Action FPS: 33.87, Action count: 50, Action shape: (50, 7) Loop duration: 1.4735s, Real FPS: 0.68, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.4755s, Real FPS: 0.68, Action FPS: 33.89, Action count: 50, Action shape: (50, 7) Loop duration: 1.4973s, Real FPS: 0.67, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5040s, Real FPS: 0.66, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5590s, Real FPS: 0.64, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5400s, Real FPS: 0.65, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.4911s, Real FPS: 0.67, Action FPS: 33.91, Action count: 50, Action shape: (50, 7) Loop duration: 1.4938s, Real FPS: 0.67, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.4853s, Real FPS: 0.67, Action FPS: 33.92, Action count: 50, Action shape: (50, 7) Loop duration: 1.4957s, Real FPS: 0.67, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.4930s, Real FPS: 0.67, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.4914s, Real FPS: 0.67, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.4878s, Real FPS: 0.67, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.4911s, Real FPS: 0.67, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.4914s, Real FPS: 0.67, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.5189s, Real FPS: 0.66, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.4915s, Real FPS: 0.67, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.5207s, Real FPS: 0.66, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.4865s, Real FPS: 0.67, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.5499s, Real FPS: 0.65, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.6458s, Real FPS: 0.61, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.6337s, Real FPS: 0.61, Action FPS: 33.98, Action count: 50, Action shape: (50, 7) Loop duration: 1.5200s, Real FPS: 0.66, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5218s, Real FPS: 0.66, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5184s, Real FPS: 0.66, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5273s, Real FPS: 0.65, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5247s, Real FPS: 0.66, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5285s, Real FPS: 0.65, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5576s, Real FPS: 0.64, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5193s, Real FPS: 0.66, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5519s, Real FPS: 0.64, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.5240s, Real FPS: 0.66, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.6051s, Real FPS: 0.62, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5251s, Real FPS: 0.66, Action FPS: 33.92, Action count: 50, Action shape: (50, 7) Loop duration: 1.5533s, Real FPS: 0.64, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.5564s, Real FPS: 0.64, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5579s, Real FPS: 0.64, Action FPS: 33.92, Action count: 50, Action shape: (50, 7) Loop duration: 1.5550s, Real FPS: 0.64, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.5526s, Real FPS: 0.64, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5507s, Real FPS: 0.64, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5511s, Real FPS: 0.64, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5557s, Real FPS: 0.64, Action FPS: 33.92, Action count: 50, Action shape: (50, 7) Loop duration: 1.5514s, Real FPS: 0.64, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5539s, Real FPS: 0.64, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5573s, Real FPS: 0.64, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5767s, Real FPS: 0.63, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.5736s, Real FPS: 0.64, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5553s, Real FPS: 0.64, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5537s, Real FPS: 0.64, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.5514s, Real FPS: 0.64, Action FPS: 33.98, Action count: 50, Action shape: (50, 7) Loop duration: 1.6261s, Real FPS: 0.61, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.6378s, Real FPS: 0.61, Action FPS: 33.94, Action count: 50, Action shape: (50, 7) Loop duration: 1.5520s, Real FPS: 0.64, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) Loop duration: 1.5588s, Real FPS: 0.64, Action FPS: 33.98, Action count: 50, Action shape: (50, 7) Loop duration: 1.5567s, Real FPS: 0.64, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.5534s, Real FPS: 0.64, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5481s, Real FPS: 0.65, Action FPS: 33.97, Action count: 50, Action shape: (50, 7) Loop duration: 1.6520s, Real FPS: 0.61, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5514s, Real FPS: 0.64, Action FPS: 33.96, Action count: 50, Action shape: (50, 7) Loop duration: 1.5552s, Real FPS: 0.64, Action FPS: 33.95, Action count: 50, Action shape: (50, 7) Loop duration: 1.5494s, Real FPS: 0.65, Action FPS: 33.93, Action count: 50, Action shape: (50, 7) ^C Client stopped by user 推理线程结束测试视频:3. 小结本文介绍了Pi0云端推理部署的完整流程。首先配置好服务器端环境并启动策略服务,然后在客户端安装所需依赖并连接机械臂与摄像头。实测下来,即使对于没见过的云宝机械臂的抓取放置成功率也能达到100%,体现了模型强大的泛化能力!
  • [活动公告] 11月15日,CANN Meetup 北京站,邀您共赴一场技术盛宴
    11月15日,CANN Meetup 北京站,邀您共赴一场技术盛宴
  • [技术干货] Pi0 模型训练
    Pi0 模型训练Pi0 是一个通用机器人策略基础模型,专为解决机器人学习中的数据稀缺、泛化能力差和鲁棒性不足等核心挑战而设计。借鉴大语言模型的训练方法,Pi0 通过大规模预训练掌握广泛的机器人操作技能,并能通过微调快速适应具体任务需求。该模型支持高效的数据利用与快速部署,在有限数据下也能实现良好性能,为机器人智能化提供了一种可扩展的解决方案。1. 环境安装在LeRobot安装及使用教程的基础上,训练Pi0需要显存较大的显卡,我租赁的实例是 H20,使用VS Code SSH远程连接服务器:# ssh -p 17825 root@region-42.seetacloud.com Host region-42 HostName region-42.seetacloud.com User root Port 17825 在安装Pi0的过程中需要访问Github和HuggingFace等国外网站,建议开启AutoDL内置的学术加速服务,由于该加速服务可能对正常网络造成一定影响,安装过程中如果失败可以多次尝试,当不再需要时建议取消学术加速。# 启用学术加速 source /etc/network_turbo cd /root/autodl-tmp git clone https://github.com/enpeizhao/openpi_episode1_student.git cd openpi_episode1_student/ pip install uv GIT_LFS_SKIP_SMUDGE=1 uv sync GIT_LFS_SKIP_SMUDGE=1 uv pip install -e . # 取消学术加速 unset http_proxy && unset https_proxy2. 转换数据Pi0训练必须是弧度制数据,安装ffmpeg转换为openpi格式:sudo apt update sudo apt install ffmpeg uv run ./examples/libero/lerobot2oppi.py \ --source-repo-id=hou/demo_move_toy \ --target-repo-id=hou/demo_move_toy_openpi \ --output-path=./demo_move_toy_openpi \ --source-dataset-root=/root/autodl-tmp/demo_move_toy \ --max-episodes=100 3. 修改配置以下是我的配置文件,为了节省训练时间num_train_steps设置为10_000:# 单臂配置:openpi_episode1_student/src/openpi/training/config.py TrainConfig( name="enpei_robot_demo_move_toy_low_mem_finetune", # Here is an example of loading a pi0 model for LoRA fine-tuning. model=pi0.Pi0Config(paligemma_variant="gemma_2b_lora", action_expert_variant="gemma_300m_lora"), data=LeRobotLiberoDataConfig( repo_id="hou/demo_move_toy_openpi", # 数据集repo_od root="./demo_move_toy_openpi", # 数据集路径 base_config=DataConfig(prompt_from_task=True), ), weight_loader=weight_loaders.CheckpointWeightLoader("/root/autodl-tmp/pi0_base/params"), num_train_steps=10_000, # The freeze filter defines which parameters should be frozen during training. # We have a convenience function in the model config that returns the default freeze filter # for the given model config for LoRA finetuning. Just make sure it matches the model config # you chose above. freeze_filter=pi0.Pi0Config( paligemma_variant="gemma_2b_lora", action_expert_variant="gemma_300m_lora" ).get_freeze_filter(), # Turn off EMA for LoRA finetuning. ema_decay=None, ), 4. 模型训练# 计算 normalization uv run scripts/compute_norm_stats.py --config-name enpei_robot_demo_move_toy_low_mem_finetune # 开启训练 XLA_PYTHON_CLIENT_MEM_FRACTION=0.9 uv run scripts/train.py enpei_robot_demo_move_toy_low_mem_finetune --exp-name=my_experiment --overwrite在训练过程中可以看到模型的LOSS在逐渐降低,也可以在终端中查看GPU的利用率,采集100个episodes数据使用H20迭代10_000步大概需要花费9个小时:训练过程中Pi0会保存多个时间点的权重checkpoint,每次约消耗磁盘12G,因此建议将代码目录放到/root/autodl-tmp数据盘目录下,这样训练过程中产生的权重文件会自动保存在/root/autodl-tmp/checkpoints下,避免系统盘因空间不足导致训练失败。5. 本文小结本文介绍了在H20实例上安装和训练Pi0模型的完整流程,包括环境配置、数据转换、修改训练配置以及模型训练等关键步骤,并提供了相关命令和注意事项,帮助读者快速上手Pi0模型训练。
  • [技术干货] Addcdiv算子的应用场景
    Addcdiv算子的核心公式是 y = input_data + value * (x1 / x2)。这个看似简单的组合操作,在机器学习和科学计算中其实是一个相当基础且重要的模式。它通常不会作为一个独立的层出现,而是作为构建更复杂模型或算法的基本砖块。其最主要的应用场景集中在以下几个方面:1. 优化算法与参数更新这是Addcdiv最经典和广泛的应用。在许多先进的优化器中,我们都能看到它的影子。最典型的代表是Adam和RMSProp等自适应学习率算法。以Adam为例:在更新模型参数时,Adam会计算梯度的一阶矩(均值)和二阶矩(未中心化的方差)估计。参数更新步骤大致为:参数 = 参数 - 学习率 * (一阶矩估计 / (sqrt(二阶矩估计) + epsilon))。映射到Addcdiv:在这里,input_data就是待更新的参数,value是负的学习率,x1是一阶矩估计,x2是sqrt(二阶矩估计) + epsilon。这个操作在每个训练步骤中为数百万甚至数十亿的参数执行一次,因此其计算效率至关重要。用高度优化的Addcdiv算子来实现,能极大提升整个训练过程的吞吐量。2. 注意力机制中的归一化操作在Transformer架构中,注意力权重的计算通常涉及一个缩放操作。标准的点积注意力公式为:Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V。映射到Addcdiv:在计算Q * K^T之后,我们需要将结果除以一个标量sqrt(d_k)。这个过程可以看作是一个广播操作:x1是注意力得分矩阵,x2是一个标量sqrt(d_k),而input_data和value在这里可以视为0和1(即纯除法)。虽然在最终实现时可能被更专用的内核融合,但从计算模式上看,它符合Addcdiv的范畴。3. 物理模拟与科学计算在这些领域,许多物理量的更新遵循类似的模式。例如,在计算流体动力学或分子动力学模拟中,一个粒子的新位置可能等于旧位置加上速度与时间的乘积(这本身是加法与乘法的组合),而速度又可能是力与质量的比值。当多个这样的基本操作组合在一起时,就可能抽象出Addcdiv的模式。虽然这些领域可能使用双精度浮点数,但其计算图与Addcdiv是相通的。4. 自定义梯度与反向传播当研究人员或工程师在开发新的模型结构时,可能会设计出自定义的数学操作。如果这个自定义操作的前向传播恰好符合a + b * (c / d)的形式,那么在编写其反向传播(求导)时,其梯度计算也极有可能包含类似的结构。拥有一个高效的Addcdiv原语,可以方便地将这些自定义操作在底层高效实现,而无需手动组合多个基础算子,从而避免了多次启动内核和中间结果读写的开销。总结来说,Addcdiv算子的用武之地在于它封装了一个频繁出现且计算密集的复合操作模式。它的价值不仅在于其数学功能,更在于其性能优势。在AI芯片上,将多个基础操作(除法、乘法、加法)融合成一个单一的Addcdiv内核,可以显著减少:内核启动开销:从启动三个内核减少到一个。内存带宽压力:中间结果(如x1/x2)可以直接在芯片的高速缓存(如UB)中进行计算,而无需写回至外部DRAM再读回。因此,尽管用户在日常编程中可能不会直接调用它,但Addcdiv作为底层支撑算子,在训练大规模神经网络、运行复杂优化算法时,默默地发挥着提升整体计算效率的关键作用。
总条数:7838 到第
上滑加载中