Paddle2.0:浅析并实现 FcaNet 模型

FcaNet通过频率域分析重新审视通道注意力,证明GAP是二维DCT的特例。据此将通道注意力推广到频域,提出多谱通道注意力框架,通过选择更多频率分量引入更多信息。实验显示,其在ImageNet和COCO数据集表现优异,基于ResNet时精度高于SENet,且实现简单。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

paddle2.0:浅析并实现 fcanet 模型 - 创想鸟

引入

注意力机制,尤其是通道注意力,在计算机视觉领域取得了巨大的成功。许多工作专注于如何设计有效的通道注意力机制,同时忽略一个基本问题,即使用全局平均池(GAP)作为毫无疑问的预处理方法。在这项工作中,作者从不同的角度出发,并使用频率域分析(Frequency Analysis)重新考虑通道的注意力。基于频率域分析,作者在数学上证明了传统的 GAP 是离散余弦变化的特例。有了证明,作者自然地在频域上概括了通道注意力机制的预处理,并提出了具有新颖的 Multi-Spectral 通道注意力的 FcaNet(Frequency Channel Attention Networks)。

相关资料

论文:FcaNet: Frequency Channel Attention Networks官方实现:cfzd/FcaNet

主要贡献

证明了 GAP(Global Average Pooling) 是 DCT(Discrete Cosine Transform) 的特例。在此基础上,将通道注意力推广到频域,提出了基于多谱通道注意力(Multi-Spectral Channel Attention)框架的 FcaNet。通过研究不同频率分量数目及其不同组合的影响,提出了频率分量的两步选择准则。大量实验表明,该方法在 lmageNet 和 COCO 数据集上都取得了最新的结果。基于 ResNet 在相同的参数数目和计算代价下,它在 ImageNet 上的 Top1 精度比 SENet 高 1.8%。而且方法简单有效,只需在现有通道注意力实现中更改一行代码即可实现。

通道注意力(Channel Attention)

通道注意力的权重学习如下式所示,它表示输入经过 GAP 处理后由全连接层学习并经过 Sigmoid 激活得到加权的 Mask。

att=sigmoid⁡(fc(gap⁡(X)))att=sigmoid(fc(gap(X)))

然后,Mask 与原始输入经过下式逐通道相乘得到注意力操作后的输出。

X~:,i,:,:=attiX:,i,:,:, s.t. i∈{0,1,⋯ ,C−1}X~:,i,:,:=attiX:,i,:,:, s.t. i∈{0,1,⋯,C−1}

离散余弦变化(DCT)

DCT 是和傅里叶变换很相似,它的基本形式如下:f∈RLf∈RL 为 DCT 的频谱,x∈RLx∈RL 为输入,LL 为输入的长度。

fk=∑i=0L−1xicos⁡(πkL(i+12)), s.t. k∈{0,1,⋯ ,L−1}fk=i=0∑L−1xicos(Lπk(i+21)), s.t. k∈{0,1,⋯,L−1}

进而,推广得到二维 DCT 如下,f2d∈RH×Wf2d∈RH×W 是二维DCT的频谱,x2d∈RH×Wx2d∈RH×W 是输入,HH 和 WW 是输入的高和宽。

fh,w2d=∑i=0H−1∑j=0W−1xi,j2dcos(πhH(i+12))cos(πwW(i+12))⏟DCT weights, s.t. h∈{0,1,⋯ ,H−1},w∈{0,1,⋯ ,W−1}fh,w2d=i=0∑H−1j=0∑W−1xi,j2dDCT weightscos(Hπh(i+21))cos(Wπw(i+21)), s.t. h∈{0,1,⋯,H−1},w∈{0,1,⋯,W−1}

同样,逆 DCT 变换的公式就如下了。

xi,j2d=∑h=0H−1∑w=0W−1fh,w2dcos(πhH(i+12))cos(πwW(i+12))⏟DCT weights, s.t. i∈{0,1,⋯ ,H−1},j∈{0,1,⋯ ,W−1}xi,j2d=h=0∑H−1w=0∑W−1fh,w2dDCT weightscos(Hπh(i+21))cos(Wπw(i+21)), s.t. i∈{0,1,⋯,H−1},j∈{0,1,⋯,W−1}

上面两个式子中,为了简单起见,移除了一些常数标准化约束因子。DCT 变换属于信号处理领域的知识,是 JPEG 图像压缩的核心算法,相当于是对重要信息的聚集。其实从这里可以看出来,DCT 变换其实也是一种对输入的加权求和,式子中的余弦部分就是权重。因此,GAP 这种均值运算可以认为是输入的最简单频谱,这显然是信息不足的,因此作者引出了下面的多谱通道注意力。

多谱注意力(Multi-Spectral Channel Attention)

这里作者首先按证明了 GAP 其实是二维 DCT 的特例,其结果和二维 DCT 的最低频分量成比例。这个证明作者是令 HH 和 WW 都为 0 得到的,其中 f0,02df0,02d 表示二维 DCT 的最低频分量,显然,从结果来看它与 GAP 是成正比。

f0,02d=∑i=0H−1∑j=0W−1xi,j2dcos⁡(0H(i+12))cos⁡(0W(j+12))⏞=1=∑i=0H−1∑j=0W−1xi,j2d=gap⁡(x2d)HWf0,02d=i=0∑H−1j=0∑W−1xi,j2dcos(H0(i+21))cos(W0(j+21))=1=i=0∑H−1j=0∑W−1xi,j2d=gap(x2d)HW

通过上面的结论,自然会想到将其他分量引入通道注意力中,首先,为了叙述方便,将二维 DCT 的基本函数记为:

Bh,wi,j=cos⁡(πhH(i+12))cos⁡(πwW(j+12))Bh,wi,j=cos(Hπh(i+21))cos(Wπw(j+21))

继而将逆二维DCT变换改写如下:

xi,j2d=∑h=0H−1∑w=0W−1fh,w2dcos(πhH(i+12))cos(πwW(j+12))=f0,02dB0,0i,j+f0,12dB0,1i,j+⋯+fH−1.W−12dBH−1,W−1i,j=gap⁡(x2d)HWB0,0i,j+f0,12dB0,1i,j+⋯+fH−1.W−12dBH−1,W−1i,js.t. i∈{0,1,⋯ ,H−1},j∈{0,1,⋯ ,W−1}xi,j2d=h=0∑H−1w=0∑W−1fh,w2dcos(Hπh(i+21))cos(Wπw(j+21))=f0,02dB0,0i,j+f0,12dB0,1i,j+⋯+fH−1.W−12dBH−1,W−1i,j=gap(x2d)HWB0,0i,j+f0,12dB0,1i,j+⋯+fH−1.W−12dBH−1,W−1i,js.t. i∈{0,1,⋯,H−1},j∈{0,1,⋯,W−1}

由这个式子其实不难发现,此前的通道注意力只应用了第一项的最低频分量部分,而没有使用下式表示的后面其他部分,这些信息都被忽略了。

X=gap(X)HWB0,0i,j⏟utilized +f0,12dB0,1i,j+⋯+fH−1,W−12dBH−1,W−1i,j⏟discarded X=utilized gap(X)HWB0,0i,j+discarded f0,12dB0,1i,j+⋯+fH−1,W−12dBH−1,W−1i,j

基于此,作者设计了多谱注意力模块(Multi-Spectral Attention Module),该模块通过推广 GAP 采用更多频率分量从而引入更多的信息。

首先,输入 XX 被沿着通道划分为多块,记为 [X0,X1,⋯ ,Xn−1][X0,X1,⋯,Xn−1],其中每个 Xi∈RC′×H×W,i∈{0,1,⋯ ,n−1},C′=CnXi∈RC′×H×W,i∈{0,1,⋯,n−1},C′=nC,每个块分配一个二维 DCT 分量,那么每一块的输出结果如下式。

Freqi=2DDCTu,v(Xi)=∑h=0H−1∑w=0W−1X:,h,wiBh,wu,vs.t. i∈{0,1,⋯ ,n−1}Freqi=2DDCTu,v(Xi)=h=0∑H−1w=0∑W−1X:,h,wiBh,wu,vs.t. i∈{0,1,⋯,n−1}

上式中的 [u,v][u,v] 表示二维 DCT 的分量下标,这就对每一块采用不同的频率分量了,因此下式得到最终的输出 Freq∈RCFreq∈RC 就是得到的多谱向量,然后再将这个向量送入通道注意力常用的全连接层中进行学习得到注意力图。

 Freq =cat⁡([ Fre q0, Fre q1,⋯ , Freq n−1]) Freq =cat([ Fre q0, Fre q1,⋯, Freq n−1])

ms−att=sigmoid⁡(fc( Freq ))ms−att=sigmoid(fc( Freq ))

以上就是全部的多谱注意力模块的设计了,现在,下图这个FcaNet整体框架中间的一部分就看得明白了,唯一留下的问题就是对分割得到的每个特征图块,如何选择 [u,v][u,v] 呢?事实上,对空间尺寸为 H×WH×W 的特征图,会有 HWHW 个频率分量,由此频率分量的组合共有 CHWCHW 种,遍历显然是非常费时的因此,文中设计了一种启发式的两步准则来选择多谱注意力模块的频率分量,其主要思想是先得到每个频率分量的重要性再确定不同数目频率分量的效果。具体而言,先分别计算通道注意力中采用各个频率分量的结果,然后,根据结果少选出 Top k 个性能最好的分量。

Paddle2.0:浅析并实现 FcaNet 模型 - 创想鸟

代码实现

导入必要的模块

In [ ]

import mathimport paddleimport paddle.nn as nnfrom paddle.vision.models import ResNet

构建多谱注意力层

In [ ]

def get_freq_indices(method):    assert method in [        'top1', 'top2', 'top4', 'top8', 'top16', 'top32', 'bot1', 'bot2',        'bot4', 'bot8', 'bot16', 'bot32', 'low1', 'low2', 'low4', 'low8',        'low16', 'low32'    ]    num_freq = int(method[3:])    if 'top' in method:        all_top_indices_x = [            0, 0, 6, 0, 0, 1, 1, 4, 5, 1, 3, 0, 0, 0, 3, 2, 4, 6, 3, 5, 5, 2,            6, 5, 5, 3, 3, 4, 2, 2, 6, 1        ]        all_top_indices_y = [            0, 1, 0, 5, 2, 0, 2, 0, 0, 6, 0, 4, 6, 3, 5, 2, 6, 3, 3, 3, 5, 1,            1, 2, 4, 2, 1, 1, 3, 0, 5, 3        ]        mapper_x = all_top_indices_x[:num_freq]        mapper_y = all_top_indices_y[:num_freq]    elif 'low' in method:        all_low_indices_x = [            0, 0, 1, 1, 0, 2, 2, 1, 2, 0, 3, 4, 0, 1, 3, 0, 1, 2, 3, 4, 5, 0,            1, 2, 3, 4, 5, 6, 1, 2, 3, 4        ]        all_low_indices_y = [            0, 1, 0, 1, 2, 0, 1, 2, 2, 3, 0, 0, 4, 3, 1, 5, 4, 3, 2, 1, 0, 6,            5, 4, 3, 2, 1, 0, 6, 5, 4, 3        ]        mapper_x = all_low_indices_x[:num_freq]        mapper_y = all_low_indices_y[:num_freq]    elif 'bot' in method:        all_bot_indices_x = [            6, 1, 3, 3, 2, 4, 1, 2, 4, 4, 5, 1, 4, 6, 2, 5, 6, 1, 6, 2, 2, 4,            3, 3, 5, 5, 6, 2, 5, 5, 3, 6        ]        all_bot_indices_y = [            6, 4, 4, 6, 6, 3, 1, 4, 4, 5, 6, 5, 2, 2, 5, 1, 4, 3, 5, 0, 3, 1,            1, 2, 4, 2, 1, 1, 5, 3, 3, 3        ]        mapper_x = all_bot_indices_x[:num_freq]        mapper_y = all_bot_indices_y[:num_freq]    else:        raise NotImplementedError    return mapper_x, mapper_yclass MultiSpectralAttentionLayer(nn.Layer):    def __init__(self,                 channel,                 dct_h,                 dct_w,                 reduction=16,                 freq_sel_method='top16'):        super(MultiSpectralAttentionLayer, self).__init__()        self.reduction = reduction        self.dct_h = dct_h        self.dct_w = dct_w        mapper_x, mapper_y = get_freq_indices(freq_sel_method)        self.num_split = len(mapper_x)        mapper_x = [temp_x * (dct_h // 7) for temp_x in mapper_x]        mapper_y = [temp_y * (dct_w // 7) for temp_y in mapper_y]        # make the frequencies in different sizes are identical to a 7x7 frequency space        # eg, (2,2) in 14x14 is identical to (1,1) in 7x7        self.dct_layer = MultiSpectralDCTLayer(dct_h, dct_w, mapper_x,                                               mapper_y, channel)        self.fc = nn.Sequential(            nn.Linear(channel, channel // reduction, bias_attr=False),            nn.ReLU(), nn.Linear(channel // reduction,                                 channel,                                 bias_attr=False), nn.Sigmoid())    def forward(self, x):        n, c, h, w = x.shape        x_pooled = x        if h != self.dct_h or w != self.dct_w:            x_pooled = nn.functional.adaptive_avg_pool2d(                x, (self.dct_h, self.dct_w))            # If you have concerns about one-line-change, don't worry.   :)            # In the ImageNet models, this line will never be triggered.            # This is for compatibility in instance segmentation and object detection.        y = self.dct_layer(x_pooled)        y = self.fc(y).reshape((n, c, 1, 1))        return x * y.expand_as(x)class MultiSpectralDCTLayer(nn.Layer):    """    Generate dct filters    """    def __init__(self, height, width, mapper_x, mapper_y, channel):        super(MultiSpectralDCTLayer, self).__init__()        assert len(mapper_x) == len(mapper_y)        assert channel % len(mapper_x) == 0        self.num_freq = len(mapper_x)        # fixed DCT init        self.register_buffer(            'weight',            self.get_dct_filter(height, width, mapper_x, mapper_y, channel))        # # fixed random init        # self.register_buffer(        #     'weight',         #     paddle.rand((channel, height, width)))        # # learnable DCT init        # self.register_parameter(        #     'weight',         #     self.get_dct_filter(height, width, mapper_x, mapper_y, channel))                # # learnable random init        # self.register_parameter(        #     'weight',         #     paddle.rand((channel, height, width)))    def forward(self, x):        assert len(x.shape) == 4, 'x must been 4 dimensions, but got ' + str(            len(x.shape))        # n, c, h, w = x.shape        x = x * self.weight        result = paddle.sum(x, axis=[2, 3])        return result    def build_filter(self, pos, freq, POS):        result = math.cos(math.pi * freq * (pos + 0.5) / POS) / math.sqrt(POS)        if freq == 0:            return result        else:            return result * math.sqrt(2)    def get_dct_filter(self, tile_size_x, tile_size_y, mapper_x, mapper_y,                       channel):        dct_filter = paddle.zeros((channel, tile_size_x, tile_size_y))        c_part = channel // len(mapper_x)        for i, (u_x, v_y) in enumerate(zip(mapper_x, mapper_y)):            for t_x in range(tile_size_x):                for t_y in range(tile_size_y):                    dct_filter[i * c_part:(i + 1) * c_part,                               t_x, t_y] = self.build_filter(                                   t_x, u_x, tile_size_x) * self.build_filter(                                       t_y, v_y, tile_size_y)        return dct_filter

构建 FcaNet 模型

基于 ResNet 修改 Bottleneck 为 FcaBottleneckIn [ ]

def conv3x3(in_planes, out_planes, stride=1):    return nn.Conv2D(in_planes,                     out_planes,                     kernel_size=3,                     stride=stride,                     padding=1,                     bias_attr=False)class FcaBottleneck(nn.Layer):    expansion = 4    def __init__(self,                 inplanes,                 planes,                 stride=1,                 downsample=None,                 groups=1,                 base_width=64,                 dilation=1,                 norm_layer=None,                 reduction=16):        global _mapper_x, _mapper_y        super(FcaBottleneck, self).__init__()        # assert fea_h is not None        # assert fea_w is not None        c2wh = dict([(64, 56), (128, 28), (256, 14), (512, 7)])        self.planes = planes        self.conv1 = nn.Conv2D(inplanes,                               planes,                               kernel_size=1,                               bias_attr=False)        self.bn1 = nn.BatchNorm2D(planes)        self.conv2 = nn.Conv2D(planes,                               planes,                               kernel_size=3,                               stride=stride,                               padding=1,                               bias_attr=False)        self.bn2 = nn.BatchNorm2D(planes)        self.conv3 = nn.Conv2D(planes,                               planes * 4,                               kernel_size=1,                               bias_attr=False)        self.bn3 = nn.BatchNorm2D(planes * 4)        self.relu = nn.ReLU()        self.att = MultiSpectralAttentionLayer(planes * 4,                                               c2wh[planes],                                               c2wh[planes],                                               reduction=reduction,                                               freq_sel_method='top16')        self.downsample = downsample        self.stride = stride    def forward(self, x):        residual = x        out = self.conv1(x)        out = self.bn1(out)        out = self.relu(out)        out = self.conv2(out)        out = self.bn2(out)        out = self.relu(out)        out = self.conv3(out)        out = self.bn3(out)        out = self.att(out)        if self.downsample is not None:            residual = self.downsample(x)        out += residual        out = self.relu(out)        return outclass FcaBasicBlock(nn.Layer):    expansion = 1    def __init__(self,                 inplanes,                 planes,                 stride=1,                 downsample=None,                 groups=1,                 base_width=64,                 dilation=1,                 norm_layer=None,                 reduction=16):        global _mapper_x, _mapper_y        super(FcaBasicBlock, self).__init__()        # assert fea_h is not None        # assert fea_w is not None        c2wh = dict([(64, 56), (128, 28), (256, 14), (512, 7)])        self.planes = planes        self.conv1 = nn.Conv2D(inplanes,                               planes,                               kernel_size=3,                               stride=stride,                               padding=1,                               bias_attr=False)        self.bn1 = nn.BatchNorm2D(planes)        self.conv2 = nn.Conv2D(planes,                               planes,                               kernel_size=3,                               padding=1,                               bias_attr=False)        self.bn2 = nn.BatchNorm2D(planes)        self.relu = nn.ReLU()        self.att = MultiSpectralAttentionLayer(planes,                                               c2wh[planes],                                               c2wh[planes],                                               reduction=reduction,                                               freq_sel_method='top16')        self.downsample = downsample        self.stride = stride    def forward(self, x):        residual = x        out = self.conv1(x)        out = self.bn1(out)        out = self.relu(out)        out = self.conv2(out)        out = self.bn2(out)        out = self.att(out)        if self.downsample is not None:            residual = self.downsample(x)        out += residual        out = self.relu(out)        return out
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:26: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations  def convert_to_list(value, n, name, dtype=np.int):

预设模型

In [ ]

def fcanet34(num_classes=1000, pretrained=False):    """Constructs a FcaNet-34 model.    Args:        pretrained (bool): If True, returns a model pre-trained on ImageNet    """    model = ResNet(FcaBasicBlock, 34, num_classes=num_classes)    model.avgpool = nn.AdaptiveAvgPool2D(1)    if pretrained:        params = paddle.load('data/data100873/fca34.pdparams')        model.set_dict(params)    return modeldef fcanet50(num_classes=1000, pretrained=False):    """Constructs a FcaNet-50 model.    Args:        pretrained (bool): If True, returns a model pre-trained on ImageNet    """    model = ResNet(FcaBottleneck, 50, num_classes=num_classes)    model.avgpool = nn.AdaptiveAvgPool2D(1)    if pretrained:        params = paddle.load('data/data100873/fca50.pdparams')        model.set_dict(params)    return modeldef fcanet101(num_classes=1000, pretrained=False):    """Constructs a FcaNet-101 model.    Args:        pretrained (bool): If True, returns a model pre-trained on ImageNet    """    model = ResNet(FcaBottleneck, 101, num_classes=num_classes)    model.avgpool = nn.AdaptiveAvgPool2D(1)    if pretrained:        params = paddle.load('data/data100873/fca101.pdparams')        model.set_dict(params)    return modeldef fcanet152(num_classes=1000, pretrained=False):    """Constructs a FcaNet-101 model.    Args:        pretrained (bool): If True, returns a model pre-trained on ImageNet    """    model = ResNet(FcaBottleneck, 152, num_classes=num_classes)    model.avgpool = nn.AdaptiveAvgPool2D(1)    if pretrained:        params = paddle.load('data/data100873/fca152.pdparams')        model.set_dict(params)    return model

模型测试

In [ ]

model = fcanet34(pretrained=True)x = paddle.randn((1, 3, 224, 224))out = model(x)print(out.shape)model.eval()out = model(x)print(out.shape)
[1, 1000][1, 1000]
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:648: UserWarning: When training, we now always track global mean and variance.  "When training, we now always track global mean and variance.")

精度测试

标称精度

Model Reported Evaluation Results

FcaNet3475.0775.02FcaNet5078.5278.57FcaNet10179.6479.63FcaNet15280.0880.02

解压数据集

In [ ]

!mkdir ~/data/ILSVRC2012!tar -xf ~/data/data68594/ILSVRC2012_img_val.tar -C ~/data/ILSVRC2012

模型评估

In [8]

import osimport cv2import numpy as npimport paddleimport paddle.vision.transforms as Tfrom PIL import Image# 构建数据集class ILSVRC2012(paddle.io.Dataset):    def __init__(self, root, label_list, transform, backend='pil'):        self.transform = transform        self.root = root        self.label_list = label_list        self.backend = backend        self.load_datas()    def load_datas(self):        self.imgs = []        self.labels = []        with open(self.label_list, 'r') as f:            for line in f:                img, label = line[:-1].split(' ')                self.imgs.append(os.path.join(self.root, img))                self.labels.append(int(label))    def __getitem__(self, idx):        label = self.labels[idx]        image = self.imgs[idx]        if self.backend=='cv2':            image = cv2.imread(image)        else:            image = Image.open(image).convert('RGB')        image = self.transform(image)        return image.astype('float32'), np.array(label).astype('int64')    def __len__(self):        return len(self.imgs)val_transforms = T.Compose([    T.Resize(256, interpolation='bicubic'),    T.CenterCrop(224),    T.ToTensor(),    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])# 配置模型model = fcanet34(pretrained=True)model = paddle.Model(model)model.prepare(metrics=paddle.metric.Accuracy(topk=(1, 5)))# 配置数据集val_dataset = ILSVRC2012('data/ILSVRC2012', transform=val_transforms, label_list='data/data68594/val_list.txt', backend='pil')# 模型验证acc = model.evaluate(val_dataset, batch_size=8, num_workers=0, verbose=1)print(acc)
{'acc_top1': 0.74838, 'acc_top5': 0.92048}

以上就是Paddle2.0:浅析并实现 FcaNet 模型的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/67556.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月12日 13:01:55
下一篇 2025年11月12日 13:29:24

相关推荐

  • Uniapp 中如何不拉伸不裁剪地展示图片?

    灵活展示图片:如何不拉伸不裁剪 在界面设计中,常常需要以原尺寸展示用户上传的图片。本文将介绍一种在 uniapp 框架中实现该功能的简单方法。 对于不同尺寸的图片,可以采用以下处理方式: 极端宽高比:撑满屏幕宽度或高度,再等比缩放居中。非极端宽高比:居中显示,若能撑满则撑满。 然而,如果需要不拉伸不…

    2025年12月24日
    400
  • 如何让小说网站控制台显示乱码,同时网页内容正常显示?

    如何在不影响用户界面的情况下实现控制台乱码? 当在小说网站上下载小说时,大家可能会遇到一个问题:网站上的文本在网页内正常显示,但是在控制台中却是乱码。如何实现此类操作,从而在不影响用户界面(UI)的情况下保持控制台乱码呢? 答案在于使用自定义字体。网站可以通过在服务器端配置自定义字体,并通过在客户端…

    2025年12月24日
    800
  • 如何在地图上轻松创建气泡信息框?

    地图上气泡信息框的巧妙生成 地图上气泡信息框是一种常用的交互功能,它简便易用,能够为用户提供额外信息。本文将探讨如何借助地图库的功能轻松创建这一功能。 利用地图库的原生功能 大多数地图库,如高德地图,都提供了现成的信息窗体和右键菜单功能。这些功能可以通过以下途径实现: 高德地图 JS API 参考文…

    2025年12月24日
    400
  • 如何使用 scroll-behavior 属性实现元素scrollLeft变化时的平滑动画?

    如何实现元素scrollleft变化时的平滑动画效果? 在许多网页应用中,滚动容器的水平滚动条(scrollleft)需要频繁使用。为了让滚动动作更加自然,你希望给scrollleft的变化添加动画效果。 解决方案:scroll-behavior 属性 要实现scrollleft变化时的平滑动画效果…

    2025年12月24日
    000
  • 如何为滚动元素添加平滑过渡,使滚动条滑动时更自然流畅?

    给滚动元素平滑过渡 如何在滚动条属性(scrollleft)发生改变时为元素添加平滑的过渡效果? 解决方案:scroll-behavior 属性 为滚动容器设置 scroll-behavior 属性可以实现平滑滚动。 html 代码: click the button to slide right!…

    2025年12月24日
    500
  • 如何选择元素个数不固定的指定类名子元素?

    灵活选择元素个数不固定的指定类名子元素 在网页布局中,有时需要选择特定类名的子元素,但这些元素的数量并不固定。例如,下面这段 html 代码中,activebar 和 item 元素的数量均不固定: *n *n 如果需要选择第一个 item元素,可以使用 css 选择器 :nth-child()。该…

    2025年12月24日
    200
  • 使用 SVG 如何实现自定义宽度、间距和半径的虚线边框?

    使用 svg 实现自定义虚线边框 如何实现一个具有自定义宽度、间距和半径的虚线边框是一个常见的前端开发问题。传统的解决方案通常涉及使用 border-image 引入切片图片,但是这种方法存在引入外部资源、性能低下的缺点。 为了避免上述问题,可以使用 svg(可缩放矢量图形)来创建纯代码实现。一种方…

    2025年12月24日
    100
  • 如何解决本地图片在使用 mask JS 库时出现的跨域错误?

    如何跨越localhost使用本地图片? 问题: 在本地使用mask js库时,引入本地图片会报跨域错误。 解决方案: 要解决此问题,需要使用本地服务器启动文件,以http或https协议访问图片,而不是使用file://协议。例如: python -m http.server 8000 然后,可以…

    2025年12月24日
    200
  • 旋转长方形后,如何计算其相对于画布左上角的轴距?

    绘制长方形并旋转,计算旋转后轴距 在拥有 1920×1080 画布中,放置一个宽高为 200×20 的长方形,其坐标位于 (100, 100)。当以任意角度旋转长方形时,如何计算它相对于画布左上角的 x、y 轴距? 以下代码提供了一个计算旋转后长方形轴距的解决方案: const x = 200;co…

    2025年12月24日
    000
  • 旋转长方形后,如何计算它与画布左上角的xy轴距?

    旋转后长方形在画布上的xy轴距计算 在画布中添加一个长方形,并将其旋转任意角度,如何计算旋转后的长方形与画布左上角之间的xy轴距? 问题分解: 要计算旋转后长方形的xy轴距,需要考虑旋转对长方形宽高和位置的影响。首先,旋转会改变长方形的长和宽,其次,旋转会改变长方形的中心点位置。 求解方法: 计算旋…

    2025年12月24日
    000
  • 旋转长方形后如何计算其在画布上的轴距?

    旋转长方形后计算轴距 假设长方形的宽、高分别为 200 和 20,初始坐标为 (100, 100),我们将它旋转一个任意角度。根据旋转矩阵公式,旋转后的新坐标 (x’, y’) 可以通过以下公式计算: x’ = x * cos(θ) – y * sin(θ)y’ = x * …

    2025年12月24日
    000
  • 如何让“元素跟随文本高度,而不是撑高父容器?

    如何让 元素跟随文本高度,而不是撑高父容器 在页面布局中,经常遇到父容器高度被子元素撑开的问题。在图例所示的案例中,父容器被较高的图片撑开,而文本的高度没有被考虑。本问答将提供纯css解决方案,让图片跟随文本高度,确保父容器的高度不会被图片影响。 解决方法 为了解决这个问题,需要将图片从文档流中脱离…

    2025年12月24日
    000
  • 如何计算旋转后长方形在画布上的轴距?

    旋转后长方形与画布轴距计算 在给定的画布中,有一个长方形,在随机旋转一定角度后,如何计算其在画布上的轴距,即距离左上角的距离? 以下提供一种计算长方形相对于画布左上角的新轴距的方法: const x = 200; // 初始 x 坐标const y = 90; // 初始 y 坐标const w =…

    2025年12月24日
    200
  • CSS元素设置em和transition后,为何载入页面无放大效果?

    css元素设置em和transition后,为何载入无放大效果 很多开发者在设置了em和transition后,却发现元素载入页面时无放大效果。本文将解答这一问题。 原问题:在视频演示中,将元素设置如下,载入页面会有放大效果。然而,在个人尝试中,并未出现该效果。这是由于macos和windows系统…

    2025年12月24日
    200
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 如何利用 CSS 选中激活标签并影响相邻元素的样式?

    如何利用 css 选中激活标签并影响相邻元素? 为了实现激活标签影响相邻元素的样式需求,可以通过 :has 选择器来实现。以下是如何具体操作: 对于激活标签相邻后的元素,可以在 css 中使用以下代码进行设置: li:has(+li.active) { border-radius: 0 0 10px…

    2025年12月24日
    100
  • 如何模拟Windows 10 设置界面中的鼠标悬浮放大效果?

    win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…

    2025年12月24日
    200
  • 如何计算旋转后的长方形在画布上的 XY 轴距?

    旋转长方形后计算其画布xy轴距 在创建的画布上添加了一个长方形,并提供其宽、高和初始坐标。为了视觉化旋转效果,还提供了一些旋转特定角度后的图片。 问题是如何计算任意角度旋转后,这个长方形的xy轴距。这涉及到使用三角学来计算旋转后的坐标。 以下是一个 javascript 代码示例,用于计算旋转后长方…

    2025年12月24日
    000
  • 为什么我的 Safari 自定义样式表在百度页面上失效了?

    为什么在 Safari 中自定义样式表未能正常工作? 在 Safari 的偏好设置中设置自定义样式表后,您对其进行测试却发现效果不同。在您自己的网页中,样式有效,而在百度页面中却失效。 造成这种情况的原因是,第一个访问的项目使用了文件协议,可以访问本地目录中的图片文件。而第二个访问的百度使用了 ht…

    2025年12月24日
    000
  • 如何用前端实现 Windows 10 设置界面的鼠标移动探照灯效果?

    如何在前端实现 Windows 10 设置界面中的鼠标移动探照灯效果 想要在前端开发中实现 Windows 10 设置界面中类似的鼠标移动探照灯效果,可以通过以下途径: CSS 解决方案 DEMO 1: Windows 10 网格悬停效果:https://codepen.io/tr4553r7/pe…

    2025年12月24日
    000

发表回复

登录后才能评论
关注微信