当前位置: 首页 > news >正文

【计算机视觉】siamfc论文复现实现目标追踪

什么是目标跟踪

使用视频序列第一帧的图像(包括bounding box的位置),来找出目标出现在后序帧位置的一种方法。

什么是孪生网络结构

孪生网络结构其思想是将一个训练样本(已知类别)和一个测试样本(未知类别)输入到两个CNN(这两个CNN往往是权值共享的)中,从而获得两个特征向量,然后通过计算这两个特征向量的的相似度,相似度越高表明其越可能是同一个类别。

在这里插入图片描述

给你一张我的正脸照(没有经过美颜处理的),你该如何在人群中找到我呢?一种最直观的方案就是:“谁长得最像就是谁”。但是对于计算机来说,如何衡量“长得像”,并不是个简单的问题。这就涉及一种基本的运算——互相关(cross-correlation)。互相关运算可以用来度量两个信号之间的相似性。互相关得到的响应图中每个像素的响应高低代表着每个位置相似度的高低。

在这里插入图片描述

在目标领域中,最早利用这种思想的是SiamFC,其网络结构如上图。图中的φ就是CNN编码器,上下两个分支使用的CNN不仅结构相同,参数也是完全共享的(说白了就是同一个网络,并不存在孪生兄弟那样的设定)。z和x分别是要跟踪的目标模版图像(尺寸为127x127)和新的一帧中的搜索范围(尺寸为255x255)。二者经过同样的编码器后得到各自的特征图,对二者进行互相关运算后则会同样得到一个响应图(尺寸为17x17),其每一个像素的值对应了x中与z等大的一个对应区域出现跟踪目标的概率。

互相关运算的步骤,像极了我们手里拿着一张目标的照片(模板图像),然后把这个照片按在需要寻找目标的图片上(搜索图像)进行移动,然后求重叠部分相似度,从而找到这个目标,只不过为了计算机计算的方便,使用AlexNet对图像数据进行了编码/特征提取

下面这个版本中有一些动图,还是会帮助理解的:https://github.com/rafellerc/Pytorch-SiamFC

SiamFC代码分析

我们对siamese的结构大致就讲完了,还有一些内容结合代码来讲,效果更好。

3.0 SiameseFC的结构

主要由以下几部分构成

  • 特征提取网络AlexNet
  • 互相关运算网络

img

3.0.1 图像特征提取网络
class AlexNet(nn.Module):def __init__(self):super(AlexNet, self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(3, 96, 11, stride=2, padding=0),nn.BatchNorm2d(96),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2, padding=0))self.conv2 = nn.Sequential(nn.Conv2d(96, 256, 5, stride=1, padding=0, groups=2),nn.BatchNorm2d(256),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2, padding=0))self.conv3 = nn.Sequential(nn.Conv2d(256, 384, 3, stride=1, padding=0),nn.BatchNorm2d(384),nn.ReLU(inplace=True))self.conv4 = nn.Sequential(nn.Conv2d(384, 384, 3, stride=1, padding=0, groups=2),nn.BatchNorm2d(384),nn.ReLU(inplace=True))self.conv5 = nn.Sequential(nn.Conv2d(384, 256, 3, stride=1, padding=0, groups=2))def forward(self, x):conv1 = self.conv1(x)conv2 = self.conv2(conv1)conv3 = self.conv3(conv2)conv4 = self.conv4(conv3)conv5 = self.conv5(conv4)return conv5
3.0.2 互相关运算网络
class _corr(nn.Module):def __init__(self):super(_corr, self).__init__()#互相关运算,设batch_size=8def forward(self, z, x):kernel = z #[8,128,6,6]group = z.size(0)  #8input = x.view(-1, group*x.size(1), x.size(2), x.size(3))#输出为[8,1,17,17], 那么反推input[8,128,22,22],kernel[1,1024,6,6] group=128/1024?错误#所以先输出[1,8,17,17],再view变换维度成[8,1,17,17],那么input[1,1024,22,22],kernel[8,128,6,6],group=1024/128=8=batch_sizeresponse_maps = F.conv2d(input, kernel,groups=group)response_maps = response_maps.view(x.size(0),-1,response_maps.size(2), response_maps.size(3))return response_maps

至此,完成了对网络框架architecture的代码分析!!!

3.1 training

3.1.1图像预处理

小超up给出训练的框图如下。训练过程中,首先要获取训练数据集的所有视频序列(每个视频序列的所有帧),我采用的是GOT-10k数据集训练;获取数据集之后进行图像预处理,对每一个视频序列抽取两帧图像并作数据增强处理(包括裁剪、resize等过程),分别作为目标模板图像和搜索图像;把经过图像处理的所有图像对加载并以batch_size输入网络得到预测输出;建立标签和损失函数,损失函数的输入是预测输出,目标是标签;设置优化策略,梯度下降损失,最终得到网络模型。

在这里插入图片描述

先贴代码,再分析:

def train(data_dir, net_path=None,save_dir='pretrained'):#从文件中读取图像数据集seq_dataset = GOT10k(data_dir,subset='train',return_meta=False)#定义图像预处理方法transforms = SiamFCTransforms(  exemplar_sz=cfg.exemplar_sz, #127instance_sz=cfg.instance_sz, #255context=cfg.context) #0.5#从读取的数据集每个视频序列配对训练图像并进行预处理,裁剪等train_dataset = GOT10kDataset(seq_dataset,transforms)

data_dir是存放GOT-10k数据集的文件路径,GOT-10k一共有9335个训练视频序列,seq_dataset返回的是所有视频序列的图片路径列表seq_dirs及对应groundtruth列表anno_files及一些其他信息,如下:

img

接下来是定义好图像预处理方法,在GOT10kDataset方法中对每个视频序列配对两帧图像,并使用定义好的图像处理方法,接下来直接进入该方法分析代码,GOT10kDataset的代码如下:

class GOT10kDataset(Dataset): #继承了torch.utils.data的Dataset类def __init__(self, seqs, transforms=None,pairs_per_seq=1):def __getitem__(self, index): #通过_sample_pair方法得到索引返回item=(z,x,box_z,box_x),然后经过transforms处理def __len__(self): #返回9335*pairs_per_seq对def _sample_pair(self, indices): #随机挑选两个索引,这里取的间隔不超过T=100def _filter(self, img0, anno, vis_ratios=None): #通过该函数筛选符合条件的有效索引val_indices

这里最重要的方法就是__getitem__,该方法最终返回处理后的图像,在内部首先调用了_sample_pair方法,用于提取两帧有效图片(有效的定义是图片目标的面积和高宽等有约束条件)的索引

因为这里我对网络在训练和测试时需要的数据集有一些疑问,通过源码以及网上博文做以下总结:

答:在训练过程中,一对图片(即模板图和搜索图)共同构成一个数据样本,而不是单独的每一帧。这意味着在Siamese网络的训练中,数据集是由多个这样的图像对组成的,每个图像对代表一个单独的训练样本。

在这里插入图片描述

在测试阶段,算法逐帧处理视频序列,每次只处理一个搜索图和对应的模板图。

在这里插入图片描述

    def track(self, img_files, box, visualize=False):frame_num = len(img_files)boxes = np.zeros((frame_num, 4))boxes[0] = boxtimes = np.zeros(frame_num)for f, img_file in enumerate(img_files):img = ops.read_image(img_file)begin = time.time()if f == 0:self.init(img, box)else:boxes[f, :] = self.update(img)times[f] = time.time() - begin

可见在测试阶段,在视频序列的第一帧选择目标区域作为模板图。这个模板图将用于整个视频序列的跟踪过程。

在得到这两帧图片和对应groundtruth之后通过定义好的transforms进行处理,transforms是SiamFCTransforms类的实例化对象,该类中主要继承了resize图片大小和各种裁剪方式等,如代码所示:

class SiamFCTransforms(object):def __init__(self, exemplar_sz=127, instance_sz=255, context=0.5):self.exemplar_sz = exemplar_szself.instance_sz = instance_szself.context = context#transforms_z/x是数据增强方法self.transforms_z = Compose([RandomStretch(),     #随机resize图片大小,变化再[1 1.05]之内CenterCrop(instance_sz - 8),  #中心裁剪 裁剪为255-8RandomCrop(instance_sz - 2 * 8),   #随机裁剪  255-8->255-8-8CenterCrop(exemplar_sz),   #中心裁剪 255-8-8->127ToTensor()])                        #图片的数据格式从numpy转换成torch张量形式self.transforms_x = Compose([RandomStretch(),                   #s随机resize图片CenterCrop(instance_sz - 8),      #中心裁剪 裁剪为255-8RandomCrop(instance_sz - 2 * 8),  #随机裁剪 255-8->255-8-8ToTensor()])                      #图片数据格式转化为torch张量def __call__(self, z, x, box_z, box_x): #z,x表示传进来的图像z = self._crop(z, box_z, self.instance_sz)       #对z(x类似)图像 1、box转换(l,t,w,h)->(y,x,h,w),并且数据格式转为float32,得到center[y,x],和target_sz[h,w]x = self._crop(x, box_x, self.instance_sz)       #2、得到size=((h+(h+w)/2)*(w+(h+2)/2))^0.5*255(instance_sz)/127z = self.transforms_z(z)                         #3、进入crop_and_resize:传入z作为图片img,center,size,outsize=255(instance_sz),随机选方式填充,均值填充x = self.transforms_x(x)                         #   以center为中心裁剪一块边长为size大小的正方形框(注意裁剪时的padd边框填充问题),再resize成out_size=255(instance_sz)return z, x

实例化对象后,直接从__call__开始运行代码,首先关注的应该是_crop函数,该函数将原始的两帧图片分别以目标为中心,裁剪一块包含上下文信息的patch,patch的边长定义如下:

在这里插入图片描述

式中,w、h分别表示目标的宽和高。下面具体讲里面的_crop函数:

    def _crop(self, img, box, out_size):# convert box to 0-indexed and center based [y, x, h, w]box = np.array([box[1] - 1 + (box[3] - 1) / 2,box[0] - 1 + (box[2] - 1) / 2,box[3], box[2]], dtype=np.float32)center, target_sz = box[:2], box[2:]context = self.context * np.sum(target_sz)size = np.sqrt(np.prod(target_sz + context))size *= out_size / self.exemplar_szavg_color = np.mean(img, axis=(0, 1), dtype=float)interp = np.random.choice([cv2.INTER_LINEAR,cv2.INTER_CUBIC,cv2.INTER_AREA,cv2.INTER_NEAREST,cv2.INTER_LANCZOS4])patch = ops.crop_and_resize(img, center, size, out_size,border_value=avg_color, interp=interp)return patch

因为GOT-10k里面对于目标的bbox是以ltwh(即left, top, weight, height)形式给出的,上述代码一开始就先把输入的box变成center based,坐标形式变为[y, x, h, w],结合下面这幅图就非常好理解在这里插入图片描述img

crop_and_resize:

def crop_and_resize(img, center, size, out_size,border_type=cv2.BORDER_CONSTANT,border_value=(0, 0, 0),interp=cv2.INTER_LINEAR):# convert box to corners (0-indexed)size = round(size)  # the size of square cropcorners = np.concatenate((np.round(center - (size - 1) / 2),np.round(center - (size - 1) / 2) + size))corners = np.round(corners).astype(int)# pad image if necessarypads = np.concatenate((-corners[:2], corners[2:] - img.shape[:2]))npad = max(0, int(pads.max()))if npad > 0:img = cv2.copyMakeBorder(img, npad, npad, npad, npad,border_type, value=border_value)# crop image patchcorners = (corners + npad).astype(int)patch = img[corners[0]:corners[2], corners[1]:corners[3]]# resize to out_sizepatch = cv2.resize(patch, (out_size, out_size),interpolation=interp)return patch

在裁剪过程中会出现越界的情况,需要对原始图像边缘填充,填充值固定为图像的RGB均值,填充大小根据图像边缘越界最大值作为填充值,具体实现过程由以下代码完成。

# padding操作#corners表示目标的[ymin,xmin,ymax,xmax]pads = np.concatenate((-corners[:2], corners[2:] - img.shape[:2]))npad = max(0, int(pads.max())) #得到上下左右4个越界值中最大的与0对比,<0代表无越界if npad > 0:img = cv2.copyMakeBorder(img, npad, npad, npad, npad,cv2.BORDER_CONSTANT, value=img_average)

实验结果:

img

3.1.2加载训练数据、标签及损失函数

图像预处理完成后,得到了用与训练的9335对图像,将图像加载批量加载输入网络得到输出结果作为损失函数的input,损失函数的target是制定好的labels。

#加载训练数据集loader_dataset = DataLoader( dataset = train_dataset,batch_size=cfg.batch_size,shuffle=True,num_workers=cfg.num_workers,pin_memory=True,drop_last=True, )#初始化训练网络cuda = torch.cuda.is_available()  #支持GPU为Truedevice = torch.device('cuda:0' if cuda else 'cpu')  #cuda设备号为0model = AlexNet(init_weight=True)corr = _corr()model = model.to(device)corr = corr.to(device)# 设置损失函数和标签logist_loss = BalancedLoss()labels = _create_labels(size=[cfg.batch_size, 1, cfg.response_sz - 2, cfg.response_sz - 2])labels = torch.from_numpy(labels).to(device).float()

本小节主要讲网络输出的labels和损失函数,接下来只是小超up个人的一些理解,代码与论文理论部分形式不一致,但效果一样。先上图,论文中labels以及损失函数如下图:

img

img

然而代码中的labels值却是1和0,损失函数使用的是二值交叉熵损失函数F.binary_cross_entropy_with_logits,如下图推导所示,解释了为什么代码实现部分真正使用的labels值是1和0,而理论部分使用的是1和-1。

img

利用下面代码的这个_creat_labels方法可以得到标签。

def _create_labels(size):def logistic_labels(x, y, r_pos):# x^2+y^2<4 的位置设为为1,其他为0dist = np.sqrt(x ** 2 + y ** 2)labels = np.where(dist <= r_pos,    #r_os=2np.ones_like(x),  #np.ones_like(x),用1填充xnp.zeros_like(x)) #np.zeros_like(x),用0填充xreturn labels#获取标签的参数n, c, h, w = size  # [8,1,15,15]x = np.arange(w) - (w - 1) / 2  #x=[-7 -6 ....0....6 7]y = np.arange(h) - (h - 1) / 2  #y=[-7 -6 ....0....6 7]x, y = np.meshgrid(x, y)       #建立标签r_pos = cfg.r_pos / cfg.total_stride  # 16/8labels = logistic_labels(x, y, r_pos)#重复batch_size个label,因为网络输出是batch_size张response maplabels = labels.reshape((1, 1, h, w))   #[1,1,15,15]labels = np.tile(labels, (n, c, 1, 1))  #将labels扩展[8,1,15,15]return labels

验证结果如下图,只截取了部分labels,得到的labels对应输入,大小都是[8,1,15,15]

if __name__ == '__main__':labels = _create_labels([8,1,15,15])  #返回的label.shape=(8,1,15,15)

其中关于np.tile、np.meshgrid、np.where函数的使用可以去看这篇博客,最后出来的一个batch下某一个通道下的label就是下面这样的

img

3.1.3 优化策略

这里主要说一下学习率lr,随着训练次数epoch增多而减小,具体值如下公式image-20240721105017162,式中,initial为初始学习率,gamma是定义的超参,epoch为训练次数。整个优化器及学习率调整实现代码如下:

#建立优化器,设置指数变化的学习率optimizer = optim.SGD(model.parameters(),lr=cfg.initial_lr,              #初始化的学习率,后续会不断更新weight_decay=cfg.weight_decay,  #λ=5e-4,正则化momentum=cfg.momentum)          #v(now)=dx∗lr+v(last)∗momemtumgamma = np.power(                   #np.power(a,b) 返回a^bcfg.ultimate_lr / cfg.initial_lr,1.0 / cfg.epoch_num)lr_scheduler = ExponentialLR(optimizer, gamma)  #指数形式衰减,lr=initial_lr*(gamma^epoch)=
3.1.4 模型的训练与保存

一切准备工作就绪后,就开始训练了。代码中设定epoch_num为50次,训练时密切加上model.train(),告诉网络处于训练状态,这样,网络运行时就会利用pytorch的自动求导机制求导;在测试时,改为model.eval(),关闭自动求导。模型训练的步骤如代码所示:

# loop over epochs
for epoch in range(self.cfg.epoch_num):# update lr at each epochself.lr_scheduler.step(epoch=epoch)# loop over dataloaderfor it, batch in enumerate(dataloader):loss = self.train_step(batch, backward=True)print('Epoch: {} [{}/{}] Loss: {:.5f}'.format(epoch + 1, it + 1, len(dataloader), loss))sys.stdout.flush()# save checkpointif not os.path.exists(save_dir):os.makedirs(save_dir)net_path = os.path.join(save_dir, 'siamfc_alexnet_e%d.pth' % (epoch + 1))torch.save(self.net.state_dict(), net_path)

至此此份repo的训练应该差不多结束了

3.2 testing

3.2.1 init(初始帧)

这一步目的是要得到6x6x128的目标模板feature map,在后续跟踪过程中,一直使用它作为卷积核不变,这也是一大SiamFC的缺点所在;init内还要初始化目标的中心所在位置、宽高、汉宁窗等后续跟踪使用。

#传入第一帧的gt和图片,初始化一些参数,计算一些之后搜索区域的中心等等def init(self, img, box):#设置成评估模式,测试模型时一开始要加这个,属于Pytorch,训练模型前,要加self.net.train()self.model.eval()#将原始的目标位置表示[l,t,w,h]->[center_y,center_x,h,w]yxhw = ltwh_to_yxhw(ltwh=box)self.center, self.target_sz = yxhw[:2], yxhw[2:]#创建汉宁窗口update使用self.response_upsz = cfg.response_up * cfg.response_sz  # 16*17=272self.hann_window = creat_hanning_window(size=self.response_upsz)#三种尺度1.0375**(-1,0,1) 三种尺度self.scale_factors = three_scales()# patch边长,两种边长:目标模板图像z_sz和搜索图像x_zscontext = cfg.context * np.sum(self.target_sz)  # 上下文信息(h+w)/2self.z_sz = np.sqrt(np.prod(self.target_sz + context))  # (h+(h+w)/2)*(w+(h+2)/2))^0.5self.x_sz = self.z_sz * cfg.instance_sz / cfg.exemplar_sz  # (h+(h+w)/2)*(w+(h+2)/2))^0.5*255/127#图像的RGB均值,返回(aveR,aveG,aveB)self.avg_color = np.mean(img, axis=(0, 1))#裁剪一块以目标为中心,边长为z_sz大小的patch,然后将其resize成exemplar_sz的大小z = z_to127(img, self.center, self.z_sz, cfg.exemplar_sz, self.avg_color)z = torch.from_numpy(z).to(    #torch.size=([1,3,127,127])self.device).permute(2, 0, 1).unsqueeze(0).float()self.kernel = self.model(z)    #torch.size=([1,128,6,6])

follow代码,先设置model.eval(),原因在training过程中讲了,初始化目标的位置信息self.center和self.target_sz分别代表目标的中心位置和高宽;接着是汉宁窗口和尺度因子,汉宁窗口如下图展示的是17x17大小的,它与response map相乘会突出response map的中心并抑制边缘。窗口大小是17*16=272,而不是response map的大小17,这样做的好处是找到更加精确的位置,相比于在17x17大小的特征图上寻找最大值,272x272大小的特征图分辨率更高,位置更精确,所以在后续跟踪过程中,得到的17x17大小的response map会resize成272x272大小;代码使用的是SiamFC_3s,所以定义了三个不同的尺度;包含上下文信息的patch边长与training不同,训练时是将两张图片以相同的patch裁剪再resize成255x255x3大小,之后在一系列数据增强的过程中将其中一张图片裁剪成127x127x3作为目标模板图像。而test过程中,目标模板图像和搜索图像的patch边长不同,如代码所示,成比例255/127关系;最后就是对init传入的初始帧图片裁剪并输入网络得到跟踪过程使用的卷积核,大小为[1,128,6,6]。

3.2.2 update(后续帧)

Update就是tracking过程,传入的参数是后续帧图片,一共可以分为三个阶段:1、经过网络的正向推导得到response map;2、根据response map的最大值反推目标在原始图片中的位置;3、参数更新。

 #传入后续帧,然后根据SiamFC跟踪流程返回目标的box坐标def update(self, img):self.model.eval()"""----------------正向推导得到response map最大值位置---------------------"""#三种patch边长 patch*3scalesx = x_to3s255(img,self.center,self.x_sz,self.scale_factors,cfg.instance_sz,self.avg_color)#numpy转为float的torch型张量x = torch.from_numpy(x).to(self.device).permute(0, 3, 1, 2).float()#[3,255,22,22]x = self.model(x)#得到三种尺度下的response mapresponses = self.corr(self.kernel, x) * cfg.out_reduce #[3,1,17,17]responses = responses.squeeze(1).cpu().numpy()   #压缩为[3,17,17]并转为numpy作后续计算处理#将17x17大小的response map->[3,272,272]responses = map_to272(responses,out_size=self.response_upsz)#对尺度变化做出相应惩罚responses[:cfg.scale_num // 2] *= cfg.scale_penalty      #response[0]*(0.9745惩罚项)responses[cfg.scale_num // 2 + 1:] *= cfg.scale_penalty  #response[2]*(0.9745惩罚项)#找到最大值属于哪个response map,并把该response map赋给responsescale_id = np.argmax(np.amax(responses, axis=(1, 2))) #里面求得三个map的最大值 再对三个值求最大值 得到索引response = responses[scale_id]   #[272,272]#一系列数据处理,重点在汉宁窗惩罚response = map_process(response,self.hann_window)loc = np.unravel_index(response.argmax(),response.shape)   #unravel_index该函数可返回索引response.argmax()的元素的坐标,逐行拉伸,返回第几行第几个"""---------------由response map最大值位置反推目标在原图像的位置------------"""disp_in_response = np.array(loc) - (self.response_upsz - 1) / 2  #峰值点相对于response中心的位移disp = disp_in_response / 16disp = disp * 8disp = disp * self.x_sz * self.scale_factors[scale_id] / cfg.instance_szself.center += disp"""---------------参数更新------------"""

参考文档

siameseFC论文和代码解析

SiamFC 学习(论文、总结与分析)

siamfc-pytorch代码讲解(一):backbone&head

siamfc-pytorch代码讲解(二):train&siamfc

SiamFC代码分析(architecture、training、test)

siamfc前世今生

Siamese跟踪发展历程

视频推荐

目标跟踪零基础代码入门(一):SiamFC_哔哩哔哩_bilibili

相关文章:

【计算机视觉】siamfc论文复现实现目标追踪

什么是目标跟踪 使用视频序列第一帧的图像(包括bounding box的位置)&#xff0c;来找出目标出现在后序帧位置的一种方法。 什么是孪生网络结构 孪生网络结构其思想是将一个训练样本(已知类别)和一个测试样本(未知类别)输入到两个CNN(这两个CNN往往是权值共享的)中&#xff0…...

数学建模学习(111):改进遗传算法(引入模拟退火、轮盘赌和网格搜索)求解JSP问题

文章目录 一、车间调度问题1.1目前处理方法1.2简单案例 二、基于改进遗传算法求解车间调度2.1车间调度背景介绍2.2遗传算法介绍2.2.1基本流程2.2.2遗传算法的基本操作和公式2.2.3遗传算法的优势2.2.4遗传算法的不足 2.3讲解本文思路及代码2.4算法执行结果&#xff1a; 三、本文…...

Golang | Leetcode Golang题解之第241题为运算表达式设计优先级

题目&#xff1a; 题解&#xff1a; const addition, subtraction, multiplication -1, -2, -3func diffWaysToCompute(expression string) []int {ops : []int{}for i, n : 0, len(expression); i < n; {if unicode.IsDigit(rune(expression[i])) {x : 0for ; i < n &…...

Unity客户端接入原生Google支付

Unity客户端接入原生Google支付 1. Google后台配置2. 开始接入Java部分C#部分Lua部分 3. 导出工程打包测试参考踩坑注意 1. Google后台配置 找到内部测试&#xff08;这个测试轨道过审最快&#xff09;&#xff0c;打包上传&#xff0c;这个包不需要接入支付&#xff0c;如果已…...

Spring Cloud之五大组件

Spring Cloud 是一系列框架的有序集合&#xff0c;为开发者提供了快速构建分布式系统的工具。这些组件可以帮助开发者做服务发现&#xff0c;配置管理&#xff0c;负载均衡&#xff0c;断路器&#xff0c;智能路由&#xff0c;微代理&#xff0c;控制总线等。以下是 Spring Cl…...

在 CentOS 7 上安装 Docker 并安装和部署 .NET Core 3.1

1. 安装 Docker 步骤 1.1&#xff1a;更新包索引并安装依赖包 先安装yum的扩展&#xff0c;yum-utils提供了一些额外的工具&#xff0c;这些工具可以执行比基本yum命令更复杂的任务 sudo yum install -y yum-utils sudo yum update -y #更新系统上已安装的所有软件包到最新…...

redis的学习(一):下载安装启动连接

简介 redis的下载&#xff0c;安装&#xff0c;启动&#xff0c;连接使用 nosql nosql&#xff0c;即非关系型数据库&#xff0c;和传统的关系型数据库的对比&#xff1a; sqlnosql数据结构结构化非结构化数据关联关联的非关联的查询方式sql查询非sql查询事务特性acidbase存…...

前端设计模式面试题汇总

面试题 1. 简述对网站重构的理解&#xff1f; 参考回答&#xff1a; 网站重构&#xff1a;在不改变外部行为的前提下&#xff0c;简化结构、添加可读性&#xff0c;而在网站前端保持一致的行为。也就是说是在不改变UI的情况下&#xff0c;对网站进行优化&#xff0c; 在扩展的…...

linux(CentOS、Ubuntu)安装python3.12.2环境

1.下载官网Python安装包 wget https://www.python.org/ftp/python/3.12.2/Python-3.12.2.tar.xz 1.1解压 tar -xf Python-3.12.2.tar.xz 解压完后切换到Python-3.12.2文件夹(这里根据自己解压的文件夹路径) cd /usr/packages/Python-3.12.2/ 1.2升级软件包管理器 CentOS系…...

CSS 中border-radius 属性

border-radius 属性在 CSS 中用于创建圆角边框。它可以接受一到四个值&#xff0c;这些值可以是长度值&#xff08;如像素 px、em 等&#xff09;或百分比&#xff08;%&#xff09;。当提供四个值时&#xff0c;它们分别对应于边框的左上角、右上角、右下角和左下角的圆角半径…...

【大数据专题】数据仓库

1. 简述数据仓库架构 &#xff1f; 数据仓库的核心功能从源系统抽取数据&#xff0c;通过清洗、转换、标准化&#xff0c;将数据加载到BI平台&#xff0c;进而满足业 务用户的数据分析和决策支持。 数据仓库架构包含三个部分&#xff1a;数据架构、应用程序架构、底层设施 1&…...

go关于string与[]byte再学深一点

目标&#xff1a;充分理解string与[]bytes零拷贝转换的实现 先回顾下string与[]byte的基本知识 1. string与[]byte的数据结构 reflect包中关于字符串的数据结构 // StringHeader is the runtime representation of a string.type StringHeader struct {Data uintptrLen int} …...

Qt 实战(7)元对象系统 | 7.4、属性系统:深度解析与应用

文章目录 一、属性系统&#xff1a;深度解析与应用1、定义属性2、属性系统的作用3、属性系统工作原理&#xff08;1&#xff09;Q_PROPERTY宏&#xff08;2&#xff09;moc 的作用&#xff08;3&#xff09;属性在元对象中的注册 4、获取与设置属性4.1、QObject::property()与Q…...

Docker核心技术:容器技术要解决哪些问题

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Docker核心技术 系列文章&#xff1a;容器技术要解决哪些问题&#xff0c;其他文章快捷链接如下&#xff1a; 应用架构演进容器技术要解决哪些问题&#xff08;本文&#xff09;Docker的基本使用Docker是如何实…...

sklearn中的增量学习:特征提取的艺术

sklearn中的增量学习&#xff1a;特征提取的艺术 在机器学习领域&#xff0c;特征提取是构建有效模型的关键步骤。然而&#xff0c;并非所有数据集都适合一次性加载到内存中进行处理&#xff0c;尤其是在处理大规模数据集时。Scikit-learn&#xff08;sklearn&#xff09;提供…...

PostgreSQL 中如何处理数据的唯一性约束?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中如何处理数据的唯一性约束&#xff1f;一、什么是唯一性约束二、为什么要设置唯一性约束…...

VAE论文阅读

在网上看到的VAE解释&#xff0c;发现有两种版本&#xff1a; 按照原来论文中的公式纯数学推导&#xff0c;一般都是了解生成问题的人写的&#xff0c;对小白很不友好。按照实操版本的&#xff0c;非常简单易懂&#xff0c;比如苏神的。但是却忽略了论文中的公式推导&#xff…...

【数据分享】2013-2022年我国省市县三级的逐月SO2数据(excel\shp格式\免费获取)

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000——2022年的省市县三级的逐月PM2.5数据和2013-2022年的省市县三级的逐月CO数据&#xff08;均可查看之前的文章获悉详情&#xff09;&#xff01; 本次我们分享的是我国2013——2022年的省…...

【Jmeter】记录一次Jmeter实战测试

Jmeter实战 1、需求2、实现2.1、新建线程组2.2、导入参数2.3、新建HTTP请求2.4、添加监听器2.5、结果 1、需求 查询某个接口在高并发场景下的响应时间(loadtime)&#xff0c;需求需要响应在50ms以内&#xff0c;接下来用Jmeter测试一下 Jmeter安装见文章《Jemeter安装教程&am…...

volatile,最轻量的同步机制

目录 一、volatile 二、如何使用&#xff1f; 三、volatile关键字能代替synchronized关键字吗&#xff1f; 四、总结&#xff1a; 还是老样子&#xff0c;先来看一段代码&#xff1a; 我们先由我们自己的常规思路分析一下代码&#xff1a;子线程中&#xff0c;一直循环&…...

在Linux、Windows和macOS上释放IP地址并重新获取新IP地址的方法

文章目录 LinuxWindowsmacOS 在Linux、Windows和macOS上释放IP地址并重新获取新IP地址的方法各有不同。以下是针对每种操作系统的详细步骤&#xff1a; Linux 使用DHCP客户端&#xff1a;大多数Linux发行版都使用DHCP&#xff08;动态主机配置协议&#xff09;来自动获取IP地址…...

Mamba-yolo|结合Mamba注意力机制的视觉检测

一、本文介绍 PDF地址&#xff1a;https://arxiv.org/pdf/2405.16605v1 代码地址&#xff1a;GitHub - LeapLabTHU/MLLA: Official repository of MLLA Demystify Mamba in Vision: A Linear AttentionPerspective一文中引入Baseline Mamba&#xff0c;指明Mamba在处理各种高…...

语音识别标记语言(SSML):自动标识中文多音字

好的&#xff0c;以下是完整的实现代码&#xff0c;包括导入库、分词、获取拼音和生成 SSML 标记的全过程&#xff1a; import thulac from pypinyin import pinyin, Style# 初始化 THULAC thu1 thulac.thulac(seg_onlyTrue)# 测试文本 text "银行行长正在走行。"…...

排序算法与复杂度介绍

1. 排序算法 1.1 排序算法介绍 排序也成排序算法&#xff08;Sort Algorithm&#xff09;&#xff0c;排序是将一组数据&#xff0c;依照指定的顺序进行排序的过程 1.2 排序的分类 1、内部排序&#xff1a; 指将需要处理的所有数据都加载到**内部存储器&#xff08;内存&am…...

Kafka介绍及Go操作kafka详解

文章目录 Kafka介绍及Go操作kafka详解项目背景解决方案面临的问题业界方案ELKELK方案的问题日志收集系统架构设计架构设计组件介绍将学到的技能消息队列的通信模型点对点模式 queue发布/订阅 topicKafka介绍Kafka的架构图工作流程选择partition的原则ACK应答机制Topic和数据日志…...

DAY05 CSS

文章目录 1 CSS选择器(Selectors)8. 后代(包含)选择器9. 直接子代选择器10. 兄弟选择器11. 相邻兄弟选择器12. 属性选择器 2 伪元素3 CSS样式优先级1. 相同选择器不同样式2. 相同选择器相同样式3. 继承现象4. 选择器不同权值的计算 4 CSS中的值和单位1. 颜色表示法2. 尺寸表示法…...

HTTPS 的加密过程 详解

HTTP 由于是明文传输&#xff0c;所以安全上存在以下三个风险&#xff1a; 窃听风险&#xff0c;比如通信链路上可以获取通信内容。篡改风险&#xff0c;比如通信内容被篡改。冒充风险&#xff0c;比如冒充网站。 HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议&#xff0c…...

spring整合mybatis,junit纯注解开发(包括连接druid报错的所有解决方法)

目录 Spring整合mybatis开发步骤 第一步&#xff1a;创建我们的数据表 第二步&#xff1a;编写对应的实体类 第三步&#xff1a;在pom.xml中导入我们所需要的坐标 spring所依赖的坐标 mybatis所依赖的坐标 druid数据源坐标 数据库驱动依赖 第四步&#xff1a;编写SpringC…...

ClusterIP、NodePort、LoadBalancer 和 ExternalName

Service 定义 在 Kubernetes 中&#xff0c;由于Pod 是有生命周期的&#xff0c;如果 Pod 重启它的 IP 可能会发生变化以及升级的时候会重建 Pod&#xff0c;我们需要 Service 服务去动态的关联这些 Pod 的 IP 和端口&#xff0c;从而使我们前端用户访问不受后端变更的干扰。 …...

【Day1415】Bean管理、SpringBoot 原理、总结、Maven 高级

0 SpringBoot 配置优先级 从上到下 虽然 springboot 支持多种格式配置文件&#xff0c;但是在项目开发时&#xff0c;推荐统一使用一种格式的配置 &#xff08;yml是主流&#xff09; 1 Bean管理 1.1 从 IOC 容器中获取 Bean 1.2 Bean 作品域 可以通过注解 Scope("proto…...

Git之repo sync -c与repo sync -dc用法区别(四十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

vite + vue3 + uniapp 项目从零搭建

vite + vue3 + uniapp 项目从零搭建 1、创建项目1.1、创建Vue3/vite版Uniapp项目1.2、安装依赖1.3、运行项目2、弹出 用户隐私保护提示 方法2.1、更新用户隐私保护指引 和 修改配置文件2.2、授权结果处理方法3、修改`App.vue`文件内容4、处理报`[plugin:uni:mp-using-component…...

在CentOS中配置三个节点之间相互SSH免密登陆

在CentOS中配置三个节点&#xff08;假设分别为node1、node2、node3&#xff09;两两之间相互SSH免密登陆&#xff0c;可以按照以下步骤进行&#xff1a; 一、生成密钥对 在所有节点上生成密钥对&#xff1a; 在每个节点&#xff08;node1、node2、node3&#xff09;上执行以…...

arm 内联汇编基础

一、 Arm架构寄存器体系熟悉 基于arm neon 实现的代码有 intrinsic 和inline assembly 两种实现。 1.1 通用寄存器 arm v7 有 16 个 32-bit 通用寄存器&#xff0c;用 r0-r15 表示。 arm v8 有 31 个 64-bit 通用寄存器&#xff0c;用 x0-x30 表示&#xff0c;和 v7 不一样…...

Java语言程序设计——篇五(1)

数组 概述数组定义实例展示实战演练 二维数组定义数组元素的使用数组初始化器实战演练&#xff1a;矩阵计算 &#x1f4ab;不规则二维数组实战演练&#xff1a;杨辉三角形 概述 ⚡️数组是相同数据类型的元素集合。各元素是有先后顺序的&#xff0c;它们在内存中按照这个先后顺…...

【香橙派开发板测试】:在黑科技Orange Pi AIpro部署YOLOv8深度学习纤维分割检测模型

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ Orange Pi AIpro开发板相关介绍1.1 &#x1f393; 核心配置1.2 ✨开发板接口详情图1.3 ⭐️开箱展示 二、2️⃣配置开发板详细教程2.1 &#x1f393; 烧录镜像系统2.2 ✨配置网络2.3 ⭐️使用SSH连接主板 三、…...

集成学习在数学建模中的应用

集成学习在数学建模中的应用 一、集成学习概述&#xff08;一&#xff09;基知&#xff08;二&#xff09;相关术语&#xff08;三&#xff09;集成学习为何能提高性能&#xff1f;&#xff08;四&#xff09;集成学习方法 二、Bagging方法&#xff08;一&#xff09;装袋&…...

WebKit 的 Web SQL 数据库:现代浏览器的本地存储解决方案

WebKit 的 Web SQL 数据库&#xff1a;现代浏览器的本地存储解决方案 随着Web应用的不断发展&#xff0c;对本地存储的需求也日益增加。WebKit作为许多现代浏览器的核心引擎&#xff0c;提供了一种强大的本地存储解决方案&#xff1a;Web SQL 数据库。本文将详细探讨Web SQL 数…...

Yolo-World网络模型结构及原理分析(三)——RepVL-PAN

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1. 网络结构2. 特征融合3. 文本引导&#xff08;Text-guided&#xff09;4. 图像池化注意力&#xff08;Image-Pooling Attention&#xff09;5. 区域文本匹配&…...

代码随想录——一和零(Leetcode474)

题目链接 0-1背包 class Solution {public int findMaxForm(String[] strs, int m, int n) {// 本题m&#xff0c;n为背包两个维度// dp[i][j]:最多右i个0和j个1的strs的最大子集大小int[][] dp new int[m 1][n 1];// 遍历strs中字符串for(String str : strs){int num0 …...

力扣题解(组合总和IV)

377. 组合总和 Ⅳ 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 思路&#xff1a; 本题实质上是给一些数字&#xff0c;让他们在满足和是targ…...

Postgresql主键自增的方法

Postgresql主键自增的方法 一.方法&#xff08;一&#xff09; 使用 serial PRIMARY KEY 插入数据 二.方法&#xff08;二&#xff09; &#x1f388;边走、边悟&#x1f388;迟早会好 一.方法&#xff08;一&#xff09; 使用 serial PRIMARY KEY 建表语句如下&#xf…...

【源码阅读】Sony的go breaker熔断器源码探究

文章目录 背景源码分析总结 背景 在微服务时代&#xff0c;服务和服务之间调用、跨部门调用都是很常见的事&#xff0c;但这些调用都存在很多不确定因素&#xff0c;如核心服务A依赖的部门B服务挂掉了&#xff0c;那么A本身的功能将会受到直接的影响&#xff0c;而这些都会影响…...

LeetCode题(66,69,35,88)--《c++》

66.加一 // // Created by wxj05 on 2024/7/20. // //法一 class Solution { public:vector<int> plusOne(vector<int>& digits) {bool carry true; // 进位标志for (int i digits.size() - 1; i > 0 && carry; --i) {digits[i] 1;carry digit…...

来参与“向日葵杯”全国教育仿真技术大赛~

可点击进行了解&#xff1a;“向日葵杯”全国教育仿真技术大赛 (sunmooc.cn) 本次大赛共分为四个赛道&#xff1a;自主命题赛道、教育知识图谱设计赛道、FPGA硬件扑克牌对抗赛道、EasyAR元宇宙空间设计赛道。 参赛对象 &#xff1a; 具有正式学籍的在校研究生&#xff0c;本科…...

SQL每日一题:删除重复电子邮箱

题干 表: Person -------------------- | Column Name | Type | -------------------- | id | int | | email | varchar | -------------------- id 是该表的主键列(具有唯一值的列)。 该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。 编写解决方案 删除 所有重复…...

3、宠物商店智能合约实战(truffle智能合约项目实战)

3、宠物商店智能合约实战&#xff08;truffle智能合约项目实战&#xff09; 1-宠物商店环境搭建、运行2-webjs与宠物逻辑实现3-领养智能合约初始化4-宠物领养实现5-更新宠物领养状态 1-宠物商店环境搭建、运行 https://www.trufflesuite.com/boxes/pet-shop 这个还是不行 或者…...

数据库系列

目录 一、数据库的概念和作用 1.数据库的特点 2.数据模型 二、数据库系统 1.数据库管理系统 2.数据库的基本操作 一、数据库的概念和作用 数据库是指长期存储在计算机内&#xff0c;有组织的、可共享的数据集合。它可视为一个电子化的文件柜&#xff0c;用来存储电子文件…...

极狐GitLab如何启用和配置PlantUML?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…...

Shell 构建flutter + Android 生成Apk

具体步骤 #shell 具体实现和说明如下: echo "build_start_apk!" echo "编译此脚本的前提条件如下:" #在Android 项目的主工程下,进入主工程文件夹,创建build-android 文件夹,在其文件夹下有build-android.sh文件,此文件就是整个文章的脚本内容(…...