CycleGAN模型解读(附源码+论文)
CycleGAN
论文链接:Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks
官方链接:pytorch-CycleGAN-and-pix2pix
老规矩,先看看效果
总体流程
先简单过一遍流程,细节在代码里说。CycleGAN有两个生成器和两个判别器。下图可以看到GeneratorA2B
和GeneratorB2A
,假设A数据集里全是马,B数据集里全是斑马,那这两个分别就是将马生成斑马和斑马生成马的生成器。DiscriminatorA
和DiscriminatorB
就是用来判别马和斑马的判别器。
上面的流程图很清晰的表示了模型的整体过程。一般生成器将马生成斑马就结束了,但是CycleGAN表示nonono,它还将生成的斑马再还原回马。因为 CycleGAN 强调循环一致性(Cycle Consistency),它通过让生成的斑马再还原回马,确保生成的斑马仍然保留了输入马的基本特征和结构。也就是说,CycleGAN 不仅要生成目标域的图像,还要通过反向转换验证生成图像的合理性。
同样的流程还会再经历一次,只不过这里的马和斑马的位置对调了一下(输入斑马,生成马)。
生成模型的损失函数有三种,拆分为六部分,分别对应对抗损失、循环一致性损失和身份损失。容易想到的,对抗损失用于训练生成器 A2B 和B2A 生成能够欺骗判别器的图像,可以理解为将真马生成为假斑马能不能让判别器判断为真的。上面流程不是有一步生成了假图还要还原回去,没错,还原回去的图与真实的图的差异,即循环一致性损失。身份损失是为了让生成器保留图像的风格或颜色特征,可以理解成除了马变成了斑马,其余背景部分不做变化。
将一匹马变成一匹斑马,我在没看这篇论文之前想的流程是,有一张马的图片,然后再做一张将马变为斑马的标签图,这样可以将生成的图片与这张标签图做损失计算进行训练。但CycleGAN根本不需要标签图,它只需要马的图片与斑马的图片就行,不需要什么人工处理的标签图,简直是福音,人工标注鬼知道有多麻烦。就像下图一样,素描鞋子作为输入,皮鞋作为标签图,需要一一对应。而现在,照片作为输入,标签图是毫不相干的油画图。
数据准备
这里说的详细一点,怎么准备数据。
公开数据集地址:Index of /cyclegan/datasets
下载自己想玩的数据集,比如horse2zebra就是马转斑马的。下载好的数据集放在datasets目录下。
预训练模型地址:Index of /cyclegan/pretrained_models
下载对应的预训练模型哦,比如horse2zebra.pth就是马转斑马的。下载好的模型放在checkpoints目录下。
别的配置看github上有详细说明。
预警:模型训练需要显卡显存至少8G及以上。
代码
数据处理
运行train.py。先进入unaligned_dataset.py看看数据集怎么处理的。
def __init__(self, opt):BaseDataset.__init__(self, opt)self.dir_A = os.path.join(opt.dataroot, opt.phase + 'A') # create a path '/path/to/data/trainA'self.dir_B = os.path.join(opt.dataroot, opt.phase + 'B') # create a path '/path/to/data/trainB'self.A_paths = sorted(make_dataset(self.dir_A, opt.max_dataset_size)) # load images from '/path/to/data/trainA'self.B_paths = sorted(make_dataset(self.dir_B, opt.max_dataset_size)) # load images from '/path/to/data/trainB'self.A_size = len(self.A_paths) # get the size of dataset Aself.B_size = len(self.B_paths) # get the size of dataset BbtoA = self.opt.direction == 'BtoA'input_nc = self.opt.output_nc if btoA else self.opt.input_nc # get the number of channels of input imageoutput_nc = self.opt.input_nc if btoA else self.opt.output_nc # get the number of channels of output imageself.transform_A = get_transform(self.opt, grayscale=(input_nc == 1))self.transform_B = get_transform(self.opt, grayscale=(output_nc == 1))
先获得训练数据集A和B的路径,然后看看路径下有多少图片,数据集A和B的图片数量可以不一样哦。因为就像我上面说的,不需要一一对应的标签图,所以取出一张A可以从数据集B中随机抽一张作为标签图。然后会通过transform做一些图片处理,比如resize、裁剪、翻转、标准化之类的。
model
进入cycle_gan_model.py看看模型怎么初始化和训练的。
self.netG_A = networks.define_G(opt.input_nc, opt.output_nc, opt.ngf, opt.netG, opt.norm,not opt.no_dropout, opt.init_type, opt.init_gain, self.gpu_ids)
self.netG_B = networks.define_G(opt.output_nc, opt.input_nc, opt.ngf, opt.netG, opt.norm,not opt.no_dropout, opt.init_type, opt.init_gain, self.gpu_ids)if self.isTrain: # define discriminatorsself.netD_A = networks.define_D(opt.output_nc, opt.ndf, opt.netD,opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.gpu_ids)self.netD_B = networks.define_D(opt.input_nc, opt.ndf, opt.netD,opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.gpu_ids)
在初始化时,最重要的是生成器和判别器的定义,我们去networks.py里看看define_G和define_D的定义。
define_G
def define_G(input_nc, output_nc, ngf, netG, norm='batch', use_dropout=False, init_type='normal', init_gain=0.02, gpu_ids=[]):net = Nonenorm_layer = get_norm_layer(norm_type=norm)if netG == 'resnet_9blocks':net = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=9)elif netG == 'resnet_6blocks':net = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=6)elif netG == 'unet_128':net = UnetGenerator(input_nc, output_nc, 7, ngf, norm_layer=norm_layer, use_dropout=use_dropout)elif netG == 'unet_256':net = UnetGenerator(input_nc, output_nc, 8, ngf, norm_layer=norm_layer, use_dropout=use_dropout)else:raise NotImplementedError('Generator model name [%s] is not recognized' % netG)return init_net(net, init_type, init_gain, gpu_ids)
图片卷积三件套Conv->BN->relu
。不过这里的BN换了一下,上面代码用了norm_layer代替,即nn.BatchNorm2d
转为nn.InstanceNorm2d
,不同点在于InstanceNorm2d对每个样本的特征通道分别进行归一化。构建网络时用的是resnet_9blocks,我们进ResnetGenerator看一看。
ResnetGenerator
def __init__(self, input_nc, output_nc, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False, n_blocks=6,padding_type='reflect'):assert (n_blocks >= 0)super(ResnetGenerator, self).__init__()if type(norm_layer) == functools.partial:use_bias = norm_layer.func == nn.InstanceNorm2delse:use_bias = norm_layer == nn.InstanceNorm2dmodel = [nn.ReflectionPad2d(3),nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0, bias=use_bias),norm_layer(ngf),nn.ReLU(True)]n_downsampling = 2for i in range(n_downsampling): # add downsampling layersmult = 2 ** imodel += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3, stride=2, padding=1, bias=use_bias),norm_layer(ngf * mult * 2),nn.ReLU(True)]mult = 2 ** n_downsamplingfor i in range(n_blocks): # add ResNet blocksmodel += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout,use_bias=use_bias)]for i in range(n_downsampling): # add upsampling layersmult = 2 ** (n_downsampling - i)model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2),kernel_size=3, stride=2,padding=1, output_padding=1,bias=use_bias),norm_layer(int(ngf * mult / 2)),nn.ReLU(True)]model += [nn.ReflectionPad2d(3)]model += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0)]model += [nn.Tanh()]self.model = nn.Sequential(*model)
在model初始构建时,我们发现卷积三件套上多了一件nn.ReflectionPad2d(3)
,这是padding的一种方式,不过不同于简单的填充,周围都填充为0,而是通过在输入特征图边界处 镜像反射 填充,如下图所示。
模型构建下面就比较简单,就是先通过卷积给图像size越卷越小,不过特征图越卷越多(3->64->128->256
)。然后来点残差块ResnetBlock
。生成器最后生成的图得跟原图一样大小,所以通过反卷积nn.ConvTranspose2d
,给图卷回原来大小,就类似上采样。同理特征图数量也得越卷越少,卷回原来的3通道(256->128->64->3
)。
define_D
我们再看看判别器怎么定义的。
def define_D(input_nc, ndf, netD, n_layers_D=3, norm='batch', init_type='normal', init_gain=0.02, gpu_ids=[]):net = Nonenorm_layer = get_norm_layer(norm_type=norm)if netD == 'basic': # default PatchGAN classifiernet = NLayerDiscriminator(input_nc, ndf, n_layers=3, norm_layer=norm_layer)elif netD == 'n_layers': # more optionsnet = NLayerDiscriminator(input_nc, ndf, n_layers_D, norm_layer=norm_layer)elif netD == 'pixel': # classify if each pixel is real or fakenet = PixelDiscriminator(input_nc, ndf, norm_layer=norm_layer)else:raise NotImplementedError('Discriminator model name [%s] is not recognized' % netD)return init_net(net, init_type, init_gain, gpu_ids)
跟生成器一样吼,先定义一个norm_layer,然后进入NLayerDiscriminator看看。
NLayerDiscriminator
def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d):super(NLayerDiscriminator, self).__init__()if type(norm_layer) == functools.partial: # no need to use bias as BatchNorm2d has affine parametersuse_bias = norm_layer.func == nn.InstanceNorm2delse:use_bias = norm_layer == nn.InstanceNorm2dkw = 4padw = 1sequence = [nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True)]nf_mult = 1nf_mult_prev = 1for n in range(1, n_layers): # gradually increase the number of filtersnf_mult_prev = nf_multnf_mult = min(2 ** n, 8)sequence += [nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias),norm_layer(ndf * nf_mult),nn.LeakyReLU(0.2, True)]nf_mult_prev = nf_multnf_mult = min(2 ** n_layers, 8)sequence += [nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=1, padding=padw, bias=use_bias),norm_layer(ndf * nf_mult),nn.LeakyReLU(0.2, True)]sequence += [nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)] # output 1 channel prediction mapself.model = nn.Sequential(*sequence)
构建过程也没啥要说的,就是不停卷积给特征图越卷越多,最后输出一个值,判定是真是假(3->64->128->256->512->1
)。
初始化好模型后进行训练,主要来看一下model.optimize_parameters()
这里的内容。
optimize_parameters
到cycle_gan_model.py看一下optimize_parameters。
def optimize_parameters(self):# forwardself.forward() # compute fake images and reconstruction images.# G_A and G_B 训练生成器 判别器不工作self.set_requires_grad([self.netD_A, self.netD_B], False) # Ds require no gradients when optimizing Gsself.optimizer_G.zero_grad() # set G_A and G_B's gradients to zeroself.backward_G() # calculate gradients for G_A and G_Bself.optimizer_G.step() # update G_A and G_B's weights# D_A and D_B 训练判别器 生成器不工作self.set_requires_grad([self.netD_A, self.netD_B], True)self.optimizer_D.zero_grad() # set D_A and D_B's gradients to zeroself.backward_D_A() # calculate gradients for D_Aself.backward_D_B() # calculate graidents for D_Bself.optimizer_D.step() # update D_A and D_B's weights
简简单单包含了前向传播和反向传播,先看看前向传播forward。
forward
def forward(self):self.fake_B = self.netG_A(self.real_A) # G_A(A)self.rec_A = self.netG_B(self.fake_B) # G_B(G_A(A))self.fake_A = self.netG_B(self.real_B) # G_B(B)self.rec_B = self.netG_A(self.fake_A) # G_A(G_B(B))
四行代码很好理解。将真实图A输入生成器A2B,输出假B;将假B输入生成器B2A,还原回A;同理,将真实图B输入生成器B2A,输出假A;将假A输入生成器A2B,还原回B。
backward_G
看看生成器的反向传播,怎么做损失计算的。
def backward_G(self):"""Calculate the loss for generators G_A and G_B"""lambda_idt = self.opt.lambda_identity # 一些缩放因子lambda_A = self.opt.lambda_Alambda_B = self.opt.lambda_B# Identity lossif lambda_idt > 0:# G_A should be identity if real_B is fed: ||G_A(B) - B||self.idt_A = self.netG_A(self.real_B) # 将真实B传入A->B网络 也能生成假Bself.loss_idt_A = self.criterionIdt(self.idt_A, self.real_B) * lambda_B * lambda_idt# G_B should be identity if real_A is fed: ||G_B(A) - A||self.idt_B = self.netG_B(self.real_A) # 将真实A传入B->A网络 也能生成假Aself.loss_idt_B = self.criterionIdt(self.idt_B, self.real_A) * lambda_A * lambda_idtelse:self.loss_idt_A = 0self.loss_idt_B = 0# GAN loss D_A(G_A(A))self.loss_G_A = self.criterionGAN(self.netD_A(self.fake_B), True) # 希望判别器将假B判为真# GAN loss D_B(G_B(B))self.loss_G_B = self.criterionGAN(self.netD_B(self.fake_A), True)# Forward cycle loss || G_B(G_A(A)) - A||self.loss_cycle_A = self.criterionCycle(self.rec_A, self.real_A) * lambda_A # 还原A与真实A的差异损失# Backward cycle loss || G_A(G_B(B)) - B||self.loss_cycle_B = self.criterionCycle(self.rec_B, self.real_B) * lambda_B# combined loss and calculate gradientsself.loss_G = self.loss_G_A + self.loss_G_B + self.loss_cycle_A + self.loss_cycle_B + self.loss_idt_A + self.loss_idt_Bself.loss_G.backward()
这里的self.idt_A
和self.idt_B
就是我上面说的身份损失,公式如下。
式中,G和F是生成器A2B和B2A。
lambda_idt就是个加权参数,缩放损失用的。生成器A2B的作用不是输入A生成B嘛,不过这里做损失是通过输入B,输出B,这两B之间的差异做损失。论文中说引入这个损失有助于促进映射以保持输入和输出之间的颜色组成。比如莫奈的画作与Flickr照片之间的映射时,生成器经常将 白天 的画作映射到 日落 时拍摄的照片,如下图所示。
self.loss_G_A
和self.loss_G_B
是我上面说的对抗损失,公式如下。
这个损失很好理解,就是我生成器生成的假图,我希望判别器判为真的。这里的判别是对每个像素点都判别是真是假,然后取平均。如果输入图片size是[256,256]
,经过判别器输出图片size是[30,30]
,对这[30,30]
的每个点判断是真是假。具体代码可以自己去networks.py的GANLoss看一下。
self.criterionGAN = networks.GANLoss(opt.gan_mode).to(self.device) # define GAN loss.
剩下最后的self.loss_cycle_A
和self.loss_cycle_B
就是循环一致性损失了,公式如下。
这个更好理解,就是看看还原回去的图与输入的图的差异损失。下图是论文中,输入->输出->还原(重建)
的过程。
====================================================================================
train需要电脑配置还挺高的,大家可以试试test,配置一下参数就行,例如下面
python test.py --dataroot datasets/horse2zebra/testA --name horse2zebra_pretrained --model test --no_dropout
数据集放在datasets/horse2zebra/testA
目录下,模型放在checkpoints/horse2zebra_pretrained
目录下,最后的结果会生成一个result目录下。
相关文章:
CycleGAN模型解读(附源码+论文)
CycleGAN 论文链接:Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks 官方链接:pytorch-CycleGAN-and-pix2pix 老规矩,先看看效果 总体流程 先简单过一遍流程,细节在代码里说。CycleGAN有…...
WebAssembly(Wasm)详解
WebAssembly 详解:开启 Web 应用的新纪元 引言 WebAssembly(简称 Wasm)是一种革命性的技术,它为 Web 应用带来了接近原生的性能,并支持使用多种编程语言进行开发。本文将深入探讨 WebAssembly 的方方面面,…...
基于物联网设计的疫苗冷链物流监测系统
一、前言 1.1 项目开发背景 随着全球经济的发展和物流行业的不断创新,疫苗和生物制品的运输要求变得越来越高。尤其是疫苗的冷链物流,温度、湿度等环境因素的控制直接关系到疫苗的质量和效力,因此高效、可靠的冷链监控系统显得尤为重要。冷…...
RabbitMQ 多种安装模式
文章目录 前言一、Windows 安装 RabbitMq1、版本关系2、Erlang2.1、下载安装 Erlang 23.12.2、配置 Erlang 环境变量 3、RabbitMQ3.1、下载安装 RabbitMQ 3.8.93.2、环境变量3.3、启动RabbitMQ 管理插件3.3、RabbitMQ3.4、注意事项 二、安装docker1、更新系统包:2、…...
视频拼接,拼接时长版本
目录 视频较长,分辨率较大,这个效果很好,不耗用内存 ffmpeg imageio,适合视频较短 视频较长,分辨率较大,这个效果很好,不耗用内存 ffmpeg import subprocess import glob import os from nats…...
【Linux探索学习】第二十七弹——信号(一):Linux 信号基础详解
Linux学习笔记: https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言: 前面我们已经将进程通信部分讲完了,现在我们来讲一个进程部分也非常重要的知识点——信号,信号也是进程间通信的一…...
有限元分析学习——Anasys Workbanch第一阶段笔记梳理
第一阶段笔记主要源自于哔哩哔哩《ANSYS-workbench 有限元分析应用基础教程》 张晔 主要内容导图: 笔记导航如下: Anasys Workbanch第一阶段笔记(1)基本信息与结果解读_有限元分析变形比例-CSDN博客 Anasys Workbanch第一阶段笔记(2)网格单元与应力奇…...
【YOLOv11改进- 注意力机制】YOLOv11+SCSA注意力机制(2024): 最新空间和通道协同注意力,助力YOLOv11有效涨点;包含二次创新
YOLOV11目标检测改进实例与创新改进专栏 专栏地址:YOLOv11目标检测改进专栏,包括backbone、neck、loss、分配策略、组合改进、原创改进等; 本文介绍 本文给大家带来的改进内容是在YOLOv11中添加SCSA注意力机制,助力有效涨点。作者提出了一种新的空间与通道协同注意模块(S…...
科技快讯 | 理想官宣:正式收费!WeChat 港币钱包拓宽商户网络;百川智能发布深度思考模型Baichuan-M1-preview
理想官宣:正式收费! 1月23日,理想汽车宣布,理想超充站超时占用费正式运营。触发超时占用费的条件为充电结束后15分钟内未将充电枪插回充电桩,收费标准为2元/分钟,单次封顶200元。理想汽车将在充电结束的四个…...
LLM架构与优化:从理论到实践的关键技术
标题:“LLM架构与优化:从理论到实践的关键技术” 文章信息摘要: 文章探讨了大型语言模型(LLM)开发与应用中的关键技术,包括Transformer架构、注意力机制、采样技术、Tokenization等基础理论,以…...
深入理解Pytest中的Setup和Teardown
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 对于简单程序而言,使用 Pytest 运行测试直截了当。然而,当你…...
PostgreSQL 约束
PostgreSQL 约束 引言 在数据库设计中,约束是确保数据完整性和一致性的关键工具。PostgreSQL,作为一款功能强大的开源关系型数据库管理系统,提供了丰富的约束类型来满足不同的数据库设计需求。本文将详细介绍PostgreSQL中的各种约束,包括其定义、用途和实现方法。 一、约…...
JAVA 接口、抽象类的关系和用处 详细解析
接口 - Java教程 - 廖雪峰的官方网站 一个 抽象类 如果实现了一个接口,可以只选择实现接口中的 部分方法(所有的方法都要有,可以一部分已经写具体,另一部分继续保留抽象),原因在于: 抽象类本身…...
【微服务与分布式实践】探索 Dubbo
核心组件 服务注册与发现原理 服务提供者启动时,会将其服务信息(如服务名、版本、所在节点的网络地址等)注册到注册中心。服务消费者则可以从注册中心发现可用的服务提供者列表,并与之通信。注册中心会存储服务的信息,…...
lightweight-charts-python 包 更新 lightweight-charts.js 的方法
lightweight-charts-python 是 lightweight-charts.js 的 python 包装,非常好用 lightweight-charts 更新比较频繁,导致 lightweight-charts-python 内置的 lightweight-charts 经常不是最新的。 新的 lightweight-charts 通常可以获得性能改进和bug修复…...
作業系統:設計與實現-母本
2023 南京大學《作業系統:設計與實現》 課程主頁(含講義):https://jyywiki.cn/OS/2023/ 【Python 实现操作系统模型 [南京大学2023操作系统-P4] (蒋炎岩)-哔哩哔哩】 https://b23.tv/jakxDbh 用Python实现操作系统模型讲义 一、操作系统基础概念 1.1 定义 操作系统(Oper…...
穿心莲内酯(andrographolide)生物合成CYP72-文献精读106
Two CYP72 enzymes function as Ent-labdane hydroxylases in the biosynthesis of andrographolide in Andrographis paniculata 两种CYP72酶在穿心莲(Andrographis paniculata)中作为Ent-labdane羟化酶,在穿心莲内酯(andrograp…...
IDM-VTON本地部署教程:双重编码 + 文字提示,解锁真实野外试穿
一、介绍 IDM-VTON:改进扩散模型,实现真实的野外虚拟试穿。 技术原理:改进扩散模型,利用视觉编码器提取服装高级语义信息并与交叉注意力层融合,通过并行 UNet 结构的 GarmentNet 捕捉服装低级特征并与自注意力层结合&…...
【微服务与分布式实践】探索 Sentinel
参数设置 熔断时长 、最小请求数、最大RT ms、比例阈值、异常数 熔断策略 慢调⽤⽐例 当单位统计时⻓内请求数⽬⼤于设置的最⼩请求数⽬,并且慢调⽤的⽐例⼤于阈值,则接下来的熔断时⻓内请求会⾃动被熔断 异常⽐例 当单位统计时⻓内请求数⽬⼤于设置…...
云计算与虚拟化技术讲解视频分享
互联网各领域资料分享专区(不定期更新): Sheet 前言 由于内容较多,且不便于排版,为避免资源失效,请用手机点击链接进行保存,若链接生效请及时反馈,谢谢~ 正文 链接如下(为避免资源失效&#x…...
[c语言日寄]越界访问:意外的死循环
【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是…...
数据结构---哈希表
基本概念 哈希函数(Hash Function)是一种将输入的数据(通常是任意大小的)映射到固定大小的输出(通常是一个固定长度的值)的函数。这个输出值通常称为“哈希值”(Hash Value)或“哈希…...
【C语言----数组详解】
目录 ---------------------------------------begin--------------------------------------- 一、什么是数组 二、数组的声明和初始化 1. 数组的声明 2. 数组的初始化 三、数组元素的访问 四、数组的遍历 五、数组的应用 六、多维数组 七、总结 --------------------…...
C语言字符串详解
1. C语言中的字符串基础 C语言中的字符串是程序设计中不可忽视的部分。与现代高级编程语言不同,C语言对字符串的处理方式直接、灵活,并且强大。在C语言中,字符串并不是一种特殊的数据类型,而是字符数组的一种表现形式。字符串通常…...
基础IO(2)
基础IO(2) 理解“⼀切皆⽂件” ⾸先,在windows中是⽂件的东西,它们在linux中也是⽂件;其次⼀些在windows中不是⽂件的东西,⽐如进程、磁盘、显⽰器、键盘这样硬件设备也被抽象成了⽂件,你可以使…...
深入理解 Python 中的 `__all__`:控制模块的公共接口
在 Python 编程中,模块化设计是构建可维护和可扩展代码的关键。模块不仅帮助我们组织代码,还能通过隐藏实现细节来提高代码的可读性和安全性。Python 提供了多种机制来控制模块的可见性,其中 __all__ 是一个非常重要但常被忽视的特性。本文将…...
Python面试宝典7 | 正则表达式的match()与search(),精准匹配与全局搜索
今天,我们来聊聊Python正则表达式中两个常用的方法:match()和search()。它们都用于在字符串中查找匹配的模式,但有着重要的区别。 理论篇:匹配的起始位置 match()和search()最主要的区别在于它们匹配的起始位置: ma…...
代码随想录算法训练营第三十八天-动态规划-完全背包-279.完全平方数
把目标值当作背包容量,每个平方数当作物品,题目变更为装满指定容量的背包,最小用几个物品会不会出现拼凑不出来的情况?不会,因为有数字1,对任意正整数百分百能拼凑出来因此此题目与上一道题就变得一模一样了…...
996引擎 - NPC-添加NPC引擎自带形象
996引擎 - NPC-添加NPC引擎自带形象 截图参考添加NPC参考资料截图参考 添加NPC 编辑NPC表:Envir\DATA\cfg_npclist.xls 1.1. 需要临时隐藏NPC时可以在id前加 // 1.2. 如果NPC朝向不对,可以调整dir 列。(按8方向,上是0顺时针数。我这里给的4) 1.3. 形象代码:NPC代码、怪物…...
基于 NodeJs 一个后端接口的创建过程及其规范 -- 【elpis全栈项目】
基于 NodeJs 一个后端接口的创建过程及其规范 一个接口的诞生: #mermaid-svg-46HXZKI3fdnO0rKV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-46HXZKI3fdnO0rKV .error-icon{fill:#552222;}#mermaid-sv…...
笔记本跑大模型尝试
1,笔记本电脑资源 我是一台联想笔记本电脑,基本配置如下: CPU:12th Gen Intel(R) Core(TM) i7-1255U 1.70 GHz (12核心,2个P核和8个E核,共计10个核心) 显卡:NVIDIA GeForce MX550 内存&am…...
[论文阅读] (37)CCS21 DeepAID:基于深度学习的异常检测(解释)
祝大家新春快乐,蛇年吉祥! 《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座,并分享给大家,希望您喜欢。由于作者的英文水平和学术能力不高,需要不断提升,所以还请大家批评指正࿰…...
常见端口的攻击思路
端口号端口说明攻击方向21/22/69FTP/TFTP文件传输协议匿名上传/下载、嗅探、爆破2049NFS服务配置不当139Sanba服务爆破、远程代码执行389Ldap目录访问协议注入、匿名访问、弱口令22SSH远程连接爆破、SSH映射隧道搭建、文件传输23Telnet远程连接爆破、嗅探、弱口令3389RDP远程桌…...
复古壁纸中棕色系和米色系哪个更受欢迎?
根据最新的搜索结果,我们可以看到棕色系和米色系在复古壁纸设计中都非常受欢迎。以下是对这两种颜色系受欢迎程度的分析: 棕色系 受欢迎程度:棕色系在复古壁纸中非常受欢迎,因为它能够营造出温暖、质朴和自然的氛围。棕色系的壁纸…...
RocketMQ消息是如何存储的?
大家好,我是锋哥。今天分享关于【RocketMQ消息是如何存储的?】面试题。希望对大家有帮助; RocketMQ消息是如何存储的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RocketMQ 使用了一个高性能、分布式的消息存储架构…...
在FreeBSD下安装Ollama并体验DeepSeek r1大模型
在FreeBSD下安装Ollama并体验DeepSeek r1大模型 在FreeBSD下安装Ollama 直接使用pkg安装即可: sudo pkg install ollama 安装完成后,提示: You installed ollama: the AI model runner. To run ollama, plese open 2 terminals. 1. In t…...
[250128] Apache HTTP Server 2.4.63 发布 | Arm 发布首个芯片系统架构的公开规范
目录 Apache HTTP Server 2.4.63 发布,十五年创新成果!Arm 发布首个芯片系统架构的公开规范 Apache HTTP Server 2.4.63 发布,十五年创新成果! Apache 软件基金会和 Apache HTTP Server 项目组自豪地宣布 Apache HTTP Server 2.4…...
为什么要学习rust
内存管理:对于我来说,我就喜欢它的内存管理。我做了一个webapi,取100万行数据,导出到xlsx,再把这个xlsx文件发送给前端。分别用了java、c#、go和rust进行了相同的操作。只有rust做到了,启动时8MB内存&#…...
Linux进程调度与等待:背后的机制与实现
个人主页:chian-ocean 文章专栏-Linux 前言: 当一个进程发起某种操作(如I/O请求、信号、锁的获取等),但该操作需要的资源暂时不可用时,进程会被操作系统挂起,进入“等待队列”或“阻塞状态”。…...
Linux任务管理与守护进程
文章目录 🍅任务管理进程组概念作业概念会话概念相关操作前台进程&后台进程jobsfgbgps命令查看指定的选项 🫒守护进程守护进程的概念作用守护进程的查看守护进程的创建原生创建守护进程调用daemon函数创建守护进程模拟实现daemon函数 🍅任…...
《Trustzone/TEE/安全从入门到精通-标准版》
CSDN学院课程连接:https://edu.csdn.net/course/detail/39573 讲师介绍 拥有 12 年手机安全、汽车安全、芯片安全开发经验,擅长 Trustzone/TEE/ 安全的设计与开发,对 ARM 架构的安全领域有着深入的研究和丰富的实践经验,能够将复杂的安全知识和处理器架构知识进行系统整…...
java 字符串日期字段格式化前端显示
在 Java 应用程序中,如果你有一个字符串类型的日期字段,并希望将其格式化后显示在前端,可以通过多种方式实现。这通常涉及到在后端将字符串转换为 Date 或 LocalDateTime 等对象,然后使用适当的注解或配置来确保它们以正确的格式序…...
LabVIEW橡胶动态特性测试系统
本文介绍了一个利用LabVIEW软件和NI高速数据采集设备构建的橡胶动态特性测试系统。该系统实现了橡胶材料动态性能的精确测量,并通过虚拟仪器技术,提高了测试数据的处理效率和准确性。系统支持实时数据处理和多种信号的动态分析,适用于工业和科…...
deepseek-r1 本地部署
deepseek 最近太火了 1:环境 win10 cpu 6c 内存 16G 2: 部署 1>首先下载ollama 官网:https://ollama.com ollama 安装在c盘 模型可以配置下载到其他盘 OLLAMA_MODELS D:\Ollama 2>下载模型并运行 ollama run deepseek-r1:<标签> 1.5b 7b 8…...
28. 【.NET 8 实战--孢子记账--从单体到微服务】--简易报表--报表定时器与报表数据修正
这篇文章是《.NET 8 实战–孢子记账–从单体到微服务》系列专栏的《单体应用》专栏的最后一片和开发有关的文章。在这片文章中我们一起来实现一个数据统计的功能:报表数据汇总。这个功能为用户查看月度、年度、季度报表提供数据支持。 一、需求 数据统计方面&…...
具身智能技术趋势
参考: 【北京大学-董豪】具身智能技术趋势分析 2024.8 回答了具身智能技术G3、G4的必要性,以及真实数据、仿真数据、互联网数据之间的关系 具身智能趋势 趋势:寻求一个通用路径实现所有的上肢操作 要求:① 低成本 ② 拓展到所有…...
JavaScript逆向高阶指南:突破基础,掌握核心逆向技术
JavaScript逆向高阶指南:突破基础,掌握核心逆向技术 JavaScript逆向工程是Web开发者和安全分析师的核心竞争力。无论是解析混淆代码、分析压缩脚本,还是逆向Web应用架构,掌握高阶逆向技术都将助您深入理解复杂JavaScript逻辑。本…...
C#面试常考随笔6:ArrayList和 List的主要区别?
在 C# 中,ArrayList和List<T>(泛型列表)都可用于存储一组对象。推荐优先使用List<T>,因为它具有更好的类型安全性、性能和语法简洁性,并且提供了更丰富的功能。只有在需要与旧代码兼容或存储不同类型对象的…...
【数据结构】 并查集 + 路径压缩与按秩合并 python
目录 前言模板朴素实现路径压缩按秩合并按树高为秩按节点数为秩 总结 前言 并查集的基本实现通常使用森林来表示不同的集合,每个集合用一棵树表示,树的每个节点有一个指向其父节点的指针。 如果一个节点是它自己的父节点,那么它就是该集合的代…...
使用 Redis List 和 Pub/Sub 实现简单的消息队列
使用 Redis List 和 Pub/Sub 实现简单的消息队列 Redis 本身不是专门的消息队列系统,但它提供了多种数据结构(如 List、Pub/Sub、Stream)来实现消息队列功能。根据不同的业务需求,可以选择不同的方式: 在 Redis 中&a…...