极限学习机(ELM)的原理和matlab代码实现

news2024/9/24 11:32:47

        单隐含层前馈神经网络(Single - hidden Layer Feedforward Neural Network,SLFN)以其良好的学习能力在许多领域得到了广泛的应用。然而,传统的学习算法(如 BP算法等)固有的一些缺点,成为制约其发展的主要瓶颈。前馈神经网络大多采用梯度下降方法,该方法主要存在以下几个方面的缺点和不足:
        ①训练速度慢。由于梯度下降法需要多次迭代,从而达到修正权值和阈值的目的,因此训练过程耗时较长。
        ②容易陷入局部极小点,无法达到全局最小。
        ③学习率η的选择敏感。学习率n对神经网络的性能影响较大,必须选择合适的n,才能获得较为理想的网络。若η太小,则算法收敛速度很慢,训练过程耗时较长;若n太大,则训练过程可能不稳定(收敛)。
        因此,探索一种训练速度快,获得全局最优解且具有良好的泛化性能的训练算法是提升前馈神经网络性能的主要目标,也是近年来的研究热点和难点。
        本篇博客将介绍一个针对SLFN 的新算法——极限学习机(Extreme Learning Machine,ELM),该算法随机产生输入层与隐含层间的连接权值及隐含层神经元的阈值,且在训练过程中无需调整,只需要设置隐含层神经元的个数,便可以获得唯一的最优解。与传统的训练方法相比,该方法具有学习速度快、泛化性能好等优点。

1 案例背景

1.1 极限学习机概述

        典型的单隐含层前馈神经网络结构如图29-1所示,由输入层、隐含层和输出层组成,输入层与隐含层、隐含层与输出层神经元间全连接。其中,输入层有n个神经元,对应n个输入变量;隐含层有l个神经元;输出层有m个神经元,对应m个输出变量。为不失一般性,设输入层与隐含层间的连接权值w为

 

1.2 ELM的学习算法

        由前文分析可知,ELM在训练之前可以随机产生w和b,只需确定隐含层神经元个数及隐含层神经元的激活函数(无限可微),即可计算出β。具体地,ELM的学习算法主要有以下几个步骤:

        值得一提的是,相关研究结果表明,在ELM中不仅许多非线性激活函数都可以使用(如S型函数、正弦函数和复合函数等),还可以使用不可微函数,甚至可以使用不连续的函数作为激活函数。

1.3 问题描述

        ELM以其学习速度快、泛化性能好等优点,引起了国内外许多专家和学者的研究与关注。ELM不仅适用于回归、拟合问题,亦适用于分类,模式识别等领域,因此,其在各个领域均得到广泛的应用。同时,不少改进的方法与策略也被不断提及,ELM的性能也得到了很大的提升,其应用的范围亦愈来愈广,其重要性亦日益体现出来。
        为了评价ELM的性能,试分别将ELM应用于非线性函数拟合和乳腺肿瘤诊断两个问题中,并将其结果与其他方法的性能和运行速度进行比较,并探讨隐含层神经元个数对ELM性能的影响。

2 模型建立

2.1设计思路

        依据问题描述中的要求,实现ELM的创建、训练及仿真测试,大体上可以分为以下几个步骤,如图29-2所示。

2.2 设计步骤

        1)训练集/测试集产生
        与传统前馈神经网络相同,为了使得建立的模型具有良好的泛化性能,ELM要求具有足够多的训练样本且具有较好的代表性。同时,训练集和测试集的格式应符合ELM训练和预测函数的要求。
        2)ELM创建/训练
        利用elmtrain()函数可以方便地创建、训练ELM,具体用法请参考第3节,值得一提的是,如前文所述,隐含层神经元个数对ELM的性能影响较大,因此,需要选择一个合适的隐含层神经元个数,具体讨论见第5节。
        3)ELM仿真测试
        利用elmpredict()函数可以方便地进行ELM的仿真测试,具体用法请参考第3节。

        4)性能评价
        通过计算测试集预测值与真实值间的误差(均方误差、决定系数、正确率等)可以对模型的泛化能力进行评价。同时,可以对比 ELM与传统前馈神经网络的运行时间,从而对ELM的运算速度进行评价。

3 极限学习机训练与预测函数

        ELM的学习算法及步骤可以方便地在 MATLAB环境下实现。为了方便读者学习,使用ELM,编写了ELM的训练和预测函数,下面详细介绍它们的调用格式和具体函数内容。

3.1 ELM训练函数———elmtrain()

        elmtrain()函数为ELM的创建、训练函数,其调用格式为:

[IW,B,LW,TF,TYPE] = elmtrain(P,T,N,TF,TYPE)
        其中,P为训练集的输入矩阵;T为训练集的输出矩阵;N为隐含层神经元的个数(默认为训练集的样本数);TF为隐含层神经元的激活函数,其取值可以为'sig '(默认) ,' sin ',' hardlim ';TYPE为ELM的应用类型,其取值可以为0(默认,表示回归、拟合)和1(表示分类);IW为输人层与隐含层间的连接权值;B为隐含层神经元的阈值;LW为隐含层与输出层的连接权值。
        elmtrain.m函数文件具体内容如下:

function [IW,B,LW,TF,TYPE] = elmtrain(P,T,N,TF,TYPE)
% ELMTRAIN Create and Train a Extreme Learning Machine
% Syntax
% [IW,B,LW,TF,TYPE] = elmtrain(P,T,N,TF,TYPE)
% Description
% Input
% P   - Input Matrix of Training Set  (R*Q)
% T   - Output Matrix of Training Set (S*Q)
% N   - Number of Hidden Neurons (default = Q)
% TF  - Transfer Function:
%       'sig' for Sigmoidal function (default)
%       'sin' for Sine function
%       'hardlim' for Hardlim function
% TYPE - Regression (0,default) or Classification (1)
% Output
% IW  - Input Weight Matrix (N*R)
% B   - Bias Matrix  (N*1)
% LW  - Layer Weight Matrix (N*S)
% Example
% Regression:
% [IW,B,LW,TF,TYPE] = elmtrain(P,T,20,'sig',0)
% Y = elmtrain(P,IW,B,LW,TF,TYPE)
% Classification
% [IW,B,LW,TF,TYPE] = elmtrain(P,T,20,'sig',1)
% Y = elmtrain(P,IW,B,LW,TF,TYPE)
% See also ELMPREDICT
% Yu Lei,11-7-2010
% Copyright www.matlabsky.com
% $Revision:1.0 $
if nargin < 2
    error('ELM:Arguments','Not enough input arguments.');
end
if nargin < 3
    N = size(P,2);
end
if nargin < 4
    TF = 'sig';
end
if nargin < 5
    TYPE = 0;
end
if size(P,2) ~= size(T,2)
    error('ELM:Arguments','The columns of P and T must be same.');
end
[R,Q] = size(P);
if TYPE  == 1
    T  = ind2vec(T);
end
[S,Q] = size(T);
% Randomly Generate the Input Weight Matrix
IW = rand(N,R) * 2 - 1;
% Randomly Generate the Bias Matrix
B = rand(N,1);
BiasMatrix = repmat(B,1,Q);
% Calculate the Layer Output Matrix H
tempH = IW * P + BiasMatrix;
switch TF
    case 'sig'
        H = 1 ./ (1 + exp(-tempH));
    case 'sin'
        H = sin(tempH);
    case 'hardlim'
        H = hardlim(tempH);
end
% Calculate the Output Weight Matrix
LW = pinv(H') * T';

3.2 ELM预测函数——elmpredict()

        elmpredict()函数为ELM的预测函数,其调用格式为
Y= elmpredict(P,IW,B,LN,TF,TYPE)
        其中,P为测试集的输入矩阵;IW为elmtrain()函数返回的输入层与隐含层间的连接权值;B为elmtrain()函数返回的隐含层神经元的阈值;LW为elmtrain()函数返回隐含层与输出层的连接权值;TF为与elmtrain()函数中一致的激活函数类型;TYPE为与elmtrain()函数中一致的 ELM应用类型;Y为测试集对应的输出预测值矩阵。
        elmpredict.m函数文件具体内容如下:
function Y = elmpredict(P,IW,B,LW,TF,TYPE)
% ELMPREDICT Simulate a Extreme Learning Machine
% Syntax
% Y = elmtrain(P,IW,B,LW,TF,TYPE)
% Description
% Input
% P   - Input Matrix of Training Set  (R*Q)
% IW  - Input Weight Matrix (N*R)
% B   - Bias Matrix  (N*1)
% LW  - Layer Weight Matrix (N*S)
% TF  - Transfer Function:
%       'sig' for Sigmoidal function (default)
%       'sin' for Sine function
%       'hardlim' for Hardlim function
% TYPE - Regression (0,default) or Classification (1)
% Output
% Y   - Simulate Output Matrix (S*Q)
% Example
% Regression:
% [IW,B,LW,TF,TYPE] = elmtrain(P,T,20,'sig',0)
% Y = elmtrain(P,IW,B,LW,TF,TYPE)
% Classification
% [IW,B,LW,TF,TYPE] = elmtrain(P,T,20,'sig',1)
% Y = elmtrain(P,IW,B,LW,TF,TYPE)
% See also ELMTRAIN
% Yu Lei,11-7-2010
% Copyright www.matlabsky.com
% $Revision:1.0 $
if nargin < 6
    error('ELM:Arguments','Not enough input arguments.');
end
% Calculate the Layer Output Matrix H
Q = size(P,2);
BiasMatrix = repmat(B,1,Q);
tempH = IW * P + BiasMatrix;
switch TF
    case 'sig'
        H = 1 ./ (1 + exp(-tempH));
    case 'sin'
        H = sin(tempH);
    case 'hardlim'
        H = hardlim(tempH);
end
% Calculate the Simulate Output
Y = (H' * LW)';
if TYPE == 1
    temp_Y = zeros(size(Y));
    for i = 1:size(Y,2)
        [max_Y,index] = max(Y(:,i));
        temp_Y(index,i) = 1;
    end
    Y = vec2ind(temp_Y); 
end
       
    

4.主函数和运行结果

4.1 分类问题主函数与运行结果

%% 极限学习机在分类问题中的应用研究

%% 清空环境变量
clear all
clc
warning off

%% 导入数据
load data.mat
% 随机产生训练集/测试集
a = randperm(569);
Train = data(a(1:500),:);
Test = data(a(501:end),:);
% 训练数据
P_train = Train(:,3:end)';
T_train = Train(:,2)';
% 测试数据
P_test = Test(:,3:end)';
T_test = Test(:,2)';

tic

%% ELM创建/训练
[IW,B,LW,TF,TYPE] = elmtrain(P_train,T_train,100,'sig',1);

%% ELM仿真测试
T_sim_1 = elmpredict(P_train,IW,B,LW,TF,TYPE);
T_sim_2 = elmpredict(P_test,IW,B,LW,TF,TYPE);

toc

%% 结果对比
result_1 = [T_train' T_sim_1'];
result_2 = [T_test' T_sim_2'];
% 训练集正确率
k1 = length(find(T_train == T_sim_1));
n1 = length(T_train);
Accuracy_1 = k1 / n1 * 100;
disp(['训练集正确率Accuracy = ' num2str(Accuracy_1) '%(' num2str(k1) '/' num2str(n1) ')'])
% 测试集正确率
k2 = length(find(T_test == T_sim_2));
n2 = length(T_test);
Accuracy_2 = k2 / n2 * 100;
disp(['测试集正确率Accuracy = ' num2str(Accuracy_2) '%(' num2str(k2) '/' num2str(n2) ')'])

%% 显示
count_B = length(find(T_train == 1));
count_M = length(find(T_train == 2));
rate_B = count_B / 500;
rate_M = count_M / 500;
total_B = length(find(data(:,2) == 1));
total_M = length(find(data(:,2) == 2));
number_B = length(find(T_test == 1));
number_M = length(find(T_test == 2));
number_B_sim = length(find(T_sim_2 == 1 & T_test == 1));
number_M_sim = length(find(T_sim_2 == 2 & T_test == 2));
disp(['病例总数:' num2str(569)...
      '  良性:' num2str(total_B)...
      '  恶性:' num2str(total_M)]);
disp(['训练集病例总数:' num2str(500)...
      '  良性:' num2str(count_B)...
      '  恶性:' num2str(count_M)]);
disp(['测试集病例总数:' num2str(69)...
      '  良性:' num2str(number_B)...
      '  恶性:' num2str(number_M)]);
disp(['良性乳腺肿瘤确诊:' num2str(number_B_sim)...
      '  误诊:' num2str(number_B - number_B_sim)...
      '  确诊率p1=' num2str(number_B_sim/number_B*100) '%']);
disp(['恶性乳腺肿瘤确诊:' num2str(number_M_sim)...
      '  误诊:' num2str(number_M - number_M_sim)...
      '  确诊率p2=' num2str(number_M_sim/number_M*100) '%']);
  
  
R = [];
for i = 50:50:500
    %% ELM创建/训练
    [IW,B,LW,TF,TYPE] = elmtrain(P_train,T_train,i,'sig',1);
    
    %% ELM仿真测试
    T_sim_1 = elmpredict(P_train,IW,B,LW,TF,TYPE);
    T_sim_2 = elmpredict(P_test,IW,B,LW,TF,TYPE);
    
    %% 结果对比
    result_1 = [T_train' T_sim_1'];
    result_2 = [T_test' T_sim_2'];
    % 训练集正确率
    k1 = length(find(T_train == T_sim_1));
    n1 = length(T_train);
    Accuracy_1 = k1 / n1 * 100;
%     disp(['训练集正确率Accuracy = ' num2str(Accuracy_1) '%(' num2str(k1) '/' num2str(n1) ')'])
    % 测试集正确率
    k2 = length(find(T_test == T_sim_2));
    n2 = length(T_test);
    Accuracy_2 = k2 / n2 * 100;
%     disp(['测试集正确率Accuracy = ' num2str(Accuracy_2) '%(' num2str(k2) '/' num2str(n2) ')'])
    R = [R;Accuracy_1 Accuracy_2];
end
  
figure
plot(50:50:500,R(:,2),'b:o')
xlabel('隐含层神经元个数')
ylabel('测试集预测正确率(%)')
title('隐含层神经元个数对ELM性能的影响')

        运行结果:

  

4.2 拟合问题主函数和运行结果

%% 极限学习机在回归拟合问题中的应用研究

%% 清空环境变量
clear all
clc

%% 导入数据
load data
% 随机生成训练集、测试集
k = randperm(size(input,1));
% 训练集——1900个样本
P_train=input(k(1:1900),:)';
T_train=output(k(1:1900));
% 测试集——100个样本
P_test=input(k(1901:2000),:)';
T_test=output(k(1901:2000));

%% 归一化
% 训练集
[Pn_train,inputps] = mapminmax(P_train,-1,1);
Pn_test = mapminmax('apply',P_test,inputps);
% 测试集
[Tn_train,outputps] = mapminmax(T_train,-1,1);
Tn_test = mapminmax('apply',T_test,outputps);

tic
%% ELM创建/训练
[IW,B,LW,TF,TYPE] = elmtrain(Pn_train,Tn_train,20,'sig',0);

%% ELM仿真测试
Tn_sim = elmpredict(Pn_test,IW,B,LW,TF,TYPE);
% 反归一化
T_sim = mapminmax('reverse',Tn_sim,outputps);

toc
%% 结果对比
result = [T_test' T_sim'];
% 均方误差
E = mse(T_sim - T_test)
% 决定系数
N = length(T_test);
R2 = (N*sum(T_sim.*T_test)-sum(T_sim)*sum(T_test))^2/((N*sum((T_sim).^2)-(sum(T_sim))^2)*(N*sum((T_test).^2)-(sum(T_test))^2))

%% 绘图
figure
plot(1:length(T_test),T_test,'r*')
hold on
plot(1:length(T_sim),T_sim,'b:o')
xlabel('测试集样本编号')
ylabel('测试集输出')
title('ELM测试集输出')
legend('期望输出','预测输出')

figure
plot(1:length(T_test),T_test-T_sim,'r-*')
xlabel('测试集样本编号')
ylabel('绝对误差')
title('ELM测试集预测误差')

        运行结果如下:


5.案例扩展

        以乳腺肿瘤识别为例,探讨隐含层神经元个数的影响。从隐含层神经元个数对ELM性能的影响图可知,并非隐含层神经元个数越多越好,从测试集的预测正确率可以看出,当隐含层神经元个数逐渐增加时,测试集的预测正确率呈逐渐减小的趋势。因此,需要综合考虑测试集的预测正确率和隐含层神经元的个数,进行折中选择.

        ELM以其学习速度快、泛化性能好、调节参数少等优点,在各个领域得到了广泛的应用。 随着研究的深人,一些专家提出了许多改进的方法,如在线学习ELM、进化ELM等,同时,一 些学者将其他算法中的思想(如SVM中的结构风险最小等)引入到ELM中,取得了不错的 效果。

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

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

相关文章

机器人操作系统【02】:如何在 ROS2 中对点云数据进行建模

一、说明 RViz和Gazebo中RADU的模拟进展顺利。在上一篇文章中&#xff0c;我们学习了如何启动机器人并使用远程节点进行操作。在本文中&#xff0c;我们将添加两个视觉传感器。首先&#xff0c;一个图像摄像机&#xff0c;用于在机器人四处移动时查看机器人的实时馈送。其次&am…

Nginx高可用集群

目录 一.简介二.案例1.实现思路2.配置文件修改3.实现效果故障转移机制 一.简介 以提高应用系统的可靠性&#xff0c;尽可能地减少中断时间为目标&#xff0c;确保服务的连续性&#xff0c;达到高可用的容错效果。例如“故障切换”、“双机热备”、“多机热备”等都属于高可用集…

03:TIM定时器

目录 一:TIM 1:介绍 2:定时器的分类 3:基本定时器 4:通用定时器 5:高级定时器 6:定时器的基本结构 二:定时中断功能 A:定时器定时器中断 1:连接图 ​编辑 2:步骤 3:函数介绍 4:代码 三:外部时钟功能 A:定时器外部时钟 1:连接图 2:函数介绍 3:外部时钟代码 一…

【FreeRTOS】【应用篇】任务创建

前言 从本篇开始&#xff0c;将不再太过于关心 FreeRTOS 的内核细节&#xff0c;把重心转移到对 FreeRTOS 的应用上来。 本篇代码大部分参考野火的 FreeRTOS 教程。 一、静态任务和动态任务创建的区别 1. 概念解析 在 FreeRTOS 中&#xff0c;我们可以选择两个不同的函数进…

微信小程序,封装身高体重选择器组件

wxml代码&#xff1a; // 微信小程序的插值语法不支持直接使用Math <wxs src"./ruler.wxs" module"math"></wxs> <view class"ruler-container"><scroll-view scroll-left"{{scrollLeft}}" enhanced"{{tru…

探索软件项目管理的本质及概念

什么是软件项目管理&#xff1f; 软件项目管理是指对软件项目从规划、组织、指挥、控制到最终交付的全过程进行有效管理的一种方法。它通过合理的资源分配、有效的沟通和高效的协作&#xff0c;确保软件项目能够按照预定的目标、时间和质量要求完成。在现代信息技术逐渐普及和…

互联网企业内部FAQ的设计指南:帮助企业用户快速解决常见问题!

在互联网企业中&#xff0c;内部FAQ&#xff08;Frequently Asked Questions&#xff09;是帮助企业用户快速解决常见问题的重要工具。一个优秀的内部FAQ不仅可以提高用户满意度&#xff0c;还可以减轻客服团队的负担。本文将介绍互联网企业内部FAQ的设计指南&#xff0c;帮助企…

知识储备--基础算法篇-动态规划

1.前言 第一次接触动态规划&#xff0c;不知道具体什么意思&#xff0c;做了题才发现动态规划就是把大问题变成小问题&#xff0c;并解决了小问题重复计算的方法称为动态规划。比如上楼梯&#xff0c;一次上一阶或二阶&#xff0c;求有多少种算法&#xff0c;就可以拆成最后一…

Flutter 小技巧之 3.13 全新生命周期 AppLifecycleListener

Flutter 3.13 在 Framework 里添加了 AppLifecycleListener 用于监听应用生命周期变化&#xff0c;并响应退出应用的请求等支持&#xff0c;那它有什么特殊之处&#xff1f;和老的相比又有什么不同&#xff1f; 简单说&#xff0c;在 Flutter 3.13 之前&#xff0c;我们一般都…

计网第三章(数据链路层)(五)

目录 一、以太网交换机自学习和转发帧的过程 1.两层交换机和三层交换机 2.以太网交换机的基本原理 3.具体实现过程 一、以太网交换机自学习和转发帧的过程 1.两层交换机和三层交换机 大家可能注意到平常做题时有叫两层交换机&#xff0c;或者三层交换机的。 两层交换机就…

为什么需要websocket?

一、为什么需要websocket&#xff1f; 前端和后端的交互模式最常见的就是前端发数据请求&#xff0c;从后端拿到数据后展示到页面中。如果前端不做操作&#xff0c;后端不能主动向前端推送数据&#xff0c;这也是http协议的缺陷。 因此&#xff0c;一种新的通信协议应运而生---…

使用kabeja库解析DXF格式文件

DXF格式是一种开源的CAD文件格式&#xff0c;如何实现Java代码对齐的解析&#xff0c;在网上找了很久&#xff0c;也没有找到非常成熟的库。很奇怪&#xff0c;开源的格式&#xff0c;正常应该会有很多的库来支持。只找到了一个kabeja库&#xff0c;最新版本还是2008年出的0.4版…

GTK3实现自定义列表

使用gtk,如果想自己定义列表,思路可以将每个列表项作为一个hbox,整个列表是一个vbox。通过对容器动态的添加删除,实现列表操作,同时添加任何自己所需要的控件。 下面的例子是实现一个显示图片、按钮和进度条的列表,并且进行上移下移,具有添加和删除列表项功能但没有演示…

网站巡查与SEO:爱校对如何确保内容的最佳质量?

随着互联网的飞速发展&#xff0c;企业和个人正在寻找优化他们网站内容的最佳方式。在这个数字化时代&#xff0c;网站巡查和SEO已成为维持网站高度相关性和可见性的关键。此时&#xff0c;工具如“爱校对”不仅帮助检查文本的质量&#xff0c;还确保内容对搜索引擎优化&#x…

STM32使用定时器实现微秒(us)级延时

STM32使用定时器实现微秒&#xff08;us&#xff09;级延时 引言前期准备介绍系统时钟定时器时钟 项目项目介绍STM32CubeMX程序 引言 目前开发STM32普遍使用HAL库&#xff0c;但 HAL 库封装的延时函数目前仅支持 ms 级别的延时&#xff0c;日常很多情况下会用到 us 延时&#…

IC封装——从基本概念到TSV

一、IC封装 在之前文章中有大致提过封装&#xff0c;这里展开讲讲 芯片生产流程_沧海一升的博客-CSDN博客每个半导体产品的制造都需要数百个工艺&#xff0c;泛林集团将整个制造过程分为八个步骤&#xff1a;晶圆加工-氧化-光刻-刻蚀-薄膜沉积-互连-测试-封装。_芯片生产流程h…

spring异步框架使用教程

背景 在需求开发过程中&#xff0c;为了提升效率&#xff0c;很容易就会遇到需要使用多线程的场景。这个时候一般都会选择建一个线程池去专门用来进行某一类动作&#xff0c;这种任务到来的时候往往伴随着大量的线程被创建调用。而还有另外一种场景是整个任务的执行耗时比较长…

ElasticSearch 7.4学习记录(DSL语法)

上文和大家一起初次了解了很多ES相关的基础知识&#xff0c;本文的内容将会是实际企业中所需要的吗&#xff0c;也是我们需要熟练应用的内容。 面对ES&#xff0c;我们最多使用的就是查询&#xff0c;当我负责这个业务时&#xff0c;现不需要我去考虑如何创建索引&#xff0c;添…

ubuntu18.04安装keil5(踩坑)看完再享用,别直接上手

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装winewine的总结 二、安装Keil5总结 前言 切记看完再享用&#xff0c;别直接上手&#xff0c;不然安装的时候会和我一样踩坑的&#xff08;走了很多弯路…

Unity之用Transform 数组加多个空物体-->简单地控制物体按照指定路线自动行驶

文章目录 **原理解释**&#xff1a;**带注释的代码**&#xff1a;实际运用 当你需要实现物体按照指定路线行驶时&#xff0c;你可以通过以下步骤来实现&#xff1a; 原理解释&#xff1a; 路径点&#xff1a;你需要定义一系列路径点&#xff0c;这些点将构成物体行驶的路线。每…