吴恩达《机器学习》——SVM支持向量机

news2024/12/23 0:23:42

SVM支持向量机

  • 1. 线性SVM
    • 1.1 从Logistic回归出发
    • 1.2 大边界分类与SVM
    • 1.3 调整正则化参数
  • 2. 非线性SVM(高斯核函数)
    • 2.1 高斯核
    • 2.2 非线性分类
    • 2.3 参数搜索

数据集、源文件可以在Github项目中获得
链接: https://github.com/Raymond-Yang-2001/AndrewNg-Machine-Learing-Homework

1. 线性SVM

1.1 从Logistic回归出发

在Logistic回归进行分类的时候,我们有 h θ ( x ) = σ ( θ ⊤ x ) h_{\theta}(x)=\sigma(\theta^{\top} x) hθ(x)=σ(θx),其中 σ \sigma σ代表了sigmoid函数。Logisit回归在进行分类的时候,会使得正类的 θ ⊤ x ≥ 0 \theta^{\top}x\ge 0 θx0,负类的 θ ⊤ x < 0 \theta^{\top}x < 0 θx<0。其损失函数如下:
J ( θ ) = ∑ i = 1 m − y ( i ) log ⁡ ( h θ ( x ( i ) ) ) − ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) J(\theta)=\sum_{i=1}^{m}{-y^{(i)}\log{(h_{\theta}(x^{(i)}))}}-(1-y^{(i)})\log{(1-h_{\theta}(x^{(i)}))} J(θ)=i=1my(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))
其中, − log ⁡ h θ ( x ) -\log{h_\theta(x)} loghθ(x) − log ⁡ ( 1 − h θ ( x ) ) -\log{(1-h_{\theta}(x))} log(1hθ(x))的函数图像如下所示:
在这里插入图片描述
对损失函数做如下修改,使得在 y = 1 y=1 y=1的时候,期望的 θ ⊤ x ≫ 1 \theta^{\top}x\gg 1 θx1而不是 θ ⊤ x ≫ 0 \theta^{\top}x\gg 0 θx0;在 y = 0 y=0 y=0的时候,期望的 θ ⊤ x ≪ − 1 \theta^{\top}x\ll -1 θx1而不是 θ ⊤ x ≪ 0 \theta^{\top}x\ll 0 θx0

这就得到了线性SVM的一般损失函数:
J ( θ ) = C ∑ i = 1 m [ y ( i ) c o s t 1 ( θ ⊤ x ) + ( 1 − y ( i ) ) c o s t 0 ( θ ⊤ x ) ] + 1 2 ∑ j = 1 n θ j 2 J(\theta)=C\sum_{i=1}^{m}{[y^{(i)}\mathrm{cost}_{1}(\theta^{\top}x)+(1-y^{(i)})\mathrm{cost}_{0}(\theta^{\top}x)]}+\frac{1}{2}\sum_{j=1}^{n}{\theta_{j}^{2}} J(θ)=Ci=1m[y(i)cost1(θx)+(1y(i))cost0(θx)]+21j=1nθj2
这里的C是正则化参数。

在线性SVM中,区别于Logistic回归输出分类概率,我们假设:
{ h θ ( x ) = 1 , θ ⊤ x ≥ 0 h θ ( x ) = 0 , e l s e \left\{ \begin{aligned} &h_{\theta}(x)=1,\quad\theta^{\top}x\ge0 \\ &h_{\theta}(x)=0,\quad\mathrm{else}\\ \end{aligned} \right. {hθ(x)=1,θx0hθ(x)=0,else
也就是说,SVM分类器直接输出分类结果。

1.2 大边界分类与SVM

前文所述,在SVM中,最小化代价函数的必要条件是,在 y = 1 y=1 y=1的时候,期望的 θ ⊤ x ≥ 1 \theta^{\top}x\ge 1 θx1而不是 θ ⊤ x ≥ 0 \theta^{\top}x\ge 0 θx0;在 y = 0 y=0 y=0的时候,期望的 θ ⊤ x ≪ − 1 \theta^{\top}x\ll -1 θx1而不是 θ ⊤ x < 0 \theta^{\top}x< 0 θx<0。事实上,使用0作为分类边界已经能很好的区分进行分类了,SVM将这个分类边界进一步“加宽”,从0变成了(-1,1),我们将SVM称作一种大边界的分类器

考虑线性SVM的损失函数,假设我们找到了符合上述条件的 θ \theta θ,那么在任何情况下,损失函数的前半部分都为0,也就是说优化目标可以简化为:
min ⁡ 1 2 ∑ j = 1 n θ j 2 = 1 2 ∣ ∣ θ ∣ ∣ 2 s . t . { θ ⊤ x ( i ) ≥ 1 , y ( i ) = 1 θ ⊤ x ( i ) ≤ − 1 , y ( i ) = 0 \min{\frac{1}{2}\sum_{j=1}^{n}{\theta_{j}^{2}}=\frac{1}{2}||\theta||^{2}} \\ \mathrm{s.t.}\left\{ \begin{aligned} &\theta^{\top}x^{(i)}\ge1,\quad y^{(i)}=1 \\ &\theta^{\top}x^{(i)}\le-1,\quad y^{(i)}=0 \\ \end{aligned} \right. min21j=1nθj2=21∣∣θ2s.t.{θx(i)1,y(i)=1θx(i)1,y(i)=0

由线性代数知识可知: θ ⊤ x ( i ) = ρ ( i ) ∣ ∣ θ ∣ ∣ \theta^{\top}x^{(i)}=\rho^{(i)}||\theta|| θx(i)=ρ(i)∣∣θ∣∣ ρ ( i ) \rho^{(i)} ρ(i) x ( i ) x^{(i)} x(i) θ \theta θ方向上的投影长度。
设我们的一种决策边界如下,蓝色线是 θ \theta θ方向,与其垂直的绿色线是决策边界:
在这里插入图片描述
在这种情况下, ρ \rho ρ比较小,为了满足 ρ ( i ) ∣ ∣ θ ∣ ∣ ≥ 1 \rho^{(i)}||\theta||\ge1 ρ(i)∣∣θ∣∣1或者 ρ ( i ) ∣ ∣ θ ∣ ∣ ≤ − 1 \rho^{(i)}||\theta||\le-1 ρ(i)∣∣θ∣∣1 ∣ ∣ θ ∣ ∣ ||\theta|| ∣∣θ∣∣要变得很大才可以满足。显然,这会使得损失函数值变大,与优化目标相反。

考虑另一种决策边界:
在这里插入图片描述
在这种情况下, ρ \rho ρ会变大,相应的 ∣ ∣ θ ∣ ∣ ||\theta|| ∣∣θ∣∣可以变得比较小。通过让间距变大,即通过这些 ρ \rho ρ等等的值,支持向量机最终可以找到一个较小的范数。这正是支持向量机中最小化目标函数的目的,也就是为什么支持向量机最终会找到大间距分类器的原因。因为它试图极大化这些 ρ \rho ρ的范数,它们是训练样本到决策边界的距离。

1.3 调整正则化参数

使用的数据集可视化如下:
在这里插入图片描述
使用正则化参数C=1

from sklearn import svm
svc = svm.LinearSVC(C=1, max_iter=1000)
svc.fit(x,y.ravel())
theta1 = [svc.intercept_[0], svc.coef_[0,0], svc.coef_[0,1]]

x_ax = np.arange(0, 4, 0.1)
xx = np.array([1.5,2.5])
y_ax = -theta1[0] / theta1[2] + (-theta1[1] / theta1[2])*x_ax
print(theta1[0],-theta1[0] / theta1[2],-theta1[1] / theta1[2])
yy = (theta1[2] / theta1[1] )*xx
plt.figure(figsize=(10,8))
plt.scatter(x=positive_data[:, 0], y=positive_data[:, 1], s=10, color="red",label="positive")
plt.scatter(x=negative_data[:, 0], y=negative_data[:, 1], s=10, label="negative")
plt.plot(x_ax, y_ax, label="Decision Boundary")
plt.plot(xx, yy, label="Direction of Theta Vector")
plt.axis('equal')
plt.legend(loc='best',framealpha=0.5)
plt.show()

在这里插入图片描述

可以看到SVM学习到了一个较好的分类器,没有受到左上角异常值的影响。

正则化参数C=1000

from sklearn import svm
svc2 = svm.LinearSVC(C=100, max_iter=100000)
svc2.fit(x,y.ravel())
theta2 = [svc2.intercept_[0], svc2.coef_[0,0], svc2.coef_[0,1]]
x_ax = np.arange(0, 4, 0.1)

y_ax = -theta2[0] / theta2[2] + (-theta2[1] / theta2[2])*x_ax

plt.figure(figsize=(10,8))
plt.scatter(x=positive_data[:, 0], y=positive_data[:, 1], s=10, color="red",label="positive")
plt.scatter(x=negative_data[:, 0], y=negative_data[:, 1], s=10, label="negative")
plt.plot(x_ax, y_ax, label="Decision Boundary")

xx = np.array([1,1.5])
yy = (theta2[2] / theta2[1] )*xx
plt.plot(xx + 1, yy, label="Direction of Theta Vector")

plt.axis('equal')
plt.legend(loc=0,framealpha=0.5)
plt.show()

在这里插入图片描述
可以看到,在C较大的情况下,SVM受到了离群值的影响,出现了过拟合的现象。

2. 非线性SVM(高斯核函数)

之前讨论的线性SVM,其优化目标的计算是基于 θ ⊤ x \theta^{\top}x θx的线性运算,当我们面对较复杂的决策边界的时候,简单的线性运算并不能很好的满足需求。就像在神经网络中引入非线性的激励函数一样,在SVM中,我们也引入非线性的核函数,来实现更复杂的分类。这类SVM叫做非线性SVM。

这相当于使用一系列新的特征来代替原样本,核函数就完成了样本到新特征的非线性映射。
f ( i ) ← x ( i ) f^{(i)} \larr x^{(i)} f(i)x(i)

2.1 高斯核

f i = s i m ( x , l ( i ) ) = exp ⁡ ( − ∣ ∣ x − l ( i ) ∣ ∣ 2 2 σ 2 ) f_{i}=sim(x,l^{(i)})=\exp{\left(-\frac{||x-l^{(i)}||^{2}}{2\sigma^{2}}\right)} fi=sim(x,l(i))=exp(2σ2∣∣xl(i)2)
x , l ( i ) x,l^{(i)} x,l(i)相接近的时候,核函数值会接近1;当二者相距比较远的是时候,核函数值会接近0。
f ( i ) = ∣ f 0 ( i ) = 1 f 1 ( i ) = s i m ( x ( i ) , l ( 1 ) ) ⋮ f m ( i ) = s i m ( x ( i ) , l ( m ) ) ∣ f^{(i)}=\left|\begin{aligned} f^{(i)}_{0}&=1 \\ f^{(i)}_{1}=&sim(x^{(i)},l^{(1)}) \\ \vdots&\\ f^{(i)}_{m}=&sim(x^{(i)},l^{(m)}) \end{aligned} \right| f(i)= f0(i)f1(i)=fm(i)==1sim(x(i),l(1))sim(x(i),l(m))

优化目标函数变为:
J ( θ ) = C ∑ i = 1 m [ y ( i ) c o s t 1 ( θ ⊤ f ( i ) ) + ( 1 − y ( i ) ) c o s t 0 ( θ ⊤ f ( i ) ) ] + 1 2 ∑ j = 1 n θ j 2 J(\theta)=C\sum_{i=1}^{m}{[y^{(i)}\mathrm{cost}_{1}(\theta^{\top}f^{(i)})+(1-y^{(i)})\mathrm{cost}_{0}(\theta^{\top}f^{(i)})]}+\frac{1}{2}\sum_{j=1}^{n}{\theta_{j}^{2}} J(θ)=Ci=1m[y(i)cost1(θf(i))+(1y(i))cost0(θf(i))]+21j=1nθj2

σ \sigma σ参数较大的时候,特征会变得更加平滑( ∣ ∣ x − l ( i ) ∣ ∣ 2 ||x-l^{(i)}||^{2} ∣∣xl(i)2的大小的变化对函数值的变化影响较小),不同样本的区分度会变小,这有利于缓解某些离群点的影响,使得模型的方差变小,减轻过拟合,但是会带来模型的偏差变大;相反,当 σ \sigma σ参数较小的时候,特征会变得区分度更大,使得模型方差变大,偏差减小。

2.2 非线性分类

进行非线性分类的数据集可视化如下所示:
在这里插入图片描述
正则化参数为100

def show_boundary(svc, scale, fig_size, fig_dpi, positive_data, negative_data, term):
    """
    Show SVM classification boundary plot
    :param svc: instance of SVC, fitted and probability=True
    :param scale: scale for x-axis and y-axis
    :param fig_size: figure size, tuple (w, h)
    :param fig_dpi: figure dpi, int
    :param positive_data: positive data for dataset (n, d)
    :param negative_data: negative data for dataset (n, d)
    :param term: width for classification boundary
    :return: decision plot
    """
    t1 = np.linspace(scale[0, 0], scale[0, 1], 500)
    t2 = np.linspace(scale[1, 0], scale[1, 1], 500)
    coordinates = np.array([[x, y] for x in t1 for y in t2])
    prob = svc.predict_proba(coordinates)
    idx1 = np.where(np.logical_and(prob[:, 1] > 0.5 - term, prob[:, 1] < 0.5 + term))[0]
    my_bd = coordinates[idx1]
    plt.figure(figsize=fig_size, dpi=fig_dpi)
    plt.scatter(x=my_bd[:, 0], y=my_bd[:, 1], s=10, color="yellow", label="My Decision Boundary")
    plt.scatter(x=positive_data[:, 0], y=positive_data[:, 1], s=10, color="red", label="positive")
    plt.scatter(x=negative_data[:, 0], y=negative_data[:, 1], s=10, label="negative")
    plt.title('Decision Boundary')
    plt.legend(loc=2)
    plt.show()

from sklearn import svm
from sklearn.metrics import classification_report
svc100 = svm.SVC(C=100, kernel='rbf', gamma=10, probability=True)
svc100.fit(x,y.ravel())
report100 = classification_report(svc100.predict(x),y,digits=4)
print(report100)
show_boundary(svc100, scale=np.array([[0,1],[0.4,1]]), fig_size=fig_size, fig_dpi=fig_dpi,positive_data=positive_data,negative_data=negative_data, term=1e-3)
              precision    recall  f1-score   support

           0     0.9791    0.9542    0.9665       393
           1     0.9625    0.9830    0.9726       470

    accuracy                         0.9699       863
   macro avg     0.9708    0.9686    0.9696       863
weighted avg     0.9701    0.9699    0.9698       863

在这里插入图片描述
正则化参数为1

svc1 = svm.SVC(C=1, kernel="rbf", gamma=10, probability=True)
svc1.fit(x,y.ravel())
report1 = classification_report(svc1.predict(x),y,digits=4)
print(report1)
show_boundary(svc1, scale=np.array([[0,1],[0.4,1]]), fig_size=fig_size, fig_dpi=fig_dpi,positive_data=positive_data,negative_data=negative_data, term=1e-3)
              precision    recall  f1-score   support

           0     0.8851    0.8582    0.8715       395
           1     0.8833    0.9060    0.8945       468

    accuracy                         0.8841       863
   macro avg     0.8842    0.8821    0.8830       863
weighted avg     0.8841    0.8841    0.8840       863

在这里插入图片描述
可以看到,在正则化参数变小的情况下,分类边界变得更加“平滑”。

2.3 参数搜索

在机器学习的应用之中,确定参数是关键的一步,不同的参数会使得算法呈现不同的性能。最常用的一个方法是进行网格搜索GridSearch

在实现网格搜索之前,我们先介绍一种评估模型性能的方法——k折交叉验证。一般情况下,在训练模型的过程中,我们只从训练集中划分出固定的一部分作为验证集;k折交叉验证将训练集划分为k部分,模型训练k次,每次使用其中一个作为验证集,其余作为训练集,用在验证集上的平均评分来评估模型性能。这种方法能够更全面的考虑整个训练集的数据分布,往往比固定验证集更能体现模型的泛化能力。

网格搜索的步骤是:

  1. 对于目标参数给出取值集合,多个参数会组成类似一个“网格”的结构
  2. 对于每个参数值组合,进行k折交叉验证(在sklearn中,默认使用k=5)
  3. 选取平均得分最高的参数组合作为最优参数组合

代码实现如下:

candidate = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 100]
parameters_grid = np.array([[c, gamma] for c in candidate for gamma in candidate])

score_list = []
from sklearn.svm import SVC
from SVM import show_boundary
from sklearn.model_selection import KFold
kf = KFold(n_splits=5)
for param in parameters_grid:
    score = []
    for tr_idx, test_idx in kf.split(train_x,train_y):
        tr_x,tr_y = train_x[tr_idx], train_y[tr_idx]
        test_x, test_y = train_x[test_idx], train_y[test_idx]

        svc = SVC(C=param[0], gamma=param[1], probability=True)
        svc.fit(tr_x, tr_y.ravel())
        score.append(svc.score(test_x, test_y.ravel()))
    score_list.append(score)

score_arr = np.array(score_list).mean(axis=1)
best_param = parameters_grid[np.argmax(score_arr)]
best_score = score_arr.max()
param_dict = {'C': best_param[0], 'gamma': best_param[1]}
best_svc = SVC(probability=True)
best_svc.set_params(**param_dict)
best_svc.fit(train_x,train_y.ravel())
print("Best parameters C={}, gamma={}, with average precision of {:.4f}".format(best_param[0], best_param[1], best_score))
Best parameters C=30.0, gamma=3.0, with average precision of 0.9244

使用sklearn进行验证

svc = SVC(probability=True)
parameters = {'C': candidate, 'gamma': candidate}
# default 5-fold
clf = GridSearchCV(svc, parameters, n_jobs=-1)
clf.fit(train_x,train_y.ravel())
print("SKlearn result: C={}, gamma={}".format(clf.best_params_.get('C'), clf.best_params_.get('gamma')))
SKlearn result: C=30, gamma=3

可视化数据集和分类边界
在这里插入图片描述

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

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

相关文章

Java编程基础

1&#xff0c;基本概念 &#xff08;1&#xff09;JDK、JRE、JVM的关系&#xff1a; JDK&#xff1a;Java Development Kit&#xff0c;Java开发工具包JRE: Java Runtime Environment&#xff0c;Java运行环境JVM&#xff1a;Java Virtual Machine&#xff0c;Java虚拟机JDK包…

2023年山东最新建筑八大员(电气施工员)模拟真题题库及答案

百分百题库提供建筑八大员&#xff08;电气&#xff09;考试试题、建筑八大员&#xff08;电气&#xff09;考试预测题、建筑八大员&#xff08;电气&#xff09;考试真题、建筑八大员&#xff08;电气&#xff09;证考试题库等,提供在线做题刷题&#xff0c;在线模拟考试&…

【UE4 第一人称射击游戏】22-拾取弹药

上一篇&#xff1a;【UE4 第一人称射击游戏】21-添加动态扩散准心本篇效果&#xff1a;当角色触碰到弹药箱后&#xff0c;玩家的后备弹夹就会多50发子弹&#xff0c;并且触碰到弹药箱后&#xff0c;会播放相应的声音和粒子特效。步骤&#xff1a;新建一个蓝图类&#xff08;父类…

MySQL-5.7 innodb在线DDL操作(增删改索引、列、外键、表、外键)

基本概念 在开始阅读前&#xff0c;先熟悉下以下概念&#xff0c;以便更加方便理解。 DML DML&#xff08;Data Manipulation Language&#xff09;数据操作语言-数据库的基本操作&#xff0c;SQL中处理数据等操作统称为数据操纵语言,简而言之就是实现了基本的“增删改查”操作…

jenkins中错误总结

每次使用jenkins都会遇到不同的bug&#xff0c;接下来我们看一下这几个 libXrender.so.1: cannot open shared object file: No such file or directory 接下来我们看一下解决方案,一步一步安装好就可以了 yum install ksh -y yum install libXext.so.6 -y yum install libX…

案例分析 - 考查点总览

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 系分 - 案例分析 - 总览知识点 往年案例一览 一般情况下&#xff0c;往下数5、6年的题目出题形式&#xff0c;具有参考意义 年份试题一试题二试题三试题四试题五2022年系统分析与建模[结构化与面向对象分析、用例…

MySQL (四)------DML操作表记录-增删改【重点】DQL操作表记录-查询【重点】

DML操作表记录-增删改【重点】 准备工作: 创建一张商品表(商品id,商品名称,商品价格,商品数量.) create table product(pid int primary key auto_increment,pname varchar(40),price double,num int ); 1.1 插入记录 1.1.1 语法 方式一: 插入指定列, 如果没有把这个列进行列…

联合证券|2022年逾200家企业IPO“撤单”,谁在“临阵脱逃”?

刚刚过去的2022年&#xff0c;A股IPO募集资达5870亿元&#xff0c;创下前史新高。不过&#xff0c;也有不少“带病闯关”的IPO项目遇阻&#xff0c;计算数据显现&#xff0c;2022年A股IPO共有234家企业撤单&#xff0c;创9年以来最大撤回潮。 谁在惊惶万状&#xff1f; 2022年…

LeetCode[剑指offer 40]最小的k个数

难度&#xff1a;简单 题目&#xff1a; 输入整数数组 arr &#xff0c;找出其中最小的 k 个数。例如&#xff0c;输入4、5、1、6、2、7、3、8这8个数字&#xff0c;则最小的4个数字是1、2、3、4。示例 1&#xff1a; 输入&#xff1a;arr [3,2,1], k 2 输出&#xff1a;[…

C 语言的 互斥锁、自旋锁、原子操作

今天不整 GO 语言&#xff0c;我们来分享一下以前写的 C 代码&#xff0c;来看看 互斥锁&#xff0c;自旋锁和原子操作的 demo 互斥锁 临界区资源已经被1个线程占用&#xff0c;另一个线程过来访问临界资源的时候&#xff0c;会被CPU切换线程&#xff0c;不让运行后来的这个线…

基础算法(二)——归并排序

归并排序 介绍 归并排序是一种复杂度O(nlog(n)nlog(n)nlog(n))的排序算法&#xff0c;并且在任何情况下都是&#xff0c;但是它不是原地算法&#xff0c;即需要额外存储空间 其原理是&#xff0c;先将区间均匀分成左右两半&#xff0c;然后再对左右两半继续二分&#xff0c;…

Large Language Models Are Reasoning Teachers

Paper name Large Language Models Are Reasoning Teachers Paper Reading Note URL: https://arxiv.org/pdf/2212.10071.pdf twitter 宣传&#xff1a; https://twitter.com/itsnamgyu/status/1605516353439354880 TL;DR 提出了 Fine-tune-CoT 方法&#xff0c;旨在利用非…

Java --- JVM对象内存布局与访问定位

目录 一、对象内存布局 1.1、对象头(Header) 1.1.1、运行时元数据(Mark Word) 1.1.2、 类型指针 1.2、实例数据(Instance Date) 1.3、对齐填充(Padding) 二、对象访问定位 一、对象内存布局 1.1、对象头(Header) 1.1.1、运行时元数据(Mark Word) 1、哈希值(HashCode) 2、G…

【高级人工智能】国科大《高级人工智能》符号主义笔记

国科大《高级人工智能》罗老师部分——符号主义笔记 罗老师上课很有意思&#xff0c;但是这部分内容还是挺难理解的&#xff0c;需要仔细思考今年考试题目这部分跟往年不一样&#xff0c;老师讲的重点&#xff08;A搜索归结原理&#xff09;也没考&#x1f605; 文章目录几个概…

FFmpeg

介绍 FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec&#xff0c;为了保证高可移植性和编解码质量&…

Windows 下安装共享文件夹(一步一步带你创建,亲测有效果)

目录1 需求2 实现1 需求 我们想要在自己的Windows电脑上面安装一个共享文件夹&#xff0c;想让其他电脑连我们的共享文件夹&#xff0c;或者我们需要使用代码&#xff0c;连接这个共享文件夹&#xff0c;所以我们必须先在Windows电脑创建一个共享文件夹 2 实现 首先我们创建…

centos7.9安装harbor-offline-installer-v2.4.1.tgz

1.首先下载安装包 可以去github上搜索下载&#xff1a; GitHub: Let’s build from here GitHub 然后选择版本进行下载&#xff0c;一般从githut上下载速度很慢,我已提前下载好&#xff0c;从csdn上下载会比较快&#xff1a; harbor-offline-installer-v2.4.1.tgz: https:…

聊聊跳表?

什么是跳表 跳表&#xff08;Skip List&#xff09;是一种类似于链表的数据结构&#xff0c;其查询、插入、删除的时间复杂度都是O(logn)。 在传统的单链表结构中&#xff0c;查找某个元素需要从链表的头部按顺序遍历&#xff0c;直到找到目标元素为止&#xff0c;查找的时间复…

PowerShell木马免杀利器: Invoke-Obfuscation(过火绒)

Invoke-Obfuscation 简介 Invoke-Obfuscation工具下载地址: https://github.com/danielbohannon/Invoke-Obfuscation Invoke-Obfuscation是一款PowerShell混淆工具&#xff0c;可以将PowerShell脚本加密&#xff0c;使得它的检测和分析变得更加困难。该工具包含多种加密方法&…

HTML实现右下角闪烁弹窗

演示 完整HTML <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&…