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

ResNet论文阅读和简单实现

论文:https://arxiv.org/pdf/1512.03385.pdf

Deep Residual Learning for Image Recognition

本模块主要是阅读论文,会做简单的翻译(至少满足我自己能看明白)。

Introduction

由上图可见,在20层和56层的网络上训练的训练误差和测试误差的变化,可以看到层数加深不一定能带来性能上的提升,甚至更糟了。这就引出了文章的疑问(有些和直觉相反的结论):为什么不是层数约多,结果越好呢?文中给出的解释是:梯度消失/爆炸问题从一开始就阻碍了收敛,虽然这一问题已经通过normalized initialization和intermediate normalization layers在很大程度上得到了解决,这使得几十层的网络可以收敛,但是当层数逐渐增加,出现了“退化”问题(degradation)。这里的“退化”指的是,随着网络的加深,accuracy先逐渐升高到达饱和,然后迅速衰退。文中指出这一问题并非由过拟合导致(并不是模型过于复杂)。这一问题也说明了,我们并不能简单的认为通过堆叠层数来优化模型。

论文中通过引入一个deep residual learning框架(深度残差)。并不使用简单堆叠层数来获得一个满意的潜在映射,而是让这些层复合残差映射。

定义:

H(x):满意的潜在映射

F(x):堆叠的非线性层产生的映射,并且满足关系F(x) := H(x) - x

原始映射:F(x) + x

假设优化残差映射要比优化原始映射更容易。极端点来说,对于一个恒等映射,将残差推到0要比吧非线性层推到0更简单(不记得在哪里听到过,理论上,通过增加层数的方法来改善模型非常符合直觉,因为我们直觉上觉得可以无限的加y=x这样的变换,来无限制的增加层数。但是就像论文中描写的那样,我们并没有得到更高的准确度,而是出现了退化现象,这可能是因为DL太善于计算非线性了,反而没办法在线性上给一个比较好的表现,我觉得这是一个直觉上比较好的解释,故在此记录)。

F(x) + x这一形式在前馈神经网络中可以采用“shortcut connections”来实现。这里所谓的“shortcut connections”指的是跳过一层或多层。在本文中,这种连接仅仅是做“identity mapping”(恒等映射:在数学中,指一个函数将每个元素映射到其自身,即输入和输出相等的映射。),这一做法并不会增加额外的参数,也不会增加计算的复杂度(反正y=x也没什么影响,也没必要更新),这就使得整个网络仍然可以采用反向传播SGD进行end-to-end的训练。文章中提到,采用的152层的网络虽然比之前的VGG网络要深,但是实际上并没有那么复杂。

Deep Residual Learning

Residual Learning

在前面的定义中(H(x):满意的潜在映射)。让我们先把H(x)看做是由几个堆叠的层拟合的潜在映射(这里的几个不一定指的是整个网络),那么此时x表示的就是这些层中第一层的输入。假设多个非线性层可以逐渐逼近residual function(即H(x)- x,假设输入和输出的dimension相同,这里看起来有点autoencoder那个感觉)。因此,与其期待用堆叠的层去近似H(x),不如让这些层去拟合residual function F(x) := H(x) - x。尽管这两种形式都应该能够渐进地逼近所需的函数(如假设的那样),但学习的难易程度可能有所不同。

简单来说就是,不再直接的拟合函数,而是拟合残差函数,并且这么做的原因是这样更容易学。

如果添加的层可以构造为identity mapping(恒等映射),那么较深的模型的训练误差不应该大于较浅的模型。退化问题表明,在逼近多个非线性层的恒等映射时可能存在困难。使用residual方法之后,如果恒等映射是最优的,那么就可以简单的把多个非线性层的权重向0逼近,这就近似于恒等变换。

Identity Mapping by Shortcuts

对每个堆叠在一起的层(every few stacked layers)使用residual learning,构建出building block。将这个building block定义为:

y = F(x, {W_i}) + x

x, y:对应的堆叠在一起的层的输入和输出。

F(x, {W_i}):学到的residual mapping(我们最后想得到的是H(x),但是这里学到的是F(x, {W_i}),也就是H(x) - x,但是没有关系,我们最后输出的是F(x, {W_i}) + x,也就是H(x) - x + x,这种思路很像小时候做那种数列找规律求和,虽然直接算很难算,但是可以加上一项之后先算出来结果,最后再把加上来的项去掉)

在figure 2中,我们有两层,也就是F = W_2\sigma(W_1x),这里σ代表ReLU,为了简化,这里省略了bias。F+x采用shortcut connection和element-wise addition(简单来说就是直接拽过来加上,既然要拽过来直接加,那么一定要满足维度的一致)。这种方法既不引入额外的参数,也不增加计算复杂度。那么如果我们要改变输入输出的通道数时,可以执行一个线性投影:

y = F(x, \left \{ {W_i} \right \}) + W_s x

F(x, {W_i})可以表示多层的卷积。

Network Architectures

卷积层大多具有3×3滤波器,并遵循两个简单的设计规则:(i)对于相同的输出特征图大小,各层具有相同数量的滤波器;(ii)如果特征图大小减半,则滤波器的数量增加一倍,以保持每层的时间复杂度。我们通过步长为2的卷积层直接执行下采样。网络以一个全局平均池化层和一个带有softmax的1000路全连接层结束。图3(中)加权层总数为34层。

对中间的plain network,增加shortcut connections,就能改成residual版本。当输入输出维度相同时,可以直接使用identity shortcut(Eqn.(1))(y = F(x, {W_i}) + x)
当维度增加时(图3中的虚线快捷方式),我们考虑两个方案:
(A)快捷方式仍然执行恒等映射,为增加维度填充额外的0。这个方案不引入额外的参数;
(B) y = F(x, \left \{ {W_i} \right \}) + W_s x中的投影shortcut用于匹配维度(通过1×1卷积完成)。

对于这两个方案,当快捷键跨越两个大小的特征映射时,它们的步幅为2。

Implementation

从图像或其水平翻转中随机采样224×224裁剪,并减去每像素平均值。使用中的标准颜色增强。在每次卷积之后和激活之前采用批归一化(BN)。初始化权重,并从头开始训练所有的plain/residual网络。使用SGD的小批量大小为256。学习率从0.1开始,当误差趋于平稳时除以10,模型的训练次数可达60 × 104次。

Experiments

Deeper Bottleneck Architectures

对于每个残差函数F,我们使用3层而不是2层的(图5)。这三层是1×1, 3×3和1×1卷积,其中1×1层负责减少然后增加(恢复)维度,使3×3层成为输入/输出维度较小的瓶颈。图5给出了一个例子,其中两种设计具有相似的时间复杂度。无参数标识快捷方式对于瓶颈体系结构尤其重要。如果将图5(右)中的标识快捷方式替换为投影,可以看出,由于shortcut连接到两个高维端点,时间复杂度和模型尺寸都增加了一倍。

关于论文的理解

卷积后特征图尺寸变化:H_out = (H_in + 2P - K) / S + 1

转载神经网络学习小记录20——ResNet50模型的复现详解_resnet50复现-CSDN博客末尾的resnet50结构图

同时针对之前论文中的结构图,要说明的是,有部分内容上面的结构图和论文都没有直接说明,比如conv1_x中需要加padding,否则(224-7)/2+1是没办法成112的,这里padding=3,conv2_x中stride=1,其他stride=2(比如56->28,(56-1)/2+1=28)

注意,在每一个小的block里面有些直接计算发现数字不对的,都是加了padding。

比如,conv2_x里面3×3那个就加了padding=1

代码实现

1

参考:https://www.youtube.com/watch?v=DkNIBBBvcPs

import torch
import torch.nn as nnclass block(nn.Module):def __init__(self, inchannels, out_channels, identity_downsample=None, stride=1):super(block, self).__init__()# 每一个resnet的block的输入和输出的通道数的比值都是1/4,也就是说通道数扩大了4倍self.expension = 4self.conv1 = nn.Conv2d(inchannels, outchannels, kernel_size=1, stride=1, padding=0)self.bn1 = nn.BatchNorm2d(out_channels)self.conv2 = nn.Conv2d(outchannels, outchannels, kernel_size=3, stride=stride, padding=1)self.bn2 = nn.BatchNorm2d(out_channels)self.conv3 = nn.Conv2d(outchannels, outchannels*self.expansion, kernel_size=1, stride=1, padding=0)self.bn3 = nn.BatchNorm2d(out_channels*self.expansion)self.relu = nn.ReLU()self.identity_downsample = identity_downsampledef forward(self, x):identity = xx = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.conv2(x)x = self.bn2(x)x = self.relu(x)x = self.conv3(x)x = self.bn3(x)if self.identity_downsample is not None:identity = self.identity_downsample(identity)# 方案A or 方案Bx += identityx = self.relu(x)return xclass ResNet(nn.Module):def __init__(self, block, layers, image_channels, num_classes):super(ResNet, self).__init__()# 在res50中block的堆叠是3 4 6 3# conv1_x# 刚刚输入的时候channel是3,在这里conv一下转成64self.in_channels = 64self.conv1 = nn.Conv2d(image_channels, 64, kernel_size=7, stride=2, padding=3)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU()# conv2_xself.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# 理论上我们在这里就可以开始一层一层写了,比如:# self.layer1 = ...# self.layer2 = ...# 直接定义一个函数替我们写self.layer1 = self._make_layer(block, layer[0], out_channel=64, stride=1)self.layer2 = self._make_layer(block, layer[1], out_channel=128, stride=2)self.layer3 = self._make_layer(block, layer[2], out_channel=256, stride=2)self.layer4 = self._make_layer(block, layer[3], out_channel=512, stride=2)self.avgpool = nn.AdaptiveAvgPool2d((1,1))self.fc = nn.Linear(512*4, num_classes)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avgpool(x)x = x.reshape(x.shape[0], -1)x = self.fc(x)return xdef _make_layer(self, block, num_residual_block, out_channels, stride):identity_downsample = Nonelayers = []# 如果不能直接相加(channel数量变化了)# 比如说conv2_x中的第一个block,输入64输出256,这种显然没办法把64硬加到256上if stride != 1 or self.inchannels != out_channels*4:identity_downsample = nn.Sequential(nn.Conv2(self.in_channels, out_channels*4, kernel_size=1,stride=1),nn.BatchNorm2d(out_channels*4))layers.append(block(self.inchannels, out_channels, identity_downsample, stride))self.inchannels = out_channels*4for i in range(num_residual_block-1):layers.append(block(self.in_channels, out_channels))return nn.Sequential(*layers)def ResNet50(img_channels, num_classes=1000):return ResNet(block, [3,4,6,3], img_channels, num_classes)

2

神经网络学习小记录20——ResNet50模型的复现详解_resnet50复现-CSDN博客

https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py

ResNet50 with PyTorch | Kaggle

GitHub - JayPatwardhan/ResNet-PyTorch: Basic implementation of ResNet 50, 101, 152 in PyTorch

3

Writing ResNet from Scratch in PyTorch

与1中的类似,引用如下:

class ResidualBlock(nn.Module):def __init__(self, in_channels, out_channels, stride = 1, downsample = None):super(ResidualBlock, self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size = 3, stride = stride, padding = 1),nn.BatchNorm2d(out_channels),nn.ReLU())self.conv2 = nn.Sequential(nn.Conv2d(out_channels, out_channels, kernel_size = 3, stride = 1, padding = 1),nn.BatchNorm2d(out_channels))self.downsample = downsampleself.relu = nn.ReLU()self.out_channels = out_channelsdef forward(self, x):residual = xout = self.conv1(x)out = self.conv2(out)if self.downsample:residual = self.downsample(x)out += residualout = self.relu(out)return outclass ResNet(nn.Module):def __init__(self, block, layers, num_classes = 10):super(ResNet, self).__init__()self.inplanes = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size = 7, stride = 2, padding = 3),nn.BatchNorm2d(64),nn.ReLU())self.maxpool = nn.MaxPool2d(kernel_size = 3, stride = 2, padding = 1)self.layer0 = self._make_layer(block, 64, layers[0], stride = 1)self.layer1 = self._make_layer(block, 128, layers[1], stride = 2)self.layer2 = self._make_layer(block, 256, layers[2], stride = 2)self.layer3 = self._make_layer(block, 512, layers[3], stride = 2)self.avgpool = nn.AvgPool2d(7, stride=1)self.fc = nn.Linear(512, num_classes)def _make_layer(self, block, planes, blocks, stride=1):downsample = Noneif stride != 1 or self.inplanes != planes:downsample = nn.Sequential(nn.Conv2d(self.inplanes, planes, kernel_size=1, stride=stride),nn.BatchNorm2d(planes),)layers = []layers.append(block(self.inplanes, planes, stride, downsample))self.inplanes = planesfor i in range(1, blocks):layers.append(block(self.inplanes, planes))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.maxpool(x)x = self.layer0(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.avgpool(x)x = x.view(x.size(0), -1)x = self.fc(x)return xnum_classes = 10
num_epochs = 20
batch_size = 16
learning_rate = 0.01model = ResNet(ResidualBlock, [3, 4, 6, 3]).to(device)# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, weight_decay = 0.001, momentum = 0.9)  # Train the model
total_step = len(train_loader)
Layers in PyTorch

Now coming to the different types of layers available in PyTorch that are useful to us:

  • nn.Conv2d: These are the convolutional layers that accepts the number of input and output channels as arguments, along with kernel size for the filter. It also accepts any strides or padding if we want to apply those
  • nn.BatchNorm2d: This applies batch normalization to the output from the convolutional layer
  • nn.ReLU: This is a type of  activation function applied to various outputs in the network
  • nn.MaxPool2d : This applies max pooling to the output with the kernel size given
  • nn.Dropout: This is used to apply dropout to the output with a given probability
  • nn.Linear: This is basically a fully connected layer
  • nn.Sequential: This is technically not a type of layer but it helps in combining different operations that are part of the same step

看起来和之前的resnet50不太一样的原因是这里是34层的。

因此这里没有313这样的结构了。但是本质上是一样的。

————————————————————————————

一些题外话,虽然在很多地方看到说resnet已经是很老的模型了,但是相比于之前的CNN方法而言,在方法上确实是非常厉害的创新,虽然现在似乎CNN已经被调侃的像上世纪的产物了orz。似乎现在已经是transformer的天下了……

相关文章:

ResNet论文阅读和简单实现

论文:https://arxiv.org/pdf/1512.03385.pdf Deep Residual Learning for Image Recognition 本模块主要是阅读论文,会做简单的翻译(至少满足我自己能看明白)。 Introduction 由上图可见,在20层和56层的网络上训练的…...

QT上位机开发(数据库sqlite编程)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 编写软件的时候,如果用户的数据比较少,那么用json保存是非常方便的。但是一旦数据量大了之后,建议还是用数据库…...

在ARMv8中aarch64与aarch32切换

需求描述 在项目调试过程中,由于内存或磁盘空间不足需要将系统从aarch64切换到aarch32的运行状态去执行,接下来记录cortexA53的调试过程。 相关寄存器描述 ARM64: SPSR_EL3 N (Negative):表示运算结果的最高位,用于指示运算结果是否为负数。 Z (Zero):表示运算结果是否…...

拧巴的 tcp

本来想说说 tcp fastopen(tfo),但没什么意义,看 rfc7413 好了,还是 tcp 的惯常套路,引入一个新特性,解决了某个问题,带来一些新问题,然后就是各种 tradeoff,哪里适用哪里不适用。久而…...

java servlet 学生管理系统myeclipse开发oracle数据库BS模式java编程网

一、源码特点 java servlet 学生管理系统是一套完善的web设计系统,对理解JSP java编程开发语言有帮助servletbeandao (mvc模式开发),系统具有完整的源代码和数据库,开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Oracle 10g…...

使用buildx构建多架构镜像

使用buildx构建多架构镜像 1. 前置条件 docker 19.03以上版本 ubuntu 22.04 2. 安装相关组件 2.1 安装docker sudo apt-get updatesudo apt-get install \apt-transport-https \ca-certificates \curl \gnupg-agent \software-properties-commoncurl -fsSL https://mirrors.…...

Crow:run的流程4 准备接收http请求

完成tcp的accept后,下一步需要接收tcp的数据,同时完成http的分析 class Connection { public:void start(){adaptor_.start([this](const asio::error_code& ec) {if (!ec){start_deadline();parser_.clear();do_read();}else{CROW_LOG_ERROR << "Could not …...

Springboot集成RabbitMq一

0、知识点 1、创建项目-生产者 默认官方start.spring.io已不支持自动生成低版本jkd的Spring项目&#xff0c;自定义用阿里云的starter即可&#xff1a;https://start.aliyun.com 2、创建配置类 package com.wym.rabbitmqprovider.utils;import org.springframework.amqp.core.…...

零知识证明(zk-SNARK)- groth16(一)

全称为 Zero-Knowledge Succinct Non-Interactive Argument of Knowledge&#xff0c;简洁非交互式零知识证明&#xff0c;简洁性使得运行该协议时&#xff0c;即便 statement 非常大&#xff0c;它的 proof 大小也仅有几百个bytes&#xff0c;并且验证一个 proof 的时间可以达…...

Spring java和go并发的实现策略

Spring Java框架和Go框架在处理并发请求时采用了不同的策略。 1. Spring Java框架&#xff1a; Spring框架基于Java语言&#xff0c;通常使用线程池来处理并发请求。具体来说&#xff0c;Spring框架中的Servlet容器&#xff08;如Tomcat、Jetty等&#xff09;会使用线程池来管…...

第二十五章 JDBC 和数据库连接池

一、JDBC 概述&#xff08;P821&#xff09; 1. 基本介绍 &#xff08;1&#xff09;JDBC 为访问不同的数据库提供了统一的接口&#xff0c;为使用者屏蔽了细节问题。 &#xff08;2&#xff09;Java 程序员使用 JDBC&#xff0c;可以连接任何提供了 JDBC 驱动程序的数据库系统…...

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率(C++)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的固定帧率功能的技术背景CameraExplorer如何查看相机固定帧率功能在NEOAPI SDK里通过函数设置相机固定帧率 Baumer工业相机通过NEOAPI SDK设置相机固定…...

基于Java课堂签到系统

基于Java课堂签到系统 功能需求 1、用户登录&#xff1a;学生需要使用学号或手机号等唯一标识登录系统。 2、签到功能&#xff1a;在课堂开始时&#xff0c;学生可以通过系统进行签到&#xff0c;以证明出席。 3、签出功能&#xff1a;在课堂结束时&#xff0c;学生可以通过…...

springboot整合webservice使用总结

因为做的项目中用到了webservice,所以在此总结一下。 一、webservice简介 Web Service也叫XML Web Service, WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求&#xff0c;轻量级的独立的通讯技术。是通过SOAP在Web上提供的软件服务&#xff0c;使…...

MySQL中的索引之分类,原理,作用,优缺点和执行计划

索引 索引的作用&#xff1a;加速查找 例如: 300w条数据的表中查询&#xff0c;无索引需要700s, 利用索引可能只需要1s用索引的时机是&#xff0c;数据量巨大&#xff0c;并且搜索快速 索引为什么能实现加速查找 基于索引的内部存储结构索引底层基于 BTree 的数据结构存储的在…...

如何做好档案数字化前的鉴定工作

要做好档案数字化前的鉴定工作&#xff0c;可以按照以下步骤进行&#xff1a; 1. 确定鉴定目标&#xff1a;明确要鉴定的档案的内容、数量和性质&#xff0c;确定鉴定的范围和目标。 2. 进行档案清点&#xff1a;对档案进行全面清点和登记&#xff0c;包括数量、种类、状况等信…...

pytorch04:网络模型创建

目录 一、模型创建过程1.1 以LeNet网络为例1.2 LeNet结构1.3 nn.Module 二、网络层容器(Containers)2.1 nn.Sequential2.1.1 常规方法实现2.1.2 OrderedDict方法实现 2.2 nn.ModuleList2.3 nn.ModuleDict2.4 三种容器构建总结 三、AlexNet网络构建 一、模型创建过程 1.1 以LeNe…...

用js让用户输入一个数累加和

需求&#xff1a;用户输入一个数&#xff0c; 计算 1 到这个数的和。 比如 用户输入的是 5&#xff0c; 则计算 1~5 之间的累加和 并且输出到控制台 <body><script>let numprompt(请输入一个数)let sum0for(let i1;i<num;i){sumi}console.log(sum)</script…...

踩坑记录-安装nuxt3报错:Error: Failed to download template from registry: fetch failed;

报错复现 安装nuxt3报错&#xff1a;Error: Failed to download template from registry: fetch failednpx nuxi init nuxt-demo 初始化nuxt 项目 报错 Error: Failed to download template from registry: fetch faile 解决方法 配置hosts Mac电脑&#xff1a;/etc/hostswin电…...

大数据学习(31)-Spark非常用及重要特性

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…...

【教学类-43-14】 20240103 (4宫格数独:正确版:576套) 不重复的基础模板数量:576套

作品展示&#xff1a;&#xff1a;——4宫格 576套不重复模板&#xff08;48页*12套题&#xff09; 背景需求&#xff1a; 生成4宫格基础模板768套&#xff0c;观看64页内容时&#xff0c;明显看到有错误 【教学类-43-13】 20240103 &#xff08;4宫格数独&#xff1a;错误版…...

AIGC开发:调用openai的API接口实现简单机器人

简介 开始进行最简单的使用&#xff1a;通过API调用openai的模型能力 OpenAI的能力如下图&#xff1a; 文本生成模型 OpenAI 的文本生成模型&#xff08;通常称为生成式预训练 Transformer 或大型语言模型&#xff09;经过训练可以理解自然语言、代码和图像。这些模型提供文…...

c基础(二)

指针&#xff1a; 含义&#xff1a;是一个值&#xff0c;一个值代表着一个内存地址&#xff0c;类似于存放路径 * 运算符 &#xff1a; 1 字符*表示指针 作用&#xff1a;通常跟在类型关键字的后面&#xff0c;表示指针指向的是什么类型的值 int * foo, * bar;声明指针后会…...

人工智能趋势报告解读:ai野蛮式生长的背后是机遇还是危机?

近期&#xff0c;Enterprise WordPress发布了生成式人工智能在营销中的应用程度的报告&#xff0c;这是一个人工智能迅猛发展的时代&#xff0c;目前人工智能已经广泛运用到内容创作等领域&#xff0c;可以预见的是人工智能及其扩展应用还将延伸到我们工作与生活中的方方面面。…...

三、C语言中的分支与循环—goto语句 (10) (完)

在C语言中&#xff0c;goto语句允许程序无条件地跳转到同一函数内的标记位置。这个标记位置通过一个标签和冒号(:)来标示。goto语句可以用于从深层嵌套的循环或条件语句中直接跳出&#xff0c;或者跳过某些代码执行。尽管goto语句在某些情况下可以使程序逻辑变得清晰&#xff0…...

RabbitMQ 常见问题

1. 如何保证消息顺序消费 在RabbitMQ中&#xff0c;消息最终会保存在队列中&#xff0c;在同一个队列中&#xff0c;消息是顺序的&#xff0c;保持先进先出的原则&#xff0c;这个由Rabbitmq保证。而不同队列中的消息&#xff0c;RabbitMQ 是无法保证其顺序性。顺序消费主要是…...

阶段二-Day10-日期类

日期类结构: 1.java.util.Date是日期类 2.DateFormat是日期格式类、SimpleDateFormat是日期格式类的子类 Timezone代表时区 3.Calendar是日历类&#xff0c;GregorianCalendar是日历的子类 一. 常用类-Date 1.1 Date构造方法 Date(long date) 使用给定的毫秒时间价值构建…...

多任务并行处理相关面试题

我自己面试时被问过两次多任务并行相关的问题&#xff1a; 假设现在有10个任务&#xff0c;要求同时处理&#xff0c;并且必须所有任务全部完成才返回结果 这个面试题的难点是&#xff1a; 既然要同时处理&#xff0c;那么肯定要用多线程。怎么设计多线程同时处理任务呢&…...

Shell脚本学习笔记

1. 写在前面 工作中&#xff0c;需要用到写一些shell脚本去完成一些简单的重复性工作&#xff0c; 于是就想系统的学习下shell脚本的相关知识&#xff0c; 本篇文章是学习shell脚本整理的学习笔记&#xff0c;内容参考主要来自C语言中文网&#xff0c; 学习过程中&#xff0c;…...

ROS-安装xacro

安装 运行下列命令进行安装&#xff0c;xxxxxx处更改为自己的版本 sudo apt-get install ros-xxxxxx-xacro运行 输入下列命令 roscd xacro如果没有报错&#xff0c;并且进入了xacro软件包的目录&#xff0c;则表示安装成功。 参考&#xff1a; [1]https://wenku.csdn.net/ans…...

北京网站制作公司都在哪里/商业推广软文范例

一.应用知识点1.2实验知识点div布局CSS相对定位CSS各种属性的应用1.3实验环境本实验环境采用带桌面的Ubuntu Linux环境&#xff0c;实验中可能会用到桌面上的程序&#xff1a;Firefox&#xff1a;浏览器&#xff0c;可以用在需要前端界面的课程里&#xff0c;只需要打开环境里写…...

代理商门户网站开发/佛山seo外包平台

收集整理自网络&#xff0c;出处不详。 由于[GOF95]是论述软件模式的著作的第一本&#xff0c;也是OO设计理论著作中最流行的一本&#xff0c;因此有些人常常使用设计模式&#xff08;Design Pattern&#xff09;一词来指所有直接处理软件的架构、设计、程序实现的任何种类的模…...

phpcms 网站根目录/网络营销渠道策略研究

获取所有的dom元素的方法:...

用yii框架做的网站如何搭建/seo客服

血型这东西似乎有点神秘。说它有点神秘&#xff0c;是因为人体本身就是一个未解的谜&#xff0c;人身上还有很多物质和现象没有被揭秘。关于血型&#xff0c;目前也只知道它是一种遗传物质&#xff0c;并按特定的遗传规律———孟德尔遗传规律传给后代。日本一些学者认为&#…...

wordpress加友情链接/新闻软文范例大全

1&#xff0c;首先&#xff0c;需要确保 /var/www/html/wp-config.php 中的mysql 账号、密码、主机、以及数据库名是否配置正确&#xff1a; 2&#xff0c;1确定没问题&#xff0c;ps aux | grep mysql确保mysql 服务是否在运行&#xff1b; 3&#xff0c;【1&#xff0c;2都…...

如何查一个网站有没有做外链/分享几个x站好用的关键词

2.1 数据类型 类型基础&#xff1a; 2.2 类型比较和转换 相等运算符&#xff08;判断两个操作数没有相同的值&#xff09;和严格相等&#xff08;判断两个操作数有没有相同的值以及是否为相同的数据类型&#xff09; 2.3 函数 基本概念&#xff1a; 函数作用域&#xff1a; …...