一文速学-GBDT模型算法原理以及实现+Python项目实战
目录
前言
一、GBDT算法概述
1.决策树
2.Boosting
3.梯度提升
使用梯度上升找到最佳参数
二、GBDT算法原理
1.计算原理
2.预测原理
三、实例算法实现
1.模型训练阶段
1)初始化弱学习器
2)对于建立M棵分类回归树:
四、Python实现
1.原始决策树累积
2.sklearn
前言
上篇文章内容已经将Adaboost模型算法原理以及实现详细讲述实践了一遍,但是只是将了Adaboost模型分类功能,还有回归模型没有展示,下一篇我将展示如何使用Adaboost模型进行回归算法训练。首先还是先回到梯度提升决策树GBDT算法模型上面来,GBDT模型衍生的模型在其他论文研究以及数学建模比赛中十分常见,例如XGBoost,LighGBM,catboost。其实将这些算法重要的点拿出来就更容易理解了,主要是五个方向的变动改进:
| 算法差异点 | GBDT | XGBoost | LightGBM | CatBoost |
| 弱学习器 | CART回归树 | 1.CART回归树 2.线性学习器 3.Dart树 | Leaf-wise树 | 对称树 |
| 寻找分裂点 | 贪心算法 | 近似算法 | 直方图算法 | 预排序算法 |
| 稀疏值处理 | 无 | 稀疏感知算法 | EFB(互斥特征捆绑) | 无 |
| 类别特征 | 不直接支持,可自行编码后输入模型 | 同GBDT | 直接支持,GS编码 | 直接支持,Ordered TS编码 |
| 并行支持 | 不可以 | 可以 | 可以 | 可以 |
本篇主讲GBDT算法模型以及应用,先把大体框架熟悉,之后的算法只需要填补功能就好了。本篇并不会提及太多专业公式以及推论公式,数学基础薄弱的不用担心,大家可以放心学习,我会尽可能简单易懂的讲明白算法原理,主要是实战以及运用和相关代码的使用。
一、GBDT算法概述
在开篇Boosting算法中有过讲到,回顾下Adaboost,我们是利用前一轮迭代弱学习器的误差率来更新训练集的权重,这样一轮轮的迭代下去。GBDT也是迭代,使用了前向分布算法,但是弱学习器限定了只能使用CART回归树模型,同时迭代思路和Adaboost也有所不同。
GBDT的思想可以用一个通俗的例子解释,假如有个人30岁,我们首先用20岁去拟合,发现损失有10岁,这时我们用6岁去拟合剩下的损失,发现差距还有4岁,第三轮我们用3岁拟合剩下的差距,差距就只有一岁了。如果我们的迭代轮数还没有完,可以继续迭代下面,每一轮迭代,拟合的岁数误差都会减小。
1.决策树
那么GBDT算法肯定有其对应的弱学习器,也就是CART回归树。
这里如果大家之前并没有了解过决策树的概念,可以去看我的这篇文章:
一文速学数模-分类模型(二)决策树(Decision Tree)算法详解及python实现
那么这个CART指的是(Classification and Regression Tree)的意思, 这里我大体讲述一下该决策树算法:,决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。

2.Boosting
Boosting的思路则是串行的,每一次训练一个模型都是建立在前一个模型的学习基础上,不断去通过新模型去减少之前的错误。
这点思路在讲AdaBoosting算法模型时候已经讲的很明确了,一图就可了解:

3.梯度提升
在梯度提升中,每个弱学习器的训练都是基于前一个弱学习器的预测误差,通过梯度下降的方式来最小化误差。具体来说,对于回归问题,我们可以选择平方损失函数作为损失函数。
关于梯度提升算法我之前在Logistic原理详解和遗传算法里面也有详解讲过,此类最优算法最核心的一点就是对于残差的使用。而损失函数就是衡量调整每一次迭代模型算法的权重的参考功能。
损失函数(loss function):为了评估模型拟合的好坏,通常用损失函数来度量拟合的程度。损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优参数。在线性回归中,损失函数通常为样本输出和假设函数的差取平方。比如对于样本,采用线性回归,损失函数为:

对于分类问题,则可以选择交叉熵损失函数。在每次迭代中,我们都会训练一个新的弱学习器,使得它能够最大程度地减少当前模型的误差。然后将这个新的学习器加入到当前的模型中,从而不断提升整个模型的预测能力。

使用梯度上升找到最佳参数
使用梯度上升找到最佳参数可以假设为爬山运动,我们总是往向着山顶的方向攀爬,当爬到一定角度以后也会驻足停留下观察自身角度是否是朝着山顶的角度上攀爬。并且我们需要总是指向攀爬速度最快的方向爬。
要找到某函数的最大值,最好的方法就是沿着该函数的梯度方向搜寻。我们假设步长为,用向量来表示的话,梯度上升算法的迭代公式如下:
。该公式停止的条件是迭代次数达到某个指定值或者算法达到某个允许的误差范围。
梯度提升的一个重要特点是它可以应用于各种类型的弱学习器,例如决策树、线性模型、神经网络等。然而,决策树是梯度提升中最常用的弱学习器之一,因为它们可以很好地处理非线性特征和交互作用,同时也可以通过剪枝等技术来避免过拟合。
二、GBDT算法原理
1.计算原理
GBDT算法的原理如下:
-
初始化。将所有样本的权重设置为相等的值,建立一个初始模型作为基准模型,可以设置为简单的平均值或者是中位数。例如建立一个弱分类器
,c即为平均值。
-
迭代训练。在每一轮迭代中,GBDT算法会先根据当前模型的预测结果计算每个样本的残差。对于回归问题,残差就是实际输出值与模型预测值之间的差异,对于分类问题,残差就是样本的实际类别与模型预测类别之间的差异。然后,GBDT会训练一个新的决策树模型,来学习如何预测这些残差。对于建立M棵CART树m=1,2,...M:
-
对i=1,2,...,N, 计算第m棵树对应的响应值(损失函数的负梯度):

-
对于i = 1,2,...N,利用CART回归树拟合数据,得到第m棵回归树,其对应的叶子节点区域为
,其中j=1,2,...,
,且
为第m棵回归叶子节点的个数。
-
对于
个叶子节点区域j=1,2,...,
,计算最佳拟合值
-
更新强学习器
:
-
-
添加新模型。新模型的预测结果会被加入到当前模型的输出中,使得模型的预测结果逐步趋近于真实值。可以将每个模型的输出进行加权求和,得到最终模型的输出。
-
终止条件。当模型的准确率达到一定阈值,或者迭代次数达到预设的最大值时,算法停止迭代。最后得到强学习器表达式:
GBDT算法通过不断训练新的决策树模型,并将它们的预测结果累加到当前模型的输出中,来逐步提升整个模型的预测能力。与传统的决策树算法相比,GBDT算法可以减少过拟合的风险,并且具有较强的鲁棒性。
2.预测原理
上述模型生成原理的数学推论和公式是绕不开的,其他算法模型也是一样,在所有的机器学习以及其他算法模型中来说,没有不存在数学公式的模型。但是预测原理我们可以尽可能简化,这里参考GBDT的原理和应用的举例比较形象:
假设我们要预测一个人是否会喜欢电脑游戏,特征包括年龄,性别是否为男,是否每天使用电脑。标记(label)为是否喜欢电脑游戏,假设训练出如下模型:

该模型又两棵树组成, tree1使用 age < 15 和 is male 作为内节点,叶子节点是输出的分数。 tree2使用是否每日使用电脑作为根节点。假设测试样本如下:

最后对某样本累加它所在的叶子节点的输出值,例如:

单独的使用GBDT模型,容易出现过拟合,在实际应用中往往使用 GBDT+LR的方式做模型训练。
三、实例算法实现
首先我们以一组数据作为训练集:
| 编号 | 车辆速度 | 道路等级 | 拥堵状态 |
| 0 | 20 | 1 | 5 |
| 1 | 30 | 2 | 4 |
| 2 | 60 | 3 | 2 |
| 3 | 70 | 4 | 2 |
测试数据如下表所示:
| 编号 | 车辆速度 | 道路等级 | 拥堵状态 |
| 0 | 50 | 3 | ? |
1.模型训练阶段
参数设置:
-
学习率:learning_rate = 0.3
-
迭代次数:n_trees = 6
-
树的深度:max_depth = 3
1)初始化弱学习器
损失函数为平方损失,因为平方损失函数是一个凸函数,可以直接求导,令导数等于零,得到:

令导数等于0:

所以初始化时,
取值为所有训练样本标签值的均值。
,此时得到的初始化学习器为
2)对于建立M棵分类回归树
:
由于我们设置了迭代次数:n_trees=6,这就是设置了M=6。
首先计算负梯度,根据上文损失函数为平方损失时,负梯度就是残差,也就是
与上一轮得到的学习器
的差值:

现将残差的计算结果列表如下:
| 编号 | 真实值 | 残差 | |
| 0 | 5 | 3.25 | 1.75 |
| 1 | 4 | 3.25 | 0.75 |
| 2 | 2 | 3.25 | -1.25 |
| 3 | 2 | 3.25 | -1.25 |
此时将残差作为样本的真实值来训练弱学习器
,即下表数据:
| 编号 | 车辆速度 | 道路等级 | 拥堵状态 |
| 0 | 20 | 1 | 1.75 |
| 1 | 30 | 2 | 0.75 |
| 2 | 60 | 3 | -0.25 |
| 3 | 70 | 4 | -1.25 |
遍历每个特征的每个可能取值。从车辆速度为20开始,到道路等级特征为4结束,分别计算分裂后两组数据的平方损失(Square Error),
为左节点的平方损失,
为右节点的平方损失,找到使平方损失和
最小的那个划分节点,即为最佳划分节点。
例如:以车辆速度为30划分节点,将小于30的样本划分为左节点,大于等于30的样本划分为右节点。
| 划分点 | 小于划分点的样本 | 大于等于划分点的样本 | |||
| 车辆速度20 | / | 0,1,2,3 | 0 | 5.25 | 5.25 |
| 车辆速度30 | 0 | 1,2,3 | 0 | 2.1875 | 2.1875 |
| 车辆速度60 | 0,1 | 2,3 | ... | ||
| 车辆速度70 | 0,1,2 | 3 | |||
| 道路等级1 | / | 0,1,2,3 | |||
| 道路等级2 | 0 | 1,2,3 | |||
| 道路等级3 | 0,1 | 2,3 | |||
| 道路等级4 | 0,1,2 | 3 | 3.675625 | 0 | 3.675625 |
以上划分点的总平方损失最小有两个划分点:车辆速度30和道路等级3.所以随机选一个作为划分点,这里我们选车辆速度30:

我们设置的参数中树的深度max_depth=3,现在树的深度只有2,需要再进行一次划分,这次划分要对左右两个节点分别进行划分:

此时我们的树深度满足了设置,还需要做一件事情,给这每个叶子节点分别赋一个参数
,来拟合残差。

这里其实和上面初始化弱学习器是一样的,对平方损失函数求导,令导数等于零,化简之后得到每个叶子节点的参数
,其实就是标签值的均值。这个地方的标签值不是原始的
,而是本轮要拟合的标残差
。
此时可更新强学习器,需要用到参数学习率:learning_rate=0.1,用
表示。更新公式为:

为什么要用学习率呢?这是Shrinkage的思想,如果每次都全部加上拟合值
,即学习率为1,很容易一步学到位导致GBDT过拟合。
重复此步骤,最后生成5棵树。
得到最后的强学习器:

四、Python实现
1.原始决策树累积
如果安装我们上一步这样原生计算推论的话,那么代码应该这样写:
from sklearn.tree import DecisionTreeRegressor
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
import pandas as pd
import pydotplus
from pydotplus import graph_from_dot_data
from sklearn.tree import export_graphviz
import os
os.environ["Path"] += os.pathsep + 'D:/Graphviz/bin'data_1=[[20,1,5],[30,2,4],[60,3,2],[70,4,2]]
data=pd.DataFrame(data_1,columns=['speed','kind','state'])X=np.array(data.iloc[:,:-1]).reshape((-1,2))
y=np.array(data.iloc[:,-1]).reshape((-1,1))
tree_reg1 = DecisionTreeRegressor(max_depth=4,random_state=10)
tree_reg1.fit(X, y)
y2 = y - np.array([3.25]*4).reshape((-1,1))
tree_reg2 = DecisionTreeRegressor(max_depth=4,random_state=10)
tree_reg2.fit(X, y2)
y3 = y2 - 0.1*np.array(tree_reg2.predict(X)).reshape((-1,1))
tree_reg3 = DecisionTreeRegressor(max_depth=4,random_state=10)
tree_reg3.fit(X, y3)
y4 = y3 - 0.1*np.array(tree_reg3.predict(X)).reshape((-1,1))
tree_reg4 = DecisionTreeRegressor(max_depth=4,random_state=10)
tree_reg4.fit(X, y4)
y5 = y4 - 0.1*np.array(tree_reg4.predict(X)).reshape((-1,1))
tree_reg5 = DecisionTreeRegressor(max_depth=4,random_state=10)
tree_reg5.fit(X, y5)
y6 = y5 - 0.1*np.array(tree_reg5.predict(X)).reshape((-1,1))
tree_reg6 = DecisionTreeRegressor(max_depth=4,random_state=10)
tree_reg6.fit(X, y6)

2.sklearn
使用sklearn的话:
estimator=GradientBoostingRegressor(random_state=10)
estimator.fit(data.iloc[:,:-1],data.iloc[:,-1])
dot_data = export_graphviz(estimator.estimators_[5,0], out_file=None, filled=True, rounded=True, special_characters=True, precision=4)
graph = pydotplus.graph_from_dot_data(dot_data)

二者树不同是因为参数学习率以及树的深度,迭代次数不一致导致,无碍。
那么我们现在拿预测样本来使用:
predict_data=pd.DataFrame({'speed':50,'kind':3},index=[0])
estimator.predict(predict_data)

至此模型建立完毕,那么让我们总结一下GBDT模型特性:
AdaBoost和GBDT都是重复选择一个表现一般的模型并且每次基于先前模型的表现进行调整。不同的是,AdaBoost是通过调整错分数据点的权重来改进模型,GBDT是通过计算负梯度来改进模型。因此,相比AdaBoost, GBDT可以使用更多种类的目标函数,而当目标函数是均方误差时,计算损失函数的负梯度值在当前模型的值即为残差。
GBDT的求解过程就是梯度下降在函数空间中的优化过程。在函数空间中优化,每次得到增量函数,这个函数就是GBDT中一个个决策树,负梯度会拟合这个函数。要得到最终的GBDT模型,只需要把初始值或者初始的函数加上每次的增量即可。
相关文章:
一文速学-GBDT模型算法原理以及实现+Python项目实战
目录 前言 一、GBDT算法概述 1.决策树 2.Boosting 3.梯度提升 使用梯度上升找到最佳参数 二、GBDT算法原理 1.计算原理 2.预测原理 三、实例算法实现 1.模型训练阶段 1)初始化弱学习器 2)对于建立M棵分类回归树: 四、Python实现 …...
前端——2.HTML基本结构标签
这篇文章我们从0来介绍一下HTML的相关标签内容 目录 1.HTML语法规范 1.1基本语法概述 1.2标签关系 2.HTML的基本结构标签 2.1第一个HTML网页 2.2基本结构标签总结 1.HTML语法规范 下面,我们来看一下HTML的语法规范的内容 1.1基本语法概述 首先,…...
OAK深度相机使用不同镜头和本地视频流进行模型推理
编辑:OAK中国 首发:oakchina.cn 喜欢的话,请多多👍⭐️✍ 内容可能会不定期更新,官网内容都是最新的,请查看首发地址链接。 ▌前言 Hello,大家好,这里是OAK中国,我是助手…...
[项目] Boost搜索引擎
目录 1.项目相关背景 2.项目宏观原理 3.技术栈和项目环境 4.正排索引&&倒排索引 5.去标签与数据清洗 6.构建索引模块Index 6.1正排索引 6.2 建立倒排 jiebacpp使用 建立分词 7.搜索引擎模块Searcher Jsoncpp -- 通过jsoncpp进行序列化和反序列化 处理Cont…...
解决新版QGIS找不到Georeferencer插件
目录1. 问题分析1.1 去 Raster 找,没找到1.2 去插件搜,未搜到1.3 插件库里也搜不到2. 解决办法在 QGIS 3.30中,按常规办法,找不到 Georeferencer插件,它并没有被安装,在库中也找不到它, 请问问题…...
c---冒泡排序模拟qsort
一、冒泡排序 二、冒泡排序优化排各种类型数据 文章目录一、冒泡排序二、冒泡排序优化排各种类型数据冒泡排序 冒泡排序原理:两两相邻元素进行比较 初级版 void bulle_sort(int* a, int sz) {int i 0;for (int i 0; i < sz-1; i){int j 0; for (j 0; j…...
Java知识复习(十四)JS
1、数据类型 基本数据类型:null、undefinde、boolean、string、number、symbol(ES6新增)引用数据类型:Function、Array、Object、Map和Set(ES6新增) 2、let、var和const的区别 var定义的变量,…...
代码随想录刷题-数组-移除元素
文章目录写在前面习题我的想法暴力解法双指针写在前面 本节对应代码随想录中:代码随想录 习题 题目链接: 27. 移除元素- 力扣(LeetCode) 给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素&a…...
聚观早报 |拼多多跨境电商业务正式登陆澳洲;中国加快6G网络研发
今日要闻:拼多多跨境电商业务正式登陆澳洲;全球自动驾驶公司排名特斯拉垫底;中国将加快 6G 网络研发;B站再次“崩”上热搜!已闪电修复;微软将必应AI聊天每次对话上限增加至8条拼多多跨境电商业务正式登陆澳…...
MDK Keil5 创建Stm32工程-理论篇(这里以Stm32F103Zet6为例)
一、文件夹创建与文件说明整个工程可以粗略的划分为几个文件夹:BSP底层驱动比如GPIO\Timer等驱动文件CMSIS内核相关的文件Firmware生成的固件下载文件Mycode用户编写的相关文件,主要编写的文件都在这个文件夹里Project工程文件startup芯片启动文件STM32F…...
应届大学生学什么技术好?哪些技术适合年轻人?
到了毕业季,应届大学生面临的就是就业问题,很多专业的大学生难以找到对口的工作,或是不得已随便就业,或者是学个技术高薪就业,那么,问题来了,应届大学生学什么技术好?哪些技术适合年…...
车企数据分类分级的实践指南出炉!“数据安全推进计划”发布,奇点云参编
日前,“数据安全推进计划”(DSI)正式发布《智能网联汽车数据分类分级实践指南》(下文简称“指南”),旨在以合规为主要导向,明确智能网联汽车数据分类分级的方法论,为数据全生命周期的…...
Nginx学习 (2) —— 虚拟主机配置
文章目录虚拟主机原理域名解析与泛域名解析(实践)配置文件中ServerName的匹配规则技术架构多用户二级域名短网址虚拟主机原理 为什么需要虚拟主机: 当一台主机充当服务器给用户提供资源的时候,并不是一直都有很大的用户量&#…...
Java 动态代理简述和实例
Java动态代理是一种在运行时动态创建代理对象的技术。它可以让我们在不修改原始代码的情况下,对原始对象进行增强或者添加额外的行为。这种代理方式可以用于很多场景,例如AOP编程、RPC框架等。动态代理是基于Java反射机制实现的,它允许程序在…...
Unity编译器扩展(Advanced Editor Scripting)
Untiy编译器扩展允许我们对编译器的增加自己编写的的功能菜单栏MenuItemContextMenu和ContextMenuItemContextMenuContextMenuItemMenuItem 该属性允许您将菜单项添加到主菜单和检查器窗口上下文菜单。 该属性将任何静态函数转换为菜单命令。只有静态函数可以使用该属性。 Men…...
AFR机制及流程介绍
AFR(Auto Fast Return)不符合3GPP协议标准,因此终端默认是disable状态。如果运营商有要求可以配置开启。 AFR有两种场景 2G或者3G AFR到4G4G AFR到5G3G AFR TO 4G AFR到LTE功能的作用就是终端从LTE Handover或者重定向到3G进行业务,等业务做完后能够快速回到LTE网络。...
9.Hbase 部署
9.Hbase部署 注意事项: 1:必须事先安装 Hadoop分布式集群,zookeeper分布式集群 2:查看版本号: hbase version1、解压文件并改名 tar -zxvf /opt/software/hbase-2.2.3-bin.tar.gz -C /usr/app/ mv hbase-2.2.3/ hba…...
【maven 学习记录】
maven 学习记录一、maven基础1. maven是什么2. maven的作用3. maven的下载安装4. maven仓库5. maven坐标6. 第一个maven项目 手工实现7. maven插件8. 依赖管理9. 生命周期二、maven进阶一、maven基础 1. maven是什么 maven的本质是一个项目管理工具,将项目开发和管…...
NB-IOT宣传这么多年,这次总算用好了吧
一、方案概述随着实体经济快速发展,石化、港口、货场、工地等区域规模日益扩大,厂区面积广阔、环境复杂、作业人员和车辆众多,如无法实时掌握工作人员状态及外来人员位置、外来车辆情况等问题,将存在非常大的安全隐患。今天小编介…...
sort函数对结构体|pair对组|vector容器|map排序|二维数组的第x列 的排序
目录 sort对 vector容器 sort对 vector<pair<int,int>>对组 sort对 结构体 结构体外部规定排序 结构体内部运算符重载 map容器的排序 map的键排序 map的值排序 sort对二维数组的排序 sort对 vector容器 sort()函数可以用于对vector容器进行排序。具体来…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
OPENCV图形计算面积、弧长API讲解(1)
一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积,这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能,常用的API…...
