学习日记_241110_局部线性嵌入(Locally Linear Embedding, LLE)

前言

提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。

相关链接:
LLE原理及推导过程
局部线性嵌入原理总结
代码抄录源

文章目录

  • 前言
  • 代码抄录
  • 代码分析
    • LLE算法介绍
      • LLE 算法步骤
      • 数学性质
      • 优点
      • 缺点
    • def make_swiss_roll(n_samples=100,noise=0.0,random_state=None)
    • def cal_pairwise_dist(x)
    • def get_n_neighbors(data,n_neighbors=10)
    • def lle(data,n_dims=2,n_neighbors=10)
      • 输入
      • 步骤
      • 输出
    • python函数库
    • 代码运行结果
  • 遗留问题


代码抄录

import numpy as np 
from sklearn.datasets import make_s_curve
import matplotlib.pyplot as plt
from sklearn.manifold import LocallyLinearEmbedding
from mpl_toolkits.mplot3d import Axes3D

def make_swiss_roll(n_samples=100,noise=0.0,random_state=None):
    t=1.5*np.pi*(1+2*np.random.rand(1,n_samples))
    x=t*np.cos(t)
    y=83*np.random.rand(1,n_samples)
    z=t*np.sin(t)
    X=np.concatenate((x,y,z))
    X+=noise*np.random.randn(3,n_samples)
    X=X.T
    t=np.squeeze(t)
    return X,t

def cal_pairwise_dist(x):
    sum_x=np.sum(np.square(x),1)
    dist=np.add(np.add(-2*np.dot(x,x.T),sum_x).T,sum_x)
    return dist

def get_n_neighbors(data,n_neighbors=10):
    dist=cal_pairwise_dist(data)
    dist[dist<0]=0
    dist=dist**0.5
    n=dist.shape[0]
    N=np.zeros((n,n_neighbors))
    for i in range(n):
        index_=np.argsort(dist[i])[1:n_neighbors+1]
        N[i]=N[i]+index_
    return N.astype(np.int32)
def lle(data,n_dims=2,n_neighbors=10):
    N=get_n_neighbors(data,n_neighbors)
    n,D=data.shape
    if n_neighbors>D:
        tol=1e-3
    else:
        tol=0
    W=np.zeros((n_neighbors,n))
    I=np.ones((n_neighbors,1))
    for i in range(n):
        Xi=np.tile(data[i],(n_neighbors,1)).T
        Ni=data[N[i]].T
        Si=np.dot((Xi-Ni).T,(Xi-Ni))
        Si=Si+np.eye(n_neighbors)*tol*np.trace(Si)
        Si_inv=np.linalg.pinv(Si)
        wi=(np.dot(Si_inv,I))/(np.dot(np.dot(I.T,Si_inv),I)[0,0])
        W[:,i]=wi[:,0]
    print("Xi.shape:",Xi.shape)
    print("Ni.shape:",Ni.shape)
    print("Si.shape:",Si.shape)
    W_y=np.zeros((n,n))
    for i in range(n):
        index=N[i]
        for j in range(n_neighbors):
            W_y[index[j],i]=W[j,i]
    I_y=np.eye(n)
    M=np.dot((I_y-W_y),(I_y-W_y).T)

    eig_val,eig_vector=np.linalg.eig(M)
    index_=np.argsort(np.abs(eig_val))[1:n_dims+1]
    print("index_:",index_)
    Y=eig_vector[:,index_]
    return Y
    
if __name__=="__main__":
    X,Y=make_swiss_roll(n_samples=500,noise=0.1,random_state=42)
    data_1=lle(X,n_neighbors=30)
    print(data_1.shape)
    data_2=LocallyLinearEmbedding(n_components=2,n_neighbors=30).fit_transform(X)

    plt.figure(figsize=(8,4))
    plt.subplot(121)
    plt.title("LLE")
    plt.scatter(data_1[:,0],data_1[:,1],c=Y)

    plt.subplot(122)
    plt.title("sklearn LLE")
    plt.scatter(data_2[:,0],data_2[:,1],c=Y)
    plt.show()

代码分析

LLE算法介绍

局部线性嵌入(Locally Linear Embedding, LLE)是一种非线性降维算法,致力于保持高维数据的局部几何结构。它通常用于揭示数据的内在流形结构。下面是对 LLE 算法的详细介绍,包括其数学原理和步骤。

LLE 算法步骤

  1. 构建邻域

    对于每个数据点 x i \mathbf{x}_i xi,确定其 k k k 个最近邻。最近邻的选择通常基于欧氏距离或其他距离度量。

  2. 线性重建权重

    以每个数据点及其邻居为基础,构建重建权重矩阵 W \mathbf{W} W。重建权重使得数据点可以由其邻居的线性组合表示,即最小化以下重构误差:

    ϵ ( W ) = ∑ i = 1 N ∥ x i − ∑ j ∈ N ( i ) W i j x j ∥ 2 \epsilon(W) = \sum_{i=1}^{N} \left\| \mathbf{x}_i - \sum_{j \in \mathcal{N}(i)} W_{ij} \mathbf{x}_j \right\|^2 ϵ(W)=i=1N xijN(i)Wijxj 2

    其中 N ( i ) \mathcal{N}(i) N(i) 是点 x i \mathbf{x}_i xi 的邻居集合,权重 W i j W_{ij} Wij 满足归一化条件:

    ∑ j ∈ N ( i ) W i j = 1 \sum_{j \in \mathcal{N}(i)} W_{ij} = 1 jN(i)Wij=1

    上述优化问题可以通过局部线性系统求解,常用的方法是通过拉格朗日乘子或约束二次规划解决。

  3. 低维嵌入

    找到低维坐标 y i \mathbf{y}_i yi ,以最小化以下嵌入误差:

    Φ ( Y ) = ∑ i = 1 N ∥ y i − ∑ j ∈ N ( i ) W i j y j ∥ 2 \Phi(\mathbf{Y}) = \sum_{i=1}^{N} \left\| \mathbf{y}_i - \sum_{j \in \mathcal{N}(i)} W_{ij} \mathbf{y}_j \right\|^2 Φ(Y)=i=1N yijN(i)Wijyj 2

    该问题转化为求解特征值问题:

    M Y = λ Y \mathbf{M} \mathbf{Y} = \lambda \mathbf{Y} MY=λY

    其中矩阵 M = ( I − W ) T ( I − W ) \mathbf{M} = (\mathbf{I} - \mathbf{W})^T (\mathbf{I} - \mathbf{W}) M=(IW)T(IW) I \mathbf{I} I 是单位矩阵。

  4. 求解特征值问题

    通过求解上述特征值问题,选择对应于最小非零特征值的特征向量作为低维嵌入坐标。通常,去掉最小的零特征值对应的特征向量(即常数特征向量)。

数学性质

  • LLE 本质上是保持局部线性关系的降维方法,假设高维数据位于低维流形上,且该流形在局部近似为线性。
  • 通过保持数据点在其邻居上的重建关系,LLE 能够揭示数据的内在几何结构。
  • LLE 不需要明确的参数化模型,也不需要迭代优化及非凸目标的求解。

优点

  • 能够有效处理非线性流形结构。
  • 保持数据的局部几何结构。
  • 不依赖于参数化模型,减少了对模型选择的依赖。

缺点

  • 对噪声和参数选择(如邻居数量)敏感。
  • 算法复杂度较高,特别是在处理大规模数据时。

LLE 算法通过保持数据的局部线性关系,能够有效地实现高维到低维的非线性降维,被广泛应用于模式识别、图像处理等领域。

def make_swiss_roll(n_samples=100,noise=0.0,random_state=None)

def make_swiss_roll(n_samples=100,noise=0.0,random_state=None):
    t=1.5*np.pi*(1+2*np.random.rand(1,n_samples))
    x=t*np.cos(t)
    y=83*np.random.rand(1,n_samples)
    z=t*np.sin(t)
    X=np.concatenate((x,y,z))
    X+=noise*np.random.randn(3,n_samples)
    X=X.T
    t=np.squeeze(t)
    return X,t

make_swiss_roll函数生成一个三维的瑞士卷数据集。这个数据集是一个形似瑞士卷蛋糕的螺旋形状,常用于测试机器学习算法。函数的数学表达可以分为以下几步:

  1. 参数:
  • n _ s a m p l e s n\_samples n_samples: 样本数。
  • n o i s e noise noise: 噪声水平。
  • r a n d o m _ s t a t e random\_state random_state: 随机种子。
  1. 生成参数 t t t:
  • t = 1.5 π ( 1 + 2 U ) t = 1.5\pi (1 + 2U) t=1.5π(1+2U), 其中 U U U 是一个均匀分布在 [ 0 , 1 ] [0, 1] [0,1] 上的随机数。
  1. 生成数据:
  • 第一维 (x轴): x = t cos ⁡ ( t ) x = t \cos(t) x=tcos(t)
  • 第二维 (y轴): y = 83 V y = 83V y=83V, 其中 V V V 是一个均匀分布在 [ 0 , 1 ] [0, 1] [0,1] 上的随机数。
  • 第三维 (z轴): z = t sin ⁡ ( t ) z = t \sin(t) z=tsin(t)
  1. 合并数据:
  • 数据点 X = ( x , y , z ) X = (x, y, z) X=(x,y,z) 通过将三个维度的值合并形成一个三维点。
  1. 添加噪声:
  • X X X 的每个坐标加上正态分布的随机噪声 N ( 0 , noise ) \mathcal{N}(0, \text{noise}) N(0,noise)
  1. 输出:
  • 返回值是一个由样本点组成的矩阵 X X X,以及对应的参数 t t t,其中 X X X 是形状为 ( n _ s a m p l e s , 3 ) (n\_samples, 3) (n_samples,3) 的矩阵。

因此,这个函数生成的瑞士卷的数学公式为:

X = [ t cos ⁡ ( t ) + noise ⋅ N ( 0 , 1 ) 83 V + noise ⋅ N ( 0 , 1 ) t sin ⁡ ( t ) + noise ⋅ N ( 0 , 1 ) ] X = \begin{bmatrix} t \cos(t) + \text{noise} \cdot N(0, 1) \\ 83V + \text{noise} \cdot N(0, 1) \\ t \sin(t) + \text{noise} \cdot N(0, 1) \end{bmatrix} X= tcos(t)+noiseN(0,1)83V+noiseN(0,1)tsin(t)+noiseN(0,1)

其中 V ∼ U ( 0 , 1 ) V \sim U(0, 1) VU(0,1) 是在 [ 0 , 1 ] [0, 1] [0,1] 上的均匀随机数, N ( 0 , 1 ) N(0, 1) N(0,1) 是正态分布的随机噪声。

使以下代码生成图像:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def make_swiss_roll(n_samples=100, noise=0.0, random_state=None):
    # 设置随机种子以保证结果的可复现性
    if random_state is not None:
        np.random.seed(random_state)

    # 生成瑞士卷数据
    t = 1.5 * np.pi * (1 + 2 * np.random.rand(1, n_samples))  # 角度
    x = t * np.cos(t)  # 瑞士卷的X坐标
    y = 83 * np.random.rand(1, n_samples)  # 瑞士卷的Y坐标
    z = t * np.sin(t)  # 瑞士卷的Z坐标

    # 将坐标组合成一个矩阵,并添加噪声
    X = np.concatenate((x, y, z))
    X += noise * np.random.randn(3, n_samples)
    X = X.T  # 转置以匹配样本数和特征数
    t = np.squeeze(t)  # 压缩维度
    return X, t

# 生成瑞士卷数据
X, t = make_swiss_roll()

# 绘制三维瑞士卷
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=t, cmap='plasma')  # 使用颜色映射
ax.set_title("Swiss Roll in 3D")
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
ax.set_zlabel("Z-axis")
plt.show()

图片如下所示:
在这里插入图片描述
在这里插入图片描述

def cal_pairwise_dist(x)

def cal_pairwise_dist(x):
    sum_x=np.sum(np.square(x),1)
    dist=np.add(np.add(-2*np.dot(x,x.T),sum_x).T,sum_x)
    return dist

得到一个 n × n n \times n n×n的矩阵,其中每个元素是对应点对之间的欧几里得距离的平方:
dist ( i , j ) = sum_x [ i ] + sum_x [ j ] − 2 ( x ⋅ x T ) i j \text{dist}(i, j) = \text{sum\_x}[i] + \text{sum\_x}[j] - 2 (x \cdot x^T)_{ij} dist(i,j)=sum_x[i]+sum_x[j]2(xxT)ij

def get_n_neighbors(data,n_neighbors=10)

def get_n_neighbors(data,n_neighbors=10):
    dist=cal_pairwise_dist(data)
    dist[dist<0]=0
    dist=dist**0.5
    n=dist.shape[0]
    N=np.zeros((n,n_neighbors))
    for i in range(n):
        index_=np.argsort(dist[i])[1:n_neighbors+1]
        N[i]=N[i]+index_
    return N.astype(np.int32)

输出可以表达为:

N [ i ] = argsort ( D [ i ] ) [ 1 : n neighbors + 1 ] 对于所有  i ∈ { 1 , 2 , … , n } N[i] = \text{argsort}(D[i])[1:n_{\text{neighbors}} + 1] \quad \text{对于所有 } i \in \{1, 2, \ldots, n\} N[i]=argsort(D[i])[1:nneighbors+1]对于所有 i{1,2,,n}
描述了如何为每个数据点找到 n neighbors n_{\text{neighbors}} nneighbors 个最近邻的索引,并将结果存储在矩阵 N N N中。

关于代码:
for i in range(n):
index_=np.argsort(dist[i])[1:n_neighbors+1]
N[i]=N[i]+index_

  • N 是一个二维数组,形状为 (n, n_neighbors),用于存储每个数据点的最近邻索引。
  • N[i] 是矩阵 N N N 的第 i i i行,用于存储第 i i i 个数据点的最近邻的索引。
  • index_ 是一个包含 n neighbors n_{\text{neighbors}} nneighbors 个最近邻索引的一维数组。
  • N[i] = N[i] + index_ 实际上是将 index_ 中的值赋给 N[i]。这里 N[i] 的初始值是一个零向量(因为 N 是通过 np.zeros 初始化的),加上 index_ 之后,结果就是 index_

def lle(data,n_dims=2,n_neighbors=10)

def lle(data,n_dims=2,n_neighbors=10):
    N=get_n_neighbors(data,n_neighbors)
    n,D=data.shape
    if n_neighbors>D:
        tol=1e-3
    else:
        tol=0
    W=np.zeros((n_neighbors,n))
    I=np.ones((n_neighbors,1))
    for i in range(n):
        Xi=np.tile(data[i],(n_neighbors,1)).T
        Ni=data[N[i]].T
        Si=np.dot((Xi-Ni).T,(Xi-Ni))
        Si=Si+np.eye(n_neighbors)*tol*np.trace(Si)
        Si_inv=np.linalg.pinv(Si)
        wi=(np.dot(Si_inv,I))/(np.dot(np.dot(I.T,Si_inv),I)[0,0])
        W[:,i]=wi[:,0]
    print("Xi.shape:",Xi.shape)
    print("Ni.shape:",Ni.shape)
    print("Si.shape:",Si.shape)
    W_y=np.zeros((n,n))
    for i in range(n):
        index=N[i]
        for j in range(n_neighbors):
            W_y[index[j],i]=W[j,i]
    I_y=np.eye(n)
    M=np.dot((I_y-W_y),(I_y-W_y).T)

    eig_val,eig_vector=np.linalg.eig(M)
    index_=np.argsort(np.abs(eig_val))[1:n_dims+1]
    print("index_:",index_)
    Y=eig_vector[:,index_]
    return Y

关于代码 Xi=np.tile(data[i],(n_neighbors,1)).T

  1. data[i]
    • data 是一个二维数组,形状为 ( n , D ) (n, D) (n,D),表示 n n n 个样本,每个样本有 D D D 个特征。
    • data[i] 选择第 i i i 个样本,结果是一个一维数组,形状为 ( D , ) (D,) (D,)
  2. np.tile(data[i], (n_neighbors, 1))
    • np.tile 函数用于重复数组。
    • (n_neighbors, 1) 是重复参数,表示将 data[i] 沿着第一个维度重复 n neighbors n_{\text{neighbors}} nneighbors 次,沿着第二个维度重复 1 次。
    • 结果是一个二维数组,形状为 ( n neighbors , D ) (n_{\text{neighbors}}, D) (nneighbors,D),其中每一行都是 data[i]

输入

  • 数据集 X ∈ R n × D \mathbf{X} \in \mathbb{R}^{n \times D} XRn×D,其中 n n n 是样本数量, D D D 是特征维度。
  • 目标维度 n dims n_{\text{dims}} ndims
  • 最近邻数量 n neighbors n_{\text{neighbors}} nneighbors

步骤

  1. 找到最近邻: 使用 get_n_neighbors 函数找到每个数据点的最近邻索引: N = get_n_neighbors ( X , n neighbors ) \mathbf{N} = \text{get\_n\_neighbors}(\mathbf{X}, n_{\text{neighbors}}) N=get_n_neighbors(X,nneighbors)

  2. 计算权重矩阵 W \mathbf{W} W

    对于每个数据点 x i \mathbf{x}_i xi

    • 取出 x i \mathbf{x}_i xi 的最近邻 N i \mathbf{N}_i Ni,用 X N i \mathbf{X}_{\mathbf{N}_i} XNi 表示这些邻居。
    • 构造局部协方差矩阵:
      S i = ( X i − X N i ) T ( X i − X N i ) \mathbf{S}_i = (\mathbf{X}_i - \mathbf{X}_{\mathbf{N}_i})^T (\mathbf{X}_i - \mathbf{X}_{\mathbf{N}_i}) Si=(XiXNi)T(XiXNi)
      其中 X i \mathbf{X}_i Xi 是将数据点 x i \mathbf{x}_i xi 复制为适当形状的矩阵。
    • 添加正则化项以确保 S i \mathbf{S}_i Si 可逆(根据 S i \mathbf{S}_i Si 的迹):
      S i = S i + tol ⋅ tr ( S i ) ⋅ I \mathbf{S}_i = \mathbf{S}_i + \text{tol} \cdot \text{tr}(\mathbf{S}_i) \cdot \mathbf{I} Si=Si+toltr(Si)I
    • 计算伪逆:
      S i − 1 = pinv ( S i ) \mathbf{S}_i^{-1} = \text{pinv}(\mathbf{S}_i) Si1=pinv(Si)
    • 计算加权系数:
      w i = S i − 1 1 1 T S i − 1 1 \mathbf{w}_i = \frac{\mathbf{S}_i^{-1} \mathbf{1}}{\mathbf{1}^T \mathbf{S}_i^{-1} \mathbf{1}} wi=1TSi11Si11
      其中 1 \mathbf{1} 1 是一个全为1的列向量。
    • 将权重 w i \mathbf{w}_i wi 存储在权重矩阵 W \mathbf{W} W 中。
  3. 构建嵌入矩阵 M \mathbf{M} M

    构造稀疏矩阵 W y \mathbf{W}_y Wy W y = ∑ i = 1 n ∑ j ∈ N i w i j e j e i T \mathbf{W}_y = \sum_{i=1}^{n} \sum_{j \in \mathbf{N}_i} \mathbf{w}_{ij} \mathbf{e}_j \mathbf{e}_i^T Wy=i=1njNiwijejeiT 其中 e j \mathbf{e}_j ej e i \mathbf{e}_i ei 为标准基向量。

    构造矩阵 M \mathbf{M} M M = ( I − W y ) ( I − W y ) T \mathbf{M} = (\mathbf{I} - \mathbf{W}_y)(\mathbf{I} - \mathbf{W}_y)^T M=(IWy)(IWy)T

  4. 特征值分解:

    求解特征值问题: M v = λ v \mathbf{M} \mathbf{v} = \lambda \mathbf{v} Mv=λv
    选择对应于最小的 n dims + 1 n_{\text{dims}} + 1 ndims+1 个特征值的特征向量(忽略最小的那个特征值,对应于平移不变性)。

  5. 生成低维嵌入:

    最终的低维嵌入是特征向量矩阵的前 n dims n_{\text{dims}} ndims 列: Y = V [ : , index_ ] \mathbf{Y} = \mathbf{V}[:, \text{index\_}] Y=V[:,index_]

输出

  • 低维嵌入 Y ∈ R n × n dims \mathbf{Y} \in \mathbb{R}^{n \times n_{\text{dims}}} YRn×ndims

python函数库

data_2=LocallyLinearEmbedding(n_components=2,n_neighbors=30).fit_transform(X)

代码运行结果

在这里插入图片描述

遗留问题

  1. 关于权重矩阵与嵌入矩阵,,

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【我的 Anti-AV 学习手札】DLL注入

无敌舍友s神免杀学了一个阶段&#xff0c;达者为师&#xff0c;向s师傅学习&#xff01;&#xff01; ps&#xff1a;我的基础实在薄弱&#xff0c;WIN编程甚至都没做过&#xff0c;所以笔记翔实些 一、注入思路 1.在进程中开辟一段空间 2.存入dll绝对路径地址的字符串 3.使用…

【HarmonyOS NEXT】一次开发多端部署(以轮播图、Tab栏、列表为例,配合栅格布局与媒体查询,进行 UI 的一多开发)

关键词&#xff1a;一多、响应式、媒体查询、栅格布局、断点、UI 随着设备形态的逐渐增多&#xff0c;应用界面适配也面临着很大问题&#xff0c;在以往的安卓应用开发过程中&#xff0c;往往需要重新开发一套适用于大屏展示的应用&#xff0c;耗时又耗力&#xff0c;而鸿蒙提供…

linux 安装 mongodb

选择MongoDB版本 https://www.mongodb.com/try/download/community-kubernetes-operator 我的系统是centos7.9 这里只能最高只能选择mongo7 复制下载链接&#xff1a;https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.15.tgz 获取安装教程&#xff1a; h…

《深入浅出Apache Spark》系列②:Spark SQL原理精髓全解析

导读&#xff1a;SQL 诞生于 20 世纪 70 年代&#xff0c;至今已有半个世纪。SQL 语言具有语法简单&#xff0c;低学习门槛等特点&#xff0c;诞生之后迅速普及与流行开来。由于 SQL 具有易学易用的特点&#xff0c;使得开发人员容易掌握&#xff0c;企业若能在其计算机软件中支…

PostgreSQL pg-xact(clog)目录文件缺失处理

一、 背景 前些天晚上突然收到业务反馈&#xff0c;查询DB中的一个表报错 Could not open file "pg-xact/005E": No such file or directory. 两眼一黑难道是文件损坏了...登录查看DB日志&#xff0c;还好没有其他报错&#xff0c;业务也反馈只有这一个表在从库查询报…

Cursor的chat与composer的使用体验分享

经过一段时间的试用&#xff0c;下面对 Composer 与 Chat 的使用差别进行总结&#xff1a; 一、长文本及程序文件处理方面 Composer 在处理长文本时表现较为稳定&#xff0c;可以对长文进行更改而不会出现内容丢失的情况。而 Chat 在更改长的程序文件时&#xff0c;有时会删除…

MATLAB课程:AI工具辅助编程——MATLAB+LLMs

给出一些可能有用的方法辅助大家写代码。 方法一&#xff1a;MATLAB软件LLM (不太懂配置的同学们为了省事可以主要用这个方法) 方法一特别针对本门MATLAB教学课程&#xff0c;给出一种辅助ai工具的操作指南。MATLAB中可以安装MatGPT插件&#xff0c;该插件通过调用ChatGPT的API…

2.索引:SQL 性能分析详解

SQL性能分析是数据库优化中重要的一环。通过分析SQL的执行频率、慢查询日志、PROFILE工具以及EXPLAIN命令&#xff0c;能够帮助我们识别出数据库性能的瓶颈&#xff0c;并做出有效的优化措施。以下将详细讲解这几种常见的SQL性能分析工具和方法。 一、SQL 执行频率 SQL执行频率…

使用Go语言编写一个简单的NTP服务器

NTP服务介绍 NTP服务器【Network Time Protocol&#xff08;NTP&#xff09;】是用来使计算机时间同步化的一种协议。 应用场景说明 为了确保封闭局域网内多个服务器的时间同步&#xff0c;我们计划部署一个网络时间同步服务器&#xff08;NTP服务器&#xff09;。这一角色将…

深度学习经典模型之VGGNet

1 VGGNet 1.1 模型介绍 ​ VGGNet是由牛津大学视觉几何小组&#xff08;Visual Geometry Group, VGG&#xff09;提出的一种深层卷积网络结构&#xff0c;他们以7.32%的错误率赢得了2014年ILSVRC分类任务的亚军&#xff08;冠军由GoogLeNet以6.65%的错误率夺得&#xff09;和…

Android的BroadcastReceiver

1.基本概念&#xff1a;BroadCast用于进程间或者线程间通信 本质上是用Binder方法&#xff0c;以AMS为订阅中心&#xff0c;完成注册&#xff0c;发布&#xff0c;监听的操作。 2.简单实现的例子 package com.android.car.myapplication;import android.content.BroadcastRe…

分布式数据库中间件mycat

MyCat MyCat是一个开源的分布式数据库系统&#xff0c;它实现了MySQL协议&#xff0c;可以作为数据库代理使用。 MyCat(中间件)的核心功能是分库分表&#xff0c;即将一个大表水平分割为多个小表&#xff0c;存储在后端的MySQL服务器或其他数据库中。 它不仅支持MySQL&#xff…

Java多线程编程(四)- 阻塞队列,生产者消费者模型,线程池

目录&#xff1a; 一.阻塞队列 二.线程池 一.阻塞队列 1.阻塞队列是⼀种特殊的队列. 也遵守 "先进先出" 的原则 阻塞队列能是⼀种线程安全的数据结构, 并且具有以下特性&#xff1a; 1.1.当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素 1.…

深度剖析JUC中LongAdder类源码

文章目录 1.诞生背景2.LongAdder核心思想3.底层实现&#xff1a;4.额外补充 1.诞生背景 LongAdder是JDK8新增的一个原子操作类&#xff0c;和AtomicLong扮演者同样的角色&#xff0c;由于采用AtomicLong 保证多线程数据同步&#xff0c;高并发场景下会导致大量线程同时竞争更新…

大数据面试题--kafka夺命连环问

1、kafka消息发送的流程&#xff1f; 在消息发送过程中涉及到两个线程&#xff1a;一个是 main 线程和一个 sender 线程。在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给双端队列&#xff0c;sender 线程不断从双端队列 RecordAccumulator 中拉取…

树形结构数据

树形结构数据 树形结构数据是一种基础且强大的数据结构&#xff0c;广泛应用于计算机科学和软件开发的各个领域。它模拟了自然界中树的层级关系&#xff0c;通过节点和它们之间的连接来组织数据。在本文中&#xff0c;我们将深入探讨树形结构数据的概念、特点、类型以及它们在…

dell服务器安装ESXI8

1.下载镜像在官网 2.打开ipmi&#xff08;idrac&#xff09;&#xff0c;将esxi镜像挂载&#xff0c;然后服务器开机 3.进入bios设置cpu虚拟化开启&#xff0c;进入boot设置启动选项为映像方式 4..进入安装引导界面3.加载完配置进入安装 系统提示点击继 5.选择安装磁盘进行…

信息安全数学基础(46)域和Galois理论

域详述 定义&#xff1a; 域是一个包含加法、减法、乘法和除法&#xff08;除数不为零&#xff09;的代数结构&#xff0c;其中加法和乘法满足交换律、结合律&#xff0c;并且乘法对加法满足分配律。同时&#xff0c;域中的元素&#xff08;通常称为数&#xff09;在加法和乘法…

Windows端口占用/Java程序启动失败-进程占用的问题解决

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…