自组织地图 (SOM) — 介绍、解释和实现

news2025/1/13 13:52:10

自组织地图 (SOM) — 介绍、解释和实现

一、说明

        什么是SOM(self orgnize map)自组织地图,是GNN类似的图神经网络的概念。因为神经网络实质上可以解释为二部图的权重,因此无论GNN还是SOM都有共同的神经网络属性。本文将叙述这中SOM内的结构模型。

二、关于 SOM

        芬兰教授Teuvo Kohonen在1980年代提出的自组织地图或SOM提供了一种在保留数据拓扑的同时对数据集进行低维和离散化表示的方法,称为“地图”。

        目标是学习一个以类似方式响应类似输入模式的地图。它被学习为一个权重数组,它被解释为一个神经元数组,其中每个神经元本身都是一个与输入数据点具有相同维度的向量,如下所示。神经元直接受到输入数据的影响。

        权重数组中神经元之间的距离用于生成表征数据分布的映射。

        SOM 具有轻松可视化特征行为的优势。由于可以从学习的表示中访问各个特征,因此表示每个特征的数据行为。

        让我们分解一下:

        “自组织”

        SOM 是一种无监督的人工神经网络。它不是使用误差最小化技术,而是使用竞争性学习。特征向量使用数据点和学习表示之间的基于距离的指标映射到低维表示,不需要任何其他计算,使其“自组织”。

“地图”

学习到的结果权重由U矩阵(统一距离矩阵,下面详细解释)表示,这是一个表示神经元之间距离的“映射”。学习SOM背后的想法是,形成的映射以类似的方式响应类似的输入,在生成的映射的某些区域中将类似的输入组合在一起。

三、在 Python 中的实现

        Eklavya 连贯地解释了该算法,提供了带有变量适当表示的分步解释,我们也将用于我们的 Python 实现。

Kohonen自组织地图

一种特殊类型的人工神经网络

towardsdatascience.com

        目标是学习一个权重数组,在我们的例子中是一个 3D 数组,但被解释为神经元大小为 x 的 2D 数组,其中每个神经元都是长度的 1D 向量。我们正在学习数据集的 2D 表示。 然后用于生成 U 矩阵 — 整个数据集的单个 2D 地图。Wlengthwidthn_featuresW

图1 - 权重数组“W”

        每个输入向量用于更新 。最接近数据点的神经元是最佳匹配单元(BMU)。其余神经元与BMU的距离用于更新邻域函数,该函数是更新的基础。中较大的值表示相似输入向量的聚类。邻域函数的学习率和半径随时间衰减,因为邻域变小,即相似的输入被分组得更紧密。WWWW

        首先,导入所有必要的库。

from sklearn.preprocessing import MinMaxScaler, StandardScaler
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import random
import time
from itertools import product

四、第一部分:从数据集导入到权重获取

        对于数据,我们使用用于预测胎儿健康的数据集,该数据集将胎儿的健康分类为 、 或使用 CTG 数据。它有 22 个功能,但我们只关注前 10 个功能:NormalSuspectPathological

filein = "fetal_health.csv"
data = np.loadtxt(open(filein, "rb"), delimiter = ",", skiprows = 1)
features = ['baseline value', 'accelerations', 'fetal_movement', 
            'uterine_contractions', 'light_decelerations', 
            'severe_decelerations', 'prolongued_decelerations', 
            'abnormal_short_term_variability', 
            'mean_value_of_short_term_variability', 
            'percentage_of_time_with_abnormal_long_term_variability']
X_data = np.array(data)[:,0:len(features)]

print("Number of datapoints: ", X_data.shape[0])
print("Number of features: ", X_data.shape[1])

        而且,由于它使用基于距离的指标,我们将继续缩放输入:

scaler = MinMaxScaler()
X_data = scaler.fit_transform(X_data) # normalizing, scaling

        现在,深入探讨算法实现的细节。首先,我们看一下超参数:

n_features = X_data.shape[1]
max_iter = 1000                                   # max. no. of iterations
length = 50                                       # length of W
width = 50                                        # width of W
W = np.random.rand([length, width, n_features])   # initial weights
aplha0 = 0.9                                      # initial learning rate
beta = [[]]                                       # neighbourhood function
sigma0 = max(length, width)                       # initial radius of beta
TC = max_iter/np.log(sigma0)                      # time constant
  • length, , — 权重矩阵的维度,其中 和 指定 feaure 地图的大小,值越高,结果越精细。使用随机值初始化。widthn_feauturesWlengthwidthW
  • max_iter— 我们想要运行算法的最大迭代次数。
  • TC— 用于学习率和邻域半径衰减的时间常数。
  • alpha0— 动态学习率的初始值。学习率衰减为时间步长或迭代次数t的指数函数:alphat
def aplhaUpdate(t):
    return aplha0*np.exp(-t/TC)
  • sigma0— 邻域函数的动态(收缩)半径的初始值。我们从一个半径开始,该半径覆盖了神经元的整个 2D 映射。它的更新方式与 相同。Walpha
def sigmaUpdate(t):
    return sigma0*np.exp(-t/TC)
  • beta一个 2D 向量,用于存储 中每个节点的邻域函数的值。BMU
  • BMU— est atching nit 是最接近输入数据点的节点,即与它的距离最短,在我们的例子中,欧几里得距离,如下所示。BMUx_n
def winningNode(x_n, W): # Find the winning node and distance to it
    dist = np.linalg.norm(x_n - W, ord =2 , axis = 2)
    d = np.min(dist)
    BMU = np.argwhere(dist == np.min(dist))
    return d, BMU
  • 要更新,我们首先需要找到权重向量中每个节点与 . 是表示每个长向量到每个其他向量的欧几里得距离的向量,其中每个向量由其 x 和 y 坐标表示。betaBMUhardDistn_featureWWcoords
hardDist = np.zeros([length, width, length, width])
for i,j,k,l in product(range(length),range(width),range(length),range(width)):
      hardDist[i,j,k,l]= ((i-k)**2 + (j-l)**2)**0.5
  • gridDistances用于访问表示距离或每个向量在位置 的 2D 数组。coords
def gridDistances(coords):
    return hardDist[coords[0][0],coords[0][1],:,:]
  • 然后我们可以更新 .对于每个输入向量,计算为最接近 的点提供最小值。betabetaBMU
def betaUpdate(coords, sigma): # neighbourhood function
    return np.exp(-gridDistances(coords)**2/(2*sigma**2))
  • 下图显示了一个权重数组,在第二张图中可以想象为矢量神经元的 2D 数组。以红色突出显示的矢量是 BMU。蓝色表面显示了每个神经元的值,在BMU处最高。的值表示二维正态分布。Wbetabeta

图 2 — W,BMU 以红色突出显示(左和右),为 sigma=1.5 绘制的 beta 值,显示 BMU 处的 beta 值最高。

  • 最后,我们可以更新 .我们看到有三个因素影响了更新:(1),它在数据集的一次迭代中是恒定的;(2)、每个向量与输入向量的差值;和(3) .将因子添加到 ,因此对于靠近输入的向量,的值更大,从而导致 中的向量值更大。WWalphaf=x_n-WWbetaalpha*beta*fWWbetaW
def weightUpdate(W, aplha, beta, x_t):
    f= (x_t-W)
    beta = np.reshape(beta,[beta.shape[0],beta.shape[1],1])
    return W+aplha*beta*f

        现在,我们已经讨论了初步内容,我们可以将它们放在一起:

errors=np.zeros([max_iter])

for t in range(max_iter): 

    t1 = time.time()
    alpha = aplhaUpdate(t)
    sigma = sigmaUpdate(t)
    
    np.random.shuffle(X_data)
    n_sample = len(X_data) # iterating over whole dataset
    QE = 0

    for n in range(n_sample):
        d, BMU = winningNode(X_data[n,:], W)
        QE = QE + d
        beta = betaUpdate(BMU, sigma)
        W = weightUpdate(W, alpha, beta, X_data[n,:])
        W /= np.linalg.norm(W, axis=2).reshape((length, width, 1))

    QE /= n_sample
    errors[t]=QE
    t1 = time.time() - t1

    print("Iteration: ", "{:05d}".format(t), " | Quantization Error: ", "{:10f}".format(QE),  " | Time: ", "{:10f}".format(t1))

让我们一步一步地看一下。

  • 对于每次迭代,并略微衰减以适应 中的逐渐变化。alphasigmaW
  • 对于数据集中的每个输入向量,我们找到 BMU 和 BMU 与输入向量的距离 .d
  • beta根据BMU进行更新,然后用于更新.W
  • W被归一化,以便在不同的值下保持可比性。Wt
  • 为了监控学习过程,我们使用量化误差,这是每个数据点到其BMU的距离的平均值。如果更新正确,它应该在迭代中减少。QEW

当我们在数据集上运行它时,我们得到以下输出:

我们可以通过沿其代表特征的最后一个维度切片来绘制各个特征图。W

图3 - 特征图

        这样就完成了学习获取单个特征图的第一步。W

五、第二部分:U矩阵获取

        第二部分是简单地计算神经元之间的距离以获得U矩阵(Unified-distance矩阵),它可以是六边形或矩形。在下图中,我们看到了查看 中神经元 2D 数组的两种方式。W

图 5 — W、六边形(左)和矩形(右)的不同解释

        U矩阵表示神经元之间的距离。下图显示了六边形和矩形表示的 U 矩阵。在两张图像中,黄色细胞表示相邻神经元之间的距离,例如,{1,2}是上图中神经元1和2之间的距离。橙色单元格表示从神经元数到周围神经元的距离的平均值,即 {1}=mean({1,2}, {1,4}) 或 {5}=mean({2,5}, {4,5}, {5,6}, {5,7}, {5,8}, {5,9}) 对于六边形 U 矩阵,{5}=mean({2,5}, {4,5}, {5,6}, {5,8}) 对于矩形矩阵。

图 6 — U 矩阵,六边形(左)和矩形(右)

        在矩形 U 矩阵中,还有一种其他类型的单元格,以蓝色突出显示。我们不能将其视为蓝色单元格角上的橙色单元格之间的距离,例如平均值({1},{5})或平均值({2},{4}),因为这些值对蓝色单元格都有效,但不相等,这将是矛盾的。因此,我们将该值作为其周围黄色单元格的平均值,从而允许最终 U 矩阵中的单元格之间更平滑地过渡。有关进一步说明,请参阅此文章。下面给出了两种类型的 U 矩阵的计算。

        对于黄色单元格,我们计算相邻神经元之间的距离,橙色和蓝色单元格计算为它们上方、下方和两侧单元格的平均值。

# CALCULATION OF RECTANGULAR U-MATRIX FROM W
def make_u_rect(W):

    U = np.zeros([W.shape[0]*2-1, W.shape[1]*2-1], dtype=np.float64)

    # YELLOW CELLS
    for i in range(W.shape[0]): # across columns
        k=1
        for j in range(W.shape[1]-1):
            U[2*i, k]= np.linalg.norm(W[i,j]-W[i,j+1], ord=2)
            k += 2

    for j in range(W.shape[1]): # down rows
        k=1
        for i in range(W.shape[0]-1):
            U[k,2*j] = np.linalg.norm(W[i,j]-W[i+1,j], ord=2)
            k+=2

    # ORANGE AND BLUE CELLS - average of cells top, bottom, left, right.
    for (i,j) in product(range(U.shape[0]), range(U.shape[1])):
        if U[i,j] !=0: continue
        all_vals = np.concatenate((
               U[(i-1 if i>0 else i): (i+2 if i<=U.shape[0]-1 else i), j],
               U[i, (j-1 if j>0 else j): (j+2 if j<=U.shape[1]-1 else j)]))
        U[i,j] = all_vals[all_vals!=0].mean()
    
    # Normalizing in [0-1] range for better visualization.
    scaler = MinMaxScaler()
    return scaler.fit_transform(U)

        对于六边形矩阵,我们使用神经元本身的值作为位置{1}、{2}、...以简化 中 {1,2}、{2,3} 等的计算。{1}, {2}, ...然后替换为其周围值的平均值。U

# CALCULATION OF HEXAGONAL U-MATRIX FROM W
def make_u_hex(W): 
    
    # Creating arrays with extra rows to accommodate hexagonal shape.
    U_temp =  np.zeros([4*W.shape[0]-1, 2*W.shape[1]-1, W.shape[2]])
    U = np.zeros([4*W.shape[0]-1, 2*W.shape[1]-1])
    """
    The U matrix is mapped to a numpy array as shown below.
    U_temp holds neuron at postion 1 in place of {1} for easy computation
    of {1,2}, {2,3} etc. in U. {1}, {2}, {3}, ... are computed later.
    [
      [    (1),        0,       0,       0,    (3)],
      [      0,    (1,2),       0,   (2,3),      0],
      [   (1,4),       0,     (2),       0,  (3,6)],
      [      0,    (2,4),       0 ,  (2,6),      0],
      [    (4),        0,    (2,5),      0,    (6)],
      [      0,    (4,5),        0,  (5,6),      0],
      [   (4,7),       0,      (5),      0,  (6,9)],
      [      0,    (2,4),        0,  (5,9),      0],
      [    (7),        0,    (5,8),      0,    (9)],
      [      0,    (7,8),        0,  (8,9),      0],
      [      0,        0,      (8),      0,      0]
    ]
    """

    # Creating a temporary array placing neuron vectors in 
    # place of orange cells.
    k=0
    indices = []
    for i in range(W.shape[0]):
        l=0
        for j in range(W.shape[1]):
            U_temp[k+2 if l%4!=0 else k,l,:] = W[i,j,:]
            indices.append((k+2 if l%4!=0 else k,l))
            l+=2
        k += 4
    
    # Finding distances for YELLOW cells.
    for (i,j),(k,l) in product(indices, indices):
        if abs(i-k)==2 and abs(j-l)==2:      # Along diagonals
            U[int((i+k)/2), int((j+l)/2)] = 
                np.linalg.norm(U_temp[i,j,:]-U_temp[k,l,:], ord=2)
        
        if abs(i-k)==4 and abs(j-l)==0:       # In vertical direction
            U[int((i+k)/2), int((j+l)/2)] = 
                np.linalg.norm(U_temp[i,j,:]-U_temp[k,l,:], ord=2)
    
    # Calculating ORANGE cells as mean of immediate surrounding cells.
    for (i,j) in indices:
        all_vals = 
          U[(i-2 if i-1>0 else i): (i+3 if i+2<U.shape[0]-1 else i), 
            (j-1 if j>0 else j): (j+2 if j<=U.shape[1]-1 else j)]
        U[i,j] = np.average(all_vals[all_vals!=0])
    
    # To remove extra rows introduced in above function.
    new_U = collapse_hex_u(U)

    # Normalizing in [0-1] range for better visualization.
    scaler = MinMaxScaler()
    return scaler.fit_transform(new_U)


def collapse_hex_u(U):

    new_U = np.zeros([int((U.shape[0]+1)/2), U.shape[1]])
    # Moving up values in every alternate column
    for j in range(1, U.shape[1], 2):
            for i in range(U.shape[0]-1):
                U[i,j]=U[i+1,j]

    # Removing extra rows
    for i in range(new_U.shape[0]): new_U[i,:] = U[2*i,:]

    return new_U

        要绘制六边形网格,我们需要自己在图上绘制六边形。对于折叠的六边形,我们可以绘制 U 矩阵,方法是为每个点绘制一个六边形,每两列有一个轻微的 y 偏移量,以制作一个网格,如图 6 所示。U

def draw_hex_grid(ax, U):

    def make_hex(ax, x, y, colour):
        if x%2==1: y=y+0.5
        xs = np.array([x-0.333,x+0.333,x+0.667,x+0.333,x-0.333,x-0.667])
        ys = np.array([  y+0.5,  y+0.5,      y,  y-0.5,  y-0.5,      y])
        ax.fill(xs, ys, facecolor = colour)
    
    ax.invert_yaxis()
    cmap = matplotlib.cm.get_cmap('jet')

    for (i,j) in product(range(U.shape[0]), range(U.shape[1])):
        if U[i,j]==0: rgba='white'
        else: rgba = cmap(U[i,j])
        make_hex(ax, i, j, rgba)
        
    ax.set_title("U-Matrix (Hexagonal)")

图 3 所示的两种类型的 U 矩阵结果为:W

图 7 — U 矩阵

        在学习过程中拍摄如图 3 所示的快照,我们可以观察每个特征图和 U 矩阵的学习情况。上面显示的颜色图显示,红色表示最大值,表示该区域中聚集的更多输入数据点,而模糊区域表示输入数据点稀疏出现的空间。W

        随着迭代的进行,学习速度变慢了。在开始的迭代中,特征图变化很大,而在以后的迭代中,它们变得有些稳定。矩阵也出现了同样的趋势,社区的规模在缩小。这也反映在 中,其下降速率随时间而降低。哈尼亚·安尤姆

 显示“W”和“U”学习的.gif图像(在新选项卡中打开以再次播放)

参考资料:
编程
数据科学
机器学习
自组织地图
聚类

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

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

相关文章

AIGC的发展

AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;&#xff0c;即人工智能生产内容&#xff0c;是人工智能在内容领域的最新进展。AIGC利用人工智能算法通过分析大量数据集&#xff0c;自动生成具有特定风格和主题的内容。AIGC涵盖了多种应用领域&#x…

ITIL4的知识体系及必要性

官方网站 www.itilzj.com 文档资料: wenku.itilzj.com 点击进入IT管理资料库 ITIL4 的必要性及历史 在这个前所未有的变革时代&#xff0c;人们身处着被誉为“第四次工业革命”的时代&#xff0c;这个时代催生出了一个日益加速、变得愈发错综复杂的环境。在这种环境下&#xf…

电脑文件夹密码怎么设置?文件夹加密介绍

文件夹是电脑管理文件必不可少的工具&#xff0c;而我们为了保护文件夹的数据安全&#xff0c;通常会采用设置密码的方法来保护文件夹。那么&#xff0c;电脑文件夹密码该怎么设置呢&#xff1f; 文件夹加密超级大师 文件夹加密超级大师不但可以为电脑文件夹设置密码&#xff…

阿里云大语言模型(LLM)实战训练营,火热开营中!

简介&#xff1a;大语言模型实战训练营已正式开营&#xff0c;汇集阿里云、黑马程序员多位AI领域资深技术专家手把手带您快速实现大语言模型从入门到应用落地&#xff01;完成课程学习任务更有机会领取LAMY钢笔、小米充电宝、双肩包等精美礼品&#xff0c;快来一起学习体验吧~ …

MySQL高可用Orchestrator

目录 一 Orchestrator简介 二 Orchestrator功能 1 Discovery(发现复制拓扑) 2 Refactoring(重构复制拓扑) 3 Recovery(恢复主库故障) 三 orchestrator支持的操作方式 四 部署要求 五 下载 六 安装 1 下载软件包 2 解压软件包 3 创建账号 第一种是 orc后端MySQL数据…

识别图片翻译怎么操作?几个好方法了解一下

图片翻译是一项非常有用的工具&#xff0c;可以让人们轻松地识别和翻译图片中的文字&#xff0c;对于一些步入职场的小伙伴尤其是从事文案编辑的朋友更是一个需要的技能&#xff0c;很多时候我们参考的多语言文献资料都是图片的格式&#xff0c;翻译内容的话会比较麻烦&#xf…

【python】python开源代理ip池

一、前言 随着互联网的不断发展&#xff0c;越来越多的应用需要使用高匿代理IP才能访问目标网站&#xff0c;而代理IP作为一种能够隐藏本机真实IP地址的工具&#xff0c;在网络抓取、搜索引擎排名、广告投放、反爬虫等方面有着广泛的应用场景。但是&#xff0c;由于代理IP的稳…

黑客自学路线

谈起黑客&#xff0c;可能各位都会想到&#xff1a;盗号&#xff0c;其实不尽然&#xff1b;黑客是一群喜爱研究技术的群体&#xff0c;在黑客圈中&#xff0c;一般分为三大圈&#xff1a;娱乐圈 技术圈 职业圈。 娱乐圈&#xff1a;主要是初中生和高中生较多&#xff0c;玩网恋…

玩转软件|钉钉个人版内测启动:AI探索未来的工作方式

目录 前言 正文 AI为核心&#xff0c;个人效率为王&#xff01; 指令中心&#xff0c;解锁AI技巧&#xff01; 灵感Store&#xff0c;探索更多可能&#xff01; 未来的AI&#xff0c;即将问世&#xff01; 个人内测体验 前言 重磅消息&#xff1a;钉钉个人版在8月16日正…

【JavaSE】详解final关键字

在Java中&#xff0c;final可以用来修饰类、方法和变量。final修饰类&#xff0c;表示该类无法被继承&#xff0c;并且此类的设计已被认为很完美而不需要进行修改或扩展。final修饰类中的方法&#xff0c;表示不可以被重写&#xff1b;也就是把该方法锁定了&#xff0c;以防止继…

最小栈00

题目链接 最小栈 题目描述 注意点 pop、top 和 getMin 操作总是在 非空栈 上调用 解答思路 由于栈先进后出的特点&#xff0c;对于任意一次入栈操作&#xff0c;只要该元素未被弹出&#xff0c;则其前面插入的元素一定都还在栈中&#xff0c;所以每次入栈时只需要根据其前…

Lnton羚通视频算法算力云平台【PyTorch】教程:学习Datasets-DataLoader基础知识

Dataset & DataLoader PyTorch 提供了两个数据处理的基本方法&#xff1a;torch.utils.data.DataLoader torch.utils.data.Dataset 允许使用预加载的数据集以及自己的数据。 Dataset 存储样本及其对应的标签&#xff0c; DataLoader 在 Dataset 基础上封装了一个可迭代的对…

苍穹外卖 day3 实现登录过程中MD5加密

一 原来是明文存的 密码可见度太高&#xff0c;MD5加密为密文图像 效果 二 密文实现步骤 修改明文密码&#xff0c;改成密文 123456 密文值&#xff1a;e10adc3949ba59abbe56e057f20f883e代码如下所示 在这里插入代码片 package com.sky.service.impl;import com.sky.con…

[bug日志]springboot多模块启动,在yml配置启动端口8081,但还是启动了8080

【问题描述】 配置的启动端口是8081&#xff0c;实际启动端口是8080 【解决方法】 1.检查application.yml的配置是否有错误(配置项中&#xff0c;显示白色就错&#xff0c;橙色无措) 2.检查pom.xml的打包方式配置项配置&#xff0c;主pom.xml中的配置项一般为&#xff1a;&l…

司徒理财:8.23黄金最新行情走势分析及操作策略

黄金走势分析&#xff1a;      黄金下跌遇阻&#xff0c;短线开启震荡调整走势&#xff0c;但跌势依旧没有改变&#xff0c;没有突破1906压力前&#xff0c;还是偏空走势&#xff0c;反弹继续干空。趋势行情&#xff0c;不要轻言翻转&#xff01;即便下跌结束&#xff0c;…

DB2的日志

在DB2中&#xff0c;该机制使用日志功能实现。所谓日志&#xff0c;可以被认为在一条事务被落实之前&#xff0c;能够保证其记录被写入永久存储系统的一种方法。 那么为什么需要日志呢&#xff1f;直接把变化的数据写入磁盘不是更好&#xff1f;之所以需要日志&#xff0c;主要…

芯科科技宣布推出下一代暨第三代无线开发平台,打造更智能、更高效的物联网

第三代平台中的人工智能/机器学习引擎可将性能提升100倍以上 Simplicity Studio 6软件开发工具包通过新的开发环境将开发人员带向第三代平台 中国&#xff0c;北京 - 2023年8月22日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&…

基于IDEA使用maven创建hibernate项目

1、创建maven项目 2、导入hibernate需要的jar包 <!--hibernate核心依赖--><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.4.1.Final</version></dependency><!--…

微信小程序:页面有内容却不显示原因

先检查&#xff0c;app.json中这两项路径是否正确 如果正确的话&#xff0c;不显示的那个页面的。js文件中需要Page({})&#xff0c;初始化&#xff0c;这个必须有&#xff1b; 如果还是不出现&#xff0c;可以先把路径删掉&#xff0c;然后刷新一下&#xff0c;这个时候会提示…

ctfshow web入门 web103-web107

1.web103 和102一样 payload: v2115044383959474e6864434171594473&v3php://filter/writeconvert.base64-decode/resource1.php post v1hex2bin2.web104 值只要一样就可以了 payload: v21 post v113.web105 考查的是$$变量覆盖,die可以带出数据,输出一条消息&#xf…