经典机器学习模型(一)感知机模型

news2025/1/9 17:11:37

经典机器学习模型(一)感知机模型

感知机可以说是一个相当重要的机器学习基础模型,是神经网络和支持向量机的基础。

感知机是一个二分类的线性分类模型,之所以说是线性,是因为它的模型是线性形式的。

从《统计学习方法》中,我们知道学习方法的三要素为模型、策略、算法,我们就从三要素来了解下感知机。

1 感知机模型的三要素

1.1 模型

1.1.1 感知机模型

在这里插入图片描述

  • 输入空间

    • 这里 χ \chi χ代表 n n n维实数空间的一个子集
    • 输入的每一个实例 x x x,用一个 n n n维的特征向量表示,它是属于输入空间 χ \chi χ的。
    • 实例 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) T x=(x^{(1)},x^{(2)},...,x^{(n)})^T x=(x(1),x(2),...,x(n))T
  • 输出空间

    • 由于这是一个二分类模型,所以这里输出空间是一个只包含+1和-1的一个集合。

    • 1 代表的是正类,-1 代表的是负类,具体的输出则是代表实例 x x x所对应的类别。

  • 感知机

    • 我们定义一个从输入空间到输出空间的函数,这个函数就称作感知机。

    • 这个函数 s i g n ( x ) sign(x) sign(x)叫做符号函数

    • w ⋅ x = ( w ( 1 ) x ( 1 ) , w ( 2 ) x ( 2 ) , . . . , w ( n ) x ( n ) ) T w\cdot x=(w^{(1)}x^{(1)},w^{(2)}x^{(2)},...,w^{(n)}x^{(n)})^T wx=(w(1)x(1),w(2)x(2),...,w(n)x(n))T

  • 假设空间

    • 特征空间里面所有可能的线性函数就称为假设空间。
  • 参数空间

    • 参数 w w w b b b的所有组合,就得到一个 n n n维的空间,也就是参数空间。

1.1.2 感知机模型的几何意义

我们从几何角度来解释一下感知器,如下图所示:

  • 线性方程 w ⋅ x + b = 0 w\cdot x +b = 0 wx+b=0代表着 n n n维特征空间里面的一个超平面 S S S

  • w w w是法向量,垂直于超平面 S S S b b b是相应的截距项。

  • 通过超平面 S S S我们就可以将整个特征空间分为两部分

    • 一部分是正类,其中的实例所对应的输出为 +1;
    • 一部分为负类,它里面的实例所对应的输出为 -1。所以这个超平面被称为分离超平面。
  • 超平面的理解。

    • 如果我们现在的特征空间是一维的,那么想区分正负类实例点,用实数轴上的一个点就可以了,比如零点。
    • 如果特征空间是两维的,实例应该就是二维空间中的一个点,要区分正负类,它的分离超平面对应的应该是一条直线(如下图)。
    • 如果可能空间是三维的,分离超平面应该就是一个二维平面了。
    • 依此类推,如果环境空间是 n n n维的,那么它所对应的超平面其实就是一个 n − 1 n-1 n1维的子空间。
  • 原点到超平面的距离为 − b ∣ ∣ w ∣ ∣ -\frac{b}{||w||} ∣∣w∣∣b

在这里插入图片描述

1.2 策略

如果假设训练数据集线性可分,我们的目标则是希望寻求到一个的分离超平面,把这些实例点完全划分为正负类

但是,要求得这样一个超平面,就需要确定模型的参数,即w和b,这就需要制定一定的学习策略。换而言之,就是要合理地定义感知机相应的损失函数

1.2.1 线性可分数据集

感知机模型,有一个比较严苛的条件,就是要求数据集必须是线性可分的。

线性可分的意思如下:

对于给定的数据集,如果存在某个超平面,使得这个数据集的所有实例点可以完全划分到超平面的两侧,也就是正类和负类。我们就称这个数据集是线性可分的,否则线性不可分。

1.2.2 感知机的损失函数

特征空间中的任意一点到超平面的距离公式如下:
1 ∣ ∣ w ∣ ∣ ∣ w ⋅ x 0 + b ∣ \frac{1}{||w||}|w\cdot x_0+b| ∣∣w∣∣1wx0+b
如果 x 0 x_0 x0是错误的分类点,那么容易得到下式:
1 ∣ ∣ w ∣ ∣ ∣ w ⋅ x 0 + b ∣ = { − w ⋅ x 0 + b ∣ ∣ w ∣ ∣ , y 0 = 1 w ⋅ x 0 + b ∣ ∣ w ∣ ∣ , y 0 = − 1 = − ( w ⋅ x 0 + b ) y 0 ∣ ∣ w ∣ ∣ \frac{1}{||w||}|w\cdot x_0+b|=\begin{cases} -\frac{w\cdot x_0+b}{||w||}, & y_0 = 1\\ \\ \frac{w\cdot x_0+b}{||w||}, & y_0 = -1 \end{cases}=-\frac{(w\cdot x_0+b)y_0}{||w||} ∣∣w∣∣1wx0+b= ∣∣w∣∣wx0+b,∣∣w∣∣wx0+b,y0=1y0=1=∣∣w∣∣(wx0+b)y0
现在我们要关注的就是这里的错误分类点,设误分类点为 x i x_i xi,那么 x i x_i xi到超平面 S S S的距离为:
− ( w ⋅ x i + b ) y i ∣ ∣ w ∣ ∣ -\frac{(w\cdot x_i+b)y_i}{||w||} ∣∣w∣∣(wxi+b)yi
如果用 M M M代表所有误分类点的集合,我们可以写出所有误分类点到超平面 S S S的距离的总和:
− 1 ∣ ∣ w ∣ ∣ ∑ x i ∈ M ( w ⋅ x i + b ) y i -\frac{1}{||w||}\sum\limits_{x_i\in M}(w\cdot x_i+b)y_i ∣∣w∣∣1xiM(wxi+b)yi
很明显, M M M中所含有的误分类点越少的时候,总距离和应该越小。在没有误分类点的时候, 这个距离和应该为 0。我们希望通过最小化总距离和来求参数。

因此,我们就得到了感知机模型的损失函数如下:
L ( w , b ) = − ∑ x i ∈ M ( w ⋅ x i + b ) y i , M 为误分类点的集合 L(w,b)=-\sum\limits_{x_i\in M}(w\cdot x_i+b)y_i,M为误分类点的集合 L(w,b)=xiM(wxi+b)yiM为误分类点的集合

1.3 算法(原始形式)

  • 假如给定训练数据集,我们通过最小化损失函数,就可以估计得到模型参数。

  • 如何求参数 w w w b b b呢?这就是一个优化问题,寻找使损失函数最小的参数

在这里插入图片描述

想求这个损失函数的极小值,可以先求梯度,即分别求偏导数,得到梯度向量,然后用梯度下降法对参数更新。

需要注意的是,梯度下降法用的是负梯度,所以我们求梯度的时候得到的负号就抵消掉了

  • 如果是批量更新,就需要每次使用所有的误分类点,这会致使每一轮的迭代都需要大量的时间。

  • 随机梯度下降法,每一轮随机选择一个误分类点,迭代的速度会快一些。

    • 这是因为,如果通过这个误分类点进行参数的更新,有可能误分类点就会减少,那么下一步我们可用来选择更新参数的实例点就会减少,这在一定程度上简化计算,节约了时间。
  • 小批量梯度下降法既不是像批量梯度下降法中那样选择了所有的样本点,也不是像随机梯度下降法中随机选取了一个样本点,而是选择部分样本点进行参数更新。

    • 但是,小批量梯度下降法,也面临许多问题,比如每次需要选择多少个样本点?选择哪些样本才合适呢?

损失函数 L ( w , b ) = − ∑ x i ∈ M ( w ⋅ x i + b ) y i , M 为误分类点的集合 对 w 和 b 分别求偏导数,可得梯度为: ∇ w L ( w , b ) = − ∑ x i ∈ M x i y i ∇ b L ( w , b ) = − ∑ x i ∈ M y i 批量梯度下降法: w ← w + η ∑ x i ∈ M x i y i , b ← b + η ∑ x i ∈ M y i 随机梯度下降法 : w ← w + η x i y i , b ← b + η y i 其中, η ( 0 < η < = 1 ) 为步长 损失函数L(w,b)=-\sum\limits_{x_i\in M}(w\cdot x_i+b)y_i,M为误分类点的集合 \\ 对w和b分别求偏导数,可得梯度为: \\ \nabla_w L(w,b)=-\sum\limits_{x_i\in M}x_iy_i \\ \nabla_b L(w,b)=-\sum\limits_{x_i\in M}y_i \\ 批量梯度下降法:w\leftarrow w + \eta\sum\limits_{x_i\in M}x_iy_i,b\leftarrow b + \eta\sum\limits_{x_i\in M}y_i \\ 随机梯度下降法: w\leftarrow w + \eta x_iy_i,b\leftarrow b + \eta y_i\\ 其中,\eta(0<\eta<=1)为步长 \\ 损失函数L(w,b)=xiM(wxi+b)yiM为误分类点的集合wb分别求偏导数,可得梯度为:wL(w,b)=xiMxiyibL(w,b)=xiMyi批量梯度下降法:ww+ηxiMxiyi,bb+ηxiMyi随机梯度下降法:ww+ηxiyi,bb+ηyi其中,η(0<η<=1)为步长

1.3.1 随机梯度下降法

现在我们以随机梯度下降法来讲解感知机的算法,如下:

在这里插入图片描述

  • 首先选择初始值。
  • 接下来,在训练集中随机选取一个实例点,用 y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)来判断这个点被分离超平面正确分类还是错误分类。
    • 如果被正确分类, y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)就是大于零的,我们不用管这个实例点了;
    • 如果被错误分类, y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)就是小于零的,我们可以把这个实例点拿来更新参数。
    • 最麻烦的就是,如果这个实例点恰好位于分离超平面上,那么 y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)就直接等于零,无法知道此时这个实例点到底是被正确分类还是错误分类。所以,本着宁肯错杀也不能放过的原则,我们把这个实例点拿来更新参数。
  • 这样第三步就完成了。
  • 接着就是步骤的重复,直到所有的实例点都确定被正确分类。

1.3.2 感知机算法例题

在这里插入图片描述

我们这里使用python代码求解该例题:

完整代码可参考:Statistical_Learning_Methods_Impl: 《统计学习方法》第二版 python代码实现

import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
%matplotlib inline

# 1、加载数据
data = np.array([
    [3, 3, 1],
    [4, 3, 1],
    [1, 1, -1]
])
# 获取X和y
X, y = data[:,:-1], data[:,-1]

# 2、画图
plt.scatter(X[:2][0], X[:2][1], label='1')
plt.scatter(X[2:][0], X[2:][0], label='-1')
plt.xlabel('x0')
plt.ylabel('x1')
# 设置x轴和y轴范围
plt.xlim(0, 7)
plt.ylim(0, 7)
plt.legend()

在这里插入图片描述

# 3、创建模型
class Perceptron(object):
    def __init__(self, num_features, l_rate=1, w='0'):
        # 初始化参数w、b以及学习率l_rate
        if w == '0':
            self.w = np.zeros(num_features, dtype=np.float32)
        elif w == '1':
            self.w = np.ones(num_features, dtype=np.float32)
        else:
            raise Exception('Unsupported parameter w')
        self.b = 0
        self.l_rate = l_rate

    def sign(self, x, w, b):
        # 计算:xw + b
        return np.dot(x, w) + b


    def fit(self, X_train, y_train):
        # 随机梯度下降法
        is_wrong = False
        while not is_wrong:
            # 误分类点的个数
            wrong_count = 0
            for index in range(len(X_train)):
                # 取出一个点
                X = X_train[index]
                y = y_train[index]
                # 如果该点为误分类点,就进行迭代
                if y * self.sign(X, self.w, self.b) <= 0:
                    # 更新w
                    self.w += self.l_rate * np.dot(y, X)
                    # 更新b
                    self.b += self.l_rate * y
                    # 误分类点+1
                    wrong_count += 1
                    print(f'取出的误分类点为x{index + 1}, 更新后w = {self.w}, b = {self.b},  wx+b = {self.w[0]}x1 + {self.w[1]}x2 + {self.b}')
            # 一次循环迭代结束后,如果没有误分类点,就结束
            if wrong_count == 0:
                is_wrong = True
        return 'Perceptron Model'

    def predict(self,X_predict):
        y = np.dot(X_predict, self.w) + self.b
        return np.sign(y)

    def score(self):
        pass
# 进行训练
num = len(X[0])
net1 = Perceptron(num_features=num)
net1.fit(X, y)
取出的误分类点为x1, 更新后w = [3. 3.], b = 1,   wx+b = 3.0x1 + 3.0x2 + 1
取出的误分类点为x3, 更新后w = [2. 2.], b = 0,   wx+b = 2.0x1 + 2.0x2 + 0
取出的误分类点为x3, 更新后w = [1. 1.], b = -1,  wx+b = 1.0x1 + 1.0x2 + -1
取出的误分类点为x3, 更新后w = [0. 0.], b = -2,  wx+b = 0.0x1 + 0.0x2 + -2
取出的误分类点为x1, 更新后w = [3. 3.], b = -1,  wx+b = 3.0x1 + 3.0x2 + -1
取出的误分类点为x3, 更新后w = [2. 2.], b = -2,  wx+b = 2.0x1 + 2.0x2 + -2
取出的误分类点为x3, 更新后w = [1. 1.], b = -3,  wx+b = 1.0x1 + 1.0x2 + -3

可以看到和书籍上迭代过程一样:

在这里插入图片描述

经过上述迭代,我们就得到最终模型:
f ( x ) = s i g n ( x ( 1 ) + x ( 2 ) − 3 ) f(x)=sign(x^{(1)}+x^{(2)}-3) f(x)=sign(x(1)+x(2)3)
需要注意的是,感知机模型并不唯一,不同的初值或者说不同的误分类点的顺序,可以得到不同的分离超平面。

我们可以实验下,将w的初始值设置为1,就得到了另一个超平面。

# 进行训练
num = len(X[0])
net2 = Perceptron(num_features=num, w='1')
net2.fit(X, y)
取出的误分类点为x3, 更新后w = [0. 0.], b = -1,  wx+b = 0.0x1 + 0.0x2 + -1
取出的误分类点为x1, 更新后w = [3. 3.], b = 0,  wx+b = 3.0x1 + 3.0x2 + 0
取出的误分类点为x3, 更新后w = [2. 2.], b = -1,  wx+b = 2.0x1 + 2.0x2 + -1
取出的误分类点为x3, 更新后w = [1. 1.], b = -2,  wx+b = 1.0x1 + 1.0x2 + -2
取出的误分类点为x3, 更新后w = [0. 0.], b = -3,  wx+b = 0.0x1 + 0.0x2 + -3
取出的误分类点为x1, 更新后w = [3. 3.], b = -2,  wx+b = 3.0x1 + 3.0x2 + -2
取出的误分类点为x3, 更新后w = [2. 2.], b = -3,  wx+b = 2.0x1 + 2.0x2 + -3
取出的误分类点为x3, 更新后w = [1. 1.], b = -4,  wx+b = 1.0x1 + 1.0x2 + -4

在这里插入图片描述

2 感知机的对偶形式算法

2.1 理解对偶算法

在之前讲解的原始形式的学习算法中,如果实例点 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,可以用它更新参数,即
w ← w + η x i y i b ← b + η y i w\leftarrow w + \eta x_iy_i \\ b\leftarrow b + \eta y_i\\ ww+ηxiyibb+ηyi
假如,每一个实例点对于参数更新,做了 n i n_i ni次贡献,那么每个实例点作用到初始参数 w 0 、 b 0 w_0、b_0 w0b0上的增量分别为 a i y i x i a_iy_ix_i aiyixi a i y i a_iy_i aiyi,其中 a i = n i η a_i=n_i\eta ai=niη

还是之前的例子:

在这里插入图片描述

  • 在这个过程中,实例 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)作为误分类点出现两次,所以 n 1 = 2 n_1=2 n1=2,即第一个实例点在迭代中贡献了 2 次。

  • ( x 2 , y 2 ) (x_2,y_2) (x2,y2)并没有出现,所以 n 2 = 0 n_2=0 n2=0,即第二个实例点在迭代中没有贡献。

  • ( x 3 , y 3 ) (x_3,y_3) (x3,y3)出现了5次,所以 n 3 = 5 n_3=5 n3=5,即第三个实例点在迭代中贡献了 5 次。

  • 恰好 n 1 + n 3 = 7 n_1 + n_3=7 n1+n3=7,就是实际迭代的次数。综合所有贡献的增量,就得到最终参数了,与原始算法的结果是相同的。

  • 对偶形式,基本思想就是通过实例点的线性组合来更新参数,其权重由贡献的大小决定的

根据以上的例子,很容易得出下面式子:

在这里插入图片描述

2.2 对偶算法

下面是感觉机学习算法对偶形式的具体步骤,可以看到把 w w w换为了 ∑ j = 1 N a i y i x j \sum\limits_{j=1}^N a_iy_ix_j j=1Naiyixj,梯度下降时候也变成了更新 a i a_i ai

在这里插入图片描述

与原始形式相比,对偶形式有什么优势呢? 这需要,仔细分析对偶形式的迭代条件。

在这里插入图片描述

  • 将迭代条件展开,我们发现,如果训练数据集固定,那么有些值是不需要重复计算的,也就是我们红框里的这 N N N个内积。

  • 如果 ( x i , y i ) (x_i, y_i) (xi,yi)是误分类点,只要读取Gram矩阵第 i i i行的值即可。

  • 我们要做的,就是在得到训练数据集之后,把这 N × N N×N N×N个内积计算出来储存到Gram矩阵,之后每次更新参数的时候读取就可以,这能节省许多计算量。

2.3 对偶算法的案例

还是之前的案例,我们使用对偶算法进行求解。

在这里插入图片描述

  • 先设置初始值,不妨还是取零向量,然后计算Gram矩阵,把9个内积的值都储存下来。

  • 接下来就是判断误分类点,可以选取 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)带入迭代条件中,计算得到零,可以用来更新参数,得到一个新的分离超平面。

在这里插入图片描述

  • 用这个新得到的分离超平面,对三个实例点分类,选取错误分类点,继续进行更新。
    在这里插入图片描述

  • 之后,重复步骤,直到没有误分类点,停止迭代。

在这里插入图片描述

2.4 上述过程的代码实现

Statistical_Learning_Methods_Impl: 《统计学习方法》第二版 python代码实现

import numpy as np

class PerceptronDuality(object):
    def __init__(self, num_features, eta=1):
        # 初始化参数G、α、w、b
        self.G = np.zeros([num_features, num_features], dtype=np.float32)
        self.α = np.zeros(num_features)
        self.b = 0
        self.eta = eta
        # w[0] * x + w[1] * y + b = 0
        self.w = [0., 0.]

    def fit(self, data, label):
        # 1、计算 Gram 矩阵
        for i in range(0, len(data)):
            for j in range(0, len(data)):
                self.G[i][j] = data[i][0] * data[j][0] + data[i][1] * data[j][1]

        print('Gram矩阵:\n', self.G)

        separated = False  # 标记是否完全分离
        while not separated:
            separated = True

            # 遍历训练集,每次取出点 (data[i][0], data[i][1])
            for i in range(0, len(data)):
                sum = 0
                for j in range(0, len(data)):
                    # 计算 ∑(α*yj*xj)x的值,相当于原始形式中的 wx
                    sum += self.α[j] * label[j] * self.G[j][i]
                # 判断是否为误分类点
                if (sum + self.b) * label[i] <= 0:
                    self.α[i] += self.eta          # 更新 α 的值
                    self.b += self.eta * label[i]  # 更新 b 的值
                    print(f'误分类点为x{i + 1},α = {self.α}, b = {self.b}')

                    separated = False  # 置回标记

        # 求出 w 的值
        for i in range(0, len(self.α)):
            self.w[0] += self.α[i] * label[i] * data[i][0]
            self.w[1] += self.α[i] * label[i] * data[i][1]

        return 'PerceptronDuality Model'

if __name__ == '__main__':
    data = np.array([
        [3, 3, 1],
        [4, 3, 1],
        [1, 1, -1]
    ])

    X, y = data[:, :-1], data[:, -1]
    # 进行训练
    num = len(X)
    net = PerceptronDuality(num_features=num)

    net.fit(X, y)

可以看到和之前手动计算的一致。

Gram矩阵:
 [[18. 21.  6.]
  [21. 25.  7.]
  [ 6.  7.  2.]]
误分类点为x1,α = [1. 0. 0.], b = 1
误分类点为x3,α = [1. 0. 1.], b = 0
误分类点为x3,α = [1. 0. 2.], b = -1
误分类点为x3,α = [1. 0. 3.], b = -2
误分类点为x1,α = [2. 0. 3.], b = -1
误分类点为x3,α = [2. 0. 4.], b = -2
误分类点为x3,α = [2. 0. 5.], b = -3

参考书籍:
李航老师《统计学习方法》第二版

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

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

相关文章

如何搭建“Docker Registry私有仓库,在CentOS7”?

1、下载镜像Docker Registry docker pull registry:2.7.1 2、运行私有库Registry docker run -d -p 5000:5000 -v ${PWD}/registry:/var/lib/registry --restartalways --name registry registry:2.7.1 3、拉取镜像 docker pull busybox 4、打标签&#xff0c;修改IP&#x…

基于直方图均衡化的图像去雾算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供有偿…

Spring-1

目录 概念 优点 Autowired和Resource关键字 相同点 不同点 依赖注入的三种方式 概念 Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用&#xff0c;但是有些扩展是针对构建J2EE&#xff08;Java平台企业版&#xff09;平台的web应用。Spring 框架目…

熔断降级的方案实现

熔断降级的方案实现 Spring Cloud Netflix Hystrix 提供线程隔离、服务降级、请求缓存、请求合并等功能可与Spring Cloud其他组件无缝集成官方已宣布停止维护&#xff0c;推荐使用Resilience4j代替 Spring Cloud Resilience4j 轻量级服务熔断库 提供类似于Hystrix的功能 具有更…

鸿蒙-自定义组件的生命周期

目录 自定义组件的生命周期 1.aboutToAppear 2.aboutToDisappear 3.onPageShow 4.onPageHide 5.onBackPress 日志输出 1.显示页面 2.页面点击返回按钮 3.页面跳转 4.页面返回 自定义组件的生命周期 先来一段列子 import router from ohos.router Entry Component…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Badge)

可以附加在单个组件上用于信息标记的容器组件。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 说明&#xff1a; 子组件类型&#xff1a;系统组件和自定义组件&#xf…

移动云行动:5.5G技术引领数字化转型

刚刚结束的全国两会上&#xff0c;有人大代表建议应尽快发挥5G-A&#xff08;5.5G&#xff09;优势&#xff0c;加快试点城市布局。此前&#xff0c;中国移动已宣布将在300多个城市启动5.5G商用部署。在通信技术的历史长河中&#xff0c;4G改变了我们的生活方式&#xff0c;而5…

【UE5】持枪状态站立移动的动画混合空间

项目资源文末百度网盘自取 创建角色在持枪状态站立移动的动画混合空间 在BlendSpace文件夹中单击右键选择动画(Animation)中的混合空间(Blend Space) 选择SK_Female_Skeleton 命名为BS_RifleStand 打开 水平轴表示角色的方向&#xff0c;命名为Direction&#xff0c;方…

springboot+poi-tl根据模板导出word(含动态表格和图片),并将导出的文档压缩zip导出

springbootpoi-tl根据模板导出word&#xff08;含动态表格和图片&#xff09; 官网&#xff1a;http://deepoove.com/poi-tl/ 参考网站&#xff1a;https://blog.csdn.net/M625387195/article/details/124855854 pom导入的maven依赖 <dependency><groupId>com.dee…

Autosar教程-Mcal教程-Lin配置教程

3.7LIN配置、生成 3.7.1 配置通用设置 3.7.2 配置Dem参数 3.7.3 配置Lin通道 3.7.4配置生成命令 参照Dio生成命令方法&#xff0c;创建Lin生成命令&#xff0c;创建完成后按下面提供的信息配置生成命令。 实际上MCAL代码并不能单独生成&#xff0c;它需要和BSW的配置文件一…

内存操作函数(C语言)

目录 memcpy使用和模拟实现 memcpy函数的模拟实现 memmove的使用和模拟实现 memmove的模拟实现 memset函数的使用 memcmp函数的使用 memcpy使用和模拟实现 mem--memory--记忆--内存 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置这…

springcloud:4.1 GateWay

概述 Gateway 简介 Spring Cloud Gateway基于Spring 5.0、SpringBoot 2.0和Project Reactor等技术开发 旨在为微服务架构提供一种简单有效的、统一的API路由管理方式&#xff0c;并为微服务架构提供安全、监控、指标和弹性等功能 其目标是替代Zuul特点 易于编写谓词和过滤器&…

MM1: Methods, Analysis Insights from Multimodal LLM Pre-training

MM1: Methods, Analysis & Insights from Multimodal LLM Pre-training 相关链接&#xff1a;arxiv 关键字&#xff1a;多模态学习、大型语言模型、预训练、视觉语言连接、混合专家模型 摘要 本文讨论了构建高性能的多模态大型语言模型&#xff08;MLLMs&#xff09;。特别…

OPTIONS请求(跨域预检查)

目录 一、什么是OPTIONS请求&#xff1f;二、简单请求、复杂请求三、特定的请求头、响应头 一、什么是OPTIONS请求&#xff1f; OPTIONS 请求方式是 HTTP 协议中的一种&#xff0c;主要用于 从响应头中获取服务器支持的HTTP请求方式。 OPTIONS 请求方式是 浏览级行为&#xf…

【SpringCloud微服务实战02】Ribbon 负载均衡

Ribbon使用 Eureka中已经集成了Ribbon,无需额外引入,通过 @LoadBalanced 注解在请求中使用 Ribbon 负载均衡: @Bean @LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate(); } Ribbon工作流程图 Ribbon负载均衡策略 修改Ribbon负载均衡策略 方式一…

从0开始启动一个Django的docker服务

本文是从0开始启动一个Django的docker服务&#xff0c;包括构建镜像,uwsgi启动服务 在服务器上安装ssh&#xff0c;git&#xff0c;生成公钥并复制到服务器上 # 安装ssh yum install openssh-clients # 生成sshkey ssh-keygen # 查看公钥 cat /root/.ssh/id_rsa.pubclone一下…

Text-to-SQL 工具Vanna | 查看训练数据、删除训练数据

1.查看训练数据vn.get_training_data vn.get_training_data 源码如下&#xff0c;可以看到返回的是df格式的数据 abstractmethoddef get_training_data(self, **kwargs) -> pd.DataFrame:"""Example:pythonvn.get_training_data()This method is used to ge…

Brute Force 算法介绍

Brute Force 算法介绍 Brute Force 算法&#xff1a;简称为 BF 算法。中文意思是暴力匹配算法&#xff0c;也可以叫做朴素匹配算法。 BF 算法思想&#xff1a;对于给定文本串 T 与模式串 p&#xff0c;从文本串的第一个字符开始与模式串 p 的第一个字符进行比较&#xff0c;如果…

计算机考研|408专业课复习教程+注意事项

408其实把真题琢磨透就已经可以了&#xff01;其实大部分考研党复习到最后真题都来不及刷完就要上考场 因为在考研后期时间分配真的很困难&#xff01;特别是数学和408 本人双非科班出身备考408成功上岸&#xff0c;在这里也想给想考408的学弟学妹们一些很中肯的&#xff0c;…

干重活儿的互联网

接女儿放学路过欧尚超市&#xff0c;我说 “十年前我每周末推着小车带你去超市&#xff0c;那时没有这么多送外卖的&#xff0c;什么东西都要自己跑过去买”&#xff0c;“你的意思是要表达科技获得很大进步了吗&#xff1f;” 女儿反问&#xff0c;“不&#xff0c;恰恰相反&a…