Python 机器学习 基础 之 算法链与管道 【通用的管道接口/网格搜索预处理步骤与模型参数/网格搜索选择使用哪个模型】的简单说明

news2024/11/26 16:22:33

Python 机器学习 基础 之 算法链与管道 【通用的管道接口/网格搜索预处理步骤与模型参数/网格搜索选择使用哪个模型】的简单说明

目录

Python 机器学习 基础 之 算法链与管道 【通用的管道接口/网格搜索预处理步骤与模型参数/网格搜索选择使用哪个模型】的简单说明

一、简单介绍

二、通用的管道接口

三、网格搜索预处理步骤与模型参数

四、网格搜索选择使用哪个模型

附录

一、参考文献


一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

Python 机器学习是利用 Python 编程语言中的各种工具和库来实现机器学习算法和技术的过程。Python 是一种功能强大且易于学习和使用的编程语言,因此成为了机器学习领域的首选语言之一。Python 提供了丰富的机器学习库,如Scikit-learn、TensorFlow、Keras、PyTorch等,这些库包含了许多常用的机器学习算法和深度学习框架,使得开发者能够快速实现、测试和部署各种机器学习模型。

Python 机器学习涵盖了许多任务和技术,包括但不限于:

  1. 监督学习:包括分类、回归等任务。
  2. 无监督学习:如聚类、降维等。
  3. 半监督学习:结合了有监督和无监督学习的技术。
  4. 强化学习:通过与环境的交互学习来优化决策策略。
  5. 深度学习:利用深度神经网络进行学习和预测。

通过 Python 进行机器学习,开发者可以利用其丰富的工具和库来处理数据、构建模型、评估模型性能,并将模型部署到实际应用中。Python 的易用性和庞大的社区支持使得机器学习在各个领域都得到了广泛的应用和发展。

二、通用的管道接口

Pipeline 类不但可用于预处理和分类,实际上还可以将任意数量的估计器连接在一起。

在机器学习中,使用管道(Pipeline)和算法链可以让数据预处理、特征选择和模型训练等步骤变得更加简洁和系统化。Scikit-learn 提供了一个通用的管道接口,通过 Pipelinemake_pipeline 来实现。这使得我们可以将多个步骤整合到一起,形成一个统一的工作流。下面是一些主要概念和如何使用通用的管道接口的详细说明。

定义

  1. Pipeline:

    • Pipeline 是一个可以串联多个处理步骤的对象。每个步骤都是一个二元组,包含一个名字和一个估计器(如预处理步骤或模型)。
    • Pipeline 的最后一步必须是一个模型(如分类器或回归器),而中间步骤可以是任何数据转换器(如标准化、特征选择等)。
  2. make_pipeline:

    • make_pipeline 是一个简化的工厂函数,用于创建一个 Pipeline 对象。它自动为每个步骤生成名称,无需手动指定名称。

共同点和区别

  • 共同点:

    • 都可以将多个处理步骤整合到一起。
    • 都提供了统一的接口,可以像单个模型一样进行训练和预测。
    • 都支持超参数的网格搜索和交叉验证。
  • 区别:

    • Pipeline 需要手动为每个步骤指定名称。
    • make_pipeline 自动为每个步骤生成名称,适合步骤较少且名称无关紧要的情况。

使用示例

  1. 使用 Pipeline
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing

# 加载数据
california = fetch_california_housing()
X_train, X_test, y_train, y_test = train_test_split(california.data, california.target, random_state=0)

# 创建管道
pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('poly', PolynomialFeatures(degree=2)),
    ('ridge', Ridge())
])

# 训练模型
pipe.fit(X_train, y_train)

# 评估模型
train_score = pipe.score(X_train, y_train)
test_score = pipe.score(X_test, y_test)

print(f"Training score: {train_score:.2f}")
print(f"Test score: {test_score:.2f}")
  1. 使用 make_pipeline
from sklearn.pipeline import make_pipeline

# 创建管道
pipe = make_pipeline(
    StandardScaler(),
    PolynomialFeatures(degree=2),
    Ridge()
)

# 训练模型
pipe.fit(X_train, y_train)

# 评估模型
train_score = pipe.score(X_train, y_train)
test_score = pipe.score(X_test, y_test)

print(f"Training score: {train_score:.2f}")
print(f"Test score: {test_score:.2f}")

选择和使用

  • 选择:

    • 使用 Pipeline 当你希望显式地为每个步骤命名时。
    • 使用 make_pipeline 当步骤名称不重要或步骤较少时。
  • 使用:

    • 管道允许你将数据预处理、特征生成和模型训练结合在一起,这样可以减少代码重复和错误。
    • 通过统一的接口,可以在整个数据处理和建模过程中保持一致性。
    • 可以将管道与 GridSearchCVRandomizedSearchCV 结合使用,进行超参数调优。

例如,你可以构建一个包含特征提取、特征选择、缩放和分类的管道,总共有 4 个步骤。同样,最后一步可以用回归或聚类代替分类。

对于管道中估计器的唯一要求就是,除了最后一步之外的所有步骤都需要具有 transform 方法,这样它们可以生成新的数据表示,以供下一个步骤使用。

在调用 Pipeline.fit 的过程中,管道内部依次对每个步骤调用 fittransform (或仅调用 fit_transform 。) ,其输入是前一个步骤中 transform 方法的输出。对于管道中的最后一步,则仅调用 fit

忽略某些细枝末节,其实现方法如下所示。请记住,pipeline.steps 是由元组组成的列表,所以 pipeline.steps[0][1] 是第一个估计器,pipeline.steps[1][1] 是第二个估计器,以此类推:

def fit(self, X, y):
    X_transformed = X
    for name, estimator in self.steps[:-1]:
        # 遍历除最后一步之外的所有步骤
        # 对数据进行拟合和变换
        X_transformed = estimator.fit_transform(X_transformed, y)
    # 对最后一步进行拟合
    self.steps[-1][1].fit(X_transformed, y)
    return self

使用 Pipeline 进行预测时,我们同样利用除最后一步之外的所有步骤对数据进行变换(transform ),然后对最后一步调用 predict :

def predict(self, X):
    X_transformed = X
    for step in self.steps[:-1]:
        # 遍历除最后一步之外的所有步骤
        # 对数据进行变换
        X_transformed = step[1].transform(X_transformed)
    # 利用最后一步进行预测
    return self.steps[-1][1].predict(X_transformed)

整个过程如图 6-3 所示,其中包含两个变换器(transformer)T1 和 T2 ,还有一个分类器(叫作 Classifier )。

图 6-3:管道的训练和预测过程概述

管道实际上比上图更加通用。管道的最后一步不需要具有 predict 函数,比如说,我们可以创建一个只包含一个缩放器和一个 PCA 的管道。由于最后一步(PCA )具有 transform 方法,所以我们可以对管道调用 transform ,以得到将 PCA.transform 应用于前一个步骤处理过的数据后得到的输出。管道的最后一步只需要具有 fit 方法。

利用上述语法创建管道有时有点麻烦,我们通常不需要为每一个步骤提供用户指定的名称。有一个很方便的函数 make_pipeline ,可以为我们创建管道并根据每个步骤所属的类为其自动命名。make_pipeline 的语法如下所示:

from sklearn.pipeline import make_pipeline
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.svm import SVC

# 标准语法
pipe_long = Pipeline([("scaler", MinMaxScaler()), ("svm", SVC(C=100))])
# 缩写语法
pipe_short = make_pipeline(MinMaxScaler(), SVC(C=100))

管道对象 pipe_long 和 pipe_short 的作用完全相同,但 pipe_short 的步骤是自动命名的。我们可以通过查看 steps 属性来查看步骤的名称:

print("Pipeline steps:\n{}".format(pipe_short.steps))
Pipeline steps:
[('minmaxscaler', MinMaxScaler()), ('svc', SVC(C=100))]

这两个步骤被命名为 minmaxscaler 和 svc 。一般来说,步骤名称只是类名称的小写版本。如果多个步骤属于同一个类,则会附加一个数字:

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

pipe = make_pipeline(StandardScaler(), PCA(n_components=2), StandardScaler())
print("Pipeline steps:\n{}".format(pipe.steps))
Pipeline steps:
[('standardscaler-1', StandardScaler()), ('pca', PCA(n_components=2)), ('standardscaler-2', StandardScaler())]

如你所见,第一个 StandardScaler 步骤被命名为 standardscaler-1 ,而第二个被命名为 standardscaler-2 。但在这种情况下,使用具有明确名称的 Pipeline 构建可能更好,以便为每个步骤提供更具语义的名称。

通常来说,你希望检查管道中某一步骤的属性——比如线性模型的系数或 PCA 提取的成分。要想访问管道中的步骤,最简单的方法是通过 named_steps 属性,它是一个字典,将步骤名称映射为估计器:

from sklearn.datasets import load_breast_cancer

# 加载并划分数据
cancer = load_breast_cancer()

# 用前面定义的管道对cancer数据集进行拟合
pipe.fit(cancer.data)
# 从"pca"步骤中提取前两个主成分
components = pipe.named_steps["pca"].components_
print("components.shape: {}".format(components.shape))
components.shape: (2, 30)

本章前面说过,使用管道的主要原因之一就是进行网格搜索。一个常见的任务是在网格搜索内访问管道的某些步骤。我们对 cancer 数据集上的 LogisticRegression 分类器进行网格搜索,在将数据传入 LogisticRegression 分类器之前,先用 Pipeline 和 StandardScaler 对数据进行缩放。首先,我们用 make_pipeline 函数创建一个管道:

from sklearn.linear_model import LogisticRegression
pipe = make_pipeline(StandardScaler(), LogisticRegression())

接下来,我们创建一个参数网格。我们在第 2 章中说过,LogisticRegression 需要调节的正则化参数是参数 C 。我们对这个参数使用对数网格,在 0.01 和 100 之间进行搜索。由于我们使用了 make_pipeline 函数,所以管道中 LogisticRegression 步骤的名称是小写的类名称 logisticregression 。因此,为了调节参数 C ,我们必须指定 logisticregression__C 的参数网格:

param_grid = {'logisticregression__C': [0.01, 0.1, 1, 10, 100]}

像往常一样,我们将 cancer 数据集划分为训练集和测试集,并对网格搜索进行拟合:

from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV

X_train, X_test, y_train, y_test = train_test_split(
    cancer.data, cancer.target, random_state=4)
grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(X_train, y_train)

那么我们如何访问 GridSearchCV 找到的最佳 LogisticRegression 模型的系数呢?我们从第 5 章中知道,GridSearchCV 找到的最佳模型(在所有训练数据上训练得到的模型)保存在 grid.best_estimator_ 中:

print("Best estimator:\n{}".format(grid.best_estimator_))
Best estimator:
Pipeline(steps=[('standardscaler', StandardScaler()),
                ('logisticregression', LogisticRegression(C=1))])

在我们的例子中,best_estimator_ 是一个管道,它包含两个步骤:standardscaler 和 logisticregression 。如前所述,我们可以使用管道的 named_steps 属性来访问 logisticregression 步骤:

print("Logistic regression step:\n{}".format(
      grid.best_estimator_.named_steps["logisticregression"]))
Logistic regression step:
LogisticRegression(C=1)

现在我们得到了训练过的 LogisticRegression 实例,下面我们可以访问与每个输入特征相关的系数(权重):

print("Logistic regression coefficients:\n{}".format(
      grid.best_estimator_.named_steps["logisticregression"].coef_))
Logistic regression coefficients:
[[-0.4475566  -0.34609376 -0.41703843 -0.52889408 -0.15784407  0.60271339
  -0.71771325 -0.78367478  0.04847448  0.27478533 -1.29504052  0.05314385
  -0.69103766 -0.91925087 -0.14791795  0.46138699 -0.1264859  -0.10289486
   0.42812714  0.71492797 -1.08532414 -1.09273614 -0.85133685 -1.04104568
  -0.72839683  0.07656216 -0.83641023 -0.64928603 -0.6491432  -0.42968125]]

这个系数列表可能有点长,但它通常有助于理解你的模型。

三、网格搜索预处理步骤与模型参数

我们可以利用管道将机器学习工作流程中的所有处理步骤封装成一个 scikit-learn 估计器。这么做的另一个好处在于,现在我们可以使用监督任务(比如回归或分类)的输出来调节预处理参数 。在前几章里,我们在应用岭回归之前使用了 boston 数据集的多项式特征。下面我们用一个管道来重复这个建模过程。管道包含 3 个步骤:缩放数据、计算多项式特征与岭回归:

from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import Ridge
from sklearn.pipeline import make_pipeline

# 加载加利福尼亚房价数据集
california = fetch_california_housing()
X_train, X_test, y_train, y_test = train_test_split(california.data, california.target,
                                                    random_state=0)

# 创建管道
pipe = make_pipeline(
    StandardScaler(),
    PolynomialFeatures(),
    Ridge())

我们怎么知道选择几次多项式,或者是否选择多项式或交互项呢?理想情况下,我们希望根据分类结果来选择 degree 参数。我们可以利用管道搜索 degree 参数以及 Ridge 的 alpha 参数。为了做到这一点,我们要定义一个包含这两个参数的 param_grid ,并用步骤名称作为前缀:

param_grid = {'polynomialfeatures__degree': [1, 2, 3],
              'ridge__alpha': [0.001, 0.01, 0.1, 1, 10, 100]}

现在我们可以再次运行网格搜索:

from sklearn.model_selection import GridSearchCV

grid = GridSearchCV(pipe, param_grid=param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)

像之前所做的那样,我们可以用热图将交叉验证的结果可视化(见图 6-4):

import matplotlib.pyplot as plt

plt.matshow(grid.cv_results_['mean_test_score'].reshape(3, -1),
            vmin=0, cmap="viridis")
plt.xlabel("ridge__alpha")
plt.ylabel("polynomialfeatures__degree")
plt.xticks(range(len(param_grid['ridge__alpha'])), param_grid['ridge__alpha'])
plt.yticks(range(len(param_grid['polynomialfeatures__degree'])),
           param_grid['polynomialfeatures__degree'])

plt.colorbar()

# plt.tight_layout()
plt.savefig('Images/05GridSearchPreprocessingStepsWithModelParameters-01.png', bbox_inches='tight')
plt.show()
图 6-4:以多项式特征的次数和岭回归的 alpha 参数为坐标轴,绘制交叉验证平均分数的热图

从交叉验证的结果中可以看出,使用二次多项式很有用,但三次多项式的效果比一次或二次都要差很多。从找到的最佳参数中也可以看出这一点:

print("Best parameters: {}".format(grid.best_params_))
Best parameters: {'polynomialfeatures__degree': 1, 'ridge__alpha': 10}
print("Test-set score: {:.2f}".format(grid.score(X_test, y_test)))
Test-set score: 0.59

为了对比,我们运行一个没有多项式特征的网格搜索:

param_grid = {'ridge__alpha': [0.001, 0.01, 0.1, 1, 10, 100]}
pipe = make_pipeline(StandardScaler(), Ridge())
grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(X_train, y_train)
print("Score without poly features: {:.2f}".format(grid.score(X_test, y_test)))
Score without poly features: 0.59

正与我们观察图 6-4 中的网格搜索结果所预料的那样,不使用多项式特征得到了明显更差的结果。

同时搜索预处理参数与模型参数是一个非常强大的策略。但是要记住,GridSearchCV 会尝试指定参数的所有可能组合 。因此,向网格中添加更多参数,需要构建的模型数量将呈指数增长。

四、网格搜索选择使用哪个模型

你甚至可以进一步将 GridSearchCV 和 Pipeline 结合起来:还可以搜索管道中正在执行的实际步骤(比如用 StandardScaler 还是用 MinMaxScaler )。这样会导致更大的搜索空间,应该予以仔细考虑。尝试所有可能的解决方案,通常并不是一种可行的机器学习策略。但下面是一个例子:在 iris 数据集上比较 RandomForestClassifier 和 SVC 。我们知道,SVC 可能需要对数据进行缩放,所以我们还需要搜索是使用 StandardScaler 还是不使用预处理。我们知道,RandomForestClassifier 不需要预处理。我们先定义管道。这里我们显式地对步骤命名。我们需要两个步骤,一个用于预处理,然后是一个分类器。我们可以用 SVC 和 StandardScaler 来将其实例化:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

pipe = Pipeline([('preprocessing', StandardScaler()), ('classifier', SVC())])

现在我们可以定义需要搜索的 parameter_grid 。我们希望 classifier 是 RandomForestClassifier 或 SVC 。由于这两种分类器需要调节不同的参数,并且需要不同的预处理,所以我们可以使用之前的“在非网格的空间中搜索”中所讲的搜索网格列表。为了将一个估计器分配给一个步骤,我们使用步骤名称作为参数名称。如果我们想跳过管道中的某个步骤(例如,RandomForest 不需要预处理),则可以将该步骤设置为 None :

from sklearn.ensemble import RandomForestClassifier

param_grid = [
    {'classifier': [SVC()], 'preprocessing': [StandardScaler(), None],
     'classifier__gamma': [0.001, 0.01, 0.1, 1, 10, 100],
     'classifier__C': [0.001, 0.01, 0.1, 1, 10, 100]},
    {'classifier': [RandomForestClassifier(n_estimators=100)],
     'preprocessing': [None], 'classifier__max_features': [1, 2, 3]}]

现在,我们可以像前面一样将网格搜索实例化并在 cancer 数据集上运行:

from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_breast_cancer

# 加载并划分数据
cancer = load_breast_cancer()

X_train, X_test, y_train, y_test = train_test_split(
    cancer.data, cancer.target, random_state=0)

grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(X_train, y_train)

print("Best params:\n{}\n".format(grid.best_params_))
print("Best cross-validation score: {:.2f}".format(grid.best_score_))
print("Test-set score: {:.2f}".format(grid.score(X_test, y_test)))
Best params:
{'classifier': SVC(), 'classifier__C': 10, 'classifier__gamma': 0.01, 'preprocessing': StandardScaler()}

Best cross-validation score: 0.99
Test-set score: 0.98

网格搜索的结果是 SVC 与 StandardScaler 预处理,在 C=10 和 gamma=0.01 时给出最佳结果。

附录

一、参考文献

参考文献:[德] Andreas C. Müller [美] Sarah Guido 《Python Machine Learning Basics Tutorial》

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

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

相关文章

【网络安全的神秘世界】Kali安装中文输入法

🌝博客主页:泥菩萨 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 今天就手把手教你如何在kali中安装和配置输入法 首先,打开终端,输入下面这行代码: # sudo apt install ibus ibus-pi…

Python第二语言(四、Python数据容器)

目录 一、 数据容器(list、tuple、str、map、dict) 1. 数据容器概念 2. 列表list( [] ) 2.1 定义方式 2.2 嵌套列表 2.3 list通过获取下标索引获取值 2.4 下标使用概念 2.5 list列表的使用(列表的方法&#xff…

【研发日记】Matlab/Simulink软件优化(二)——通信负载柔性均衡算法

文章目录 前言 背景介绍 初始代码 优化代码 分析和应用 总结 前言 见《【研发日记】Matlab/Simulink软件优化(一)——动态内存负荷压缩》 背景介绍 在一个嵌入式软件开发项目中,需要设计一个ECU节点的CAN网路数据发送,需求是在500k的通信波特率上&a…

特征工程技巧—Bert

前段时间在参加比赛,发现有一些比赛上公开的代码,其中的数据预处理步骤值得我们参考。 平常我们见到的都是数据预处理,现在我们来讲一下特征工程跟数据预处理的区别。 数据预处理是指对原始数据进行清洗、转换、缩放等操作,以便为…

制造执行MES系统在光伏行业的应用

全球对可再生能源的需求不断增长,光伏能源作为一种清洁、可持续的能源形式,已经在广泛应用中受到了广泛关注。为满足工业领域的光伏能源需求,光伏制造执行系统(MES)作为一种集成化的技术解决方案,提供了更高效、更可靠的解决方案。…

海外仓系统推荐:中小型海外仓和家庭海外仓如何低投入高营收

随着海外仓行业整体竞争的加剧,海外仓的管理和经营成本可以说也是水涨船高。这对一些集团性质的大型海外仓影响不大,因为他们可以通过规模效应来摊薄成本。 但是对中小型海外仓和一些家庭海外仓来说,影响将是巨大的。一方面,海外…

GLM-4开源版本终于发布!!性能超越Llama3,多模态媲美GPT-4V,MaaS平台全面升级

今天上午,在 AI 开放日上,备受关注的大模型公司智谱 AI 公布了一系列行业落地数据: 根据最新统计,智谱 AI 大模型开放平台目前已拥有 30 万注册用户,日均调用量达到 4000 亿 Tokens。GPT-4o深夜发布!Plus免…

【重学C语言】十八、SDL2 图形编程介绍和环境配置

【重学C语言】十八、SDL2 图形编程介绍和环境配置 **SDL2介绍**SDL 2用途SDL 在哪些平台上运行?下载和安装 SDL2安装 SDL2 clion 配置 SDL2 SDL2介绍 SDL2(Simple DirectMedia Layer 2)是一个开源的跨平台多媒体开发库,主要用于游…

Cortex系列详解

Cortex系列属于ARMv7架构(ARM公司在经典处理器ARM11以后的产品改用Cortex命名) 一、Cortex-A系列 “A”系列面向尖端的基于虚拟内存的操作系统和用户应用。 A 系列处理器适用于具有高计算要求、运行丰富操作系统以及提供交互媒体和图形体验的应用领域。 具体案例如:智能手…

2024百度之星 跑步

原题链接:码题集OJ-跑步 题目大意:一个n个人在绕圈跑,第i个人跑一圈的时间是i分钟,每二个人位置相同就会打一次招呼,如果同时来到终点,他们就会停下来,请问会打多少次招呼? 思路&a…

文件加密软件排行榜前五名|好用的五款文件加密软件分享

你的公司是否存在这些问题: 数据泄露事件常有发生,数据安全的重要性日益凸显,而文件加密软件则是保护数据安全的重要工具。 市场上存在众多文件加密软件,每款都有其独特的特点和优势。 本文将为您分享五款好用的文件加密软件&…

java通过ftp上传文件到服务器

依赖 <!-- https://mvnrepository.com/artifact/com.jcraft/jsch --><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency> 代码 package com.cyz; impor…

Docker高级篇之Dockerfile解析

文章目录 1. DockerFile简介2. DockerFile的构建过程3. DockerFile的常用保留字4. 使用案例5. 虚悬镜像 1. DockerFile简介 DockerFile是用来构建Docker镜像的文本文件&#xff0c;是由一条条构建镜像的指令和参数构成的脚本。 2. DockerFile的构建过程 DockerFile内容的基…

2.3 OpenCV随手简记(四)

阈值处理是很多高级算法底层处理的预方法之一。 自己求图像平均阈值&#xff1a; # -*- codingGBK -*- import cv2 as cv import numpy as np #求出图像均值作为阈值来二值化 def custom_image(image): gray cv.cvtColor(image, cv.COLOR_BGR2GRAY) cv.imshow("原来&qu…

精选网络安全书单:打造数字世界的钢铁长城!

目录 1.前言 2.书单推荐 2.1. 《内网渗透实战攻略》 2.2. 《Kali Linux高级渗透测试&#xff08;原书第4版&#xff09;》 2.3. 《CTF那些事儿》 2.4. 《权限提升技术&#xff1a;攻防实战与技巧》 2.5. 《数字政府网络安全合规性建设指南&#xff1a;密码应用与数据安全…

CentOS6系统因目录有隐含i权限属性致下属文件无法删除的故障一例

CentOS6服务器在升级openssh时因系统目录权限异常&#xff08;有隐含i权限属性&#xff09;&#xff0c;下属文件无法删除&#xff0c;导致系统问题的故障一例。 一、问题现象 CentOS6在升级openssh时&#xff0c;提示如下问题&#xff1a; warning: /etc/ssh/sshd_config c…

五个超实用的 ChatGPT-4o 提示词

GPT-4o 是 OpenAI 最近推出的最新人工智能模型&#xff0c;不仅具备大语言模型的能力&#xff0c;而且拥有多模态模型的看、读、说等能力&#xff0c;而且速度比 GPT-4 更快。下面我们就来介绍几个超实用的 GPT-4o 提示词&#xff0c;帮助大家更好地了解 GPT-4o 的功能和应用场…

Vuforia AR篇(五)— 地平面检测

目录 前言一、什么是地平面识别&#xff1f;二、使用步骤三、示例代码四、效果五、总结 前言 在增强现实&#xff08;AR&#xff09;应用程序的开发中&#xff0c;地平面识别是一项关键技术&#xff0c;它允许虚拟对象与现实世界的地面进行互动。Vuforia 是一个功能强大的 AR …

SpringBoot引入WebSocket依赖报ServerContainer no avaliable

1、WebSocketConfig 文件报错 Configuration EnableWebSocket public class WebSocketConfig {Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}2、报错内容 Exception encountered during context initialization - canc…

UFS协议—新手快速入门(二)【5-6】

目录 五、UFS协议栈 六、UFS技术演进与详解 1、UFS应用层 设备管理器 任务管理器 2、UFS传输层 3、UFS互联层 UFS协议—新手快速入门&#xff08;一&#xff09;【1-4】 五、UFS协议栈 UFS&#xff08;Universal Flash Storage&#xff09;协议是针对固态存储设备&…