一.研究背景

锂电池指标,什么是soh估计,rul预测,怎么测的,估算方法及相关理论,有哪些应用场景和价值

1. 锂电池基础核心指标梳理

关键参数

专业通俗含义

核心作用(和SOH强相关)

1. 额定容量

电池出厂时,标准环境下标定的理论固定最大电量,单位Ah/mAh,终身不变。

SOH计算公式固定分母,是电池健康判定的唯一基准参照值。

2. 实际容量

电池当前老化工况下,真实可完整释放的有效电量,随使用持续降低。

电池老化核心实测依据,直接代入公式核算实时精准SOH数值。

3. 充放电倍率

界定电池充放电快慢的核心指标,倍率越大,工作电流越强,充放电节奏越快。

高频大倍率工况会加速电芯材料损耗,直接加快SOH不可逆衰减节奏。

4. 内阻

电池内部综合等效电阻,涵盖欧姆内阻、极化内阻,电芯老化后会同步大幅升高。

内阻越高,电池发热越严重、快充掉速越明显,是辅助核验SOH的关键隐性指标。

5. 循环寿命

全新锂电池常规工况下,持续充放电直至SOH衰减至80%退役阈值的完整循环总次数。

标定电池整体耐用上限,是贴合工况精准推算电池RUL剩余寿命的核心依据。

6. 工作温度区间

锂电池安全稳定运行的适配温度区间,常规商用锂电标准区间为0℃~45℃,极值温区易损伤电芯。

超温、低温违规工况会不可逆损伤电芯活性,极速拉低SOH,还会诱发热失控安全隐患。

指标名称

完整含义

变化特点

实际用途

SOC 电量状态

电池当前还剩多少电,就是手机显示的百分比电量。

实时来回波动,充一下就涨,用一下就降,可恢复。

看实时剩余续航,日常用电管理。

SOH 健康状态

电池整体老化程度,对比新电池还剩多少性能。

只降不升,不可逆,慢慢衰减,不会自己恢复。

判断电池要不要换、评估电池健康好坏。

RUL 剩余寿命

电池从现在开始,还能正常用到报废的剩余循环次数/时间。

越用越少,随着充放电持续减少。

提前预警故障,规划电池更换与梯次利用。

特征类别

具体原始特征名称

在模型里的作用

电压类电气特征

充电电压、放电电压、单体端电压实时波动值

反映电池内部极化变化,是判断老化最核心电气信号。

电流类电气特征

实时充电电流、实时放电电流、平均工作电流

体现充放电负荷大小,直接关联电池老化快慢程度。

温度环境特征

电池表面实时温度、温度变化速率、最高最低温

温度是影响SOH衰减的关键外因,必须送入模型学习。

时序老化标签特征

累计充放电循环次数、当前实时实际容量、时间戳

给模型标注时间老化节奏,帮助精准拟合SOH下降曲线。

特征名称

具体含义

物理含义

与SOH关系

与RUL关系

相关性

模型为什么需要这个特征

放电电压

电池向外供电、放电过程中实时采集的两端电压数值

反映电池当前真实能带负载的电势水平,体现内部极化大小

电池越老化,内阻越大,放电电压跌落越快,SOH越低

电压跌落越快,说明电池寿命越短,剩余可用循环越少

正相关

SOH最核心判断信号,CNN用来提取关键老化波形特征

充电电压

电池接入电源充电时,实时监测的两端工作电压

反映电池接受电能的能力,体现内部阻抗极化程度

老化越严重,内阻越高,同等电流下充电电压越高,SOH越低

充电电压异常偏高,代表电池衰减严重,剩余寿命变短

负相关

辅助判断内部老化程度,补充反向工况特征,提升模型精度

放电电流

电池对外带负载工作时,实时流出的电流大小

代表电池实际工作负荷、放电倍率大小

长期大电流放电加速发热老化,会快速降低SOH

放电电流越大、工况越恶劣,电池剩余使用寿命越短

负相关

让模型学习不同负载工况下,SOH衰减快慢不一样

充电电流

充电过程中,流入电池内部的实时电流数值

代表充电速度、快充倍率强弱,决定充电负荷压力

大电流快充损伤负极、析出锂金属,加速SOH下降

经常大电流充电,电池老化加快,RUL快速缩短

负相关

模拟真实快充场景,提升模型在实际工况下的泛化能力

电池表面温度

电池外表面传感器实时测得的工作温度数值

反映电池内部电化学反应剧烈程度和整体发热状态

温度越高,电解液分解越快,材料损伤越严重,SOH越低

长期高温工作,电池寿命大幅缩短,RUL快速下降

负相关

温度是影响老化第一外因,模型必须学温度补偿规律

温度变化率

每一秒/每段时间内,电池温度上升或下降的快慢程度

代表电池瞬时发热烈度,直接反映内阻发热功率大小

温度变化越剧烈,内阻越大,电池老化越快,SOH越低

温度波动越大,电池损伤越重,剩余寿命越少

负相关

捕捉瞬间异常发热特征,提前识别隐性老化故障

累计充放电循环次数

电池从全新开始,累计跑完的完整充放电轮回总数

代表电池实际使用时长、自然老化时间标尺

循环次数越多,损耗累积越多,SOH必然越来越低

已用循环越多,离报废越近,剩余RUL越少

负相关

给ASTLSTM提供时间时序轴,专门学习长期老化下降趋势

当前实际可用容量

每一圈循环结束后,实测出来电池当前真实能放出的电量

直接体现电芯活性材料剩余储能能力强弱

实际容量越小,电池老化越重,SOH数值越低

容量衰减越快,说明剩余能用的寿命周期越短

正相关

模型训练的真实标签真值,用来反向训练、校正网络权重

2. 什么是 SOH 估计

  • 利用锂电池的电压、电流、温度、循环次数等运行数据,通过测试、经验公式或智能算法,定量计算电池当前老化衰减程度,评估电池相比于全新状态还剩余多少健康性能的技术。
  • 代替传统离线容量标定,实现在线实时评估电池健康度、判断电池老化程度、是否需要更换,同时为RUL 剩余寿命预测提供基础依据。
  • 全新电池:SOH≈100%
  • 行业退役标准:SOH≤80% 判定为电池退役、需要梯次利用或更换

3. 什么是 RUL 预测

  • RUL 完整定义:从当前健康状态到退役阈值(如 SOH=80%)剩余的生命周期
  • SOH 和 RUL 的强关联关系:SOH 持续衰减→推算 RUL
  • 工程上 RUL 的表达形式:剩余循环次数、剩余使用天数

        核心底层原理

  • 锂电池 SOH 随循环次数增加单调不可逆下降
  • 先通过模型拟合出 SOH 随循环的衰减曲线
  • 把曲线向后外推预测未来的 SOH 变化;
  • 找到曲线与 SOH=80% 退役线 的交点;
  • 用「报废循环数 - 当前循环数」,差值就是 RUL(剩余循环次数)

4. SOH/RUL 传统怎么实测

传统 SOH 测量流程:

电池离线拆机 → 恒温静置稳压 → 恒流恒压充放电标定 → 计算当前实际容量 → 实际容量 ÷ 额定容量 → 得出SOH

传统 RUL 预测流程:

采集多轮循环 SOH 老化数据 → 拟合简单衰减趋势曲线 → 设定退役阈值 SOH=80% → 曲线向后外推 → 求得寿命终止循环数 → 减去当前循环数 → 得出RUL 剩余寿命

5. SOH/RUL 主流估算方法及相关理论

模型驱动方法:

  • 数学模型 (Mathematical Model)
    • 核心思想:这类模型通过分析电池的外部测量数据(如电压、电流曲线)来推断内部状态和健康指标,通常不涉及复杂的物理化学机制模拟,因此被称为“无损”方法。
    • 典型方法
      • 增量容量分析 (Incremental Capacity Analysis, ICA):通过对充电或放电曲线进行微分,识别出电池内部电极反应的特征峰,这些峰的位置和高度变化与电池老化状态密切相关,可用于 SOH 估计。
      • 微分电压分析 (Differential Voltage Analysis, DVA):与 ICA 类似,通过对电压曲线相对于容量的变化率进行分析,揭示电池内部的退化模式。
    • 应用:广泛用于 SOH 估计,因其操作简便且不损害电池。
  • 机理模型 (Mechanism Model)
    • 核心思想:这类模型旨在模拟电池内部的物理和化学过程,从而更深入地理解电池的动态响应和退化行为。它们分为两种主要路径:
      • 偏微分方程 (Partial Differential Equations, PDEs):通过建立描述质量传输(如锂离子扩散)和电荷传输(如电化学反应动力学)的 PDEs,来模拟电池内部的电化学过程。
      • 物理化学反应分析:分析电池内部发生的物理和化学反应,并用简化的模型来描述其宏观行为。
    • 典型方法
      • 电化学模型 (Electrochemical Model):最著名的是 P2D (Pseudo-two-dimensional) 模型。它通过模拟电极孔隙率、活性物质颗粒内锂离子扩散、电解液中锂离子传输等微观过程,来预测电池的电压、电流响应和老化行为。P2D 模型因其物理基础强,能够提供深入的电池内部状态洞察,但计算复杂度较高。
      • 等效电路模型 (Equivalent Circuit Model, ECM):通过电阻、电容和电感等基本电路元件的组合来模拟电池的动态电学特性。这些元件的参数与电池的 SOH、温度等因素相关,易于在线实现,计算效率高,但缺乏对电池内部物理化学过程的直接描述。
    • 应用:用于描述电池动态响应和退化行为,以及日历老化预测。

数据驱动方法:

数据驱动方法,尤其是神经网络 (NNs),因其自适应性、灵活性以及无需预设物理化学机理的优势,在锂离子电池的健康状态 (SOH) 估计和剩余使用寿命 (RUL) 预测领域获得了广泛关注。

数据驱动方法研究进展:

该领域的研究进展主要体现在以下几个方面:

  • 输入特征的演变

    • 从单一变量到多变量输入:早期研究可能仅使用单一变量(如容量)作为 NNs 输入。然而,为了更全面地捕获电池退化数据中嵌入的信息,研究人员开始将多个变量作为 NNs 的输入,例如:
      • 荷电状态 (SOC)、电流和阻抗谱:被用作循环神经网络 (RNNs) 的输入,以并行估计电池的内阻和容量 [17]。
      • 电压、电流和温度变化:在其他 SOH 任务中,这些变量也被输入到 RNNs 中以进行 SOH 估计 [18]。
    • 设计动机:多变量输入能够提供更丰富的电池运行和退化信息,帮助 NNs 更准确地学习和识别复杂的退化模式。
  • 训练数据源的扩展

    • 从单电池到多电池数据训练:为增强基于神经网络的估计器的泛化能力,研究不再局限于使用单个电池的数据进行训练。
    • 多电池数据:通过汇集多个电池的数据来训练模型,旨在构建一个更通用、更鲁棒的框架,能够适用于不同电池个体。
  • 神经网络架构的创新

    • 多项式神经网络 (Polynomial NN) 与群方法数据处理 (GMDH):将电压曲线特性输入到结合了 GMDH 的多项式 NN 中,以估算 SOH [15]。这表明了将传统机器学习技术与 NN 结合的尝试。
    • 基于先验知识的神经网络 (Prior Knowledge-based NN):通过从单个电池的衰老过程中提取端电压特征,并将其输入到基于先验知识的 NN 中来估算 SOH [16]。这提示了在 NN 设计中融入领域知识的重要性。
    • 混合神经网络框架:为进一步提升模型性能和捕获复杂依赖关系,研究人员开始结合不同类型的神经网络:
      • 卷积神经网络 (CNN) 预测框架 [19]:CNN 擅长从序列数据中提取局部特征和层次模式。
      • 主动状态跟踪长短期记忆神经网络 (AST-LSTM NN) 预测框架 [20]:LSTM 及其变体特别适用于处理时间序列数据中的长期依赖关系。AST-LSTM NN 进一步优化了对状态的跟踪能力。
RUL预测方法:

剩余使用寿命(RUL)的预测通常作为电池健康状态(SOH)评估的补充,在锂离子电池管理中至关重要。近年来,长短期记忆(LSTM)神经网络因其在处理时间序列数据中固有的长短期依赖关系方面的卓越能力,成为RUL预测的主流方法。

这些基于LSTM的RUL预测方法在多个关键方面呈现出多样性:

  • 输入类型 (Input Type)

    • 容量特征 (Capacity Features):部分研究选择提取更抽象的容量特征,例如通过经验模态分解(EMD)获得的几个子层系数。EMD能够将复杂的信号分解为一系列固有模态函数,这些系数可能代表电池容量衰减的不同频率或模式。
    • 原始记录容量 (Raw Recorded Capacities):另一些研究则直接使用电池在不同循环周期中测得的原始容量数据作为输入。这种方法旨在让神经网络直接从原始数据中学习退化模式,减少了特征工程的复杂性。
  • 数据处理 (Data Curation)

    • 多电池数据训练 (Multiple Cells' Data to Train):为了提高模型的泛化能力和鲁棒性,一些方法采用来自多个电池的数据集进行训练。这有助于模型学习更普遍的电池退化规律,而非仅限于特定电池的特性。
    • 单电池数据训练 (One Cell's Data to Train):相反,也有研究选择仅使用单个电池的数据来训练模型。这种方法可能更专注于捕捉特定电池的独特退化行为,但其泛化能力可能受限。
  • 神经网络使用 (NN Usage)

    • 独立预测模型 (Individual Forecasting Model)
      • 标准LSTM NN (Standard LSTM NN):结合了如Dropout技术(用于防止过拟合)和Adam算法(一种高效的优化器)。
      • 双向LSTM NN (Bidirectional LSTM NN):能够同时处理序列的前向和后向信息,从而更全面地捕捉上下文依赖。
      • ASTLSTM NN (ASTLSTM NN):主动状态跟踪长短期记忆网络,可能在标准LSTM的基础上对细胞状态管理进行了优化。
    • 结合不同模型 (Combine Different Models)
      • Elman NN 和 LSTM NN 的结合 (Combination of Elman NN and LSTM NN):Elman网络是一种具有上下文单元的递归神经网络,与LSTM结合可以综合利用各自在时间序列建模上的优势。
      • CNN 和 LSTM NN 的混合 (Hybridization of CNN and LSTM NN):CNN擅长从局部区域提取空间层次特征,而LSTM擅长处理时间序列中的长期依赖。两者的结合旨在同时捕获电池退化过程中的多尺度空间特征和时间动态。
面临的挑战:

挑战一:混合神经网络模型的实际应用复杂性与有效性验证不足

  • 证据与理论意义的鸿沟:研究指出,SOH估算和RUL预测中,通过混合(即结合)多个独立的NN模型(如[26]和[25]所示)确实能够同时捕捉电池数据中的多样化模式,从而取得有前景的结果。这表明混合模型在理论上具有优势。
  • 实际复杂性与验证需求:然而,作者强调,在缺乏进一步证据证明此类混合方法在实际应用中不复杂的情况下,其当前的意义可能仅停留在“理论意义”层面。这意味着,尽管模型在性能上可能有所提升,但其在部署、维护或计算资源方面的开销,以及是否能在真实、动态的电池管理系统中灵活应用,仍是未经验证的问题。
  • CNN与LSTM结合的优化问题:该段落特别提出,需要深入研究何种特定类型的长短期记忆(LSTM)神经网络能与卷积神经网络(CNN)进行最有效的结合。CNN擅长提取空间特征,而LSTM擅长处理时间序列的长期依赖,两者的混合(如CNN-LSTM)旨在综合利用各自优势,但其最佳结合方式仍需探索,以确保获得更有效的模型而非简单堆叠。

挑战二:超参数调优的效率低下与自动化方法的局限性

  • 手动调优的“艺术性”:现有的SOH和RUL模型训练通常需要多次神经网络训练迭代,并且高度依赖实验者对模型参数化(如何选择模型架构和组件)和超参数(如学习率、层数、隐藏单元数量等)的“合理默认值”设定。这种手动调整过程被描述为“艺术而非科学”,因为它缺乏系统性和可重复性,导致已发表结果难以重现和推广([17-26])。
  • 自动机器学习(AutoML)的潜力与先验分布缺失:为了解决手动调优的难题,自动机器学习算法,特别是利用贝叶斯估计进行超参数优化([27]),被提出可以减少人工干预。贝叶斯优化通过构建一个目标函数的代理模型(surrogate model)来高效搜索最佳超参数组合。
  • 电池数据先验分布的缺失限制了AutoML的适用性:然而,该段落指出,由于电池数据上“缺乏超参数的先验分布”,这些先进的AutoML方法在SOH和RUL任务中并不特别适用。先验分布在贝叶斯优化中至关重要,它提供了关于超参数可能取值范围和概率的初始信念。如果缺乏这些领域特定的先验知识,AutoML算法可能无法高效地探索超参数空间,或者其性能可能不如预期。这意味着需要更多研究来为电池数据相关的NN超参数建立合适的先验分布,以充分发挥AutoML在电池健康预测中的潜力。

6. 论文突破点

CNN-ASTLSTM NN模型的提出

首先,CNN-ASTLSTM NN被定位为一种新型混合神经网络模型,其设计理念在于结合两种不同类型神经网络的优势:

  1. 一维卷积神经网络 (1D CNN):CNN以其在提取局部特征和层次模式方面的强大能力而闻名。在一维数据(如时间序列或序列特征)中,1D CNN能够通过卷积核滑动操作,捕捉数据在不同抽象层次上的空间相关性或局部模式。在这里,它负责“分层捕获退化数据的特征”,这意味着它能从原始电池测量数据(如电压、电流、温度等随时间变化的序列)中,自动学习并提取出与电池退化相关的多尺度、多层次的抽象特征表示。
  2. 主动状态跟踪长短期记忆神经网络 (Active-State-Tracking Long-Short-Term Memory Neural Network, AST-LSTM NN):LSTM是处理时间序列中长期依赖的有效工具,而AST-LSTM NN可能在标准LSTM的基础上,通过某种机制(如文献[20]所述的“主动状态跟踪”)进一步优化了对时间依赖性的学习和管理。该组件旨在“主动学习嵌入在这些特征中的时间依赖性”,即在CNN提取的静态或局部特征基础上,理解这些特征随时间演变的关系,这对于预测电池SOH和RUL至关重要,因为电池退化是一个动态的、具有时间记忆的过程。

通过将这两种网络“混合”或“结合”,CNN-ASTLSTM NN旨在实现**端到端(end-to-end)**的学习:从原始的电池退化数据输入,经过特征提取和时间依赖性建模,直接输出SOH和RUL的预测结果,从而避免了传统方法中复杂的手动特征工程。

其次,该段落强调了对这种新型混合模型进行**“实际性能”“综合评估”**。这不仅仅是关注预测精度,更是从多个关键维度对模型的实用性和效率进行全面考量:

  • 预测误差 (Prediction Error):这是衡量模型预测准确性的最直接指标,通常通过均方根误差(RMSE)、平均绝对误差(MAE)等来量化。
  • 参数量 (Parameters):指模型中可学习权重和偏置的总数量。参数量直接影响模型的复杂性、存储需求以及在有限数据集上过拟合的风险。
  • 浮点运算次数 (FLOPs, Floating Point Operations):衡量模型执行一次前向传播或训练迭代所需的计算量,是评估模型计算效率和推理速度的关键指标。
  • 延迟 (Latency):指模型从接收输入到产生输出所需的时间,对于实时性要求高的电池管理系统(BMS)应用至关重要。
  • 存储大小 (Storage Size):指训练好的模型文件在存储介质上占用的空间,对于部署到嵌入式系统等资源受限平台具有重要意义。
  • 训练时间 (Training Time):指模型在给定数据集上完成训练所需的总时间,是评估模型开发效率和资源消耗的指标。

通过在统一的框架下,将CNN-ASTLSTM NN与现有的一些个体神经网络模型(如RNN、S-LSTM、AST-LSTM)和其他混合模型(如CNN-LSTM)进行比较评估,本研究旨在全面证明所提出模型的优越性,不仅体现在预测准确性上,也体现在计算效率和资源消耗等实用性方面,从而为其实际应用提供有力支撑。

利用改进的贝叶斯优化算法实现神经网络超参数的自动化配置

首先,自动超参数配置是核心目标。传统上,超参数(如学习率、网络层数、隐藏单元数量等)的调整往往依赖于经验或耗时的人工试错,这不仅效率低下,且难以保证结果的最优性与可重现性。通过自动化配置,研究旨在减少人工干预,从而使研究过程更易于推广和重现

其次,实现自动化的关键在于引入贝叶斯优化算法。贝叶斯优化是一种全局优化算法,特别适用于昂贵(即评估成本高)的黑盒函数优化问题,如神经网络的超参数优化。它的核心思想是:

  1. 构建代理模型(Surrogate Model):贝叶斯优化不会直接评估真实的损失函数,而是维护一个关于目标函数(在此即损失函数)的概率模型,也称为替代模型。这个模型通过少量真实的函数评估点来学习目标函数的整体形状。
  2. 利用采集函数(Acquisition Function):基于代理模型,贝叶斯优化使用一个采集函数来决定下一个最有希望评估的超参数组合。采集函数平衡了“探索”(在不确定区域进行评估)和“利用”(在已知表现良好区域附近进行评估)。

在此框架中,柯尔莫哥洛夫-斯米尔诺夫(KS)检验扮演了关键角色。KS检验是一种非参数统计检验,用于比较一个样本的经验分布函数与一个参考理论分布函数,或者比较两个样本的经验分布函数。在这里,它被用于获得神经网络损失函数值的先验分布。这意味着在贝叶斯优化开始之前,研究者并非对超参数的表现一无所知,而是通过KS检验对不同超参数设置下神经网络可能产生的损失值建立了一个初步的概率分布认知。

“将损失分布视为指定给神经网络的超参数的替代分布”是理解该方法的重要一步。通常,贝叶斯优化中的替代模型直接建模超参数与真实损失函数之间的关系。而这里,通过KS检验得到的损失函数值的先验分布,被用作超参数本身的一个代理或间接表示。这意味着,这个先验分布间接地反映了不同超参数组合对模型性能(通过损失函数值体现)的潜在影响。

最后,基于超参数的先验分布,研究建立贝叶斯概率替代模型。这个替代模型不再是简单的超参数到损失函数的直接映射,而是结合了通过KS检验得到的先验知识,使得模型能够更有效地自动选择最有希望的超参数来评估真实的损失函数。这种改进的贝叶斯优化策略,通过整合先验知识,有望更高效地搜索超参数空间,从而找到性能更优的神经网络配置。

二.理论基础

全文用到的算法基础和理论基础,什么是cnn,什么是rnn,什么是lstm,什么是贝叶斯优化?

1.CNN-ASTLSTM神经网络设计

  • 特征图 (Feature Map):卷积层对输入数据执行卷积操作后生成的输出,表示输入数据中提取的特征集合。
  • 激活函数 (Activation Function):非线性函数,应用于卷积层的输出,引入非线性,使神经网络能够学习更复杂的模式。
  • 局部感受野 (Local Receptive Field):卷积核在输入数据上覆盖的局部区域,卷积操作在此区域内提取特征。
  • 步长 (Stride Size):卷积核在输入数据上移动的步长,影响输出特征图的尺寸。
  • 最大池化 (Max Pooling):一种下采样技术,通过在局部区域内选取最大值来减少数据的空间维度,同时保留主要特征。
  • 下采样 (Downsampling):通过减少数据点的数量来降低数据维度,常用于卷积神经网络中以减少计算量和控制过拟合。
  • 层级模式 (Hierarchical Patterns):通过多层神经网络逐步提取出的,从简单到复杂的、不同抽象级别的特征模式。
  • 主动状态跟踪长短期记忆网络 (Active-State-Tracking Long-Short-Term Memory Neural Network, AST-LSTM NN):一种改进的循环神经网络,用于学习序列数据中的长期时间依赖性,特别适用于处理电池退化等时间序列任务。
  • 时间依赖性 (Temporal Dependencies):序列数据中不同时间点上的数据值之间的相互关系或影响。

  • AST-LSTM Layer (AST-LSTM 层):一种长短期记忆神经网络的变体,用于处理序列数据并捕获其中的时间依赖性,特别设计用于主动跟踪状态。
  • Forget Gate (遗忘门):AST-LSTM内部的一个门控机制,通过Sigmoid函数控制前一时刻的细胞状态有多少信息应被遗忘。
  • Candidate Gate (候选门):AST-LSTM内部的一个门控机制,通过tanh函数生成当前输入和前一隐藏状态的候选信息,用于更新细胞状态。
  • Logistic Sigmoid (逻辑Sigmoid):一种激活函数,将输入压缩到(0,1)区间,常用于门控单元以决定信息通过的比例。
  • Hyperbolic Tangent (双曲正切tanh):一种激活函数,将输入压缩到(-1,1)区间,常用于生成候选信息和对细胞状态进行激活。
  • Fused State Inputs (融合状态输入):结合遗忘门和窥视孔连接的细胞状态,决定新信息有多少输入到细胞状态。
  • Cell States (细胞状态):AST-LSTM的核心组件,负责在时间步之间传递长期信息,其更新由门控单元控制。
  • Peephole (窥视孔):一种连接,允许门控单元直接访问和利用细胞状态的信息,以更好地控制信息流。
  • Point-wise Multiplication (点乘):对应元素相乘的操作,在AST-LSTM中用于门控单元选择性地过滤信息。
  • Output Gate (输出门):AST-LSTM内部的一个门控机制,通过Sigmoid函数控制当前细胞状态有多少信息应被输出为隐藏状态。
  • Block Outputs (块输出/隐藏状态):AST-LSTM层的输出,反映了当前时间步的信息,并作为下一个时间步或下一层的输入。
  • Full Connection Weights (全连接权重):连接AST-LSTM层输出到最终预测结果的线性变换权重。

2. CNN-ASTLSTM神经网络超参数优化

这段内容详尽阐释了基于贝叶斯优化和期望提升(EI)准则的超参数优化框架。它首先将原始的超参数优化问题重新定义为通过K折交叉验证评估损失函数期望,进而引入EI准则作为代理函数,以解决未知自然分布下的损失评估难题。EI准则的计算依赖于基于超参数配置的损失条件概率密度函数,并通过Parzen窗估计和Kolmogorov-Smirnov(KS)检验来构建这些概率密度,最终指导最优超参数的选择。

  • 贝叶斯优化 (Bayesian Optimization):一种全局优化算法,通过构建目标函数的概率代理模型(如高斯过程)来选择下一个评估点,以最小化目标函数的评估次数。
  • 超参数 (Hyper-parameter):在机器学习模型训练之前设定的参数,它们不通过模型训练过程学习,而是影响模型的学习过程和性能,例如学习率、批次大小、网络层数等。
  • 期望提升 (Expected Improvement, EI):贝叶斯优化中常用的一种采集函数(acquisition function),用于衡量在代理模型下,选择某个新点能比当前已知最佳值带来更大改进的期望,指导超参数搜索方向。
  • 损失函数 (Loss Function):衡量模型预测输出与真实值之间差异的函数,目标是在训练过程中最小化损失函数。
  • 泛化误差 (Generalization Error):模型在未见过的新数据(即来自真实未知数据分布的数据)上的预期性能误差,反映了模型的泛化能力。
  • K折交叉验证 (k-fold cross-validation):一种评估模型性能的统计学方法,将数据集分成K个子集,每次用K-1个子集训练模型,用剩下的一个子集进行验证,重复K次取平均。
  • CNN-ASTLSTM NN (Convolutional Neural Network - Active-State-Tracking Long-Short-Term Memory Neural Network):论文中提出的混合神经网络模型,结合了卷积神经网络(CNN)提取层次特征的能力和主动状态追踪长短期记忆网络(AST-LSTM)处理时间序列依赖性的能力。
  • 代理模型 (Surrogate Model):在贝叶斯优化中,用于近似复杂或计算成本高的目标函数的简单模型,以便更有效地进行优化搜索。
  • 密度估计 (Density Estimate):从有限的数据样本中估计数据概率分布的方法,如Parzen窗估计。
  • Parzen窗估计 (Parzen Estimator):一种非参数概率密度估计方法,通过在每个数据点周围放置一个核函数(如高斯核)来估计整体密度函数。
  • 高斯核 (Gaussian Kernel):在核密度估计和支持向量机等算法中常用的一种核函数,其形状为钟形曲线(高斯分布)。
  • 带宽 (Bandwidth):在核密度估计中,控制核函数平滑程度的参数,影响估计密度的平滑性。
  • Kolmogorov-Smirnov (KS) 检验 (Kolmogorov-Smirnov Test):一种非参数检验方法,用于比较一个样本的经验分布函数与理论分布函数,或者比较两个样本的经验分布函数,以评估它们是否来自相同的分布。
  • 经验分布函数 (Empirical Distribution Function, EDF):基于观测数据计算的累积分布函数,反映了样本中数据点小于或等于某个值的比例。

3. CNN-ASTLSTM神经网络应用

这段文本详细阐述了基于CNN-ASTLSTM神经网络的电池健康状态(SOH)估计和剩余使用寿命(RUL)预测模型。它定义了SOH的训练和在线估计公式,以及RUL的实际与预测计算方法,并说明了RUL预测模型(包括训练和在线预测)如何利用历史和预测容量数据进行构建。

这些公式共同构建了一个端到端的框架,用于在训练和在线阶段对锂电池的SOH和RUL进行准确估计与预测。

  • CNN-ASTLSTM NN (Convolutional Neural Network - Active-State-Tracking Long-Short-Term Memory Neural Network):论文中提出的混合神经网络模型,用于捕捉电池退化的层次特征和时间依赖性。
  • SOH (State-of-Health):电池健康状态,通常表示为当前容量与初始容量的百分比,是评估电池性能的关键指标。
  • RUL (Remaining Useful Life):剩余使用寿命,指电池在达到其性能阈值(如EOL)之前还能继续运行的循环次数或时间。
  • 历史样本 (History samples):在某个循环中,电池的电压 (V)、温度 (T)、电流 (I) 和采样时间 (t) 等随时间变化的记录数据。
  • 历史容量 (History capacity):电池在特定循环下的实际容量。
  • 滑动窗口 (Sliding window):一个固定长度的时间或循环区间,用于从连续数据流中截取输入序列。
  • 初始容量 (Initial capacity):电池全新时的额定容量。
  • 在线估计 (Online estimation):在电池实际运行过程中,基于实时或近期观测数据进行的SOH或RUL预测。
  • 观测样本 (Observed samples):在某一循环中,实际测量到的电池数据。
  • EOL (End-of-life):寿命终止,指电池容量下降到其初始容量的某个预设百分比(如70%)时的状态。
  • 实际循环次数 (Actual cycle):电池在实际使用中经历的循环次数。
  • 预测开始时的循环次数 (Cycle when prediction gets started):开始进行RUL预测时的电池循环次数。
  • 预测窗口 (Prediction window):在RUL预测中,模型用于预测未来容量或EOL循环次数的时间或循环区间长度。
  • 预测容量 (Predicted capacities):模型对未来电池容量的估计值。
  • 观测容量 (Observed capacities):实际测量到的电池容量。

三.模型拆解

核心模型架构,cnn-astlstm神经网络架构,画出完整的网络结构框图,模型分模块拆解

层类型 核心参数
Conv1D 卷积层 kernel_size=7,strides=4,filters=46,padding='same',activation='relu',输入为 660 个时间步、4 个特征通道
MaxPooling1D 池化层 pool_size=2,padding='valid',默认步长 = pool_size=2

1.卷积层

公式符号 代入你的代码参数 对应代码含义
n n=1 代表网络的第 1 个卷积层
输入Un​ U1​∈R660×4 卷积层的输入,就是你 reshape 后的时序数据:660 个时间步、4 个特征通道
x 取值范围:0≤x≤164(共 165 个位置) 输出特征图的时序位置,输出宽度 = ceil (660/4)=165,和你的数据流完全一致
cout​ 取值范围:0≤cout​≤45(共 46 个通道) 输出通道数,对应你代码里的filters=46
激活函数σ σ=ReLU,即σ(z)=max(0,z) 对应你代码里的activation='relu'
步长s s=4 对应你代码里的strides=4
卷积核Kn​ K1​∈R7×4×46 卷积核参数:kernel_size=7(宽度)、4 个输入通道、46 个输出通道
局部邻域NKn​ NK1​={(i,cin​)∣0≤i≤6, 0≤cin​≤3} 卷积核的局部感受野范围:i 是卷积核内的时序位置(0~6,共 7 个点),c_in 是输入通道(0~3,共 4 个)
i 取值范围:0≤i≤6 卷积核内部的时序位置索引,对应 kernel_size=7
cin​ 取值范围:0≤cin​≤3 输入特征的通道索引,对应输入的 4 个特征

卷积层的作用:

核心定位

专门从电池时序数据里,挖掘和老化强相关的局部规律,把原始的、无差别的电压 / 电流 / 温度采样值,转换成有业务语义的「老化特征」,是整个模型的 “特征放大镜”。

针对你的场景,4 个核心作用

  1. 捕捉时序局部关联,提取老化相关的微观模式你的卷积核kernel_size=7,本质就是让模型聚焦连续 7 个采样步的时序变化,专门抓全连接层无法识别的短周期规律:

    • 比如:放电阶段电压的下降斜率、电流的波动幅度、温度的上升速率、电压 - 电流的相位差变化;
    • 这些微观变化,是电池内阻升高、活性材料衰减的直接信号,也是 SOH 预测的核心依据,卷积层就是专门把这些信号从原始采样数据里挖出来。
  2. 权重共享,大幅减少参数量,避免过拟合这是卷积层相比全连接层的核心优势,用你的代码参数可以直观对比:

层类型 输入形状 输出形状 参数量计算 总参数量
你的 Conv1D(权重共享) (660, 4) (165, 46) 卷积核大小7 × 输入通道4 × 输出通道46 + 输出通道46(偏置) 1288 + 46 = 1334
等效全连接层(无权重共享) (660, 4) (165, 46) 输出时间步165 × 输出通道46 × (7×4) + 输出通道46(偏置) 212520 + 46 = 212566

你的 46 个卷积核,每个核的权重,会在 165 个输出时间步上重复使用 165 次,不需要给每个位置单独配权重;

而等效全连接层,每个位置都要有独立的权重,所以参数量是卷积层的165 倍(刚好是输出时间步的数量);

对应你的电池 SOH 场景:电池老化的特征(比如电压下降斜率、温度上升速率),不管出现在时序的第 10 个时间步还是第 100 个时间步,都是同一个特征,用同一套权重就能识别,不需要给每个位置单独配权重,既大幅减少了参数量,又提升了模型的泛化能力,避免过拟合。

  1. 时序偏移不敏感,泛化能力更强卷积层具备「平移等变性」:同一个老化特征,不管出现在时序的第 10 个采样步,还是第 100 个采样步,卷积核都能精准识别。对应你的场景:电池老化的电压波动特征,不会因为出现在循环前期还是后期,就被模型忽略,大幅提升了模型对不同老化阶段数据的适配能力。

  2. 特征升维,把原始物理量映射为高维语义特征你的输入只有 4 个原始物理量(电压、电流、温度、时间),经过filters=46的卷积层后,输出变成 46 个通道。本质就是:用 46 个不同的卷积核,学习 46 种不同的老化模式,每个通道对应一种特征(比如 “电压骤降特征”“温度上升特征”“电流波动特征” 等),把低维的原始数据,转换成了高维的、对 SOH 预测更有用的特征,给后续的 LSTM 层提供高质量输入。

2.池化层

公式符号 代入你的代码参数 对应代码含义
输入Fn​ F1​∈R165×46 池化层的输入,就是上面卷积层的输出:165 个时间步、46 个通道
x 取值范围:0≤x≤81(共 82 个位置) 输出特征图的时序位置,输出宽度 = floor (165/2)=82,和你的数据流完全一致
cout​ 取值范围:0≤cout​≤45(共 46 个通道) 池化不改变通道数,和卷积层输出通道数一致
池化窗口大小Q Q=2 对应你代码里的pool_size=2
池化步长d d=2 MaxPooling1D 默认步长 = pool_size,这里为 2
j 取值范围:0≤j≤1 池化窗口内的时序位置索引,对应 pool_size=2

池化层作用:

核心定位:

在卷积层之后,对提取到的特征做精简、降维、去噪,只保留对 SOH 预测最关键的核心信息,是整个模型的 “信息精简器”。

针对你的场景,4 个核心作用:

  1. 时序降维,大幅减少计算开销这是池化层最直观的作用:你的卷积层输出是 165 个时间步,经过pool_size=2的最大池化后,时间步直接压缩到 82,数据量减半。带来的直接收益:后续 ATSLSTM 层的计算量、参数量直接减半,模型训练速度大幅提升,内存占用也显著降低,避免了长时序带来的计算压力。

  2. 筛选关键特征,过滤测量噪声你用的是最大池化MaxPooling,核心逻辑是「在 2 个时间步的窗口里,只保留最大的数值」。对应你的场景:最大值往往代表最显著的老化信号(比如电压突然下跌的尖峰、温度骤升的峰值、内阻突变的拐点),而那些微小的测量噪声、无关的采样波动,会直接被过滤掉。相当于帮模型做了一次 “信息提纯”,让后续的 LSTM 只关注最核心的老化信号。

  3. 扩大感受野,让模型看到更长的时序周期感受野 = 模型能看到的原始输入的长度:

    • 卷积层的单个输出,只能看到原始输入的 7 个采样步;
    • 经过 2 倍池化后,后续 ATSLSTM 层的单个时间步,就能对应原始输入的 14 个采样步。相当于用很小的计算代价,让模型能捕捉到更长周期的老化趋势,更贴合电池 SOH 预测 “长期时序依赖” 的需求。
  4. 提升泛化能力,防止过拟合池化层通过压缩细节,强制模型放弃对训练数据里无关细节的记忆(比如某次采样的偶然波动、设备的测量误差),只学习通用的、普适的电池老化规律。简单说:池化层让模型不会 “死记硬背” 训练数据,而是真正学到老化的核心逻辑,在未见过的测试数据上表现更好。

3.ASTLSTM层

不管第一层还是第二层,单个 ATSLSTM 层的执行逻辑完全一样

固定 4 步流程(所有 ATSLSTM 通用)

  1. 走内置 LSTM:提取每个时间步的时序记忆特征
  2. 算注意力分数:给 82 个时间步打分(重要的时刻分高)
  3. 特征加权:每个时间步的特征 × 它的分数
  4. 输出结果:按参数决定输出完整序列 or 最终总结

一、第一层 ATSLSTM (24, return_sequences=True)

输入数据:(82, 46)

层内 4 步执行:

  1. LSTM 提取特征把 46 个特征 → 压缩成 24 个核心记忆特征输出临时形状:(82, 24)(82 个时刻,每个时刻 24 个老化规律)

  2. 注意力打分给 82 个时刻,每个时刻算一个重要性权重(比如电压波动大的时刻,权重更高)

  3. 特征加权82 个时刻的特征 × 对应权重,强化重要信息

  4. 输出控制(True)保留所有 82 个时间步,不合并、不丢弃

第一层最终输出:(82, 24)

二、第二层 ATSLSTM (28, return_sequences=False)

输入数据:(82, 24) (第一层的输出)

层内 4 步执行:

  1. LSTM 提取特征把 24 个特征 → 扩展成 28 个高级组合特征输出临时形状:(82, 28)

  2. 注意力打分再次给 82 个时刻重新打分,精准定位对 SOH 最关键的时刻

  3. 特征加权再次强化重要时刻的特征

  4. 输出控制(False)→ 最关键一步!把 82 个时间步的加权特征,全部加起来,合并成 1 个向量!扔掉时间维度,只保留最终总结

第二层最终输出:(28,)

(没有时间步了,只有 28 个数字,总结了 82 步所有信息)

三、最后两步

1. Dropout 层

随机扔掉 6% 的特征,防止模型死记硬背(过拟合)输入:(28,) → 输出:(28,)

2. Dense (1) 全连接层

把 28 个总结特征 → 映射成1 个数字就是你要的:电池 SOH 预测值

四、全程数据流 + 形状变化

(82, 46)  原始时序特征
↓
第一层ATSLSTM(24, True)
(82, 24)  82步全部保留,24个核心记忆
↓
第二层ATSLSTM(28, False)
(28,)     82步合并成1个总结向量,28个高级特征
↓
Dropout
(28,)
↓
Dense(1)
1个数字   最终SOH预测值

五、用最通俗的比喻,彻底刻进脑子里

第一层 ATSLSTM = 全程记笔记

  • 看 82 个时刻
  • 每个时刻都记一条笔记(24 个字)
  • 最后交上来82 条笔记

第二层 ATSLSTM = 写总结作文

  • 拿着 82 条笔记
  • 挑重点(注意力打分)
  • 把 82 条笔记揉成一篇最终作文(28 个字)
  • 只交作文,不交笔记

最终 Dense = 根据作文打分

  • 看这篇 28 字的作文
  • 给出 SOH 分数

六、一句话终极总结

  1. 第一层:保留所有时间步,提取核心时序特征
  2. 第二层:合并所有时间步,输出最终总结特征
  3. 注意力:全程给重要时刻加权,让模型只看关键信息
  4. ATSLSTM = 带重点标记的时序记忆模型

4.完整数据流

步骤 操作 形状变化 核心含义
1 加载原始 CSV (N,) → 单列长序列 4 个特征按时间交错排列
2 滑动窗口切分 (样本数, 2640) → 每个样本 2640 个数值 取连续 660 个采样点的完整数据
3 Reshape 重组 (样本数, 660, 4) → 660 行 4 列 还原为 “时间步 × 特征数” 的标准格式
4 Conv1D (None, 660, 4)(None, 165, 46) 提取 4 个特征的局部时序关联
5 MaxPooling1D (None, 165, 46)(None, 82, 46) 压缩时间维度,保留核心特征
6 ATSLSTM1 (None, 82, 46)(None, 82, 24) 注意力机制捕捉长时序依赖
7 ATSLSTM2 (None, 82, 24)(None, 28) 输出全局时序特征
8 Dense (None, 28)(None, 1) 输出最终 SOH 预测值
步骤 操作 形状变化(单个样本 / 批量) 核心含义
1 加载原始 CSV (200,) → 单列容量长序列 读取 4 个电池的容量 CSV,只取第二列容量值,各取前 50 行拼接成 200 个连续容量点
2 滑动窗口切分 (样本数, 30) → 每个样本 30 个连续容量 look_back=30 滑动窗口,取过去 30 个循环的容量作为输入特征
3 Reshape 重组 (样本数, 30)(样本数, 10, 3) 把 30 个连续容量拆成「10 个时间步 × 3 个特征」,适配 Conv1D 的 3 维输入要求
4 Conv1D (None, 10, 3)(None, 4, 52) 用 52 个 6 长度的卷积核,提取容量衰减的局部时序趋势特征
5 MaxPooling1D (None, 4, 52)(None, 2, 52) 用 2 长度池化窗口压缩时间维度,保留核心衰减特征
6 ATSLSTM (None, 2, 52)(None, 23) 仅 1 层 ATSLSTM,神经元数 23,用注意力机制捕捉容量长期衰减依赖,输出最后一个时间步的全局特征
7 Dropout (None, 23)(None, 23) 随机失活 3.5% 神经元,防止模型过拟合
8 Dense (None, 23)(None, 1) 输出最终预测值:下 1 个循环的容量

5.超参数调优

符号 对应你的代码 / 场景 人话解释
θ∗ 你训练完保存的soh_model.h5里的所有权重参数 模型的最优可训练参数
θ∈Θ 模型所有可训练参数的集合 θ包括:CNN 卷积核权重、ASTLSTM 里 LSTM 的 4 组门权重、注意力的 W/b/u、Dense 层的权重偏置;Θ是这些参数的取值范围
θ∈Θargmin​ 你代码里的 Adam 优化器 「找能让后面损失函数最小的那组参数」
EU∼GU​​ 你代码里的 12 个电池数据集(vltm5~vltm56) 对所有电池时序数据的平均误差期望,U是电池充放电时序数据,GU​是电池老化数据的分布
L(…) 你代码里的loss='mean_squared_error' 损失函数,这里就是 SOH 预测值和真实值的均方误差 MSE
Aθ​(DU​) 你的整个Sequential()模型 带参数θ的 CNN-ASTLSTM 模型,输入电池数据集DU​(你代码里的X_train),输出 SOH 预测值

找到一组最优的模型参数,让模型在所有电池数据上的平均 SOH 预测误差最小

  • 对应model.compile(loss='mean_squared_error', optimizer=adam):定义了损失函数L就是 MSE,优化器 Adam 负责求解argmin
  • 对应model.fit(X, y, ...):训练过程就是不断调整θ,让 MSE 不断变小,最终收敛到θ∗
  • 你代码里合并 12 个电池数据做训练,就是为了拟合EU∼GU​​的平均误差,保证模型对不同电池都有泛化能力

符号 对应你的代码 / 场景 人话解释
θc​ 你代码里的Conv1D层参数 CNN 卷积层的可训练参数(46 个 7 长度的卷积核权重 + 偏置)
θa​ 你代码里的ATSLSTM层 +Dense层参数 ASTLSTM 的 LSTM 门权重、注意力 W/b/u、输出层的权重偏置
k 交叉验证的折数 论文用 k 折交叉验证避免过拟合,你代码里简化为 70% 训练 / 30% 测试的单折拆分
k1​∑i=1k​ k 折交叉验证的平均损失 避免模型在单一数据集上过拟合,保证泛化能力
DU,train(i)​ 你代码里的train_scaled 第 i 折的训练集
DU,valid(i)​ 你代码里的test5_scaled 第 i 折的验证 / 测试集

公式 (10) 的可落地版本,把模型参数拆分为 CNN 和 ASTLSTM 两部分,用 k 折交叉验证训练,找让 k 折平均训练 + 验证误差最小的最优参数,避免模型只在训练集上表现好、测试集拉胯。

  • 你代码里train_size_* = int(dataset_*.shape[0] * 0.7)拆分训练 / 测试集,就是这里的Dtrain​和Dvalid​
  • 你代码里model.add(Conv1D(...))就是Aθc​​,model.add(ATSLSTM(...))就是Aθa​​
  • 你代码里的for i in range(nb_epoch)循环训练,就是每一轮都在优化θc​和θa​,让损失L不断变小

符号 对应你的调参场景 人话解释
EI Expected Improvement,期望改进值 一组超参数的「潜力值」,值越高,越有可能让模型误差更小
e∗ 当前你模型的最小测试误差(比如最小 RMSE) 目前已经找到的最好结果
e 用某组超参数训练后,模型的预测误差 随机变量,因为训练有随机性
max(e∗−e,0) 改进量 只有新误差e比当前最好的e∗还小,才有正的改进;否则改进为 0
$P_F(e \boldsymbol{\theta}_{c,a})$ 给定超参数θc,a​时,误差e的概率分布 贝叶斯优化用高斯过程拟合这个分布,猜这组超参数能得到什么误差
θc,a​ 你要调的超参数 包括 CNN 的卷积核数量 / 大小、ASTLSTM 的 units 数、学习率、dropout 率、batch_size 等

计算一组超参数(比如 ASTLSTM 的 units=32/48、学习率 0.001)的潜力:它能不能让模型的误差比现在最好的结果更低,平均能改进多少。EI 值越高,这组超参数越值得拿去训练模型。

你代码里的所有固定超参数,都是论文用这个公式遍历寻优得到的:

  • 比如ATSLSTM(24, return_sequences=True)的 24、ATSLSTM(28, return_sequences=False)的 28
  • 比如Dropout(0.0609)的 0.0609、Adam(lr=0.0009)的 0.0009
  • 比如batch_size=14nb_epoch=153

给超参数分「好坏」:

  • 如果一组超参数能让误差e比当前最优e∗还小(好超参数),就给它更高的概率ℓ(θ)
  • 如果不能带来改进(坏超参数),就给它更低的概率g(θ)用来更新贝叶斯优化的概率模型,让它越来越会猜哪些超参数是好的。

这 4 个公式是公式 (12) 的数学变形与化简,核心目的是把复杂的积分变成工程上可以直接计算的式子,最终得到公式 (17) 的可直接代码实现的 EI 计算公式

其中γ是「这组超参数能带来改进的概率」,整个式子就是把公式 (12) 的积分,用贝叶斯定理、全概率公式化简后,得到的可直接计算的最终 EI 值

用 ** 公式 (10)(11)** 定义模型训练目标,用你的代码训练初始 CNN-ASTLSTM 模型,得到当前最优误差e 

 用 ** 公式 (12)-(17)** 的 EI 准则,做贝叶斯优化:遍历超参数组合,计算每个组合的 EI 值

符号 对应你的论文 / 代码 人话解释
P^ℓ/g​(θc,a​) 超参数的概率密度估计值 「当前这组超参数θc,a​是好参数 / 坏参数」的概率,对应之前公式 (13) 的ℓ(好参数,误差小)、g(坏参数,误差大)
k 已经试过的超参数组合总数 比如你已经试了 10 组不同的 ASTLSTM units、学习率组合,k=10
h 核函数的带宽(窗口大小) 控制概率分布的平滑程度,值越大分布越平滑,越小越贴合样本
kh1​ 归一化系数 保证最终算出来的概率总和为 1,符合概率分布的定义
KG​ 高斯核函数(Gaussian Kernel) 最常用的平滑核函数,把离散的样本点拟合成连续的概率分布
L(Aθc,a​​,DU​) 当前待评估超参数的模型损失 就是你代码里的 MSE 均方误差(SOH 预测值和真实值的误差)
L(Aθc,a​(i)​,DDU​(i)​) 第i组已试过的超参数的损失 之前训练得到的历史误差值

你已经试了k组超参数,知道每组超参数对应的模型误差是多少。这个公式就是用这些历史样本,通过高斯核平滑,拟合出「任意一组新超参数,能让模型误差变小的概率」

给你之前的 EI 期望改进公式提供核心的PF​概率分布 —— 只有知道了超参数对应的误差概率,才能算出这组超参数的潜力值,决定要不要拿它去训练模型。

符号 对应你的场景 人话解释
Fe​(e) 误差的经验累积分布函数 「模型误差小于等于e的概率」
n 已有的模型误差样本总数 比如你训练了 20 次模型,得到了 20 个测试误差,n=20
Ej​ 第j个历史误差样本 每次训练得到的 SOH 预测 RMSE/MSE 值
I[−∞,e]​(Ej​) 指示函数(示性函数) 规则非常简单:如果Ej​≤e,函数值 = 1;否则 = 0

把你所有历史训练得到的误差从小到大排序,数一下「有多少个误差小于等于当前的e」,再除以总样本数n,得到的就是误差不超过e的概率

举个例子:你有 100 个误差样本,其中 35 个小于 0.05,那么Fe​(0.05)=35/100=0.35,也就是「模型误差≤0.05 的概率是 35%」。

给后面的 KS 检验(公式 20)提供「真实的样本分布」,用来和你拟合的理论分布做对比,验证分布的准确性。

符号 对应你的场景 人话解释
Dn​ KS 检验统计量 衡量「拟合分布」和「真实样本分布」的最大差距,值越小,拟合越准
supe​ 上确界(可以理解为「最大值」) 遍历所有可能的e,找到两个分布的最大差值
Fe​(e) 公式 (19) 算出来的经验分布 你的真实误差样本的分布(标准答案)
F(e) 公式 (18) 拟合出来的理论分布 你用来算 EI 的分布(待验证的答案)

这个公式是检查你用公式 (18) 拟合的概率分布,和你实际的误差样本分布,最大的差距有多大

  • Dn​越小:拟合的分布越接近真实情况,你算出来的 EI 值越靠谱,选出来的超参数越准
  • Dn​越大:拟合的分布严重偏离真实情况,EI 准则会失效,选出来的超参数不可信

贝叶斯优化的核心是「靠概率分布选超参数」,如果分布拟合错了,整个优化就白做了。KS 检验就是用来给你拟合的分布「做质检」的。

符号 对应你的场景 人话解释
K 你算出来的 KS 统计量Dn​(公式 20) 你的分布拟合误差
Kα​ KS 检验的临界值 固定查表得到的数值,由显著性水平α和样本量n决定(比如α=0.05,n=100时,Kα​≈0.136)
α 显著性水平 常用值α=0.05,代表「5% 的误判概率」
1−α 置信水平 对应α=0.05,置信水平就是 95%

如果你的 KS 统计量Dn​≤Kα​,那么你就有(1−α)的把握说:我拟合的分布和真实的误差分布是一致的,可以用来做 EI 计算和超参数优化

举个例子:α=0.05,你算出来的Dn​=0.11,小于临界值Kα​=0.136,那么你就有 95% 的把握,确认你拟合的分布是合格的。

给你的分布拟合结果「下最终结论」:只有通过了这个检验,你才能放心用 EI 准则去寻优;如果没通过,就需要增加更多的超参数样本,重新拟合分布。

这 4 个公式和之前的 EI 公式,共同组成了论文里的全自动超参数优化流程:
先随机试几组超参数,得到
k
组超参数对应的模型损失(就是你代码里的 MSE)
用公式 (18) 核密度估计,拟合出超参数对应的误差概率分布
用公式 (19) 计算误差的经验分布,再用公式 (20) 算 KS 统计量,检查拟合的分布和真实分布的差距
用公式 (21) 判断:如果D n​ ≤K α,说明分布合格;否则增加样本重新拟合
分布合格后,代入之前的 EI 公式,计算所有候选超参数的 EI 值,选 EI 最高的一组去训练模型
把新训练得到的损失加入样本库,重复上述步骤,直到找到最优超参数(就是你代码里用的 24/28、0.0009、0.0609 这些值)

6.SOH训练与预测

公式符号 对应含义 和你代码的关系
SOH 电池真实健康状态,行业标准定义为「当前实际容量 / 出厂初始容量 ×100%」 你代码里训练用的标签 y
F(…) 电池测试台的「实测容量计算逻辑」(库仑计数法) 不是代码实现的,是实验室硬件设备完成的,代码只需要用它的结果
U(V,T,I,t),tHi​​ 第i个充放电循环里,电压 (V)、温度 (T)、电流 (I)、时间 (t) 的历史时序数据 完全对应你代码里的输入特征 X,也就是 CSV 里前 2640 个点,reshape 成 (660,4) 的部分
sw​ 滑动窗口长度 完全对应你代码里的look_back=2640(reshape 后 660 个时间步)
∣UCHi​​ 条件项:给定第i个循环的历史实测容量 电池测试台实测的电池当前实际容量,用来计算真实 SOH
C0​ 电池出厂标称的初始容量(固定常数,比如 2.4Ah) 预处理阶段用来把实测容量转成 SOH 百分比,代码里不直接出现
×100% 把比值转成百分比(100%= 全新电池,80%= 行业通用报废阈值) 预处理阶段提前完成,代码里的标签直接是百分比数值

电池的真实 SOH,是用专业测试台通过充放电实验实测的当前容量,除以电池出厂的初始容量,得到的百分比。实测容量的计算,依赖该循环的电压、电流、温度、时间时序数据,以及历史循环的实测容量。

你代码里的标签 y,就是用这个公式在数据集预处理阶段提前算好的

  1. 电池测试台给每个充放电循环做实验,实测出当前容量UCHi​​
  2. 用公式 (22) 算好 SOH = 实测容量 /C0​×100%
  3. 把这个 SOH 值放在 CSV 文件里每 2641 个点的最后 1 个位置(也就是你代码里dataset[i + look_back]取的那个值)
  4. 你的代码直接读取这个值当训练标签,不需要自己实现容量计算和 SOH 转换,所以你在代码里看不到C0​、UC​这些符号。

公式符号 对应含义 和你代码的关系
SOH 模型预测的 SOH 值 完全对应你代码里Dense(1)层的最终输出
F(…) 这里就是你训练好的CNN-ASTLSTM 神经网络模型 完全对应你代码里的Sequential()结构,从 Conv1D、MaxPooling、两层 ASTLSTM、Dropout 到 Dense 的完整流程
U(V,T,I,t),tOj​​ 第j个待预测的测试集 / 在线采集的 V/T/I/t 时序数据 你代码里的测试集输入 X,或者推理时的实时电池数据
无∣UCHi​​ 推理时不需要历史实测容量,只需要 V/T/I/t 四个特征 完全符合你的代码逻辑:模型输入只有 4 维特征,不需要任何容量、历史 SOH 数据

把待预测的电压、电流、温度、时间时序数据,喂给训练好的 CNN-ASTLSTM 模型,模型输出预测的当前容量,再除以初始容量转成百分比,就是最终的预测 SOH 值。

你的代码做了一个工程简化,把「除以C0​转百分比」的步骤提前做到了标签预处理里:

  • 论文标准逻辑:模型输出预测容量 → 除以C0​ → 得到 SOH(公式 23)
  • 你的代码逻辑:标签提前算成 SOH 百分比 → 模型直接学习「V/T/I/t 时序数据 → SOH 百分比」的映射,输出就是 SOH,不需要再做除以C0​的操作

这个公式就是你整个代码的核心目标:训练一个 CNN-ASTLSTM 模型,输入电池的时序运行数据,输出准确的 SOH 预测值。

怎么通过电压电流温度时间求当前实际容量,我在代码里怎么没找到?

你的代码里确实没有「通过电压 / 电流 / 温度 / 时间计算当前容量」的逻辑!

原因很简单:

  1. 电池容量不是靠 V/T/I/t 算出来的,是电池测试台直接「实测」出来的
  2. 你的代码是直接从 CSV 文件里读取已经算好 / 实测好的容量 / SOH 标签,不需要自己算

我在数据集里没有找到标签,根据代码帮我找找?

  1. 你的 CSV 是单列数据,不是多列
  2. 标签位置:每 2641 个数据点里的 第 2641 个点
  3. 输入特征:前 2640 个点,按 V/T/I/t 顺序排列,reshape 成 (660, 4)

你可以打开你的 CSV 文件,数一下:

  • 第 2641 行、第 5282 行(2641×2)、第 7923 行(2641×3)……
  • 这些行里的数值,就是 SOH 标签!(应该是在 0.8 到 1.0 之间的小数,或者 80 到 100 之间的百分比)

验证:打开data中的vltm5,找到2641行,值为1.8565,打开5-capacity,能对应。

7.RUI训练与预测

公式 24:真实 RUL 怎么算

代码里的真实含义

  • qeol​ = 电池报废的循环号(第 168 次循环)

  • qs​ = 你开始预测的循环号(第 50 次循环)

forecast_predict = make_forecast(..., timesteps=118)

118 = 168 - 50

还能跑多少次循环 = 报废总次数 - 已经跑到的次数

公式 25:预测 RUL 怎么算

代码里的含义

  • q^​eol​ = 模型预测出来的报废循环号

  • qs​ = 50(不变)

make_forecast 预测未来118步容量
→ 找到预测容量 < 1.295 的那一步
→ 步数就是 RUL

模型预测还能跑多少次循环 = 预测的报废循环号 - 当前循环号

公式 26:训练阶段(你的模型训练全过程)

q^​eol(train)​=F(UC,qs​​,…,UC,qs​−sw​+1​∣UC,qs​+1​,…)

公式符号

代码里是什么

F

你的 CNN-ASTLSTM 模型

UC,qs​...​

过去 30 个容量

UC,qs​+1​

第 31 个容量(标签)

sw​

look_back = 30

# 造训练数据:30个容量 → 预测下1个容量
a = dataset[i:i+look_back]  # 前30个 → 特征X
data_y.append(dataset[i+look_back])  # 第31个 → 标签Y

训练:用前 30 个容量,学习预测下一个容量这就是公式 26 的全部。

公式 27:预测阶段(滚动多步预测)

q^​eol(online)​=F(UCP​,UCO​)

符号

代码含义

UCO​

真实历史容量

UCP​

模型预测出来的容量

F

训练好的 CNN-ASTLSTM

def make_forecast(...):
    cur_predict = model.predict(...)  # 预测下一个
    look_back_buffer = delete(old)    # 删掉最老
    look_back_buffer = concat(new)    # 加入新预测

用真实历史开头 → 模型一步一步往后猜 → 直到报废 → 步数就是 RUL

最终极简总结:

公式 24:真实 RUL = 168 - 50 = 118

公式 25:预测 RUL = 预测报废点 - 50

公式 26:训练 = 30 个容量 → 预测下 1 个容量

公式 27:预测 = 滚动往后猜 118 步 → 得到 RUL

四.数值实验

该研究利用一个包含34个锂离子电池(编号#5-7, 18, 25-32, 33-34, 36, 38-56)的放电过程数据作为基准数据集。为了SOH估计和RUL预测任务,对数据进行了特定的预处理和结构化。具体而言,每个电池的数据被重塑为一个三维数组,其维度分别代表:

  1. 类型维度(Type dimension):包含不同类型的数据,即容量(C)、电压(V)、电池温度(T)、电流(I)和采样时间(t)。这些是表征电池健康状态和退化过程的关键多物理量特征。
  2. 采样维度(Sampling dimension):存储每种数据类型在特定采样间隔内的具体测量值,反映了数据在时间轴上的细粒度变化。
  3. 循环维度(Cycle dimension):按顺序包含放电过程的循环次数,用于追踪电池的长期老化过程。

在数据集划分方面,针对SOH任务,数据被随机划分为70%的训练数据和30%的测试数据。对于RUL任务,则选取3个电池(#5, 6, 18)的前50个循环数据作为训练集,其余循环数据用于测试。此外,为了全面评估模型的鲁棒性,额外选择了16个电池(#29-34, 36, 38-44, 49, 52)的数据专门用于测试容量预测,这些鲁棒性测试数据不参与模型的训练过程,确保了评估的独立性和客观性。

  • 放电过程容量 (Discharge-process capacity):电池在特定放电循环中释放的电量,是评估电池健康状况(SOH)和剩余使用寿命(RUL)的关键指标之一。
  • 三维数组 (Three-dimensional array):一种数据结构,用于存储和组织多维度、多类型的时间序列数据,通常包括数据类型(如V、T、I、C)、采样点和循环次数维度,便于神经网络处理。
  • 类型维度 (Type dimension):数据重塑后三维数组的一个维度,用于区分不同的测量物理量,如容量(C)、电压(V)、电池温度(T)、电流(I)和采样时间(t)。
  • 采样维度 (Sampling dimension):数据重塑后三维数组的一个维度,表示在每个数据类型(如V、T、I、C)下,根据采样间隔存储的具体测量值序列。
  • 循环维度 (Cycle dimension):数据重塑后三维数组的一个维度,按顺序记录电池的放电循环次数,用于跟踪电池的老化和性能退化过程。
  • SOH任务 (SOH task):指电池健康状态(State-of-Health)估计任务,旨在预测电池当前的健康水平。
  • RUL任务 (RUL task):指剩余使用寿命(Remaining Useful Life)预测任务,旨在预测电池还能正常工作的循环次数或时间。
  • 训练数据 (Training data):用于训练机器学习模型的数据子集,模型通过学习这些数据的模式来建立预测能力。
  • 测试数据 (Test data):用于评估已训练模型性能的数据子集,这些数据在训练过程中未被模型学习过,以检验模型的泛化能力。
  • 鲁棒性 (Robustness):模型在面对未见过的数据、噪声或不同操作条件下,仍能保持良好性能的能力。
  • 容量预测 (Capacity prediction):根据历史数据估算电池当前或未来可用容量的过程。

QA1这段话怎么理解,但是根据代码,soh的数据被分成了4维,rul的数据被分成了3维才对啊?

论文里说的「三维数组」是概念上的维度定义,你代码里的「4 维 / 3 维」是工程实现上的张量形状,两者本质完全一致,只是:

  1. 论文的「类型维度」在 SOH 代码里是 4 个特征(V/T/I/t),在 RUL 代码里被拆成了 3 个伪特征(纯为了适配 Conv1D 输入)
  2. 论文的「采样维度」在 SOH 代码里是 660 个采样点,在 RUL 代码里是 10 个时间步
  3. 论文的「循环维度」在两者代码里都是「样本数」

一、先拆解论文里的「概念三维数组」定义

论文里说的三维是从数据物理含义出发的分类,不是代码里的张量维度数:

论文概念维度

物理含义

包含内容

类型维度

数据的物理类型

容量 (C)、电压 (V)、温度 (T)、电流 (I)、采样时间 (t) → 共 5 种类型

采样维度

时间轴上的细粒度采样点

每个充放电循环里,按固定间隔采集的测量值(比如一个循环采 660 个点)

循环维度

长期老化的循环次数

第 1 次充放电、第 2 次... 第 N 次循环 → 用于追踪老化

二、对应你的 SOH 代码:(样本数,660, 4) 怎么对应论文三维?

你的 SOH 代码输入形状是 (样本数, 660, 4),完全对应论文的概念三维:

论文概念维度

SOH 代码里的对应

说明

循环维度

样本数

每个样本对应一个充放电循环,样本数 = 循环数

采样维度

660

每个循环里有 660 个细粒度采样点

类型维度

4

论文提了 5 种类型,你代码只用了 4 种:电压 (V)、温度 (T)、电流 (I)、时间 (t),没单独用容量 (C) 当输入(容量是用来算标签 SOH 的)

三、对应你的 RUL 代码:(样本数,10, 3) 怎么对应论文三维?

你的 RUL 代码输入形状是 (样本数, 10, 3),这里有个工程变形,但本质还是论文的概念三维:

论文概念维度

RUL 代码里的对应

说明

循环维度

样本数

每个样本对应一段连续的循环历史,样本数 = 循环相关的样本数

采样维度

10

把论文里的「30 个连续循环的容量」,拆成了 10 个时间步(纯为了适配 Conv1D 的 3 维输入要求)

类型维度

3

论文里 RUL 只用了 1 种类型(容量 C),你代码把 30 个容量强行拆成了「10 个时间步 ×3 个伪特征」,这里的 3 没有物理含义,只是为了满足input_shape=(10,3)

RUL 代码的 (样本数,10,3),是论文概念三维的「工程适配版」

  • 本质还是用「循环维度的历史数据」+「采样维度的容量序列」

  • 只是因为 Conv1D 要求 3 维输入,你把 1 个容量类型拆成了 3 个伪特征,把 30 个采样点拆成了 10 个时间步,没有改变论文的三维数据结构本质。

四、总结:为什么看起来不一样但本质一致?

对比项

论文概念三维

SOH 代码实现

RUL 代码实现

循环维度

循环次数

样本数

样本数

采样维度

细粒度采样点

660 个采样点

10 个时间步(30 个循环拆成)

类型维度

C/V/T/I/t(5 种)

V/T/I/t(4 种)

容量 C(1 种拆成 3 个伪特征)

张量形状

概念三维

(样本数,660,4)

(样本数,10,3)

核心原因:论文说的是「数据怎么组织」的物理概念,你代码写的是「怎么喂给模型」的工程实现

  • SOH 代码完全贴合论文概念,用了 4 种物理类型、660 个采样点

  • RUL 代码为了适配 Conv1D 的 3 维输入要求,做了一个小的 reshape 变形,把 1 种类型拆成了 3 个伪特征,但本质还是用「循环历史 + 容量序列」的三维数据结构。

1.CNN-ASTLSTM神经网络超参数分布

核心内容: 本节详细阐述了在健康状态(SOH)估计剩余使用寿命(RUL)预测任务中,如何通过Kolmogorov-Smirnov (KS) 检验来确定 CNN-ASTLSTM 神经网络及其他基准模型超参数的先验分布。这一过程是贝叶斯优化自动配置超参数的基础,旨在减少人工干预并提高模型的可复现性。

主要步骤和要点:

  1. 超参数配置空间定义与初始化:

    • 首先定义了 CNN-ASTLSTM NN 以及其他对比模型(如RNN、S-LSTM、AST-LSTM、CNN-LSTM)的超参数配置空间。
    • 对每个超参数(如卷积层数Lc、核数量Kn、核大小Ks、步长s、池化大小Ps、LSTM隐藏层Lh、块数Nb、最后一层神经元数Nl、学习率lr、批次大小b、训练轮数epoch、丢弃率dr等)进行了初始赋值。
    • 特别指出,某些超参数(如Lc、sw、pw)没有进行KS检验,因为它们的配置是手动设定的或不适合自动优化。
  2. 损失函数与独立试验:

    • 选择**均方误差(MSE)**作为评估模型性能的损失函数。
    • 针对每个超参数,在保持其他超参数不变的情况下,进行十次独立的随机试验。每次试验都会得到一个不同的模型配置和相应的MSE损失函数值。
  3. 概率密度估计与KS检验:

    • 使用标准核函数估计方法,基于十次试验的损失函数值来估计每个超参数的概率密度(如图3所示)。
    • 运用Kolmogorov-Smirnov (KS) 检验来判断这些估计出的概率密度是否符合候选分布函数(如均匀分布、对数均匀分布、高斯分布、对数正态分布)。
    • 如果估计的密度在显著性水平 α≤0.1α≤0.1 下不被接受,则会进行更多次试验,直到找到一个可接受的分布函数。
  4. 先验分布的确定与汇总:

    • 通过KS检验确定的分布函数类型,结合试验中观察到的间隔、均值和标准差,构建了超参数的先验分布
    • 表1和表2分别汇总了SOH和RUL任务中,各种神经网络超参数的先验分布。

结论: 本节强调了即使SOH和RUL任务的数据整理和目标不同,大部分超参数的函数类型(即先验分布)在两种任务中保持一致,除了少数几个(如Lh、s和dr)。这一系统化的方法为后续的贝叶斯优化奠定了基础,使其能够自动选择最有前景的超参数配置,从而提高模型的准确性和可重复性。

表 1 SOH任务中神经网络超参数的先验分布

总体目的: 这张表格的核心目的是为各种神经网络模型(RNN, S-LSTM, AST-LSTM, CNN-LSTM, CNN-ASTLSTM)在进行锂电池SOH估计时,提供其关键超参数的先验分布信息。这些先验分布是贝叶斯优化算法的基础,它能够指导算法在超参数空间中高效搜索最优配置,从而减少手动调参的工作量,并提高模型性能的可复现性。简单来说,它告诉我们每个超参数在被优化之前,最可能服从哪种统计分布,以及该分布的具体参数(如均值、标准差或范围)。

表格结构与内容拆解:

表格分为两大部分:

  • 第一列:Hyperparameters (超参数) - 列出了参与优化的各种神经网络超参数的名称。
  • 顶部行:Methods (方法) - 列出了五种不同的神经网络模型,它们是本研究中用于SOH估计的对比模型或提出的模型。

接下来,我们将逐行解释每个超参数及其在不同方法中的先验分布:

  1. K_n (卷积核数量)

    • RNN, S-LSTM, AST-LSTM: 这些模型由于不包含卷积层,因此该超参数不适用,用“—”表示。
    • CNN-LSTM: log N (3.30, 0.18)。这表示卷积核数量的对数服从均值为3.30,标准差为0.18的正态分布。
    • CNN-ASTLSTM: log N (3.69, 0.14)。与CNN-LSTM类似,但均值和标准差略有不同。
  2. K_s (卷积核大小)

    • RNN, S-LSTM, AST-LSTM: 不适用。
    • CNN-LSTM: log N (1.61, 0.18)。卷积核大小的对数服从均值为1.61,标准差为0.18的正态分布。
    • CNN-ASTLSTM: log N (1.95, 0.11)
  3. s (步长)

    • RNN, S-LSTM, AST-LSTM: 不适用。
    • CNN-LSTM: N (3, 0.45)。步长服从均值为3,标准差为0.45的正态分布。
    • CNN-ASTLSTM: N (4, 0.50)。步长服从均值为4,标准差为0.50的正态分布。
  4. P_s (池化大小)

    • RNN, S-LSTM, AST-LSTM: 不适用。
    • CNN-LSTM: N (5, 1.20)。池化大小服从均值为5,标准差为1.20的正态分布。
    • CNN-ASTLSTM: N (3, 0.50)。池化大小服从均值为3,标准差为0.50的正态分布。
  5. L_h (LSTM隐藏层数量)

    • RNN: U (1, 4)。隐藏层数量服从1到4之间的均匀分布。
    • S-LSTM, AST-LSTM, CNN-LSTM, CNN-ASTLSTM: 它们的对数都服从均值为0.69,标准差分别为0.18或0.10的正态分布。这表明在这些模型中,隐藏层数量的对数在一个相对狭窄的范围内。
  6. N_b (块数量)

    • RNN: log N (3.69, 0.34)。块数量的对数服从均值为3.69,标准差为0.34的正态分布。
    • S-LSTM, AST-LSTM, CNN-LSTM, CNN-ASTLSTM: 它们的对数都服从均值在3.40到4.87之间,标准差在0.14到0.26之间的正态分布。
  7. lr (学习率)

    • 所有模型(RNN, S-LSTM, AST-LSTM, CNN-LSTM, CNN-ASTLSTM)的学习率的对数都服从正态分布。均值在-7.01到-5.65之间,标准差在0.18到0.26之间。这通常意味着学习率本身是一个非常小的正数,因为其对数是负值。
  8. b (批次大小)

    • 所有模型的批次大小的对数都服从正态分布。均值在2.30到3.22之间,标准差在0.41到0.64之间。
  9. e (训练轮数)

    • 所有模型的训练轮数的对数都服从正态分布。均值在4.70到5.14之间,标准差在0.14到0.18之间。
  10. dr (丢弃率)

    • RNN, S-LSTM, AST-LSTM, CNN-LSTM: 丢弃率的对数都服从负均值(-3.69到-3.00)和0.18到0.26的标准差的正态分布。这表明丢弃率本身是一个相对较小的值。
    • CNN-ASTLSTM: U (0.01, 0.10)。丢弃率服从0.01到0.10之间的均匀分布。这是一个有趣的例外,表明在CNN-ASTLSTM模型中,丢弃率的先验分布被确定为一个特定范围内的均匀分布,而不是对数正态分布。

关键信息点明:

  • 分布类型: 表格中主要出现了两种类型的分布:

    • U (a, b) (均匀分布): 表示超参数值在 a 和 b 之间等概率取值。例如,RNN的L_h超参数。
    • log N (μ, σ) (对数正态分布): 表示超参数值的对数 log(X) 服从均值为 μ,标准差为 σ 的正态分布。这种分布常用于超参数搜索,因为它允许参数在较大范围内变化,且能更好地处理乘性效应。例如,K_nK_sL_hN_blrbedr 中的大多数。
    • N (μ, σ) (正态分布): 表示超参数值服从均值为 μ,标准差为 σ 的正态分布。例如,CNN-LSTM和CNN-ASTLSTM的sP_s超参数。
  • 模型差异性:

    • 非卷积模型(RNN, S-LSTM, AST-LSTM) 没有K_nK_ssP_s等卷积层相关超参数的先验分布,因为它们不包含卷积结构。
    • CNN-ASTLSTM 作为本文提出的混合模型,其超参数先验分布与其他模型有所不同,特别是在dr(丢弃率)上,它采用了均匀分布,而非对数正态分布,这可能反映了该模型对丢弃率的敏感性或其优化空间的不同特性。
  • 贝叶斯优化的基础: 这些先验分布是贝叶斯优化算法的起点。算法会根据这些先验知识,结合每次实验得到的模型性能(损失函数值),更新对超参数真实分布的“信念”(后验分布),并据此选择下一组最有希望的超参数组合进行评估,从而更有效地找到最优解。

总之,这张表格为理解研究中超参数自动优化过程提供了关键的输入信息,展示了不同模型在SOH任务中,其超参数在经过预分析后被假定服从的统计行为。

QA2这些参数表里的数据都是哪里来的?

这些参数表(包括您提到的 SOH 任务超参数表和 RUL 任务超参数表)里的数据,是论文作者通过一个特定的过程推导和确定的,而不是凭空设定的。这个过程的核心是Kolmogorov-Smirnov (KS) 检验经验分布函数

以下是这些数据来源的详细解释:

  1. 超参数配置空间的定义与初始化:

    • 首先,作者需要为每个神经网络模型(如 CNN-ASTLSTM NN、CNN-LSTM NN、RNN 等)定义一个超参数的初始赋值。这些初始值是用于启动实验的起点,例如在第 5 页的 3.1 节 SOH Task 部分提到,CNN-ASTLSTM NN 和 CNN-LSTM NN 的初始超参数赋值为 {L_c = 1, K_n = 32, K_s = 4, s = 4, P_s = 2, L_h = 1, N_b = 32, N_l = 1, I_r = 0.001, b = 64, e = 50, dr = 0.1}
    • 对于那些不属于卷积层的模型(如 RNN、S-LSTM、AST-LSTM),它们没有卷积相关的超参数(L_cK_nK_ssP_s)。
  2. 独立试验与损失函数值的生成:

    • 为了确定每个超参数的先验分布,作者针对每个超参数独立进行了一系列试验。例如,在 SOH 任务中,作者“指定了十个随机种子来执行一个超参数的十次独立试验,保持其余超参数不变”(第 5 页 3.1 节)。
    • 在每次试验中,作者使用均方误差 (MSE) 作为损失函数来评估模型的性能。
    • 这样,对于每个被独立试验的超参数,都会得到十个对应的损失函数值
  3. 概率密度估计 (Probability Density Estimation):

    • 得到了十个损失函数值后,作者使用标准核函数 (standard kernel function) 的估计器来估计这些损失函数值的概率密度 (probability densities)。这在图 3 中有直观展示,图中 (a)-(j) 就是不同超参数对应的损失函数值概率密度图。
  4. Kolmogorov-Smirnov (KS) 检验的应用:

    • 核心步骤: 接下来,作者使用 Kolmogorov-Smirnov (KS) 检验来确定哪种预定义的分布函数类型(如均匀分布 U(a, b)、对数均匀分布 logU(a, b)、高斯分布 N(μ, σ)、对数正态分布 logN(μ, σ))最能**“接受”**上述估计出的概率密度。
    • 如何工作: KS 检验通过比较经验分布函数 (Empirical Distribution Function, ECDF) 和理论累积分布函数 (Cumulative Distribution Function, CDF) 之间的最大距离来判断样本是否来自某个特定分布。如果距离小于临界值,则接受原假设(即样本来自该理论分布)。
    • 参数确定: 如果一个分布类型被接受,那么该分布的参数(例如,U(a, b) 中的 a 和 bN(μ, σ) 和 logN(μ, σ) 中的 μ 和 σ)就是根据这十次试验中观察到的区间、均值和标准差来确定的。
  5. 迭代与细化:

    • 如果初步的十次试验得到的概率密度在设定的显著性水平 α (例如 α ≤ 0.1) 下不能被任何预定义分布函数接受,作者会进行更多的试验,直到找到一个能够被接受的分布。

总结来说,这些数据的来源是一个系统性的统计推断过程:

  • 起始点: 神经网络超参数的初始配置。
  • 实验数据: 通过对每个超参数进行独立试验并计算损失函数值而获得的样本数据。
  • 统计工具: 使用核密度估计器计算损失函数值的概率密度。
  • 核心算法: 运用 Kolmogorov-Smirnov (KS) 检验来选择最匹配这些概率密度的理论分布类型。
  • 参数提取: 根据被选定的理论分布,从实验数据中提取其参数(均值、标准差或范围),从而形成表格中所示的“先验分布”。

这些先验分布随后被贝叶斯优化算法用作代理模型 (surrogate model) 的一部分,以指导超参数的进一步搜索和优化,以找到模型的最佳配置。

表2 神经网络在剩余使用寿命(RUL)任务中超参数的先验分布

总体目的:

这个表格的目的是展示在进行锂电池剩余使用寿命 (RUL) 预测任务时,不同神经网络模型(具体是 AST-LSTM 和 CNN-ASTLSTM)的关键超参数所服从的先验分布。这些先验分布是贝叶斯优化算法的基础,用于自动选择最优的超参数配置,从而减少人工调参的工作量,并提高模型的性能。简而言之,它告诉我们每个超参数在优化开始前,根据实验数据和统计检验,被认为最可能遵循的统计规律和参数范围。

内容结构与分步拆解:

表格分为三列:

  1. Hyperparameters (超参数):列出了神经网络模型中需要优化的各个超参数的名称。
  2. Methods (方法):这一列进一步细分为 AST-LSTM 和 CNN-ASTLSTM,代表了两种不同的神经网络模型。表格中显示了这两种模型下对应超参数的先验分布。

现在,我们逐行解释每个超参数的含义及其在两种模型下的先验分布:

超参数详解:

  1. KnKn​ (卷积层核数量,Kernels in convolutional layer)

    • 含义:表示一维卷积神经网络 (1D CNN) 中每个卷积层使用的滤波器(或称为核)的数量。每个滤波器负责提取输入数据中的特定特征。
    • AST-LSTM:表格中显示为 "-"。这表示 AST-LSTM 模型本身不包含卷积层,因此没有此超参数。
    • CNN-ASTLSTMlog N (4.25, 0.22)。这表示 KnKn​ 的对数服从一个均值为 4.25,标准差为 0.22 的正态分布。这意味着 KnKn​ 本身服从对数正态分布,其值通常围绕 exp⁡(4.25)exp(4.25) 且具有一定的波动性。对数正态分布常用于描述取值范围为正数且偏斜的数据。
  2. KsKs​ (卷积核大小,Kernel size)

    • 含义:表示卷积核的长度。核大小决定了卷积层在输入数据上“看到”的局部感受野范围。
    • AST-LSTM:"-",同 KnKn​,AST-LSTM 不含卷积层。
    • CNN-ASTLSTMlog N (1.50, 0.26)。KsKs​ 的对数服从一个均值为 1.50,标准差为 0.26 的正态分布。同样,这意味着 KsKs​ 本身服从对数正态分布。
  3. ss (步长,Stride size)

    • 含义:表示卷积核在输入数据上移动的步长。步长会影响输出特征图的空间尺寸。
    • AST-LSTM:"-",同 KnKn​,AST-LSTM 不含卷积层。
    • CNN-ASTLSTMlog N (1.25, 0.18)。ss 的对数服从一个均值为 1.25,标准差为 0.18 的正态分布。ss 也服从对数正态分布。
  4. PsPs​ (池化大小,Pool size)

    • 含义:表示池化层(通常是最大池化或平均池化)的窗口大小,用于下采样特征图,减少维度并提高模型的鲁棒性。
    • AST-LSTM:"-",同 KnKn​,AST-LSTM 不含卷积层。
    • CNN-ASTLSTMN (1.40, 0.21)。这表示 PsPs​ 服从一个均值为 1.40,标准差为 0.21 的正态分布。正态分布表示 PsPs​ 的值集中在均值附近。
  5. LhLh​ (隐藏层数量,Hidden layers)

    • 含义:指长短期记忆 (LSTM) 或 AST-LSTM 网络中隐藏层的数量。多层可以捕获更复杂的时序依赖关系。
    • AST-LSTMlog N (0, 0.18)。LhLh​ 的对数服从一个均值为 0,标准差为 0.18 的正态分布。
    • CNN-ASTLSTMN (1.20, 0.22)。LhLh​ 服从一个均值为 1.20,标准差为 0.22 的正态分布。
  6. NbNb​ (块数量,Number of blocks)

    • 含义:在 AST-LSTM 模型中,这指的是网络中 AST-LSTM 块的数量。每个块包含门控机制和记忆单元,用于处理时序信息。
    • AST-LSTMlog N (4.09, 0.18)。NbNb​ 的对数服从一个均值为 4.09,标准差为 0.18 的正态分布。
    • CNN-ASTLSTMlog N (3.69, 0.29)。NbNb​ 的对数服从一个均值为 3.69,标准差为 0.29 的正态分布。
  7. lrlr (学习率,Learning rate)

    • 含义:优化算法(如 Adam)在训练过程中更新模型权重时使用的步长。学习率对模型的收敛速度和最终性能至关重要。
    • AST-LSTMlog N (-7.13, 0.26)。lrlr 的对数服从一个均值为 -7.13,标准差为 0.26 的正态分布。这意味着 lrlr 本身服从对数正态分布,其值通常较小。
    • CNN-ASTLSTMlog N (-7.26, 0.26)。lrlr 的对数服从一个均值为 -7.26,标准差为 0.26 的正态分布。
  8. bb (批次大小,Batch size)

    • 含义:在每次模型参数更新之前,用于训练的样本数量。批次大小影响训练的稳定性和计算效率。
    • AST-LSTMlog N (3.22, 0.30)。bb 的对数服从一个均值为 3.22,标准差为 0.30 的正态分布。
    • CNN-ASTLSTMlog N (3.09, 0.26)。bb 的对数服从一个均值为 3.09,标准差为 0.26 的正态分布。
  9. ee (训练周期,Epoch)

    • 含义:表示整个训练数据集被模型遍历的次数。
    • AST-LSTMlog N (4.61, 0.26)。ee 的对数服从一个均值为 4.61,标准差为 0.26 的正态分布。
    • CNN-ASTLSTMlog N (4.58, 0.26)。ee 的对数服从一个均值为 4.58,标准差为 0.26 的正态分布。
  10. drdr (丢弃率,Dropout rate)

    • 含义:一种正则化技术,在训练过程中随机丢弃(设置为零)一部分神经元的输出,以防止过拟合。
    • AST-LSTMN (5.5e-2, 9e-3)。drdr 服从一个均值为 5.5×10−25.5×10−2 (即 0.055),标准差为 9×10−39×10−3 (即 0.009) 的正态分布。
    • CNN-ASTLSTMlog N (-3.00, 0.26)。drdr 的对数服从一个均值为 -3.00,标准差为 0.26 的正态分布。

核心信息与设计原理:

这个表格揭示了以下关键信息和设计原理:

  1. 模型架构差异导致超参数不同

    • AST-LSTM 模型不包含卷积层,因此没有与卷积相关的超参数(Kn,Ks,s,PsKn​,Ks​,s,Ps​),这些在表格中以 "-" 表示。
    • CNN-ASTLSTM 模型结合了 CNN 和 AST-LSTM,因此它拥有所有这些超参数。CNN 部分用于从原始电池数据中提取分层特征 (hierarchical features),而 AST-LSTM 部分则用于捕获这些特征中的时间依赖性 (temporal dependencies)
  2. 先验分布类型的重要性

    • 大多数超参数的先验分布被确定为对数正态分布 (log⁡NlogN) 或正态分布 (NN)
      • 对数正态分布常用于描述那些取值必须为正数,且其效应呈现乘性而非加性(例如学习率、批次大小、核数量等)的超参数。使用对数正态分布意味着在对数空间中进行均匀或正态采样,这在优化中更为有效,因为它可以更均匀地探索不同数量级的值。
      • 正态分布则用于描述那些取值范围相对集中,且其效应更偏向于加性的超参数(例如某些池化大小和隐藏层数量)。
    • 这些先验分布是贝叶斯优化算法(论文中提到使用“改进的贝叶斯优化算法”和“预期改进 (EI) 准则”)的核心组成部分。贝叶斯优化通过构建一个目标函数的代理模型(通常是高斯过程),并利用先验知识(即这些超参数的先验分布)来指导搜索,从而更高效地找到最优超参数组合。
  3. 数据驱动的先验知识

    • 这些先验分布并不是凭空猜测的,而是通过Kolmogorov-Smirnov (KS) 检验(如论文 3.1 节所述)从一系列实验中获得的。作者首先对每个超参数进行多次独立试验,计算出模型的损失函数值,然后利用 KS 检验来判断这些损失函数值最符合哪种理论分布,并由此确定分布的参数。这种方法确保了先验分布是基于电池退化数据的实际影响来构建的,而不是任意设定的。
  4. 优化目标

    • 通过为超参数设定这样的先验分布,贝叶斯优化算法能够更智能地探索超参数空间。它利用这些先验信息,结合模型在不同超参数配置下的性能(损失函数值),来预测哪些配置最有可能带来更好的结果,从而实现自动化的超参数配置,减少人工干预,并提高 RUL 预测的准确性。

总而言之,Table 2 提供的是 RUL 预测任务中,两种关键神经网络模型超参数的统计画像。这些画像是经过严谨的统计分析得出的,为后续的贝叶斯优化提供了重要的先验知识,是论文实现高效、准确的电池 RUL 预测的关键一步。

图 3. CNN-ASTLSTM NN 超参数上损失函数值的概率密度,其中 (a)–(j) 分别表示 𝐾𝑛、𝐾𝑠、𝗌、𝑃𝑠、𝐿ℎ、𝑁𝑏、lr、𝖻、𝖾 和 dr 上的密度。

这张图是论文中的 Fig. 3. Probability densities of the loss function values over CNN-ASTLSTM NN hyperparameters,中文可译为“CNN-ASTLSTM 神经网络超参数的损失函数值概率密度”。它由 (a) 到 (j) 共 10 个子图组成,分别展示了 CNN-ASTLSTM 模型不同超参数(Kn,Ks,s,Ps,Lh,Nb,lr,b,e,drKn​,Ks​,s,Ps​,Lh​,Nb​,lr,b,e,dr)在 SOH (State-of-Health) 任务中,对应模型训练损失函数值(通常是均方误差 MSE)的概率密度分布。

一、总体目的与核心思想

这张图的核心目的是可视化不同超参数对模型性能(通过损失函数值衡量)的影响模式。在贝叶斯优化(Bayesian Optimization)中,我们需要构建一个代理模型(Surrogate Model)来近似真实的目标函数(即超参数配置与损失函数值之间的映射关系)。这些损失函数值的概率密度分布,正是构建这个代理模型的关键输入之一。

简单来说,当我们在为 CNN-ASTLSTM 模型寻找最佳超参数时,我们会尝试多组超参数配置,每次配置都会得到一个损失函数值。将这些损失函数值进行统计分析,画出它们的概率密度图,就能看到哪些损失值出现的频率更高,以及这些损失值是如何分布的。这有助于我们理解在给定超参数下,模型性能的潜在变动范围和中心趋势。

论文中提到,这些图是使用标准核函数估计器 (standard kernel function estimator) 来估计概率密度的,而不是直接显示离散的损失值点。这意味着图中平滑的曲线是对实际实验结果的统计平滑。

二、图内容分步拆解与关键信息

每个子图的横轴都是 Loss function value (损失函数值),纵轴是 Probability density (概率密度)。损失函数值越小通常代表模型性能越好。

我们将按照图的编号 (a) 到 (j) 逐一解释:

三、关键信息与协作关系

  1. 先验分布的视觉表示:这些概率密度图直观地展示了论文 Table 2 中列出的超参数先验分布的来源。例如,对于那些显示为 log N(对数正态分布)的超参数,其损失函数值的分布可能呈现偏斜或多峰,通过核密度估计器可以平滑地捕捉这些特征。而对于 N(正态分布)的超参数,其损失函数值分布可能更集中。
  2. 贝叶斯优化的基础:这些密度分布图是贝叶斯优化算法中的代理模型 (Surrogate Model) 的关键组成部分。代理模型的目标是近似真实损失函数在超参数空间中的行为。通过分析这些分布,贝叶斯优化算法可以更好地理解哪些超参数配置可能导致高或低的损失,从而更智能地选择下一次要评估的超参数组合(即,选择那些在低损失区域概率密度较高的配置)。
  3. 洞察超参数敏感性
    • 尖锐的峰值(如 lr,elr,e)表明这些超参数对模型性能高度敏感,微小的变化可能导致损失函数值大幅波动,需要更精细的优化。
    • 宽泛的峰值(如 s,Pss,Ps​)表明这些超参数在一定范围内对模型性能的影响相对平滑,优化空间可能更宽松。
    • 多峰分布(如 Kn,Lh,Nb,b,drKn​,Lh​,Nb​,b,dr)暗示存在多个局部最优解,贝叶斯优化需要能够探索这些不同的区域以找到全局最优。
  4. 指导手动调参(如果需要):即使是自动化优化,这些图也能为研究人员提供有价值的直觉。例如,看到 lrlr 和 ee 在非常低的损失函数值处有尖锐的峰值,就提示在实际应用中,这些超参数可能需要非常精确地设置。

总而言之,Fig. 3 通过可视化每个超参数配置下模型损失函数值的概率密度,为理解超参数如何影响模型性能提供了直观的洞察。这些分布图是论文中改进的贝叶斯优化算法能够高效、自动化地寻找最优超参数配置,从而提升 SOH 和 RUL 预测准确性的重要统计基础。

QA3我没看懂这个图,损失函数不应该在y轴吗?

这是一个非常好的问题,它触及了统计图表和机器学习中一些核心概念的理解。你提出“损失函数不应该在y轴吗”的疑问,恰好说明你正在深入思考这张图的含义。

你的直觉是对的,在大多数情况下,我们习惯将“结果”或“目标”放在 Y 轴。

但是,这张图(Fig. 3)的重点不是展示损失函数值本身,而是展示损失函数值的 概率密度分布

我们来一步步拆解,以帮助你理解:

1. 什么是“损失函数值”?

在机器学习中,损失函数(Loss Function)是用来衡量模型预测结果与真实值之间差异的函数。损失函数值越小,代表模型性能越好,预测越准确。 例如,在 SOH 估计任务中,损失函数可能是均方误差 (MSE),它计算预测的 SOH 值与实际 SOH 值之间的平均平方差。

2. 什么是“概率密度分布”?

假设我们对一个超参数(比如学习率 lrlr)进行了很多次实验,每次实验都使用不同的 lrlr 值,然后记录下每次实验得到的损失函数值。我们会得到一堆损失函数值,比如:0.0001, 0.00008, 0.0003, 0.00009, 0.001, ...

如果我们把这些损失函数值画成直方图,横轴是损失函数值,纵轴是每个损失函数值区间出现的“次数”或“频率”。直方图的条形越高,表示该区间的损失函数值出现的频率越高。

概率密度函数 (Probability Density Function, PDF) 就是直方图的平滑版本。它不是显示“次数”,而是显示“密度”。对于连续变量(如损失函数值),我们不能说某个精确值出现的概率,因为概率是0。我们只能说某个区间内的值出现的概率。概率密度函数在某个点的值越高,意味着这个点附近的数值出现的可能性越大

所以,这张图的 Y 轴是“概率密度 (Probability density)”,而不是“损失函数值”。

3. 为什么这张图的损失函数值在 X 轴?

这张图是在回答一个问题:“当我在不同的超参数配置下训练模型时,我得到的损失函数值是如何分布的?”

  • X 轴 (Loss function value):代表我们关心的那个变量——模型训练后得到的损失函数值。我们想知道这些值是如何变化的。
  • Y 轴 (Probability density):代表 X 轴上每个损失函数值附近出现的可能性或者密度。Y 轴越高,说明 X 轴对应的损失函数值出现的概率越大。

举个例子来理解:

假设你正在玩一个射击游戏,你的目标是打靶。

  • 靶心:可以类比为“最低的损失函数值”(X 轴上靠近0的地方)。
  • 你每次射击的得分:就是“损失函数值”。
  • 这张图的作用:不是显示你每次射击的具体得分,而是显示你所有射击得分的分布情况

如果你的射击技术很好,那么这张图的 X 轴(得分)会在靶心附近有一个很高的 Y 轴峰值(概率密度),这表示你大部分的射击都集中在靶心附近,得分很高(损失函数值很低)。 如果你的射击技术很差,那么 X 轴上的得分可能会分布得很广,Y 轴的峰值会比较低且分散,表示你的得分很不稳定,大部分射击都偏离靶心。

回到论文的上下文:

论文的目标是找到最佳的超参数组合,使得模型在 SOH 或 RUL 任务中的损失函数值尽可能低。这张图就是为了帮助理解不同超参数在经过多次实验后,产生的损失函数值(即模型性能)的统计特征

  • 如果某个超参数(比如 Fig. 3(g) 的 lr)对应的损失函数值在 X 轴的左侧(值很小的地方)有一个很高的 Y 轴峰值,这意味着当尝试不同的 lr 值时,模型有很大的可能性会得到一个非常低的损失,这通常是好的。
  • 如果一个超参数对应的损失函数值在 X 轴分布很广,且峰值较低,说明这个超参数可能会导致模型性能很不稳定,或者说它对模型性能的影响比较复杂,需要更精细的探索。

总结一下:

这张图的 Y 轴是概率密度,它告诉我们 X 轴上每个损失函数值出现的可能性有多大。损失函数值本身是被分析的对象,所以它被放在了 X 轴。

希望这个解释能帮助你更好地理解这张图!如果你还有其他疑问,请随时提出。

QA4那这个概率密度图能解释什么呢?

好的,我们来深入解释这个概率密度图(Fig. 3)能解释什么,以及它在论文中的具体意义和作用。

核心:它帮助我们理解不同超参数对模型性能(通过损失函数值衡量)的“敏感度”和“行为模式”。

具体来说,这张图主要能解释以下几个方面:

1. 超参数对模型性能(损失函数值)的影响范围与集中度

  • 影响范围: 观察每个子图在X轴(损失函数值)上的分布宽度。
    • 窄而高的峰值: 如果一个超参数对应的概率密度图在X轴上分布很窄,并且有一个很高的峰值(例如 Fig. 3(a) KnKn​ 或 Fig. 3(c) SS),这表明无论超参数取什么值,模型最终的损失函数值都倾向于集中在一个较小的范围内。这意味着模型对这个超参数的变化可能不太敏感,或者说它在多数情况下都能达到相对稳定的性能。
    • 宽而平的分布: 如果分布很宽且峰值较低(例如 Fig. 3(f) NbNb​ 或 Fig. 3(h) bb),这表明损失函数值分布在一个更广的范围内,模型性能波动较大。这意味着模型对这个超参数的变化非常敏感,不同的取值可能导致截然不同的性能表现。

2. 超参数的“良好”取值范围(或潜在的最佳性能区域)

  • 峰值位置: 概率密度曲线的峰值(最高点)所在的X轴位置,指示了最常出现的损失函数值。
    • 峰值偏左(损失函数值较小): 如果峰值位于X轴的左侧,靠近0(例如 Fig. 3(a) KnKn​),这表示在尝试不同的超参数值时,模型更容易达到较低的损失函数值,即更好的性能。这暗示了该超参数可能更容易找到好的配置。
    • 峰值偏右(损失函数值较大): 如果峰值偏右,表示模型更容易得到较高的损失函数值,性能可能不佳。
    • 多个峰值: 偶尔可能会出现多个峰值,这可能表示存在多个局部最优区域,或者超参数在某些特定条件下表现出不同的行为模式。

3. 为贝叶斯优化提供先验信息

这在论文中是最关键的应用

论文中提到:“The Kolmogorov-Smirnov (KS) test is employed to obtain the prior distribution over the NNs' loss function values. We regard the loss distribution as a surrogate distribution of the hyperparameters specified to the NNs.” (第2页,右侧,倒数第二段)。

  • 先验分布 (Prior Distribution): 在贝叶斯优化中,我们需要对超参数的潜在性能(在这里是损失函数值)有一个初始的“猜测”或“信念”,这被称为先验分布。
  • 如何使用: Fig. 3 展示的概率密度图,就是通过KS检验得到的损失函数值的先验分布。贝叶斯优化算法会利用这些先验知识来指导其搜索过程。
  • 作用: 如果某个超参数的损失函数值在低值区域有更高的概率密度(即图上峰值偏左),贝叶斯优化算法会倾向于在该超参数的这个区域进行更密集的探索,因为它更有可能找到更好的模型配置。这有助于提高优化的效率和效果,减少盲目搜索。

4. 评估超参数的调优难度

  • 调优难度:
    • 对于分布很窄且峰值偏左的超参数,可能相对容易调优,因为随便取值都可能得到不错的结果。
    • 对于分布很宽且峰值分散的超参数,调优难度较大,需要更精细的搜索策略才能找到最佳配置,因为性能波动很大。

5. 对比不同神经网络的超参数行为(虽然Fig. 3只展示了CNN-ASTLSTM NN)

如果论文提供了其他神经网络(如RNN、S-LSTM)的类似图表,那么通过对比不同网络的这些图,可以:

  • 比较不同网络对同一超参数的敏感度: 哪个网络对哪个超参数更敏感,哪个更稳定。
  • 识别不同网络的性能瓶颈或优势: 某些网络可能在特定超参数下更容易获得低损失,而另一些则不然。

总结来说,Fig. 3 中的概率密度图是贝叶斯优化算法的“导航图”。它告诉优化算法:

  • 哪些超参数的调整可能对性能影响最大(分布宽)。
  • 哪些超参数在大多数情况下表现稳定(分布窄)。
  • 哪些超参数更有可能在低损失区域找到好的配置(峰值偏左)。

通过这些信息,贝叶斯优化能够更智能地选择下一组要尝试的超参数,而不是随机选择,从而大大提高了超参数调优的效率和最终模型的性能。

2.CNN-ASTLSTM神经网络的离线训练

2.1. 超参数自动优化

这一子节详细阐述了如何利用贝叶斯优化算法,为SOH(健康状态)和RUL(剩余使用寿命)预测任务自动配置CNN-ASTLSTM NN的超参数。

  • SOH任务的超参数优化:
    • 配置空间定义: 首先,为CNN-ASTLSTM NN定义了一个超参数配置空间,并设定了初始值。这些超参数包括CNN层数、卷积核大小、步长、池化大小、AST-LSTM隐藏层、批次大小、学习率、训练轮数(epoch)和dropout率等。
    • 损失函数: 使用均方误差(MSE)作为损失函数来评估模型性能。
    • 优化过程:
      • 对每个超参数,进行10次独立的试验,保持其他超参数不变,以观察其对损失函数值的影响。
      • 通过 Kolmogorov-Smirnov (KS) 检验获取了损失函数值的先验分布(如 Fig. 3 所示的概率密度图),这些分布被视为超参数的代理分布。
      • 基于这些先验分布,结合贝叶斯优化算法(具体使用了期望提升,EI 准则),自动选择最有希望的超参数组合来评估真实的损失函数。
      • 整个优化过程对所有超参数进行了20次运行,每次运行后,优化算法都会根据当前性能(损失函数值)和先验知识做出“有根据的猜测”,选择下一组最有希望的超参数。
    • 结果: 优化过程(如 Fig. 4 所示)显示,超参数倾向于收敛到特定区域,这些区域能产生更密集的探索。最终优化的超参数配置列在 Table 3 中,并且观察到CNN-ASTLSTM NN比其他网络收敛更快。
  • RUL任务的超参数优化:
    • RUL任务的超参数优化过程与SOH任务类似,主要区别在于配置空间是根据 Table 2 定义的。
    • 同样,优化算法会搜索出CNN-ASTLSTM NN和AST-LSTM NN的最佳超参数(Table 4)。

图 4. 优化过程中超参数搜索的演变

这是一张散点图矩阵 (Scatter Plot Matrix),用于可视化多个超参数在优化过程中的采样分布以及它们之间、与模型性能(以均方误差MSE衡量)之间的关系。

总体目的:

这张图的用意在于全面地展示贝叶斯优化算法如何探索超参数空间,以及这些超参数的组合如何影响模型的预测性能。通过这张图,研究者可以直观地理解:

  1. 哪些超参数在优化过程中被探索得更频繁。
  2. 不同超参数之间的潜在相互作用。
  3. 最重要的是,不同超参数组合对应的模型性能(MSE)如何分布,从而找到那些能带来较低MSE值的“有希望”的超参数区域。

图表结构与内容拆解:

这张图是一个对称的矩阵,对角线是每个超参数的直方图,非对角线是任意两个超参数之间的散点图。图中的颜色条表示均方误差(MSE),颜色从红色(MSE低,性能好)到紫色(MSE高,性能差)变化,其数值范围是 1×10−41×10−4 到 11×10−411×10−4。

1. 对角线上的直方图:

对角线上的每个子图都是一个超参数的直方图,其Y轴表示n.samples(样本数量)。这显示了该超参数在优化过程中被采样的频率和分布情况。

  • Kn​ (CNN卷积核数量):直方图显示 Kn​ 主要集中在20-40之间被采样,且在这个范围内有较多的采样点。
  • Ks​ (CNN卷积核大小): Ks​ 主要在6-8之间被采样。
  • s (CNN步长): s主要在3-4之间被采样。
  • Ps​ (CNN池化大小): Ps​ 主要在2-3之间被采样。
  • Lh​ (AST-LSTM隐藏层数量): Lh 主要在1-2之间被采样。
  • Nb​ (AST-LSTM块数量): Nb​ 主要在20-40之间被采样。
  • lr×10−3 (学习率):学习率主要在 0.5×10−3 到 1.5×10−3 之间被采样。
  • b (批次大小): b 主要在20-40之间被采样。
  • e (训练轮数Epoch): e 主要在40-60和100-140之间被采样。
  • dr (Dropout率): dr 主要在0.05-0.1之间被采样。

这些直方图揭示了优化算法在超参数空间中探索的“热点区域”,即哪些值范围被算法认为更有可能包含最优解,因此被采样得更频繁。

2. 非对角线上的散点图:

非对角线上的每个子图是两个超参数之间的散点图。每个点代表一次超参数组合的尝试,其颜色则由该组合对应的MSE值决定。

  • 横轴与纵轴: 对于位于第 ii 行第 jj 列的散点图,其横轴是第 jj 个超参数的值,纵轴是第 ii 个超参数的值。例如,第一行第二列的散点图,横轴是 KsKs​,纵轴是 KnKn​。
  • 颜色编码 (MSE):
    • 红色/橙色点: 代表MSE值较低(性能较好)的超参数组合。
    • 蓝色/紫色点: 代表MSE值较高(性能较差)的超参数组合。

通过观察这些散点图,我们可以发现:

  • 性能好的区域: 寻找图中密集出现红色或橙色点的区域。这些区域表示在该超参数组合下,模型获得了更好的性能。例如,在 Kn​ 和 Ks​ 的散点图中,如果某些 Kn​ 和 Ks​ 的组合出现了较多的红色点,则说明这些组合是比较理想的。
  • 超参数之间的相互作用: 观察散点图中点的分布模式。
    • 如果红点集中在某个特定的超参数区域,这表明该超参数在该区域内对模型性能有积极影响。
    • 如果红点没有明显的聚集,或者分布比较分散,可能意味着这两个超参数之间的相互作用不那么强,或者它们的最优值可能在更广阔的范围内。
  • 优化过程的演变: 理论上,随着优化过程的进行,算法会更多地探索那些具有较低MSE值的超参数区域,因此我们应该看到红点在某些区域逐渐增多。

关键信息点明:

这张图的核心价值在于可视化了贝叶斯优化在寻找最佳超参数时的探索策略和结果。它直观地展示了:

  1. 哪些超参数组合是“有前景的”: 通过颜色编码,我们可以看到哪些超参数的特定取值范围或组合(红色/橙色点)能够带来更低的MSE,即更好的SOH或RUL预测性能。这有助于研究人员理解模型的敏感性和优化方向。
  2. 优化算法的“学习”过程: 虽然图表是静态的,但它反映了算法如何根据之前的尝试(即已采样点的MSE值)来决定下一步在哪里采样,从而逐步收敛到更好的超参数配置。这种“有根据的猜测”体现在红点往往集中在某些区域,而不是随机散布。
  3. 为后续分析提供依据: 这张图为理解 Table 3 和 Table 4 中最终确定的优化超参数提供了视觉背景,解释了这些最优值是如何从广泛的搜索空间中被“筛选”出来的。

QA5图四中的直方图,为什么ks是带峰的,dr是宽平的

好的,我们来详细解析图4中 KsKs​ 直方图带峰和 drdr 直方图宽平的原因,这背后反映了这两个超参数对模型性能(损失函数值MSE)的不同影响特性。

核心概念回顾:

  • 直方图的横轴(Loss function value / MSE): 表示模型性能,值越小越好。
  • 直方图的纵轴(Probability density): 表示该MSE值出现的概率密度。峰值越高,说明该MSE值出现的可能性越大。
  • 直方图的形状:
    • 带峰的窄分布: 表明该超参数的某些特定取值范围倾向于产生相似且相对较好的模型性能。模型性能对该超参数的某些变化不那么敏感,或者在某个“甜点”区域附近有稳定的表现。
    • 宽平的分布: 表明该超参数在不同取值下,模型性能的波动较大,没有明显的集中趋势。或者说,模型性能对该超参数的取值非常敏感,即使是很小的变化也可能导致性能的显著差异。

1. 超参数 Ks 的直方图带峰的原因(图4(c)):

Ks代表的是 卷积核大小(Kernel Size)。从图4(c)中可以看到,KsKs​ 的直方图在较低的MSE值区域(例如 0.5×10−40.5×10−4 到 1.0×10−41.0×10−4 之间)有一个明显的峰值,并且分布相对较窄。

原因分析:

  • 卷积核作用: 卷积核是CNN中用于提取局部特征的关键组件。它通过在输入数据上滑动并进行卷积操作,来捕捉数据中的模式。
  • 对特征提取的影响: 适当大小的卷积核能够有效地捕捉到电池退化数据中的局部空间相关性或模式
  • 存在“最优范围”: 对于电池退化数据,可能存在一个相对“最优”或“有效”的卷积核大小范围。
    • 过小的卷积核: 可能无法捕捉到足够大的上下文信息,导致特征提取不足。
    • 过大的卷积核: 可能引入过多无关信息,或者增加计算复杂度而效果不佳。
  • 搜索结果的集中性: 在超参数搜索过程中,当 KsKs​ 取值在这个“有效范围”内时,模型倾向于获得相似且相对较低的损失值。因此,这些较低的MSE值被频繁地观察到,从而在直方图上形成了明显的峰值。这说明模型对于这个超参数的特定范围是相对稳定的,并且在这个范围内性能表现良好。
  • 论文中的佐证: 表1中显示 KsKs​ 的先验分布是 N(3,0.45)N(3,0.45) 或 N(4,0.50)N(4,0.50) (对于CNN-LSTM和CNN-ASTLSTM),这表明作者在实验中发现 KsKs​ 在3或4附近取值时,性能较好且分布集中,这与图4(c)的带峰形状一致。

2. 超参数 dr 的直方图宽平的原因(图4(j)):

dr 代表的是 Dropout Rate(丢弃率)。从图4(j)中可以看到,drdr 的直方图分布相对宽平,没有非常尖锐的峰值,并且在较大的MSE值区域也有分布。

原因分析:

  • Dropout 作用: Dropout 是一种正则化技术,用于防止神经网络过拟合。它在训练过程中随机“丢弃”一部分神经元及其连接,迫使网络学习更鲁棒的特征。
  • 对过拟合/欠拟合的敏感性: Dropout Rate 是一个对模型泛化能力影响非常敏感的超参数:
    • 过低的丢弃率 (dr 接近0): 可能导致模型过拟合,尤其是在数据量有限或模型复杂度较高时。过拟合的模型在训练集上表现好,但在测试集上性能差,对应较高的MSE。
    • 过高的丢弃率 (dr 接近1): 可能导致模型欠拟合,因为太多的信息被丢弃,网络无法学习到足够的有用特征。欠拟合的模型在训练集和测试集上都表现不佳,同样对应较高的MSE。
    • 适中的丢弃率: 能够有效平衡过拟合和欠拟合,使模型泛化能力更好,对应较低的MSE。
  • 缺乏稳定“甜点”或高敏感性:
    • 与卷积核大小可能存在一个相对稳定的“有效区间”不同,Dropout Rate 的“最佳值”往往是一个非常精细的平衡点,稍微偏离就可能导致性能显著下降。
    • 因此,在超参数搜索过程中,当 drdr 取值不同时,模型性能(MSE)可能在较宽的范围内波动,很难在某个特定MSE值上形成高度集中的峰值。这导致了直方图的宽平形状,表明模型性能对Dropout Rate的选取非常敏感,且没有一个非常“稳定”的性能区域。
  • 论文中的佐证: 表1中 dr 的先验分布多为 logN 或 V 类型,且方差相对较大(例如 logN(-3.22, 0.26)),这暗示了其分布的范围可能较广,并且在对数空间中表现出某种模式,这与图4(j)的宽平形状是一致的。

总结:

  • Ks​ 的带峰: 暗示了存在一个相对稳定的卷积核大小区间,在该区间内,模型能够有效提取特征并获得较好的性能。
  • dr 的宽平: 暗示了Dropout Rate对模型性能的影响非常敏感,缺乏一个宽泛且稳定的“最佳区间”,其取值需要精确调整以平衡过拟合和欠拟合,因此在不同取值下性能波动较大,难以形成集中的峰值。

这种差异反映了不同超参数在神经网络设计中的内在特性和对模型训练结果的不同影响机制。

2.2. 独立训练

在自动超参数优化完成后,这一子节描述了如何使用这些优化后的超参数进行模型的独立训练。

  • 基于优化结果: 利用 Table 3 和 Table 4 中得到的优化超参数,对SOH和RUL任务的神经网络进行独立的重新训练。
  • 训练效果评估:
    • 损失曲线: Fig. 5(a) 和 5(b) 展示了所有神经网络在SOH和RUL任务中的损失曲线,表明它们都得到了充分训练。尽管RNN的损失曲线波动较大,但其范围相对较低,仍可接受。
    • 激活图: Fig. 5(c) 和 5(d) 展示了CNN-ASTLSTM NN在SOH和RUL任务中提取的特征的激活图。这些图通过叠加在原始数据上,展示了模型特征对预测的影响。随着电池数据(从1到30个循环)的增加,感兴趣区域扩大,激活水平增强(从蓝色到红色),表明CNN捕获的特征对预测有更显著的影响。

表 3 SOH任务中应用的神经网络的优化超参数。

 表4 RUL任务中应用的神经网络的优化超参数

图 5. 独立再训练过程,其中 (a)-(b) 分别为 SOH 和 RUL 任务中神经网络的损失曲线;(c)-(d) 分别为 SOH 和 RUL 任务中 CNN-ASTLSTM 神经网络提取的特征的激活图。

QA6我还是不知道怎么从表一表二,那种根据先验数据进行ks检验后拟合成的各种概率分布范围,就自动优化到表三表四那种具体的最优超参数值的?

这是一个非常好的问题,它触及了贝叶斯优化(Bayesian Optimization)的核心原理,以及如何将先验分布(通过KS检验得到)与最终最优超参数(表3、表4)联系起来。

让我来一步步拆解这个过程:

核心思想:贝叶斯优化是“试错+学习”的过程

贝叶斯优化不是直接从先验分布中“挑选”最佳值,而是一个迭代的、智能的试错过程。它利用先验信息指导搜索,并通过每次试验(运行模型并评估性能)的结果来更新对“哪里可能出现最佳值”的认知。


第一步:构建超参数空间(由表1、表2的先验分布定义)

  • 表1和表2的作用: 它们定义了每个超参数的**“搜索范围”和“初始偏好”**。例如,对于 KsKs​,SOH任务中先验分布是 N(3,0.45)N(3,0.45)。这告诉优化器:
    • 范围: KsKs​ 最好在正整数范围内搜索(因为它是卷积核大小)。
    • 初始偏好: 算法在开始时会更倾向于在均值3附近探索 KsKs​ 的值,因为根据先验知识,这个区域可能产生更好的结果。
  • 如何从分布到具体值: 这些概率分布(如高斯分布 N(μ,σ)N(μ,σ) 或对数正态分布 logN(μ,σ)logN(μ,σ))并不直接给出具体的超参数值,而是描述了超参数在某个范围内的可能性。优化算法在每次迭代中,会根据这些分布(以及后续更新的后验分布)来“建议”一组超参数值进行试验。

第二步:贝叶斯优化的核心机制——代理模型与采集函数

贝叶斯优化主要包含两个关键组件:

  1. 代理模型 (Surrogate Model):

    • 作用: 它是一个廉价的模型(通常是高斯过程,Gaussian Process),用来拟合超参数与模型性能(损失函数值,如RMSE或MSE)之间的关系。它比直接运行神经网络模型(真实的目标函数)要快得多。
    • 如何利用先验: 在优化开始时,代理模型会利用表1、表2中定义的先验分布来建立对超参数空间性能的初步估计。例如,如果 KsKs​ 的先验是 N(3,0.45)N(3,0.45),代理模型在初始化时就会“认为” Ks=3Ks​=3 附近性能可能较好,同时也会考虑到这些分布的方差。
    • 学习与更新: 每当贝叶斯优化选择一组超参数进行真实模型训练(例如,用 Ks=3Ks​=3 训练CNN-ASTLSTM,得到一个MSE值)后,这个真实结果会被反馈给代理模型。代理模型会根据这些新的真实观测数据来更新其对超参数-性能关系的估计,使其更准确。
  2. 采集函数 (Acquisition Function):

    • 作用: 这是一个决策函数,它根据当前的代理模型(即对超参数-性能关系的估计),来决定下一次应该在哪组超参数处进行真实模型试验。采集函数的目标是平衡“探索”和“利用”。
    • 探索 (Exploration): 尝试那些代理模型不确定但可能有潜在好结果的超参数区域。
    • 利用 (Exploitation): 尝试那些代理模型认为当前表现最好的超参数区域。
    • 论文中提到的EI (Expected Improvement): 这就是一种常见的采集函数。EI 函数会计算“预期提升”,即如果选择某个超参数组合进行试验,模型性能可能比目前最好的结果提升多少。它会同时考虑代理模型的均值(当前预测的性能)和方差(预测的不确定性)。
    • 如何利用先验: 采集函数在决定下一个试验点时,会参考代理模型中的先验信息。例如,如果 Ks=3Ks​=3 附近的先验概率高,代理模型会在此处给出相对乐观的性能预测,采集函数就可能引导优化器先尝试这个区域。

第三步:迭代优化过程(从分布到具体值的转变)

整个过程是这样的:

  1. 初始化: 贝叶斯优化器会根据表1、表2的先验分布,随机或策略性地选择几组超参数进行首次真实模型训练(例如,从 N(3,0.45)N(3,0.45) 中抽取 KsKs​ 的初始值,再从其他分布中抽取其他超参数的初始值)。
  2. 评估: 运行这些神经网络模型(真实目标函数),得到对应的损失函数值(MSE或RMSE)。
  3. 更新代理模型: 将这些超参数-损失值对作为观测数据,更新代理模型对超参数空间的预测。现在,代理模型不仅有先验信息,还有了真实的观测数据。
  4. 使用采集函数建议下一个试验点: 采集函数(如EI)根据更新后的代理模型,计算出在哪个超参数组合下,最有可能获得最大的性能提升。这个“最有可能提升”的点,就是贝叶斯优化器下一次要尝试的具体超参数值
  5. 重复: 重复步骤2-4,直到达到预设的迭代次数(论文中提到“20 runs for all the hyperparameters”)或性能收敛。

在这个迭代过程中,贝叶斯优化器会逐渐“聚焦”到性能表现最佳的超参数组合上。

第四步:得到最优超参数(表3、表4的最终结果)

  • 最终选择: 在贝叶斯优化过程结束后(例如20次迭代后),算法会从所有已经试验过的超参数组合中,选择那个导致模型性能(损失函数)最低的组合
  • 这就是表3和表4中的具体数值: 例如,表3中CNN-ASTLSTM的 Ks=46Ks​=46,这就是在贝叶斯优化过程中,经过多次迭代和尝试后,最终发现能使模型SOH任务性能最好的卷积核大小。这个值可能与先验分布的均值 N(3,0.45)N(3,0.45) 稍有不同,因为贝叶斯优化会根据实际数据进行调整和学习。

以 Ks​ 为例的直观理解:

  1. 先验: 表1说 KsKs​ 的先验是 N(3,0.45)N(3,0.45)。贝叶斯优化器知道“哦, KsKs​ 在3附近可能不错”。
  2. 第一次尝试: 优化器可能建议尝试 Ks=3Ks​=3。运行模型,得到MSE=0.01。
  3. 第二次尝试: 优化器根据第一次结果,结合先验,可能建议尝试 Ks=4Ks​=4。运行模型,得到MSE=0.008(比0.01好)。
  4. 第三次尝试: 优化器发现 Ks=4Ks​=4 效果更好,可能会在4附近继续探索,或者尝试更远的 Ks=5Ks​=5,得到MSE=0.009。
  5. 多次迭代后: 优化器可能发现当 Ks=46Ks​=46 时,MSE达到了0.0072(这是表5中CNN-ASTLSTM SOH任务的RMSE,假设是MSE)。即使46离初始均值3有点远,但由于真实数据验证了它的优越性,贝叶斯优化器会“记住”这个最佳结果。

所以,从表1、表2到表3、表4,是:

  • 表1、表2: 提供起点和指导方向(先验知识)。
  • 贝叶斯优化算法(代理模型 + 采集函数): 负责智能地探索和学习超参数空间。
  • 真实模型训练: 提供真实反馈(目标函数评估)。
  • 表3、表4: 是经过学习和探索后,最终找到的性能最优的具体超参数值。

简单来说,先验分布就像是一张初步的“藏宝图”,指明了宝藏可能的大致区域。而贝叶斯优化算法,就像一个聪明的寻宝猎人,拿着这张图,每挖一铲土(进行一次试验),都会根据挖出的东西(模型性能)来更新对藏宝图的理解,并更精确地决定下一铲土应该挖在哪里,直到找到真正的宝藏(最优超参数)。

3.CNN-ASTLSTM神经网络的在线测试

本节详细阐述了所提出的 CNN-ASTLSTM 神经网络在 SOH 估计和 RUL 预测任务中的在线测试结果,并将其性能与多种现有神经网络模型进行了对比。

  1. SOH 估计的评估:

    • 数据: 使用每块电池剩余 30% 的历史数据进行 SOH 估计。
    • 评估指标: 采用绝对误差 (AE)、均方根误差 (RMSE) 和平均均方根误差 (ARMSE) 作为评估标准。
    • 结果:
      • AE 曲线: 自动优化的 CNN-ASTLSTM 模型的 AE 曲线普遍低于其他自动优化的神经网络模型(见图 6(a)-(l))。这表明其估计值更接近真实值。
      • RMSE 分布: 从表 5 的箱线图(图 6(m))可以看出,CNN-ASTLSTM 模型的最大值、上四分位数、中位数、下四分位数和最小值都处于较低位置,表明其 SOH 估计误差更小、更稳定。
      • 鲁棒性测试: 针对性能严重退化的电池(#29-34, 36, 38-44, 49, 51),在不使用其数据作为辅助训练的情况下进行鲁棒性测试。图 6(s) 的 RMSE 箱线图也显示,CNN-ASTLSTM 在这些挑战性条件下依然表现出更好的性能,具有更低的上四分位数、中位数和下四分位数。
    • 结论: CNN-ASTLSTM 在 SOH 估计任务中展现出优越的准确性和鲁棒性。
  2. RUL 预测的评估:

    • 数据: 选择 #5 电池作为基准进行多步 RUL 预测,该预测通过同步更新数据来实现,比简单计数更具挑战性。
    • 评估指标: 采用 AE (重定义为 RUL - 预测 RUL)、全局 ARMSE (GARMSE) 和全局平均 AE (GAAE) 来评估全局性能。
    • 结果:
      • 预测容量曲线: 图 7(a)-(j) 显示,随着起始预测周期 (qs) 的增加,预测容量曲线越接近实际容量,但预测窗口长度 (pw) 的增加则会产生相反的效果(即误差可能增大)。
      • RMSE 和 AE 分布: 图 7(k)-(l)(基于表 6 的 RMSE 和 AE)的箱线图表明,CNN-ASTLSTM 模型具有更低的箱线分布,再次验证了其在 RUL 预测任务中的卓越性能。
    • 结论: CNN-ASTLSTM 在多步 RUL 预测任务中也表现出更佳的性能。

总而言之,3.3 节通过详尽的在线测试和与其他方法的对比,有力地证明了所提出的 CNN-ASTLSTM 神经网络在电动汽车锂电池的 SOH 估计和 RUL 预测方面具有显著的优势,其误差更低、鲁棒性更好。

表 5 常规 SOH 测试不同方法的在线 RMSE

表 6 不同方法对 #5 电池的预测误差

4.CNN-ASTLSTM神经网络的综合性能分析

本节旨在全面评估所提出的 CNN-ASTLSTM 神经网络在 SOH 估计和 RUL 预测任务中的综合性能,并与现有方法进行对比。这种综合分析不仅考虑了预测精度,还着眼于未来汽车电子架构(域处理器)中 BMS 数据处理和算法计算功能转移的实际应用场景,其中计算能力更强,为神经网络的应用提供了机遇。

  1. 分析动机:

    • 随着汽车电子技术的发展,下一代电-电子架构将把电池管理系统 (BMS) 的数据处理和算法计算功能转移到域处理器,这些处理器具有更强大的计算能力,为神经网络的实际应用提供了机会。
    • 因此,有必要对现有方法进行全面性能分析,以找到在未来应用场景中 SOH 估计的最佳权衡点。
    • 此外,本分析旨在展示自动超参数优化如何减少人工干预、降低训练难度并改善预测模型的其他性能。
  2. 评估指标:

    • 除了预测精度(RMSE, ARMSE, GAAE, AE, AAE)外,还引入了以下关键性能指标:
      • FLOPs (浮点运算次数): 作为衡量计算复杂度的间接指标(乘加操作次数)。
      • Parameters (参数数量): 影响模型存储大小的间接指标。
      • Training time (训练时间): 模型的训练耗时。
      • Inference time (推理延迟): 模型输出估计容量的耗时,通过 Python 的 time.time 函数计算,并对所有测试样本取平均值和标准差。
      • Storage size (存储大小): 模型在存储介质上所占的空间大小,通过 Python 的 os.path.getsize 函数计算。
  3. 结果与分析:

    • 自动优化模型的优势: 表 7 显示,与手动调优的模型相比,自动优化模型的各项指标(FLOPs, Parameters, Training time, Inference latency, Storage size)均有所降低。
    • 模型准确性与成本的权衡: 在实际应用中,模型的准确性以及训练成本(训练时间、FLOPs、参数)和硬件成本(推理时间、存储大小)都需要综合考虑。
    • 最佳权衡表现: 结合表 5(RMSE)和表 7(其他性能指标),通过对指标的成对组合分析,图 8 展示了所有方法的性能分布。结果显示,所提出的 CNN-ASTLSTM 方法在每个性能分布中都位于左下角,这意味着它在所有指标上都实现了最佳的权衡性能,即在保持高准确性的同时,具有较低的计算复杂度、参数量、训练时间、推理延迟和存储大小。

总而言之,3.4 节通过引入多维度性能指标并进行全面的对比分析,不仅再次确认了 CNN-ASTLSTM 在预测准确性上的优势,更重要的是,它证明了该方法在计算效率、资源消耗和自动化程度方面也表现出色,使其成为未来电池健康管理系统中极具潜力的解决方案。自动超参数优化在此过程中发挥了关键作用,大大简化了模型构建和优化过程。

表7 不同方法在SOH估计任务中的综合性能。

图 8. 所有方法的性能分布,其中 (a)–(b) 分别为 FLOPs-ARMSE、参数-ARMSE、训练时间-ARMSE 和推理延迟-ARMSE 分布。

五.代码学习

复现跑一边实验代码,逐模块拆解与论文的数据实验对应,用代码来理解公式进而理解数据流

1.soh_train

import os
import time
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import joblib
from math import sqrt
from pandas import read_csv
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler
from keras import backend as K
from keras import optimizers
from keras.models import Sequential
from keras.layers import Conv1D, MaxPooling1D, Dense, Dropout
from keras.layers import *  # 一次性导入所有层,包括 Layer
# from keras.utils import plot_model  # 【已注释】不需要画图,避免 pydot 报错

os.environ["CUDA_VISIBLE_DEVICES"]="0"
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ['PYTHONHASHSEED'] = '0'

seed = 7
np.random.seed(seed)

gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.9)
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1, gpu_options=gpu_options)
tf.set_random_seed(1234)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)

loss_list = []


class ATSLSTM(Layer):
	def __init__(self, units, return_sequences=False, **kwargs):
		self.units = units
		self.return_sequences = return_sequences
		super(ATSLSTM, self).__init__(**kwargs)
		self.lstm = LSTM(units, return_sequences=True)

	def build(self, input_shape):
		self.W = self.add_weight(name='attention_W',
								 shape=(self.units, self.units),
								 initializer='glorot_uniform',
								 trainable=True)
		self.b = self.add_weight(name='attention_b',
								 shape=(self.units,),
								 initializer='zeros',
								 trainable=True)
		self.u = self.add_weight(name='attention_u',
								 shape=(self.units, 1),
								 initializer='glorot_uniform',
								 trainable=True)
		super(ATSLSTM, self).build(input_shape)

	def call(self, x):
		h = self.lstm(x)

		# 注意力机制
		uit = K.tanh(K.dot(h, self.W) + self.b)
		ait = K.dot(uit, self.u)
		ait = K.squeeze(ait, -1)
		ait = K.exp(ait - K.max(ait, axis=1, keepdims=True))
		ait_weights = ait / K.sum(ait, axis=1, keepdims=True)
		ait_weights = K.expand_dims(ait_weights, axis=-1)

		output = h * ait_weights
		if not self.return_sequences:
			output = K.sum(output, axis=1)
		return output

	def compute_output_shape(self, input_shape):
		if self.return_sequences:
			return (input_shape[0], input_shape[1], self.units)
		else:
			return (input_shape[0], self.units)
# scale train and test data to [-1, 1]
def scale(train, test):
	scaler = MinMaxScaler(feature_range=(-1, 1))
	scaler = scaler.fit(train)
	train = train.reshape(train.shape[0], train.shape[1])
	train_scaled = scaler.transform(train)
	test = test.reshape(test.shape[0], test.shape[1])
	test_scaled = scaler.transform(test)
	return scaler, train_scaled, test_scaled


# inverse scaling for a forecasted value
def invert_scale(scaler, X, value):
	new_row = [x for x in X] + [value]
	array = np.array(new_row)
	array = array.reshape(1, len(array))
	inverted = scaler.inverse_transform(array)
	return inverted[0, -1]


# fit an AST-LSTM network to training data
def fit_lstm(train, batch_size, nb_epoch, neurons):
	X, y = train[:, 0:-1], train[:, -1]
	X = X.reshape(X.shape[0], 660, 4)
	model = Sequential()
	model.add(Conv1D(filters=46, kernel_size=7, strides=4, padding='same', activation='relu', input_shape=(X.shape[1], X.shape[2])))
	model.add(MaxPooling1D(pool_size=2, padding='valid'))
	model.add(ATSLSTM(24, return_sequences=True))
	model.add(ATSLSTM(28, return_sequences=False))
	model.add(Dropout(0.0609))
	model.add(Dense(1))
	adam = optimizers.Adam(lr=0.0009, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
	model.compile(loss='mean_squared_error', optimizer=adam)
	for i in range(nb_epoch):
		print('Epoch:',i)
		history = model.fit(X, y, epochs=1, batch_size=batch_size, verbose=1, shuffle=False)
		loss_list.append(history.history['loss'][0])
		with open('./result/soh_loss.txt', 'a', encoding='utf-8') as f:
			f.write(str(history.history['loss'][0]) + "\n")
		model.reset_states()
		# plot_model(model, to_file=r'./result/soh_model_structure.png', show_shapes=True) # 【已注释】不需要画图
	model.save(r'./result/soh_model.h5')
	return model


# make a one-step forecast
def forecast_lstm(model, batch_size, X):
	X = X.reshape(1, 660, 4)
	yhat = model.predict(X, batch_size=batch_size)
	return yhat[0,0]


# convert an array of values into a dataset matrix
def create_dataset(dataset, look_back=1):
	dataX, dataY = [], []
	for i in range(0, len(dataset)-look_back, 2641):
		a = dataset[i:(i+look_back)]
		dataX.append(a)
		dataY.append(dataset[i + look_back])
	dataY= np.array(dataY)
	dataY = np.reshape(dataY,(dataY.shape[0],1))
	for i in range(len(dataY)):
		if dataY[i].astype("float64") == 0:
			dataY[i] = str(dataY[i-1][0].astype("float64"))
	dataset = np.concatenate((dataX,dataY),axis=1)
	return dataset,dataY


def experiment(series5, series6, series7, series18, series45, series46, series47, series48, series53, series54,
			   series55, series56, updates, look_back, neurons, n_epoch, batch_size):
	index = []
	raw_values5 = series5.values
	raw_values6 = series6.values
	raw_values7 = series7.values
	raw_values18 = series18.values
	raw_values45 = series45.values
	raw_values46 = series46.values
	raw_values47 = series47.values
	raw_values48 = series48.values
	raw_values53 = series53.values
	raw_values54 = series54.values
	raw_values55 = series55.values
	raw_values56 = series56.values
	raw_values = np.concatenate((raw_values5, raw_values6, raw_values7, raw_values18, raw_values45, raw_values46, raw_values47, raw_values48, raw_values53, raw_values54, raw_values55, raw_values56), axis=0)

	dataset, dataY = create_dataset(raw_values,look_back)
	dataset_5, dataY_5 = create_dataset(raw_values5,look_back)
	dataset_6, dataY_6 = create_dataset(raw_values6,look_back)
	dataset_7, dataY_7 = create_dataset(raw_values7,look_back)
	dataset_18, dataY_18 = create_dataset(raw_values18,look_back)
	dataset_45, dataY_45 = create_dataset(raw_values45,look_back)
	dataset_46, dataY_46 = create_dataset(raw_values46,look_back)
	dataset_47, dataY_47 = create_dataset(raw_values47,look_back)
	dataset_48, dataY_48 = create_dataset(raw_values48,look_back)
	dataset_53, dataY_53 = create_dataset(raw_values53,look_back)
	dataset_54, dataY_54 = create_dataset(raw_values54,look_back)
	dataset_55, dataY_55 = create_dataset(raw_values55,look_back)
	dataset_56, dataY_56 = create_dataset(raw_values56,look_back)

	train_size_5 = int(dataset_5.shape[0] * 0.7)
	train_size_6 = int(dataset_6.shape[0] * 0.7)
	train_size_7 = int(dataset_7.shape[0] * 0.7)
	train_size_18 = int(dataset_18.shape[0] * 0.7)
	train_size_45 = int(dataset_45.shape[0] * 0.7)
	train_size_46 = int(dataset_46.shape[0] * 0.7)
	train_size_47 = int(dataset_47.shape[0] * 0.7)
	train_size_48 = int(dataset_48.shape[0] * 0.7)
	train_size_53 = int(dataset_53.shape[0] * 0.7)
	train_size_54 = int(dataset_54.shape[0] * 0.7)
	train_size_55 = int(dataset_55.shape[0] * 0.7)
	train_size_56 = int(dataset_56.shape[0] * 0.7)

	# split into train and test sets
	train_5, test_5 = dataset_5[0:train_size_5], dataset_5[train_size_5:]
	train_6, test_6 = dataset_6[0:train_size_6], dataset_6[train_size_6:]
	train_7, test_7 = dataset_7[0:train_size_7], dataset_7[train_size_7:]
	train_18, test_18 = dataset_18[0:train_size_18], dataset_18[train_size_18:]
	train_45, test_45 = dataset_45[0:train_size_45], dataset_45[train_size_45:]
	train_46, test_46 = dataset_46[0:train_size_46], dataset_46[train_size_46:]
	train_47, test_47 = dataset_47[0:train_size_47], dataset_47[train_size_47:]
	train_48, test_48 = dataset_48[0:train_size_48], dataset_48[train_size_48:]
	train_53, test_53 = dataset_53[0:train_size_53], dataset_53[train_size_53:]
	train_54, test_54 = dataset_54[0:train_size_54], dataset_54[train_size_54:]
	train_55, test_55 = dataset_55[0:train_size_55], dataset_55[train_size_55:]
	train_56, test_56 = dataset_56[0:train_size_56], dataset_56[train_size_56:]

	train = np.concatenate((train_5, train_6, train_7, train_18, train_45, train_46, train_47, train_48, train_53, train_54, train_55, train_56), axis=0)
	np.random.shuffle(train)
	features = train[:, :-1]
	labels = train[:, -1]

	scaler, train_scaled, test5_scaled = scale(train, test_5)
	joblib.dump(scaler, r'.\result\scaler_soh.pickle')

	starttime = time.time()
	# fit the model
	lstm_model = fit_lstm(train_scaled, batch_size, n_epoch, neurons)
	endtime = time.time()
	dtime = endtime - starttime

	# forecast the entire training dataset to build up state for forecasting
	print('Forecasting Training Data')
	predictions_train = list()
	for i in range(len(train_scaled)):
		# make one-step forecast
		X, y = train_scaled[i, 0:-1], train_scaled[i, -1]
		yhat = forecast_lstm(lstm_model, batch_size, X)
		# invert scaling
		yhat = invert_scale(scaler, X, yhat)
		# store forecast
		predictions_train.append(yhat)
		expected = labels[i]
		print('Cycle=%d, Predicted=%f, Expected=%f' % (i + 1, yhat, float(expected)))

	# report performance
	rmse_train = sqrt(mean_squared_error(np.array(labels).astype("float64")/2, np.array(predictions_train)/2))
	print('Train RMSE: %.3f' % rmse_train)
	index.append(rmse_train)

	# forecast the test data(#5)
	print('Forecasting Testing Data')
	predictions_test = list()
	for i in range(len(test5_scaled)):
		# make one-step forecast
		X, y = test5_scaled[i, 0:-1], test5_scaled[i, -1]
		yhat = forecast_lstm(lstm_model, batch_size, X)
		# invert scaling
		yhat = invert_scale(scaler, X, yhat)
		# store forecast
		predictions_test.append(yhat)
		expected = dataY_5[len(train_5) + i]
		print('Cycle=%d, Predicted=%f, Expected=%f' % (i+1, yhat, expected))

	# report performance using RMSE
	rmse_test = sqrt(mean_squared_error(dataY_5[-len(test5_scaled):].astype("float64")/2, np.array(predictions_test)/2))
	print('Test RMSE: %.3f' % rmse_test)
	print("程序训练时间:%.8s s" % dtime)

	index.append(rmse_test)
	index.append(dtime)
	with open(r'./result/soh_prediction_result.txt', 'a', encoding='utf-8') as f:
		for j in range(len(index)):
			f.write(str(index[j]) + "\n")

	with open(r'./result/soh_prediction_data_#5.txt', 'a', encoding='utf-8') as f:
		for k in range(len(predictions_test)):
			f.write(str(predictions_test[k]) + "\n")
		dataY_5 = np.array(dataY_5)
	# line plot of observed vs predicted
	fig, ax = plt.subplots(1)
	ax.plot(dataY_5[-len(test5_scaled):].astype("float64"), label='original', color='blue')
	ax.plot(predictions_test, label='predictions', color='red')
	ax.legend(loc='upper right')
	ax.set_xlabel("Cycle",fontsize = 16)
	ax.set_ylabel('Capacity '+ r'$(AH)$',fontsize = 16)
	plt.savefig(r'./result/soh_result.png')
	plt.show()


def run():
	file_name1 = './data/soh/vltm5.csv'
	file_name2 = './data/soh/vltm6.csv'
	file_name3 = './data/soh/vltm7.csv'
	file_name4 = './data/soh/vltm18.csv'
	file_name5 = './data/soh/vltm45.csv'
	file_name6 = './data/soh/vltm46.csv'
	file_name7 = './data/soh/vltm47.csv'
	file_name8 = './data/soh/vltm48.csv'
	file_name9 = './data/soh/vltm53.csv'
	file_name10 = './data/soh/vltm54.csv'
	file_name11 = './data/soh/vltm55.csv'
	file_name12 = './data/soh/vltm56.csv'

	series1 = read_csv(file_name1, header=None, parse_dates=[0], squeeze=True)
	series2 = read_csv(file_name2, header=None, parse_dates=[0], squeeze=True)
	series3 = read_csv(file_name3, header=None, parse_dates=[0], squeeze=True)
	series4 = read_csv(file_name4, header=None, parse_dates=[0], squeeze=True)
	series5 = read_csv(file_name5, header=None, parse_dates=[0], squeeze=True)
	series6 = read_csv(file_name6, header=None, parse_dates=[0], squeeze=True)
	series7 = read_csv(file_name7, header=None, parse_dates=[0], squeeze=True)
	series8 = read_csv(file_name8, header=None, parse_dates=[0], squeeze=True)
	series9 = read_csv(file_name9, header=None, parse_dates=[0], squeeze=True)
	series10 = read_csv(file_name10, header=None, parse_dates=[0], squeeze=True)
	series11 = read_csv(file_name11, header=None, parse_dates=[0], squeeze=True)
	series12 = read_csv(file_name12, header=None, parse_dates=[0], squeeze=True)

	look_back = 2640
	neurons = [64, 64]
	n_epochs = 153
	updates = 1
	batch_size = 14
	experiment(series1, series2, series3, series4, series5, series6, series7, series8, series9, series10,
			   series11, series12, updates,look_back, neurons, n_epochs, batch_size)


run()
fig = plt.figure()
plt.plot(loss_list, label='loss', color='blue')
plt.legend()
plt.title('model loss')
plt.savefig('./result/soh_loss.png')
plt.show()

2.rul_train

import numpy
import pandas
import time

from keras import optimizers
from keras.utils import plot_model
from keras.layers import Dense, LSTM ,Dropout, ATSLSTM, SimpleRNN, Conv1D, MaxPooling1D
from keras.models import Sequential, load_model
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler, Imputer
from sklearn.externals import joblib
from tqdm import trange
from math import sqrt

numpy.random.seed(30)


def load_dataset(datasource1: str, datasource2: str, datasource3: str, datasource4: str) -> (numpy.ndarray, MinMaxScaler):
    dataframe1 = pandas.read_csv(datasource1, usecols=[1])
    dataframe1 = dataframe1.fillna(method='pad')
    dataset1 = dataframe1.values
    dataset1 = dataset1.astype('float32')
    dataset1 = dataset1[0:50]

    dataframe2 = pandas.read_csv(datasource2, usecols=[1])
    dataframe2 = dataframe2.fillna(method='pad')
    dataset2 = dataframe2.values
    dataset2 = dataset2.astype('float32')
    dataset2 = dataset2[0:50]

    dataframe3 = pandas.read_csv(datasource3, usecols=[1])
    dataframe3 = dataframe3.fillna(method='pad')
    dataset3 = dataframe3.values
    dataset3 = dataset3.astype('float32')
    dataset3 = dataset3[0:50]

    dataframe4 = pandas.read_csv(datasource4, usecols=[1])
    dataframe4 = dataframe4.fillna(method='pad')
    dataset4 = dataframe4.values
    dataset4 = dataset4.astype('float32')

    dataset = numpy.concatenate((dataset1, dataset2, dataset3, dataset4), axis=0)

    scaler = MinMaxScaler(feature_range=(0, 1))
    dataset = scaler.fit_transform(dataset)
    return dataset, scaler


def create_dataset(dataset: numpy.ndarray, look_back: int=1) -> (numpy.ndarray, numpy.ndarray):
    data_x, data_y = [], []
    for i in range(len(dataset)-look_back-1):
        a = dataset[i:(i+look_back), 0]
        data_x.append(a)
        data_y.append(dataset[i + look_back, 0])
    return numpy.array(data_x), numpy.array(data_y)


def build_model() -> Sequential:
    model = Sequential()
    model.add(Conv1D(filters=52, kernel_size=6, strides=3, padding='same', activation='relu',input_shape=(10, 3)))
    model.add(MaxPooling1D(pool_size=2, padding='valid'))
    model.add(ATSLSTM(23, stateful=False))
    model.add(Dropout(0.035))
    model.add(Dense(1))
    optimizer = optimizers.Adam(lr=0.0012, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
    model.compile(loss='mean_squared_error', optimizer=optimizer)
    return model


def make_forecast(model: Sequential, look_back_buffer: numpy.ndarray, timesteps: int=1, batch_size: int=1):
    forecast_predict = numpy.empty((0, 1), dtype=numpy.float32)
    for _ in trange(timesteps, desc='predicting data\t', mininterval=1.0):
        # make prediction with current lookback buffer
        cur_predict = model.predict(look_back_buffer, batch_size)
        # add prediction to result
        forecast_predict = numpy.concatenate([forecast_predict, cur_predict], axis=0)
        # add new axis to prediction to make it suitable as input
        cur_predict = numpy.reshape(cur_predict, (cur_predict.shape[1], cur_predict.shape[0], 1))
        look_back_buffer = look_back_buffer.reshape(1, 30, 1)
        # remove oldest prediction from buffer
        look_back_buffer = numpy.delete(look_back_buffer, 0, axis=1)
        # concat buffer with newest prediction
        look_back_buffer = numpy.concatenate([look_back_buffer, cur_predict], axis=1)
        look_back_buffer = look_back_buffer.reshape(1, 10, 3)
    return forecast_predict


def main():
    datasource5 = r'.\data\rul\5-capacity168.csv'
    datasource6 = r'.\data\rul\6-capacity168.csv'
    datasource7 = r'.\data\rul\7-capacity168.csv'
    datasource18 = r'.\data\rul\18-capacity132.csv'

    dataset, scaler = load_dataset(datasource5, datasource6, datasource18, datasource7)
    joblib.dump(scaler, r'.\result\scaler_rul.pickle')

    look_back = 30
    dataset_x, dataset_y = create_dataset(dataset, look_back)
    dataset_x = numpy.concatenate((dataset_x[0:20], dataset_x[50:70], dataset_x[100:120], dataset_x[150:]), axis=0)
    dataset_y = numpy.concatenate((dataset_y[0:20], dataset_y[50:70], dataset_y[100:120], dataset_y[150:]), axis=0)
    dataset_x = numpy.reshape(dataset_x, (dataset_x.shape[0], 10, 3))

    batch_size = 13
    loss_list = []
    starttime = time.time()
    model = build_model()
    for _ in trange(150, desc='fitting model\t', mininterval=1.0):
        history = model.fit(dataset_x, dataset_y, nb_epoch=1, batch_size=batch_size, verbose=1, shuffle=False)
        plot_model(model, to_file=r'./result/rul_model_structure.png', show_shapes=True)
        loss_list.append(history.history['loss'][0])
        with open('./result/rul_loss.txt', 'a', encoding='utf-8') as f:
            f.write(str(history.history['loss'][0]) + "\n")
        model.reset_states()
    model.save(r'./result/rul_model.h5')
    endtime = time.time()
    dtime = endtime - starttime

    # generate predictions for training
    dataset_predict = model.predict(dataset_x, batch_size)

    # generate forecast predictions
    forecast_predict = make_forecast(model, dataset_x[19:20, :], timesteps=118, batch_size=batch_size)

    # invert dataset and predictions
    dataset = scaler.inverse_transform(dataset)
    dataset_predict = scaler.inverse_transform(dataset_predict)
    dataset_y = scaler.inverse_transform([dataset_y])
    forecast_predict = scaler.inverse_transform(forecast_predict)

    with open(r'./result/rul_prediction_data' + ".txt", 'a', encoding='utf-8') as f:
        for m in range(len(forecast_predict)):
            f.write(str(forecast_predict[m]) + "\n")
    print("程序运行时间:%.8s s" % dtime)
    index = []

    dataset_score = sqrt(mean_squared_error(dataset_y[0], dataset_predict[:, 0]))
    print('Train Dataset Score: %.2f RMSE' % dataset_score)
    forecast_score = sqrt(mean_squared_error(dataset_y[0, -118:], forecast_predict[:, 0]))
    print('Test Dataset Score: %.2f RMSE' % forecast_score)
    index.append('train_dataset_score: %.5f' % dataset_score)
    index.append('test_dataset_score: %.5f' % forecast_score)
    index.append('time: %1f' % dtime)

    with open(r'./result/soh_prediction_result_#7_50.txt', 'a', encoding='utf-8') as f:
        for j in range(len(index)):
            f.write(str(index[j]) + "\n")


if __name__ == '__main__':
    main()

六.画模型图

了解论文中类似fig1中的模型框架图是怎么画的,并进行实践

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐