自编码器(autoencoder)

news2024/11/20 1:26:13

1.自编码器的由来

最初的自编码器是用来降维的,后来也逐渐用于去噪生成任务

2.自编码器的基本结构

自编码器(autoencoder)内部有一个隐藏层 h,可以产生编码(code)表示输入。该网络可以看作由两部分组成:一个由函数 h = f ( x ) h = f(x) h=f(x) 表示的编码器和一个生成重构的解码器 r = g ( h ) r = g(h) r=g(h),整体结构如下图所示:
在这里插入图片描述
自编码器通过内部表示或编码 h 将输入 x 映射到输出(称为重构)r。自编码器具有两个组件:编码器 f (将 x 映射到 h)和解码器 g(将 h 映射到 r)。映射关系可以分别表示为 p e n c o d e r ( h ∣ x ) p_{encoder}(h|x) pencoder(hx) p d e c o d e r ( r ∣ h ) p_{decoder}(r|h) pdecoder(rh)

3.自编码器的一些基本概念

3.1欠完备与过完备

①欠完备自编码器:h维度<x维度。
学习欠完备的表示将强制自编码器捕捉训练数据中最显著的特征。“学习欠完备的表示”意味着编码器被设计成只能生成比输入数据更简单、更压缩的表示。举一个简单的例子:
假设你有一堆猫和狗的图片。一个没有任何限制的自编码器可能会尝试记住每张图片的所有细节(毛色、背景等等)。但是,如果我们限制自编码器只能生成非常简化的表示,它就会被迫关注猫和狗最明显的特征,比如猫的尖耳朵和狗的长尾巴,而忽略背景和毛色等次要特征。

②过完备自编码器:h维度>=x维度。
过完备则与欠完备相反。“过完备”意味着编码器的表示空间非常大,能够容纳甚至超过输入数据中的所有信息。举一个简单的例子:
假设你有一堆猫和狗的图片。一个过完备自编码器可能会记住每张图片的所有细节,包括背景、毛色、姿态等等。这使得它在训练数据上表现非常好,但在遇到新的猫狗图片时,可能无法很好地识别出它们的共同特征。
在过完备的情况下,可能会出现编码器无法学习到有效信息的情况。这是因为:当编码维数与输入维数相等或更大时,自编码器的表示空间非常大,足以容纳输入数据中的所有信息。在这种情况下,甚至简单的线性编码器和解码器也可以直接将输入复制到输出,而不需要提取任何有用的特征。这意味着自编码器没有被迫去学习数据的分布特征,因为它可以简单地记住所有的数据。这种记忆机制使得模型在训练数据上表现很好,但在面对新数据时可能表现很差,因为它没有学到数据的内在模式或结构。

3.2自编码器的目的与损失函数

自编码器的目的是得到编码后的有效表示h,而这种目的是通过尝试将网络输入复制到输出来实现的。所以自编码器最简单的损失函数如下:
l o s s = L ( x , g ( f ( x ) ) ) loss=L(x,g(f(x))) loss=L(x,g(f(x))),其中L就表示一个函数,如L2范数。
在这里插入图片描述

3.3自编码器的正则化

3.2中提到自编码器是通过输入输出的loss来达到有效表示h的目的,而当过完备时,编码器又可能无法学习到有效的h。所以有了自编码器的正则化,使得过完备时网络仍能得到有效的h。举个例子:
比如在稀疏自编码器中,损失函数修改为 L ( x , g ( f ( x ) ) ) + Ω ( h ) L(x,g(f (x))) + Ω(h) L(x,g(f(x)))+(h),针对h稀疏特性而增加了 Ω ( h ) Ω(h) (h)部分。虽然引入稀疏性惩罚项 Ω(ℎ)会导致稀疏自编码器的复制动作变差,即重构误差可能增加,但这种修改能够迫使模型学习到更加有用的特征,提高模型在后续任务中的性能和泛化能力。这种权衡在实际应用中通常是有益的。

4.多种自编码器

自编码器可以分为以下几种:在这里插入图片描述
下面介绍几种常见的自编码器。

4.1 传统自编码器(AE)

AE的网络结构如下:包含三层——输入层、隐藏层、输出层,每一层都是由若干个神经元组成的。
在这里插入图片描述
上面的网络可以表示为
①编码:输入层+隐藏层
h = f ( x ) = f ( W 1 X + b 1 ) h = f (x) = f (W_1X + b_1) h=f(x)=f(W1X+b1) W 1 W_1 W1表示神经元的权重, b 1 b_1 b1表示神经元的偏置。
②解码:隐藏层+输出层
X d = g ( x ) = g ( W 2 h + b 2 ) X^d = g(x) = g(W_2h + b_2) Xd=g(x)=g(W2h+b2)
③损失函数
θ \theta θ表示网络的权重和偏置参数,则损失函数为:
J A E ( θ ) = J ( X , X d ) = − ∑ i = 1 n ( x i log ⁡ ( x i d ) + ( 1 − x i ) log ⁡ ( 1 − x i d ) ) J_{AE}(\theta)=J(X,X^{d})=-\sum_{i=1}^{n}(x_{i}\log(x_{i}^{d})+(1-x_{i})\log(1-x_{i}^{d})) JAE(θ)=J(X,Xd)=i=1n(xilog(xid)+(1xi)log(1xid))
采用梯度下降法即可进行训练。
此外,为了控制权重降低的程度,防止自编码器的过拟合,将在上述损失函数中加入正则化项(也称重量衰减项),变为正则化自编码器。
J R e A E ( θ ) = J ( X , X d ) + λ ∥ W ∥ 2 2 J_{\mathrm{ReAE}}(\theta)=J(X,X^{d})+\lambda\parallel W\parallel_{2}^{2} JReAE(θ)=J(X,Xd)+λW22
通过约束网络权重从而间接使得隐藏层神经元稀疏,提高了整个自编码器模型的泛化性。

4.2 去噪自编码器(DAE)

DAE的网络结构如下,AE的目的是求h,但它没有使用h的真实值来训练,所以是无监督的。而DAE的目的是使得网络能够进行去噪,目的是求X,但它用到了X真实值做loss,所以他是监督学习。
在这里插入图片描述
DAE的动机是主动给X加噪,使得网络带有去噪的能力。但是在每次网络训练之前,人为地在干净的输入信号中加入噪声,增加了模型的处理时间。而且,如果加入过多的噪声,会导致输入样本的严重失真,从而降低算法的性能。

4.3稀疏自编码器(SAE)

在这里插入图片描述

稀疏自编码器利用了X的先验信息,这个先验信息就是X的稀疏度。它的网络结构和AE没有什么区别,但是损失函数变了,添加了一项KL散度,是编码后h的稀疏度和真实稀疏度之间的散度。其中 β \beta β是控制稀疏惩罚的系数,为0~1.
J S A E ( θ ) = J ( X , X d ) + β ∑ j = 1 t K L ( ρ ∥ ρ ^ j ) J_{SAE}(\theta)=J(X,X^d)+\beta\sum_{j=1}^tKL(\rho\parallel\hat{\rho}_j) JSAE(θ)=J(X,Xd)+βj=1tKL(ρρ^j)
首先定义每个隐藏单元 j j j的平均激活值 ρ ^ j : \hat{\rho}_j: ρ^j:
ρ ^ j = 1 n ∑ i = 1 n h j ( x i ) \hat{\rho}_j=\frac{1}{n}\sum_{i=1}^nh_j{(x_i)} ρ^j=n1i=1nhj(xi)
其中, n n n是训练样本数量, h j ( x i ) h_j{(x_i)} hj(xi)是第 i i i个样本对于隐藏单元 j j j的激活值。
然后定义目标稀疏度 ρ \rho ρ,这是希望隐藏单元的平均激活值。例如,如果 ρ \rho ρ较小(如0.05),则希望大多数隐藏单元在任何给定时间都不活跃。
最后,将稀疏惩罚项加入到损失函数中,使用KL散度来衡量目标稀疏度和实际稀疏度之间的差异:
K L ( ρ ∣ ∣ ρ ^ j ) = ρ log ⁡ ρ ρ ^ j + ( 1 − ρ ) log ⁡ 1 − ρ 1 − ρ ^ j \mathrm{KL}(\rho||\hat{\rho}_j)=\rho\log\frac{\rho}{\hat{\rho}_j}+(1-\rho)\log\frac{1-\rho}{1-\hat{\rho}_j} KL(ρ∣∣ρ^j)=ρlogρ^jρ+(1ρ)log1ρ^j1ρ
稀疏惩罚项的总和是所有隐藏单元的KL散度之和:
∑ j = 1 t K L ( ρ ∣ ∣ ρ j ^ ) \sum_{j=1}^{t}\mathrm{KL}(\rho||\hat{\rho_j}) j=1tKL(ρ∣∣ρj^)
KL散度是描述两个分布之间差异的指标,KL散度越小,分布越接近,具体公式如下:
K L ( ρ ∥ ρ ^ j ) = ρ log ⁡ ρ ρ ^ j + ( 1 − ρ ) log ⁡ 1 − ρ 1 − ρ ^ j KL(\rho\parallel\hat{\rho}_j)=\rho\log\frac{\rho}{\hat{\rho}_j}+(1-\rho)\log\frac{1-\rho}{1-\hat{\rho}_j} KL(ρρ^j)=ρlogρ^jρ+(1ρ)log1ρ^j1ρ

4.4 收缩自编码器(CAE)

这里的收缩指的是在学习过程中对隐藏层表示进行收缩,使得隐藏层表示对输入数据的小变化不敏感,从而增强模型的鲁棒性和特征提取能力。
使得隐藏层表示对输入数据的小变化不敏感?也就是说X变化,h不变或变化很小,如果这种关系用导数关系来表示,h对X的一阶导应该越小越好,所以有如下损失函数,同样通过系数 λ \lambda λ来控制收缩。
J C A E ( θ ) = J ( X , X d ) + λ ∥ J f ( x ) ∥ F 2 J_{CAE}(\theta)=J(X,X^d)+\lambda\parallel J_f(x)\parallel_F^2 JCAE(θ)=J(X,Xd)+λJf(x)F2
其中, ∥ J f ( x ) ∥ F 2 = ∑ j = 1 t ∑ i = 1 n ( ∂ h j ( x ) ∂ x i ) 2 \parallel J_f(x)\parallel_F^2=\sum_{j=1}^t\sum_{i=1}^n(\frac{\partial h_j(x)}{\partial x_i})^2 Jf(x)F2=j=1ti=1n(xihj(x))2 J f ( x ) J_f(x) Jf(x)是雅可比矩阵(Jacobian Matrix),雅可比矩阵是向量值函数对其输入向量的偏导数组成的矩阵。
Tips:①这里可以看到,如果CAE的编码是线性的,那么CAE就和正则化自编码器没有区别了,因为线性的一阶导就是权重参数。
②CAE和DAE都对带噪数据有鲁棒性,CAE是对提取的特征有鲁棒性;DAE是对输出的去噪数据有鲁棒性。

4.5 卷积自编码器(CoAE)

卷积自编码器使用卷积层和池化层处理二维或三维数据,保留空间结构并减少参数数量,而普通自编码器使用全连接层处理一维向量数据,参数数量较多且不保留数据的空间结构。二维空间结构信息对图像来说十分重要,用AE时,需要把图像变为一维向量输入网络,这就破坏了图像的二维空间信息。
在这里插入图片描述
从上图可以看出,网络的输入输出都是二维的图像,其损失函数如下:
J C o A E ( θ ) = J ( X , X d ) + λ ∥ W ∥ 2 2 J_{CoAE}(\theta)=J(X,X^d)+\lambda\parallel W\parallel_2^2 JCoAE(θ)=J(X,Xd)+λW22

4.6 变分自编码器(VAE)

关于变分自编码器,知乎上的这篇文章写的很好。首先说明变分自编码器的总体意义:VAE是在自编码器基础上结合了变分贝叶斯推断的方法,旨在学习数据的隐含结构,并能够生成新的、类似于训练数据的样本。可以说VAE的主要目的是生成新的数据。VAE通过显式地建模潜在变量的概率分布,使得潜在空间结构更加明确和可解释,最终能生成新样本。这在生成对抗网络(GAN)出现之前是一个重要的进展。
下面介绍VAE的主要做法:
VAE的整体网络结构简图如下:
在这里插入图片描述
针对一个输入 x i x_i xi(比如一个样本就是一张图像),网络结构如下(下图中的 μ i ′ \mu_{i}^{\prime} μi就是输出的 X d X^d Xd):
在这里插入图片描述
在这里插入图片描述
具体公式推导参考上面的那篇博客,下面是对博客推导思想的简单总结:
在这里插入图片描述
为了更好理解,还是直接博客的代码吧:

# -*- coding: utf-8 -*-

"""
Created on January 28, 2021

@author: Siqi Miao
"""

import os
from tqdm import tqdm
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

import torch
import torch.nn as nn

from torchvision import transforms
from torchvision.utils import save_image
from torchvision.datasets import MNIST


class VAE(nn.Module):

    def __init__(self, in_features, latent_size, y_size=0):
        super(VAE, self).__init__()

        self.latent_size = latent_size

        self.encoder_forward = nn.Sequential(
            nn.Linear(in_features + y_size, in_features),
            nn.LeakyReLU(),
            nn.Linear(in_features, in_features),
            nn.LeakyReLU(),
            nn.Linear(in_features, self.latent_size * 2)  # latent_size表示潜变量的个数,每一个变量有均值和方差两个数值
        )

        self.decoder_forward = nn.Sequential(
            nn.Linear(self.latent_size + y_size, in_features), # 解码器输入的时候只需要输入编码器输出的潜在变量的均值
            nn.LeakyReLU(),
            nn.Linear(in_features, in_features),
            nn.LeakyReLU(),
            nn.Linear(in_features, in_features),
            nn.Sigmoid()
        )

    def encoder(self, X):
        out = self.encoder_forward(X)
        mu = out[:, :self.latent_size] # 前latent_size个数据是均值
        log_var = out[:, self.latent_size:] # 后latent_size个数据是log(方差)
        return mu, log_var

    def decoder(self, z):
        mu_prime = self.decoder_forward(z)
        return mu_prime

    def reparameterization(self, mu, log_var):  # Reparameterization Trick
        epsilon = torch.randn_like(log_var) # 产生和log_var维度一样的高斯分布数据
        z = mu + epsilon * torch.sqrt(log_var.exp()) # log_var.exp()=var,sqrt(var)就是sigema
        return z

    def loss(self, X, mu_prime, mu, log_var): # mu_prime编码器的输出;mu潜变量的均值,也就是潜变量的值了;log_var潜变量的log(方差)
        # reconstruction_loss = F.mse_loss(mu_prime, X, reduction='mean') is wrong!
        #print(mu_prime.shape) # [1024,784]
        #print(mu.shape) # [1024,64]
        #print(log_var.shape) # [1024,64]
        # torch.square 是一个用于计算张量中每个元素的平方的函数。这个函数返回一个新的张量,其中包含原始张量中每个元素的平方值
        reconstruction_loss = torch.mean(torch.square(X - mu_prime).sum(dim=1)) # sum(dim=1)表示对列求和,torch.mean就相当于是对1024个样本求均值了,也就是公式里的1/n

        latent_loss = torch.mean(0.5 * (log_var.exp() + torch.square(mu) - log_var).sum(dim=1)) # sum(dim=1)表示对潜变量求和,torch.mean相当于是对1024个样本求均值
        return reconstruction_loss + latent_loss

    def forward(self, X, *args, **kwargs):
        mu, log_var = self.encoder(X)
        z = self.reparameterization(mu, log_var)
        mu_prime = self.decoder(z)
        return mu_prime, mu, log_var


class CVAE(VAE): # 继承VAE类,所以可以使用VAE的编码和解码器

    def __init__(self, in_features, latent_size, y_size):
        super(CVAE, self).__init__(in_features, latent_size, y_size)

    def forward(self, X, y=None, *args, **kwargs):
        y = y.to(next(self.parameters()).device)
        #print(y.shape) # [1024]
        X_given_Y = torch.cat((X, y.unsqueeze(1)), dim=1) 
        #print(X_given_Y.shape) # [1024,785]
        
        mu, log_var = self.encoder(X_given_Y)
        z = self.reparameterization(mu, log_var)
        z_given_Y = torch.cat((z, y.unsqueeze(1)), dim=1)

        mu_prime_given_Y = self.decoder(z_given_Y)
        return mu_prime_given_Y, mu, log_var


def train(model, optimizer, data_loader, device, name='VAE'):
    model.train()

    total_loss = 0
    pbar = tqdm(data_loader)
    for X, y in pbar:
        #print(X.shape) # [1024,1,28,28]
        #print(y.shape) # [1024]
        batch_size = X.shape[0]
        X = X.view(batch_size, -1).to(device)
        #print(X.shape) # [1024,784]
        model.zero_grad() #将模型中所有参数的梯度缓存清零。在进行反向传播计算梯度之前,必须先将之前计算的梯度清零。这是因为在 PyTorch 中,梯度是累积的。

        if name == 'VAE':
            mu_prime, mu, log_var = model(X)
        else:
            mu_prime, mu, log_var = model(X, y)

        loss = model.loss(X.view(batch_size, -1), mu_prime, mu, log_var)
        loss.backward()
        optimizer.step()

        total_loss += loss.item()
        pbar.set_description('Loss: {loss:.4f}'.format(loss=loss.item()))

    return total_loss / len(data_loader)


@torch.no_grad()
def save_res(vae, cvae, data, latent_size, device):
    num_classes = len(data.classes)

    # raw samples from dataset
    out = [] # 用于存储每个类别的图像
    for i in range(num_classes): 
        # 提取类别为 i 的图像
        img = data.data[torch.where(data.targets == i)[0][:num_classes]]
        out.append(img)
    out = torch.stack(out).transpose(0, 1).reshape(-1, 1, 28, 28) # 将图像堆叠在一起,并转置维度以便于保存
    save_image(out.float(), './img/raw_samples.png', nrow=num_classes, normalize=True) # 100张图像

    # samples generated by vanilla VAE
    z = torch.randn(num_classes ** 2, latent_size).to(device)
    # print(z.shape) # [100,64]
    out = vae.decoder(z)
    save_image(out.view(-1, 1, 28, 28), './img/vae_samples.png', nrow=num_classes)

    # sample generated by CVAE
    z = torch.randn(num_classes ** 2, latent_size).to(device)
    y = torch.arange(num_classes).repeat(num_classes).to(device)
    z_given_Y = torch.cat((z, y.unsqueeze(1)), dim=1)
    out = cvae.decoder(z_given_Y)
    save_image(out.view(-1, 1, 28, 28), './img/cvae_samples.png', nrow=num_classes)


def main():
    device = 'cuda' if torch.cuda.is_available() else 'cpu'
    device = torch.device(device)

    batch_size = 256 * 4
    epochs = 50
    latent_size = 64
    in_features = 28 * 28
    lr = 0.001

    data = MNIST('./dataset/', download=True, transform=transforms.ToTensor())
    data_loader = torch.utils.data.DataLoader(data, batch_size=batch_size, shuffle=True)

    # train VAE
    vae = VAE(in_features, latent_size).to(device)
    optimizer = torch.optim.AdamW(vae.parameters(), lr=lr)

    print('Start Training VAE...')
    for epoch in range(1, 1 + epochs):
        loss = train(vae, optimizer, data_loader, device, name='VAE')
        print("Epochs: {epoch}, AvgLoss: {loss:.4f}".format(epoch=epoch, loss=loss))
    print('Training for VAE has been done.')

    # train VCAE
    cvae = CVAE(in_features, latent_size, y_size=1).to(device)
    optimizer = torch.optim.AdamW(cvae.parameters(), lr=lr)

    print('Start Training CVAE...')
    for epoch in range(1, 1 + epochs):
        loss = train(cvae, optimizer, data_loader, device, name='CVAE')
        print("Epochs: {epoch}, AvgLoss: {loss:.4f}".format(epoch=epoch, loss=loss))
    print('Training for CVAE has been done.')

    save_res(vae, cvae, data, latent_size, device)


if __name__ == '__main__':
    main()

VAE的变种:条件变分自编码器(CVAE)
传统的VAE可以近似地生成输入数据,但不能定向地生成特定类型的数据。为解决这一问题,将数据x和x的部分标签( y )输入到CVAE的编码器部分。这样就会生成指定类别的数据。CVAE的结构与VAE相似,因此CVAE的计算方法和优化方法与VAE一致。由于在输入中存在一些标签Y,CVAE成为一种半监督学习形式。
参考资料:
[1]《Deep Learning》
[2] Li P, Pei Y, Li J. A comprehensive survey on design and application of autoencoder in deep learning[J]. Applied Soft Computing, 2023, 138: 110176.
[3] https://zhuanlan.zhihu.com/p/348498294

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

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

相关文章

yolo模型训练出的.pt文件过大

当我们使用yolov8训练时候&#xff0c;保存的模型变大&#xff0c;如下图&#xff1a; 原模型 训练出来的模型 经过仔细调查&#xff0c;发现是保存的模型中多了很多数据。 原模型 训练出来的模型 只需要把文件中.pt文件读取&#xff0c;重写一遍保存。 from ultralytics im…

【RabbitMQ】MQ相关概念

一、MQ的基本概念 定义&#xff1a;MQ全称为Message Queue&#xff0c;是一种提供消息队列服务的中间件&#xff0c;也称为消息中间件。它允许应用程序通过读写队列中的消息来进行通信&#xff0c;而无需建立直接的连接。作用&#xff1a;主要用于分布式系统之间的通信&#x…

[工具]GitHub + PicGo 搭建免费博客图床

文章目录 起因GitHub新建GitHub仓库新建token授予picgo权限 PicGOPicGO上传失败原因 起因 还是觉得个人博客记录最好还是不要money&#x1f625;&#xff0c;所以还是想白嫖&#xff0c;找到了GitHub PicGO的方式&#xff0c;记录一下。 GitHub 过程和搭建博客链接类似&…

【C++】红黑树的应用(封装map和set)

✨ 青山一道同云雨&#xff0c;明月何曾是两乡 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;C学习 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &…

SpringBoot3 JDK21 Vue3开源后台RBAC管理系统 | 2024年好用的开源RBAC管理系统 | 数据权限的探索

序言 项目现已全面开源&#xff0c;商业用途完全免费&#xff01; 当前版本&#xff1a;v0.7.2。 如果喜欢这个项目或支持作者&#xff0c;欢迎Star、Fork、Watch 一键三连 &#x1f680;&#xff01;&#xff01; 在构建此代码框架的过程中&#xff0c;我已投入了大量精力&…

51单片机嵌入式开发:20、STC89C52R基于C51嵌入式点阵广告屏的设计

STC89C52R基于C51嵌入式点阵广告屏的设计 1 概述2 LED点阵介绍2.1 特点和优势2.2 工作原理&#xff1a;2.3 使用方法&#xff1a; 3 LED点阵原理3.1 Led点阵内部电路3.2 原理图电路3.3 74HC595 4 软件实现点阵图案的滑动4.1 软件工程代码4.2 Protues仿真 5 总结 配套示例程序 1…

寻找事业伴侣:男人如何找到匹配自己事业的女人

寻找事业伴侣&#xff1a;男人如何找到匹配自己事业的女人 前言 在攀登事业的征途上&#xff0c;每位男士都渴望有一位能够并肩作战的伴侣。她不仅要理解你的抱负&#xff0c;还要支持你的每一个决定。但现实中&#xff0c;找到这样的女人并非易事。 以下是一些深入的建议&a…

Linux信号上

信号 概念 信号是由于进程产生&#xff0c;但是由内核调度传递给另一个进程&#xff1a; 产生信号 按键产生信号: Ctrc --> 2)SIGINT(终止/中断) Ctrz --> 20)SIGTSTOP(终端暂停) Ctr\ --> 3)SIGQUIT(退出) 系统调用产生: kill(2), raise, abort软件条件产生: 如定…

Adobe Acrobat Pro DC for Mac:PDF处理软件

Adobe Acrobat Pro DC for Mac是一款专为Mac用户设计的PDF处理软件&#xff0c;它凭借出色的功能和卓越的性能&#xff0c;成为了处理PDF文件的理想选择。 首先&#xff0c;Acrobat Pro DC for Mac支持全方位的PDF编辑。用户可以对PDF文档进行文本编辑、图像处理、表格制作等操…

【区块链】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能

审核看清楚了 &#xff01; 这是以太坊测试网络&#xff01;用于学习的测试网络&#xff01;&#xff01;&#xff01; 有关web3 和区块链的内容为什么要给我审核不通过&#xff1f; 别人凭什么可以发&#xff01; 目标成果&#xff1a; 实现功能分析&#xff1a; 显示账户信…

CORS-跨域资源共享

CORS-跨域资源共享 什么是CORS &#xff1f; 在前后端分离的项目中&#xff0c;我们往往会遇到跨域问题。 跨域问题只会出现在浏览器发起AJAX&#xff08;XMLHttpRequest、Fetch&#xff09;请求的时候&#xff0c;因为浏览器限制了AJAX只能从同一个源请求资源&#xff0c;除…

DeadSec CTF 2024 Misc Writeup

文章目录 MiscWelcomeMic checkflag_injectionGoLPartyMAN in the middleForgotten Password CryptoFlag killer 好久没做这么爽了噜 DK盾云服务器&#xff1a; https://www.dkdun.cn/ 最近活动是香港的1-1-3 9.9/月 Misc Welcome 进discord群签到即可 Mic check 就是他说…

echarts所遇到的问题,个人记录

TreeMap 矩形树图&#xff0c;label设置富文本之后&#xff0c;无法垂直居中 font-size 支持rem&#xff0c;其余不支持 font-size 支持 rem&#xff0c;但是其余的属性如height&#xff0c;width等不支持 echarts-for-react 绑定事件&#xff0c;会覆盖实例上绑定的 当给cha…

通过服务端注入的广告被拦截 YouTube现在可能会出现黑屏静音视频段

为避免用户使用广告拦截程序直接拦截 YouTube 平台的所有广告&#xff0c;这段时间谷歌正在采取各种措施与社区进行技术对抗&#xff0c;即谷歌不停地开发新的广告检测方式阻止用户使用广告拦截程序&#xff0c;广告拦截程序则不停地开发应对方法用来继续屏蔽广告和各种提示。 …

uni-app全局文件与常用API

文章目录 rpx响应式单位import导入css样式及scss变量用法与static目录import导入css样式uni.scss变量用法 pages.json页面路由globalStyle的属性pages设置页面路径及窗口表现tabBar设置底部菜单选项及iconfont图标 vite.config中安装插件unplugin-auto-import自动导入vue和unia…

AJAX(2)——URL

URL 什么是URL&#xff1f; 定义&#xff1a;统一资源定位符&#xff0c;缩写&#xff1a;URL&#xff0c;或称统一资源定位器、定位地址&#xff0c;URL地址,俗称网页地址&#xff0c;简称网址&#xff0c;是因特网上标准的资源的地址。 概念&#xff1a;URL就是统一资源定…

Linux下C++动态链接库的生成以及使用

目录 一.前言二.生成动态链接库三.使用动态链接库 一.前言 这篇文章简单讨论一下Linux下如何使用gcc/g生成和使用C动态链接库&#xff08;.so文件&#xff09;。 二.生成动态链接库 先看下目录结构 然后看下代码 //demo.h#ifndef DEMO_H #define DEMO_H#include<string&…

【C++】C++应用案例-检验幻方

“幻方”是数学上一个有趣的问题&#xff0c;它让一组不同的数字构成一个方阵&#xff0c;并且每行、每列、每个对角线的所有数之和相等。比如最简单的三阶幻方&#xff0c;就是把1~9的数字填到九宫格里&#xff0c;要求横看、竖看、斜着看和都是15。 口诀&#xff1a;二四为肩…

Pip换源实战指南:加速你的Python开发

1. Pip换源的重要性 在使用Python进行软件开发或数据分析时&#xff0c;pip 是Python的包管理工具&#xff0c;用于安装和管理第三方库。然而&#xff0c;由于网络环境的差异&#xff0c;特别是在某些国家&#xff0c;访问默认的PyPI&#xff08;Python Package Index&#xff…

debain12中安装mysql8

本文安装使用的官方deb&#xff0c;最新的官方安装包地址&#xff1a;https://repo.mysql.com/mysql-apt-config_0.8.29-1_all.deb 前期准备&#xff1a; 1.安装了debain12.6的虚拟机&#xff0c;我是用的virtualBox安装的12.6 Edu的镜像&#xff1b; 开始安装&#xff1a; …