目标检测算法改进系列之Backbone替换为RepViT
RepViT简介
轻量级模型研究一直是计算机视觉任务中的一个焦点,其目标是在降低计算成本的同时达到优秀的性能。轻量级模型与资源受限的移动设备尤其相关,使得视觉模型的边缘部署成为可能。在过去十年中,研究人员主要关注轻量级卷积神经网络(CNNs)的设计,提出了许多高效的设计原则,包括可分离卷积 [2] 、逆瓶颈结构 [3] 、通道打乱 [4] 和结构重参数化 [5] 等,产生了 MobileNets [2, 3],ShuffleNets [4] 和 RepVGG [5] 等代表性模型。
另一方面,视觉 Transformers(ViTs)成为学习视觉表征的另一种高效方案。与 CNNs 相比,ViTs 在各种计算机视觉任务中表现出了更优越的性能。然而,ViT 模型一般尺寸很大,延迟很高,不适合资源受限的移动设备。因此,研究人员开始探索 ViT 的轻量级设计。许多高效的ViTs设计原则被提出,大大提高了移动设备上 ViTs 的计算效率,产生了EfficientFormers [6] ,MobileViTs [7] 等代表性模型。这些轻量级 ViTs 在移动设备上展现出了相比 CNNs 的更强的性能和更低的延迟。
轻量级 ViTs 优于轻量级 CNNs 的原因通常归结于多头注意力模块,该模块使模型能够学习全局表征。然而,轻量级 ViTs 和轻量级 CNNs 在块结构、宏观和微观架构设计方面存在值得注意的差异,但这些差异尚未得到充分研究。这自然引出了一个问题:轻量级 ViTs 的架构选择能否提高轻量级 CNN 的性能?在这项工作中,我们结合轻量级 ViTs 的架构选择,重新审视了轻量级 CNNs 的设计。我们的旨在缩小轻量级 CNNs 与轻量级 ViTs 之间的差距,并强调前者与后者相比在移动设备上的应用潜力。
原文地址:RepViT: Revisiting Mobile CNN From ViT Perspective

RepViT代码实现
import torch.nn as nn
import numpy as np
from timm.models.layers import SqueezeExcite
import torch__all__ = ['repvit_m1', 'repvit_m2', 'repvit_m3']def replace_batchnorm(net):for child_name, child in net.named_children():if hasattr(child, 'fuse_self'):fused = child.fuse_self()setattr(net, child_name, fused)replace_batchnorm(fused)elif isinstance(child, torch.nn.BatchNorm2d):setattr(net, child_name, torch.nn.Identity())else:replace_batchnorm(child)def _make_divisible(v, divisor, min_value=None):"""This function is taken from the original tf repo.It ensures that all layers have a channel number that is divisible by 8It can be seen here:https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py:param v::param divisor::param min_value::return:"""if min_value is None:min_value = divisornew_v = max(min_value, int(v + divisor / 2) // divisor * divisor)# Make sure that round down does not go down by more than 10%.if new_v < 0.9 * v:new_v += divisorreturn new_vclass Conv2d_BN(torch.nn.Sequential):def __init__(self, a, b, ks=1, stride=1, pad=0, dilation=1,groups=1, bn_weight_init=1, resolution=-10000):super().__init__()self.add_module('c', torch.nn.Conv2d(a, b, ks, stride, pad, dilation, groups, bias=False))self.add_module('bn', torch.nn.BatchNorm2d(b))torch.nn.init.constant_(self.bn.weight, bn_weight_init)torch.nn.init.constant_(self.bn.bias, 0)@torch.no_grad()def fuse_self(self):c, bn = self._modules.values()w = bn.weight / (bn.running_var + bn.eps)**0.5w = c.weight * w[:, None, None, None]b = bn.bias - bn.running_mean * bn.weight / \(bn.running_var + bn.eps)**0.5m = torch.nn.Conv2d(w.size(1) * self.c.groups, w.size(0), w.shape[2:], stride=self.c.stride, padding=self.c.padding, dilation=self.c.dilation, groups=self.c.groups,device=c.weight.device)m.weight.data.copy_(w)m.bias.data.copy_(b)return mclass Residual(torch.nn.Module):def __init__(self, m, drop=0.):super().__init__()self.m = mself.drop = dropdef forward(self, x):if self.training and self.drop > 0:return x + self.m(x) * torch.rand(x.size(0), 1, 1, 1,device=x.device).ge_(self.drop).div(1 - self.drop).detach()else:return x + self.m(x)@torch.no_grad()def fuse_self(self):if isinstance(self.m, Conv2d_BN):m = self.m.fuse_self()assert(m.groups == m.in_channels)identity = torch.ones(m.weight.shape[0], m.weight.shape[1], 1, 1)identity = torch.nn.functional.pad(identity, [1,1,1,1])m.weight += identity.to(m.weight.device)return melif isinstance(self.m, torch.nn.Conv2d):m = self.massert(m.groups != m.in_channels)identity = torch.ones(m.weight.shape[0], m.weight.shape[1], 1, 1)identity = torch.nn.functional.pad(identity, [1,1,1,1])m.weight += identity.to(m.weight.device)return melse:return selfclass RepVGGDW(torch.nn.Module):def __init__(self, ed) -> None:super().__init__()self.conv = Conv2d_BN(ed, ed, 3, 1, 1, groups=ed)self.conv1 = Conv2d_BN(ed, ed, 1, 1, 0, groups=ed)self.dim = eddef forward(self, x):return self.conv(x) + self.conv1(x) + x@torch.no_grad()def fuse_self(self):conv = self.conv.fuse_self()conv1 = self.conv1.fuse_self()conv_w = conv.weightconv_b = conv.biasconv1_w = conv1.weightconv1_b = conv1.biasconv1_w = torch.nn.functional.pad(conv1_w, [1,1,1,1])identity = torch.nn.functional.pad(torch.ones(conv1_w.shape[0], conv1_w.shape[1], 1, 1, device=conv1_w.device), [1,1,1,1])final_conv_w = conv_w + conv1_w + identityfinal_conv_b = conv_b + conv1_bconv.weight.data.copy_(final_conv_w)conv.bias.data.copy_(final_conv_b)return convclass RepViTBlock(nn.Module):def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se, use_hs):super(RepViTBlock, self).__init__()assert stride in [1, 2]self.identity = stride == 1 and inp == oupassert(hidden_dim == 2 * inp)if stride == 2:self.token_mixer = nn.Sequential(Conv2d_BN(inp, inp, kernel_size, stride, (kernel_size - 1) // 2, groups=inp),SqueezeExcite(inp, 0.25) if use_se else nn.Identity(),Conv2d_BN(inp, oup, ks=1, stride=1, pad=0))self.channel_mixer = Residual(nn.Sequential(# pwConv2d_BN(oup, 2 * oup, 1, 1, 0),nn.GELU() if use_hs else nn.GELU(),# pw-linearConv2d_BN(2 * oup, oup, 1, 1, 0, bn_weight_init=0),))else:assert(self.identity)self.token_mixer = nn.Sequential(RepVGGDW(inp),SqueezeExcite(inp, 0.25) if use_se else nn.Identity(),)self.channel_mixer = Residual(nn.Sequential(# pwConv2d_BN(inp, hidden_dim, 1, 1, 0),nn.GELU() if use_hs else nn.GELU(),# pw-linearConv2d_BN(hidden_dim, oup, 1, 1, 0, bn_weight_init=0),))def forward(self, x):return self.channel_mixer(self.token_mixer(x))class RepViT(nn.Module):def __init__(self, cfgs):super(RepViT, self).__init__()# setting of inverted residual blocksself.cfgs = cfgs# building first layerinput_channel = self.cfgs[0][2]patch_embed = torch.nn.Sequential(Conv2d_BN(3, input_channel // 2, 3, 2, 1), torch.nn.GELU(),Conv2d_BN(input_channel // 2, input_channel, 3, 2, 1))layers = [patch_embed]# building inverted residual blocksblock = RepViTBlockfor k, t, c, use_se, use_hs, s in self.cfgs:output_channel = _make_divisible(c, 8)exp_size = _make_divisible(input_channel * t, 8)layers.append(block(input_channel, exp_size, output_channel, k, s, use_se, use_hs))input_channel = output_channelself.features = nn.ModuleList(layers)self.channel = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]def forward(self, x):input_size = x.size(2)scale = [4, 8, 16, 32]features = [None, None, None, None]for f in self.features:x = f(x)if input_size // x.size(2) in scale:features[scale.index(input_size // x.size(2))] = xreturn featuresdef switch_to_deploy(self):replace_batchnorm(self)def update_weight(model_dict, weight_dict):idx, temp_dict = 0, {}for k, v in weight_dict.items():# k = k[9:]if k in model_dict.keys() and np.shape(model_dict[k]) == np.shape(v):temp_dict[k] = vidx += 1model_dict.update(temp_dict)print(f'loading weights... {idx}/{len(model_dict)} items')return model_dictdef repvit_m1(weights=''):"""Constructs a MobileNetV3-Large model"""cfgs = [# k, t, c, SE, HS, s [3, 2, 48, 1, 0, 1],[3, 2, 48, 0, 0, 1],[3, 2, 48, 0, 0, 1],[3, 2, 96, 0, 0, 2],[3, 2, 96, 1, 0, 1],[3, 2, 96, 0, 0, 1],[3, 2, 96, 0, 0, 1],[3, 2, 192, 0, 1, 2],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 1, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 192, 0, 1, 1],[3, 2, 384, 0, 1, 2],[3, 2, 384, 1, 1, 1],[3, 2, 384, 0, 1, 1]]model = RepViT(cfgs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)['model']))return modeldef repvit_m2(weights=''):"""Constructs a MobileNetV3-Large model"""cfgs = [# k, t, c, SE, HS, s [3, 2, 64, 1, 0, 1],[3, 2, 64, 0, 0, 1],[3, 2, 64, 0, 0, 1],[3, 2, 128, 0, 0, 2],[3, 2, 128, 1, 0, 1],[3, 2, 128, 0, 0, 1],[3, 2, 128, 0, 0, 1],[3, 2, 256, 0, 1, 2],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 512, 0, 1, 2],[3, 2, 512, 1, 1, 1],[3, 2, 512, 0, 1, 1]]model = RepViT(cfgs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)['model']))return modeldef repvit_m3(weights=''):"""Constructs a MobileNetV3-Large model"""cfgs = [# k, t, c, SE, HS, s [3, 2, 64, 1, 0, 1],[3, 2, 64, 0, 0, 1],[3, 2, 64, 1, 0, 1],[3, 2, 64, 0, 0, 1],[3, 2, 64, 0, 0, 1],[3, 2, 128, 0, 0, 2],[3, 2, 128, 1, 0, 1],[3, 2, 128, 0, 0, 1],[3, 2, 128, 1, 0, 1],[3, 2, 128, 0, 0, 1],[3, 2, 128, 0, 0, 1],[3, 2, 256, 0, 1, 2],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 1, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 256, 0, 1, 1],[3, 2, 512, 0, 1, 2],[3, 2, 512, 1, 1, 1],[3, 2, 512, 0, 1, 1]]model = RepViT(cfgs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)['model']))return modelif __name__ == '__main__':model = repvit_m1('repvit_m1_distill_300.pth')inputs = torch.randn((1, 3, 640, 640))res = model(inputs)for i in res:print(i.size())
Backbone替换
yolo.py修改
def parse_model函数
def parse_model(d, ch): # model_dict, input_channels(3)# Parse a YOLOv5 model.yaml dictionaryLOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation')if act:Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU()LOGGER.info(f"{colorstr('activation:')} {act}") # printna = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchorsno = na * (nc + 5) # number of outputs = anchors * (classes + 5)is_backbone = Falselayers, save, c2 = [], [], ch[-1] # layers, savelist, ch outfor i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, argstry:t = mm = eval(m) if isinstance(m, str) else m # eval stringsexcept:passfor j, a in enumerate(args):with contextlib.suppress(NameError):try:args[j] = eval(a) if isinstance(a, str) else a # eval stringsexcept:args[j] = an = n_ = max(round(n * gd), 1) if n > 1 else n # depth gainif m in {Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}:c1, c2 = ch[f], args[0]if c2 != no: # if not outputc2 = make_divisible(c2 * gw, 8)args = [c1, c2, *args[1:]]if m in {BottleneckCSP, C3, C3TR, C3Ghost, C3x}:args.insert(2, n) # number of repeatsn = 1elif m is nn.BatchNorm2d:args = [ch[f]]elif m is Concat:c2 = sum(ch[x] for x in f)# TODO: channel, gw, gdelif m in {Detect, Segment}:args.append([ch[x] for x in f])if isinstance(args[1], int): # number of anchorsargs[1] = [list(range(args[1] * 2))] * len(f)if m is Segment:args[3] = make_divisible(args[3] * gw, 8)elif m is Contract:c2 = ch[f] * args[0] ** 2elif m is Expand:c2 = ch[f] // args[0] ** 2elif isinstance(m, str):t = mm = timm.create_model(m, pretrained=args[0], features_only=True)c2 = m.feature_info.channels()elif m in {repvit_m1}: #可添加更多Backbonem = m(*args)c2 = m.channelelse:c2 = ch[f]if isinstance(c2, list):is_backbone = Truem_ = mm_.backbone = Trueelse:m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # modulet = str(m)[8:-2].replace('__main__.', '') # module typenp = sum(x.numel() for x in m_.parameters()) # number paramsm_.i, m_.f, m_.type, m_.np = i + 4 if is_backbone else i, f, t, np # attach index, 'from' index, type, number paramsLOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # printsave.extend(x % (i + 4 if is_backbone else i) for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelistlayers.append(m_)if i == 0:ch = []if isinstance(c2, list):ch.extend(c2)for _ in range(5 - len(ch)):ch.insert(0, 0)else:ch.append(c2)return nn.Sequential(*layers), sorted(save)
def _forward_once函数
def _forward_once(self, x, profile=False, visualize=False):y, dt = [], [] # outputsfor m in self.model:if m.f != -1: # if not from previous layerx = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layersif profile:self._profile_one_layer(m, x, dt)if hasattr(m, 'backbone'):x = m(x)for _ in range(5 - len(x)):x.insert(0, None)for i_idx, i in enumerate(x):if i_idx in self.save:y.append(i)else:y.append(None)x = x[-1]else:x = m(x) # runy.append(x if m.i in self.save else None) # save outputif visualize:feature_visualization(x, m.type, m.i, save_dir=visualize)return x
创建.yaml配置文件
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
anchors:- [10,13, 16,30, 33,23] # P3/8- [30,61, 62,45, 59,119] # P4/16- [116,90, 156,198, 373,326] # P5/32# 0-P1/2
# 1-P2/4
# 2-P3/8
# 3-P4/16
# 4-P5/32# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, repvit_m1, [False]], # 4[-1, 1, SPPF, [1024, 5]], # 5]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [512, 1, 1]], # 6[-1, 1, nn.Upsample, [None, 2, 'nearest']], # 7[[-1, 3], 1, Concat, [1]], # cat backbone P4 8[-1, 3, C3, [512, False]], # 9[-1, 1, Conv, [256, 1, 1]], # 10[-1, 1, nn.Upsample, [None, 2, 'nearest']], # 11[[-1, 2], 1, Concat, [1]], # cat backbone P3 12[-1, 3, C3, [256, False]], # 13 (P3/8-small)[-1, 1, Conv, [256, 3, 2]], # 14[[-1, 10], 1, Concat, [1]], # cat head P4 15[-1, 3, C3, [512, False]], # 16 (P4/16-medium)[-1, 1, Conv, [512, 3, 2]], # 17[[-1, 5], 1, Concat, [1]], # cat head P5 18[-1, 3, C3, [1024, False]], # 19 (P5/32-large)[[13, 16, 19], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]
相关文章:
目标检测算法改进系列之Backbone替换为RepViT
RepViT简介 轻量级模型研究一直是计算机视觉任务中的一个焦点,其目标是在降低计算成本的同时达到优秀的性能。轻量级模型与资源受限的移动设备尤其相关,使得视觉模型的边缘部署成为可能。在过去十年中,研究人员主要关注轻量级卷积神经网络&a…...
学习 Kubernetes的难点和安排
Kubernetes 技术栈的特点可以用四个字来概括,那就是“新、广、杂、深”: 1.“新”是指 Kubernetes 用到的基本上都是比较前沿、陌生的技术,而且版本升级很快,经常变来变去。 2.“广”是指 Kubernetes 涉及的应用领域很多、覆盖面非…...
【MATLAB源码-第42期】基于matlab的人民币面额识别系统(GUI)。
操作环境: MATLAB 2022a 1、算法描述 基于 MATLAB 的人民币面额识别系统设计可以分为以下步骤: 1. 数据收集与预处理 数据收集: 收集不同面额的人民币照片,如 1 元、5 元、10 元、20 元、50 元和 100 元。确保在不同环境、不…...
【软件测试】软件测试的基础概念
一、一个优秀的测试人员需要具备的素质 技能方面: 优秀的测试用例设计能力:测试用例设计能力是指,无论对于什么类型的测试,都能够设计出高效的发现缺陷,保证产品质量的优秀测试用例。这就需要我们掌握设计测试用例的方…...
Docker-mysql,redis安装
安装MySQL 下载MySQL镜像 终端运行命令 docker pull mysql:8.0.29镜像下载完成后,需要配置持久化数据到本地 这是mysql的配置文件和存储数据用的目录 切换到终端,输入命令,第一次启动MySQL容器 docker run --restartalways --name mysq…...
五种I/O模型
目录 1、阻塞IO模型2、非阻塞IO模型3、IO多路复用模型4、信号驱动IO模型5、异步IO模型总结 blockingIO - 阻塞IOnonblockingIO - 非阻塞IOIOmultiplexing - IO多路复用signaldrivenIO - 信号驱动IOasynchronousIO - 异步IO 5种模型的前4种模型为同步IO,只有异步IO模…...
用nativescript开发ios程序常用命令?
NativeScript是一个用于跨平台移动应用程序开发的开源框架,允许您使用JavaScript或TypeScript构建原生iOS和Android应用程序。以下是一些常用的NativeScript命令,用于开发iOS应用程序: 1、创建新NativeScript项目: tns create m…...
6.Tensors For Beginners-What are Convector
Covectors (协向量) What‘s a covector Covectors are “basically” Row Vectors 在一定程度上,可认为 协向量 基本上就像 行向量。 但不能简单地认为 这就是列向量进行转置! 行向量 和 列向量 是根本不同类型的对象。 …...
Linux多线程网络通信
思路:主线程(只有一个)建立连接,就创建子线程。子线程开始通信。 共享资源:全局数据区,堆区,内核区描述符。 线程同步不同步需要取决于线程对共享资源区的数据的操作,如果是只读就不…...
矩阵的c++实现(2)
上一次我们了解了矩阵的运算和如何使用矩阵解决斐波那契数列,这一次我们多看看例题,了解什么情况下用矩阵比较合适。 先看例题 1.洛谷P1939 【模板】矩阵加速(数列) 模板题应该很简单。 补:1<n<10^9 10^9肯定…...
RPC 框架之Thrift入门(一)
📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言Ὅ…...
【C++】运算符重载 ⑥ ( 一元运算符重载 | 后置运算符重载 | 前置运算符重载 与 后置运算符重载 的区别 | 后置运算符重载添加 int 占位参数 )
文章目录 一、后置运算符重载1、前置运算符重载 与 后置运算符重载 的区别2、后置运算符重载添加 int 占位参数 上 2 2 2 篇博客 【C】运算符重载 ④ ( 一元运算符重载 | 使用 全局函数 实现 前置 自增运算符重载 | 使用 全局函数 实现 前置 - - 自减运算符重载 )【C】运算符…...
538. 把二叉搜索树转换为累加树
题目描述 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提醒一下,二叉搜索树满足下列约束…...
java8日期时间工具类
【README】 1)本文总结了java8中日期时间常用工具方法;包括: 日期时间对象格式化为字符串;日期时间字符串解析为日期时间对象;日期时间对象转换; 转换过程中,需要注意的是: Instan…...
算法-动态规划/trie树-单词拆分
算法-动态规划/trie树-单词拆分 1 题目概述 1.1 题目出处 https://leetcode.cn/problems/word-break/description/?envTypestudy-plan-v2&envIdtop-interview-150 1.2 题目描述 2 动态规划 2.1 解题思路 dp[i]表示[0, i)字符串可否构建那么dp[i]可构建的条件是&…...
React框架核心原理
一、整体架构 三大核心库与对应的组件 history -> react-router -> react-router-dom react-router 可视为react-router-dom 的核心,里面封装了<Router>,<Route>,<Switch>等核心组件,实现了从路由的改变到组件的更新…...
python-pytorch 利用pytorch对堆叠自编码器进行训练和验证
利用pytorch对堆叠自编码器进行训练和验证 一、数据生成二、定义自编码器模型三、训练函数四、训练堆叠自编码器五、将已训练的自编码器级联六、微调整个堆叠自编码器 一、数据生成 随机生成一些数据来模拟训练和验证数据集: import torch# 随机生成数据 n_sample…...
制作 3 档可调灯程序编写
PWM 0~255 可以将数据映射到0 75 150 225 尽可能均匀电压间隔...
源码分享-M3U8数据流ts的AES-128解密并合并---GoLang实现
之前使用C语言实现了一次,见M3U8数据流ts的AES-128解密并合并。 学习了Go语言后,又用Go重新实现了一遍。源码如下,无第三方库依赖。 package mainimport ("crypto/aes""crypto/cipher""encoding/binary"&quo…...
CSDN Q: “这段代码算是在STC89C52RC51单片机上完成PWM呼吸灯了吗?“
这是 CSDN上的一个问题 这段代码算是在STC89C52RC51单片机上完成PWM呼吸灯了吗,还是说得用上定时器和中断函数#include <regx52.h> 我个人认为: 效果上来说, 是的! 码以 以Time / 100-Time 调 Duty, 而 for i loop成 Period, 加上延时, 实现了 PWM周期, 虽然…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
文章目录 一、开启慢查询日志,定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...
Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...
MyBatis-Plus 常用条件构造方法
1.常用条件方法 方法 说明eq等于 ne不等于 <>gt大于 >ge大于等于 >lt小于 <le小于等于 <betweenBETWEEN 值1 AND 值2notBetweenNOT BETWEEN 值1 AND 值2likeLIKE %值%notLikeNOT LIKE %值%likeLeftLIKE %值likeRightLIKE 值%isNull字段 IS NULLisNotNull字段…...
