☰
【零基础学智能仿真-14】神经网络基础——从集成学习走向深度学习
2026/9/25 14:39:34 网站建设 项目流程

课程摘要

上一节通过Stacking组合多个机器学习模型,本节进一步学习能够自动构造非线性特征的神经网络。课程以悬臂梁最大弯曲应力预测为案例,讲解神经元、权重、偏置、激活函数、网络层、前向传播、损失函数和反向传播,并完成数据标准化、MLP训练、验证集早停和独立测试。学习者将理解神经网络“如何预测、怎样学习、如何判断可靠”,为后续CNN、LSTM、Transformer和PINN课程建立基础。


一、承接第十三节:为什么继续学习神经网络?

第十三节使用Ridge、随机森林、梯度提升和RBF-SVR构建了Stacking模型,其基本思想是:

\[ \text{多个基模型的预测} \longrightarrow \text{元学习器} \longrightarrow \text{最终预测} \]

Stacking的优势是综合已有模型,但每个基模型仍需人工选择。面对应力场、位移场、裂纹图像和瞬态响应等高维问题,传统模型会遇到三个困难:

  1. 输入可能包含成千上万个网格节点或像素;
  2. 几何、载荷和材料之间存在复杂非线性耦合;
  3. 很难完全依靠人工设计特征。

神经网络可以在训练过程中自动构造中间特征:

\[ \text{原始输入} \longrightarrow \text{多层特征变换} \longrightarrow \text{力学响应} \]

本节先从最基本的多层感知机开始。后续的CNN、LSTM、Transformer和PINN,本质上都建立在神经元、激活函数、前向传播与反向传播之上。


二、本节学习目标

完成本节后,学习者应能够:

  • 解释神经元中权重和偏置的作用;
  • 理解激活函数为什么能够引入非线性;
  • 区分输入层、隐藏层和输出层;
  • 说清楚前向传播、损失计算和反向传播的关系;
  • 使用MLP预测悬臂梁最大弯曲应力;
  • 正确划分训练集、验证集和测试集;
  • 查看训练曲线、预测散点图和残差图;
  • 认识神经网络在力学预测中的能力边界。

三、从一个神经元开始

3.1 神经元的计算过程

设神经元接收四个标准化后的力学参数:

\[ \tilde{\boldsymbol{x}} = \begin{bmatrix} \tilde{F}\\ \tilde{L}\\ \tilde{b}\\ \tilde{h} \end{bmatrix} \]

其中:

  • \(F\):载荷;
  • \(L\):梁长;
  • \(b\):截面宽度;
  • \(h\):截面高度。

神经元首先进行加权求和:

\[ z= w_1\tilde{F} +w_2\tilde{L} +w_3\tilde{b} +w_4\tilde{h} +c \]

式中:

  • \(w_1,w_2,w_3,w_4\) 为权重;
  • \(c\) 为偏置;
  • \(z\) 为神经元的线性输入。

这里用 \(c\) 表示偏置,避免与截面宽度 \(b\) 混淆。

随后,神经元通过激活函数得到输出:

\[ a=\phi(z) \]

因此,一个神经元包含两个步骤:

\[ \boxed{ \text{加权求和} \longrightarrow \text{激活函数} } \]


3.2 一个可以手算的例子

假设输入为:

\[ \tilde{\boldsymbol{x}} = \begin{bmatrix} 1&0&-1&0.5 \end{bmatrix}^{\mathrm T} \]

权重和偏置为:

\[ \boldsymbol{w} = \begin{bmatrix} 0.4&0.2&-0.3&-0.6 \end{bmatrix}^{\mathrm T} \]\[ c=0.1 \]

则加权求和结果为:

\[ \begin{aligned} z &=0.4\times1 +0.2\times0 +(-0.3)\times(-1)\\ &\quad+(-0.6)\times0.5 +0.1\\ &=0.5 \end{aligned} \]

如果使用Tanh激活函数:

\[ a=\tanh(0.5)\approx0.4621 \]

这里的 \(0.4621\) 是神经元产生的中间特征值,不直接代表应力或位移。


四、为什么必须使用激活函数?

假设一个两层网络没有激活函数:

\[ \boldsymbol{a}^{(1)} = \boldsymbol{W}^{(1)}\boldsymbol{x} +\boldsymbol{c}^{(1)} \]\[ \hat{\boldsymbol{y}} = \boldsymbol{W}^{(2)}\boldsymbol{a}^{(1)} +\boldsymbol{c}^{(2)} \]

将第一式代入第二式:

\[ \hat{\boldsymbol{y}} = \boldsymbol{W}^{(2)} \boldsymbol{W}^{(1)} \boldsymbol{x} + \boldsymbol{W}^{(2)} \boldsymbol{c}^{(1)} + \boldsymbol{c}^{(2)} \]

无论叠加多少层,最终仍然是关于输入的线性函数。

激活函数可以打破这种线性关系,使网络能够学习:

  • 应力与梁高之间的平方反比关系;
  • 材料进入塑性后的非线性响应;
  • 裂纹扩展的突变趋势;
  • 接触状态改变产生的分段响应;
  • 多种材料参数和边界条件的耦合关系。

五、常用激活函数

5.1 ReLU函数

\[ \operatorname{ReLU}(z)=\max(0,z) \]

当 \(z<0\) 时:

\[ \operatorname{ReLU}(z)=0 \]

当 \(z\geq0\) 时:

\[ \operatorname{ReLU}(z)=z \]

ReLU计算简单,在深层网络和CNN中使用非常广泛。


5.2 Tanh函数

\[ \tanh(z) = \frac{e^z-e^{-z}}{e^z+e^{-z}} \]

输出范围为:

\[ -1<\tanh(z)<1 \]

Tanh连续、平滑,在某些平滑力学响应和物理信息神经网络中较常见。

【正文插图1:ReLU与Tanh激活函数】

需要注意,隐藏层使用Tanh,并不意味着最终预测应力只能在 \(-1\) 到 \(1\) MPa之间。回归网络的输出层通常使用线性函数,标准化后的结果还会被恢复为原来的应力单位。


六、从神经元组成多层感知机

多个神经元可以组成一层,多层神经元连接后形成多层感知机,即MLP。

本节采用的网络结构为:

\[ 4 \longrightarrow 32 \longrightarrow 32 \longrightarrow 1 \]

它表示:

网络层神经元数量作用
输入层4接收 \(F,L,b,h\)
第一隐藏层32提取初级非线性特征
第二隐藏层32组合更复杂的特征
输出层1预测最大弯曲应力

需要强调的是,普通神经网络的隐藏神经元通常没有明确的物理名称。不能直接断言某个神经元代表弯矩,另一个神经元代表惯性矩。


6.1 网络参数量

输入层到第一隐藏层:

\[ 4\times32+32=160 \]

第一隐藏层到第二隐藏层:

\[ 32\times32+32=1056 \]

第二隐藏层到输出层:

\[ 32\times1+1=33 \]

总参数量为:

\[ 160+1056+33=1249 \]

也就是说,这个看起来并不大的网络,已经包含1249个需要从数据中学习的参数。


七、神经网络如何完成预测?

对于一个样本,第一隐藏层计算:

\[ \boldsymbol{a}^{(1)} = \tanh \left( \boldsymbol{W}^{(1)} \tilde{\boldsymbol{x}} + \boldsymbol{c}^{(1)} \right) \]

第二隐藏层计算:

\[ \boldsymbol{a}^{(2)} = \tanh \left( \boldsymbol{W}^{(2)} \boldsymbol{a}^{(1)} + \boldsymbol{c}^{(2)} \right) \]

输出层计算:

\[ \hat{\tilde{\sigma}} = \boldsymbol{W}^{(3)} \boldsymbol{a}^{(2)} +c^{(3)} \]

这一过程称为前向传播:

\[ \boxed{ \text{输入} \longrightarrow \text{隐藏层1} \longrightarrow \text{隐藏层2} \longrightarrow \text{预测结果} } \]

前向传播只负责使用当前参数完成预测,还没有修改网络参数。


八、神经网络如何学习?

8.1 计算损失

对于回归问题,可以使用均方误差:

\[ \mathcal{L}_{\mathrm{data}} = \frac{1}{N} \sum_{i=1}^{N} \left( \hat{\tilde{\sigma}}_i - \tilde{\sigma}_i \right)^2 \]

损失越小,说明预测值整体越接近目标值。

为了抑制过大的权重,还可以加入L2正则化:

\[ \mathcal{L} = \mathcal{L}_{\mathrm{data}} + \alpha \sum_l \left\| \boldsymbol{W}^{(l)} \right\|_2^2 \]

其中 \(\alpha\) 控制正则化强度。


8.2 反向传播

反向传播利用链式法则计算:

\[ \frac{\partial\mathcal{L}} {\partial\boldsymbol{W}^{(l)}} \]

以及:

\[ \frac{\partial\mathcal{L}} {\partial\boldsymbol{c}^{(l)}} \]

它回答的问题是:

某个权重发生微小变化时,预测误差将怎样变化?


8.3 参数更新

得到梯度后,优化器更新参数:

\[ \boldsymbol{W}_{t+1} = \boldsymbol{W}_t - \eta \frac{\partial\mathcal{L}} {\partial\boldsymbol{W}_t} \]

其中 \(\eta\) 是学习率。

完整训练循环为:

\[ \boxed{ \text{前向预测} \rightarrow \text{计算损失} \rightarrow \text{反向传播} \rightarrow \text{更新参数} } \]

反向传播负责计算梯度,Adam等优化器负责根据梯度更新参数,两者不是同一个概念。


九、实战项目:悬臂梁最大应力预测

9.1 力学模型

矩形截面悬臂梁自由端承受集中载荷 \(F\)。

固定端弯矩为:

\[ M=FL \]

截面惯性矩为:

\[ I=\frac{bh^3}{12} \]

截面最外缘距离中性轴:

\[ c=\frac{h}{2} \]

最大弯曲正应力为:

\[ \sigma_{\max} = \frac{Mc}{I} = \frac{6FL}{bh^2} \]

当载荷使用N、尺寸使用mm时:

\[ 1\ \mathrm{N/mm^2}=1\ \mathrm{MPa} \]


9.2 数据范围

生成1000组教学数据:

参数范围
载荷 \(F\)10~50 N
梁长 \(L\)300~600 mm
梁宽 \(b\)15~30 mm
梁高 \(h\)10~20 mm

目标数据为:

\[ \sigma_{\mathrm{target}} = \frac{6FL}{bh^2} +\varepsilon \]

其中:

\[ \varepsilon \sim \mathcal{N}(0,0.40^2) \]

这里加入小幅可重复扰动,用于模拟含噪声数据的训练过程。本节数据来自解析公式,并非真实有限元计算结果。


十、准备数据

from copy import deepcopy import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.neural_network import MLPRegressor from sklearn.linear_model import Ridge from sklearn.metrics import ( mean_squared_error, mean_absolute_error, r2_score ) def rmse(y_true, y_pred): return float( np.sqrt(mean_squared_error(y_true, y_pred)) ) rng = np.random.default_rng(42) n_samples = 1000 F = rng.uniform(10.0, 50.0, n_samples) L = rng.uniform(300.0, 600.0, n_samples) b = rng.uniform(15.0, 30.0, n_samples) h = rng.uniform(10.0, 20.0, n_samples) sigma_theory = 6.0 * F * L / (b * h**2) sigma_target = ( sigma_theory + rng.normal(0.0, 0.40, n_samples) ) features = [ "load_N", "length_mm", "width_mm", "height_mm" ] X = pd.DataFrame({ "load_N": F, "length_mm": L, "width_mm": b, "height_mm": h })

十一、划分训练集、验证集和测试集

X_dev, X_test, y_dev, y_test = train_test_split( X, sigma_target, test_size=0.20, random_state=42 ) X_train, X_val, y_train, y_val = train_test_split( X_dev, y_dev, test_size=0.20, random_state=42 ) print("训练集:", len(X_train)) print("验证集:", len(X_val)) print("测试集:", len(X_test))

实际输出:

训练集: 640 验证集: 160 测试集: 200

三类数据的职责不同:

  • 训练集用于更新网络参数;
  • 验证集用于选择最佳训练轮次;
  • 测试集只用于最终评价。

测试集不能参与标准化器拟合、训练轮数选择和模型参数调整。


十二、为什么神经网络需要标准化?

四个输入特征的数值尺度明显不同:

\[ F\approx10\sim50 \]\[ L\approx300\sim600 \]\[ h\approx10\sim20 \]

如果直接输入网络,梁长的数值可能在梯度计算中占据过大影响。

标准化公式为:

\[ \tilde{x}_j = \frac{x_j-\mu_{j,\mathrm{train}}} {s_{j,\mathrm{train}}} \]

代码如下:

input_scaler = StandardScaler() target_scaler = StandardScaler() X_train_scaled = input_scaler.fit_transform(X_train) X_val_scaled = input_scaler.transform(X_val) X_test_scaled = input_scaler.transform(X_test) y_train_scaled = target_scaler.fit_transform( y_train.reshape(-1, 1) ).ravel() print(X_train_scaled.shape) print(y_train_scaled.shape)

实际输出:

(640, 4) (640,)

标准化器只能在训练集上调用fit。验证集、测试集和后续新工况只能调用transform。


十三、建立MLP网络

model = MLPRegressor( hidden_layer_sizes=(32, 32), activation="tanh", solver="adam", learning_rate_init=0.001, alpha=0.0001, batch_size=64, random_state=42, early_stopping=False )

主要参数含义:

参数本节设置作用
hidden_layer_sizes(32, 32)两个隐藏层,每层32个神经元
activationtanh隐藏层激活函数
solveradam参数优化方法
learning_rate_init0.001初始学习率
alpha0.0001L2正则化强度
batch_size64每批训练样本数
random_state42保证结果可重复

定义预测函数,将标准化结果恢复为MPa:

def predict_mpa(network, X_scaled): pred_scaled = network.predict(X_scaled) return target_scaler.inverse_transform( pred_scaled.reshape(-1, 1) ).ravel()

十四、逐轮训练并保存最佳模型

history = [] best_val_rmse = np.inf best_epoch = 0 best_model = None max_epochs = 1500 patience = 120 for epoch in range(1, max_epochs + 1): model.partial_fit( X_train_scaled, y_train_scaled ) train_pred = predict_mpa( model, X_train_scaled ) val_pred = predict_mpa( model, X_val_scaled ) train_error = rmse( y_train, train_pred ) val_error = rmse( y_val, val_pred ) history.append([ epoch, train_error, val_error ]) if val_error < best_val_rmse: best_val_rmse = val_error best_epoch = epoch best_model = deepcopy(model) if epoch - best_epoch >= patience: break model = best_model print("实际训练轮数:", len(history)) print("最佳模型轮数:", best_epoch) print( f"最佳验证RMSE:" f"{best_val_rmse:.6f} MPa" )

实际运行输出:

实际训练轮数: 1374 最佳模型轮数: 1254 最佳验证RMSE:0.427851 MPa

deepcopy用于保存当时的模型参数副本。如果只写:

best_model = model

两个变量会指向同一个持续更新的对象,无法真正保留最佳轮次。


十五、分析训练曲线

import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = [ "Microsoft YaHei", "SimHei", "DejaVu Sans" ] plt.rcParams["axes.unicode_minus"] = False history_array = np.asarray(history) plt.figure(figsize=(9, 4.5)) plt.plot( history_array[:, 0], history_array[:, 1], label="训练集" ) plt.plot( history_array[:, 0], history_array[:, 2], label="验证集" ) plt.axvline( best_epoch, linestyle="--", color="gray", label=f"保留第{best_epoch}轮" ) plt.yscale("log") plt.xlabel("训练轮数 Epoch") plt.ylabel("RMSE(MPa,对数刻度)") plt.legend() plt.grid(alpha=0.2) plt.tight_layout() plt.show()

【正文插图2:神经网络训练曲线】

从曲线可以看到:

  1. 训练初期,误差迅速下降;
  2. 约200轮后,网络已经学到主要非线性趋势;
  3. 后期误差仍在缓慢下降;
  4. 第1254轮取得最低验证误差;
  5. 此后连续120轮没有刷新最佳值,训练停止。

本例后期验证曲线基本趋于平稳,并未出现明显的大幅上升。因此,更准确的判断是模型已经接近收敛,而不是严重过拟合。


十六、独立测试与线性基线比较

为了判断神经网络是否真正学到了非线性关系,使用相同训练数据建立Ridge基线。

mlp_pred = predict_mpa( model, X_test_scaled ) ridge = Ridge(alpha=1.0) ridge.fit( X_train_scaled, y_train ) ridge_pred = ridge.predict( X_test_scaled ) print( f"Ridge测试RMSE:" f"{rmse(y_test, ridge_pred):.6f} MPa" ) print( f"MLP测试RMSE:" f"{rmse(y_test, mlp_pred):.6f} MPa" ) print( f"MLP测试MAE:" f"{mean_absolute_error(y_test, mlp_pred):.6f} MPa" ) print( f"MLP测试R²:" f"{r2_score(y_test, mlp_pred):.6f}" )

实际运行输出:

Ridge测试RMSE:4.696376 MPa MLP测试RMSE:0.470548 MPa MLP测试MAE:0.367447 MPa MLP测试R²:0.998709

结果说明,在只输入 \(F,L,b,h\) 四个原始特征的条件下,MLP比线性模型更好地学习了:

\[ \sigma_{\max} = \frac{6FL}{bh^2} \]

中的乘法、除法和平方关系。

这个实验不表示神经网络比解析公式更合适。已知准确公式时,直接计算更快速、更透明。本例使用解析问题,是为了核验神经网络是否学到了正确的输入输出关系。


十七、查看预测结果与残差

【正文插图3:测试集预测和残差】

左图中,散点整体接近理想预测线:

\[ \hat{\sigma}=\sigma \]

右图展示残差:

\[ e_i= \hat{\sigma}_i-\sigma_i \]

残差图可以帮助发现:

  • 模型是否整体偏高或偏低;
  • 高应力区域是否误差更大;
  • 是否存在少量异常工况;
  • 误差是否随目标值发生系统变化。

虽然测试集 \(R^2\) 达到0.9987,但高应力区域仍出现较大的个别残差。因此,不能只看一个综合指标。

对于工程应用,还应检查:

\[ e_{\max} = \max_i \left| \hat{\sigma}_i-\sigma_i \right| \]

以及相对误差:

\[ e_{\mathrm{relative},i} = \frac{ \left| \hat{\sigma}_i-\sigma_i \right| }{ \left| \sigma_i \right|+\epsilon } \times100\% \]


十八、预测一个新工况

设新工况为:

\[ F=30\ \mathrm{N} \]\[ L=450\ \mathrm{mm} \]\[ b=22\ \mathrm{mm} \]\[ h=15\ \mathrm{mm} \]

理论应力为:

\[ \begin{aligned} \sigma_{\max} &= \frac{6\times30\times450} {22\times15^2}\\ &= 16.363636\ \mathrm{MPa} \end{aligned} \]

网络预测代码:

new_case = pd.DataFrame( [[30.0, 450.0, 22.0, 15.0]], columns=features ) new_case_scaled = input_scaler.transform( new_case ) new_prediction = predict_mpa( model, new_case_scaled )[0] theory_value = ( 6.0 * 30.0 * 450.0 / (22.0 * 15.0**2) ) print( f"理论应力:" f"{theory_value:.6f} MPa" ) print( f"网络预测:" f"{new_prediction:.6f} MPa" ) print( f"绝对误差:" f"{abs(new_prediction-theory_value):.6f} MPa" )

实际运行输出:

理论应力:16.363636 MPa 网络预测:16.391931 MPa 绝对误差:0.028295 MPa

新工况位于训练参数范围之内,因此属于插值预测。若输入:

\[ F=100\ \mathrm{N} \]

或者:

\[ h=5\ \mathrm{mm} \]

就可能进入训练范围之外。此时即使程序能够给出数值,也不能直接认为预测可靠。


十九、与第十三节结果应该怎样比较?

第十三节中,RBF-SVR和Stacking也取得了很高精度;本节MLP的测试RMSE为:

\[ 0.470548\ \mathrm{MPa} \]

它与上一节的优秀模型处于接近水平。不过两节的训练方案存在差异:

  • 第十三节使用800条开发数据进行基模型拟合;
  • 第十四节从开发集中划出160条验证数据;
  • 本节只有640条样本直接参与网络参数更新;
  • 模型选择和训练过程也不完全相同。

因此,这些结果适合帮助理解算法特点,不应作为严格的排行榜。

若要正式比较,应使用相同的数据划分、相同的评价流程和重复交叉验证。


二十、如何迁移到真实有限元项目?

真实项目可以将输入扩展为:

\[ \boldsymbol{x} = \begin{bmatrix} \text{几何参数}\\ \text{材料参数}\\ \text{载荷参数}\\ \text{边界条件编码}\\ \text{网格参数} \end{bmatrix} \]

输出可以是:

\[ \boldsymbol{y} = \begin{bmatrix} U_{\max}\\ \sigma_{\mathrm{Mises,max}}\\ J\\ K_I\\ N_f \end{bmatrix} \]

一个实际工作流可以写成:

Abaqus参数化建模 ↓ 多工况批量计算 ↓ ODB结果提取 ↓ 工况级数据划分 ↓ 输入与目标标准化 ↓ 神经网络训练 ↓ 验证集选择模型 ↓ 独立工况测试 ↓ 物理合理性检查

这里有三个必须保持的习惯。

第一,模型与标准化器应同时保存。只有网络参数而没有训练时的均值、标准差和特征顺序,模型不能可靠部署。

第二,输出量的定义必须统一。例如“固定位置的名义应力”和“全模型最大积分点应力”不是同一个目标。

第三,普通MLP只从数据误差中学习。本节损失函数没有加入平衡方程、本构方程或边界条件,因此它属于数据驱动网络,不属于PINN。


二十一、常见问题

1. 隐藏层越多越好吗?

不一定。网络加深会增加参数量和训练难度。对于本节这种四输入、单输出的小问题,两层隐藏层已经具有足够的表达能力。

2. 神经元越多越准确吗?

不一定。神经元过少可能欠拟合,过多则可能增加过拟合风险和计算成本,应根据验证集结果选择。

3. 损失下降就表示模型可靠了吗?

只能说明优化过程取得进展。最终还需要独立测试、残差分析、物理趋势检查和适用范围检查。

4. 为什么同一代码可能得到略有不同的结果?

网络权重初始化和批次训练包含随机过程。固定random_state可以提高可重复性,但不同软件版本或计算环境仍可能导致最后几位存在差异。

5. 神经网络会自动学会力学定律吗?

不保证。它可能在训练范围内很好地拟合数据,却在外推区域违反单调性、对称性、平衡关系或边界条件。


二十二、课后练习

练习一:改变网络规模

将:

hidden_layer_sizes=(32, 32)

改为:

hidden_layer_sizes=(16, 16)

计算新网络的参数量,并比较验证集与测试集误差。

其参数量应为:

\[ 4\times16+16 + 16\times16+16 + 16\times1+1 = 369 \]


练习二:比较激活函数

分别设置:

activation="tanh"

和:

activation="relu"

比较:

  • 最佳验证RMSE;
  • 达到最佳结果所需的训练轮数;
  • 高应力区域的最大残差。

练习三:加入物理特征

构造新特征:

\[ q=\frac{FL}{bh^2} \]

根据力学公式:

\[ \sigma_{\max}=6q \]

使用单变量线性回归预测应力,并与MLP比较。

这个练习可以说明:

合理的物理特征能够显著降低模型学习难度。


练习四:检查物理单调性

固定 \(F,L,b\),让梁高 \(h\) 从10 mm增加到20 mm,绘制网络预测曲线。

理论上应满足:

\[ \frac{\partial\sigma_{\max}}{\partial h} = -\frac{12FL}{bh^3}<0 \]

也就是说,梁高增大时,应力应单调下降。检查神经网络是否遵守这一趋势。


二十三、本节小结

本节从第十三节的集成学习过渡到神经网络,建立了后续深度学习课程需要的基本概念:

\[ \boxed{ \text{神经元} = \text{加权求和} + \text{激活函数} } \]\[ \boxed{ \text{网络预测} = \text{多层前向传播} } \]\[ \boxed{ \text{网络训练} = \text{损失计算} + \text{反向传播} + \text{参数更新} } \]

神经网络能够学习复杂的力学映射,但模型的可靠性仍依赖于数据覆盖、验证方法、物理检查和适用范围。


完整课程附件

完整代码建议放在本节末尾的“附录:完整可运行代码”中。正文保留分段代码,便于学习者跟随讲解逐步运行。

  • [完整可运行代码]
  • [悬臂梁教学数据]
  • [逐轮训练记录]
  • [实际运行结果]
  • [模型与标准化器文件]

附件地址:

【零基础学智能仿真-14】神经网络基础-从集成学习走向深度学习资源-CSDN下载

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询