DETR:End-to-End Object Detection with Transformers
【DETR 论文精读【论文精读】-哔哩哔哩】 https://b23.tv/Iy9k4O2
【DETR源码解读4-哔哩哔哩】 https://b23.tv/Qp1uH5v
摘要:
将目标检测看作一个集合预测的问题
任务:给定一张图片,预测一组框,每个框需要得到坐标信息和包含的物体类别信息,将框可以视为集合,不同图片所对应的框不同,则所对应的集合就不同
去除:NMS、生成anchor
创新:
①提出一个目标函数,通过二分图匹配的方式强制模型输出一组独一无二的预测(去除冗余框,每个物体的理想状态下就会生成一个框)
②使用Transformer 的encoder、decoder架构:
(1)在Transformer解码器中提出learned object query,它可以和全局图像信息结合,通过不停做注意力操作,让模型直接输出一组预测框
(2)并行出框
导言:
背景:
大部分目标检测器采用间接方式预测,或用回归和分类替代目标检测问题
性能受限于后处理(NMS)操作,处理大量冗余框
流程:
①用卷积神经网络提取特征
②将特征拉直,送入Transformer的encoder、decoder,进一步学习全局信息,将每一个点的信息与全局做交互
③生成框输出,通过object query限制框的个数
④使用二分图匹配计算Loss,计算预测框和GT Box的matching loss决定预测框中对应GT Box的框;选择后计算分类损失、Bounding Box Loss;没有匹配上的框被标记为背景
相关工作:
两阶段目标检测:proposal
单阶段目标检测:anchor、center
基于集合:
关系型网络、Learnable NMS利用类似于自注意力的方法去处理物体间联系
无需后处理
性能低,使用了人工干预
基于Encoder Decoder:
得到更全局的信息
并行输出目标框,时效性增强
Encoder:
代码结构与图对应 :
(0): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))
# 图像特征和位置编码相加得到了q、k
q = k = self.with_pos_embed(src, pos)
# value还是特征
src2 = self.self_attn(q, k, value=src, attn_mask=src_mask,key_padding_mask=src_key_padding_mask)[0]
改进后的Decoder:
# 将encoder出来的4个值传入decoder进行处理
hs = self.decoder(tgt, memory, memory_key_padding_mask=mask,pos=pos_embed, query_pos=query_embed)
代码结构与图对应:
(0): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False))
解码器部分的第一部分用到的是Multi-Head Self-Attention ,而第二部分用到的则是Multi-Head Attention
第一个MHSA:
q = k = self.with_pos_embed(tgt, query_pos)
# tgt当作第一个value进行self-aattention
# 计算每个目标表示与其他目标表示之间的注意力分数tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask,key_padding_mask=tgt_key_padding_mask)[0]
第二个MHA:
# 通过多头自注意力层计算目标表示和图像特征表示之间的注意力分数
tgt2 = self.multihead_attn(# q:第一个attention的输出+位置编码query=self.with_pos_embed(tgt, query_pos),# k:encoder输出+position embedding(空间位置编码)key=self.with_pos_embed(memory, pos),# v:encoder输出(memory)value=memory, attn_mask=memory_mask,key_padding_mask=memory_key_padding_mask)[0]
原因:
Queries 内部先进行协同工作(通过 MHSA)
然后再与图像特征交互提取有用的信息(通过 MHA)
DETR:
class DETR(nn.Module):def __init__(self, num_classes, hidden_dim, nheads, num_encoder_layers, num_decoder_layers, num_queries):super(DETR, self).__init__()# Encoderself.transformer = TransformerEncoder(d_model=hidden_dim, nhead=nheads, num_encoder_layers=num_encoder_layers)# Decoderself.transformer_decoder = TransformerDecoder(d_model=hidden_dim, nhead=nheads, num_decoder_layers=num_decoder_layers)# Object queriesself.query_embed = nn.Embedding(num_queries, hidden_dim)# Prediction headsself.class_embed = nn.Linear(hidden_dim, num_classes + 1) # +1 for backgroundself.bbox_embed = MLP(hidden_dim, hidden_dim * 4, 4, 3)def forward(self, images):# 假设images已经通过CNN处理成[batch_size, num_channels, H, W]# 这里略过CNN部分,直接模拟CNN输出特征src = ... # [batch_size, src_seq_len, hidden_dim],其中src_seq_len是特征图的序列长度# 目标查询hs = self.query_embed.weight.unsqueeze(0).repeat(images.shape[0], 1, 1) # [batch_size, num_queries, hidden_dim]# Encodermemory = self.transformer(src)# Decodertgt = torch.zeros_like(hs) # 初始化为零的目标查询outputs = self.transformer_decoder(tgt, memory, tgt_mask=None, memory_key_padding_mask=None)# 输出预测outputs_class = self.class_embed(outputs)outputs_coord = self.bbox_embed(outputs).sigmoid() # 假设使用sigmoid来限制坐标范围return outputs_class, outputs_coord
基于集合的目标函数:
使用cost matrix:类似于三个工人分配三个工作,使每个工人被分配其最擅长的工作
使用scipy包中提供的linear-sum-assignment函数,将cost matrix作为函数输入
a、b、c看作100个框,x、y、z看作GT框
损失函数:
包含分类Loss和出框Loss
为了使两个Loss在相近的取值空间,将log去除,得到更好的效果
在Bounding Box中,使用L_1 Loss可能会产生问题,于是加入了genralized IoU Loss(与框大小无关)
细节:为了让模型收敛更快,训练的更稳定,在Decoder后加入很多auxiliary loss(额外的目标函数);在6个(重复六次)Decoder后都加了FFN(共享参数),去得到目标检测输出从而得到Loss
网络框架:
模型创建:
detr = DETR(num_classes=91, hidden_dim=256, nheads=8, num_encoder_layers=6, num_decoder_layers=6)
整体架构:
DETR((transformer): Transformer((encoder): TransformerEncoder((layers): ModuleList((0): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))(1): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))(2): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))(3): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))(4): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))(5): TransformerEncoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False))))(decoder): TransformerDecoder((layers): ModuleList((0): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False))(1): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False))(2): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False))(3): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False))(4): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False))(5): TransformerDecoderLayer((self_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(multihead_attn): MultiheadAttention((out_proj): NonDynamicallyQuantizableLinear(in_features=256, out_features=256, bias=True))(linear1): Linear(in_features=256, out_features=2048, bias=True)(dropout): Dropout(p=0.1, inplace=False)(linear2): Linear(in_features=2048, out_features=256, bias=True)(norm1): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm2): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(norm3): LayerNorm((256,), eps=1e-05, elementwise_affine=True)(dropout1): Dropout(p=0.1, inplace=False)(dropout2): Dropout(p=0.1, inplace=False)(dropout3): Dropout(p=0.1, inplace=False)))(norm): LayerNorm((256,), eps=1e-05, elementwise_affine=True)))
# ********(class_embed): Linear(in_features=256, out_features=92, bias=True)(bbox_embed): MLP((layers): ModuleList((0): Linear(in_features=256, out_features=256, bias=True)(1): Linear(in_features=256, out_features=256, bias=True)
# 最后输出中心坐标xy和wh(2): Linear(in_features=256, out_features=4, bias=True)))
# decoder使用的可学习参数(query_embed): Embedding(100, 256)
# 将backbone抽取的2048维度转换为transformer使用的256维度(input_proj): Conv2d(2048, 256, kernel_size=(1, 1), stride=(1, 1))
# # ********(backbone): Joiner((0): Backbone((body): IntermediateLayerGetter((conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)(bn1): FrozenBatchNorm2d()(relu): ReLU(inplace=True)(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)(layer1): Sequential((0): Bottleneck((conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)(downsample): Sequential((0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): FrozenBatchNorm2d()))(1): Bottleneck((conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(2): Bottleneck((conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)))(layer2): Sequential((0): Bottleneck((conv1): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)(downsample): Sequential((0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): FrozenBatchNorm2d()))(1): Bottleneck((conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(2): Bottleneck((conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(3): Bottleneck((conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)))(layer3): Sequential((0): Bottleneck((conv1): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)(downsample): Sequential((0): Conv2d(512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): FrozenBatchNorm2d()))(1): Bottleneck((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(2): Bottleneck((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(3): Bottleneck((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(4): Bottleneck((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(5): Bottleneck((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)))(layer4): Sequential((0): Bottleneck((conv1): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)(downsample): Sequential((0): Conv2d(1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): FrozenBatchNorm2d()))(1): Bottleneck((conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True))(2): Bottleneck((conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): FrozenBatchNorm2d()(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): FrozenBatchNorm2d()(conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): FrozenBatchNorm2d()(relu): ReLU(inplace=True)))))(1): PositionEmbeddingSine())
)
前向过程:
①输入图像[3*800*1066],通过卷积网络得到一些特征
# 模型定义
self.backbone = nn.Sequential(*list(resnet50(pretrained=True).children())[:-2])
# 前向传播
x = self.backbone(inputs)
# 卷积神经网络提取特征
class Backbone(BackboneBase):"""ResNet backbone with frozen BatchNorm."""def __init__(self, name: str,train_backbone: bool,return_interm_layers: bool,dilation: bool):# getattr返回torchivision.models的对象属性值backbone = getattr(torchvision.models, name)(replace_stride_with_dilation=[False, False, dilation],pretrained=is_main_process(), norm_layer=FrozenBatchNorm2d)# 最后一层特征层的大小 根据网络结构设置num_channels = 512 if name in ('resnet18', 'resnet34') else 2048super().__init__(backbone, train_backbone, num_channels, return_interm_layers)
② 走到卷积网络最后一层(conv5)时得到[2048*25*34],而25和34分别为800和1066的1/32,2048为对应的通道数
③输入Transformer时需要一个降维操作,通过[1*1*256]的卷积核降维得到[256*25*34]
# 投射层 将2048变为256
self.conv = nn.Conv2d(2048, hidden_dim, 1)
# 前向传播
h = self.conv(x)
# 输入进transformer 跳input_proj
hs = self.transformer(self.input_proj(src), mask, self.query_embed.weight, pos[-1])[0]# input_proj转换通道数
self.input_proj = nn.Conv2d(backbone.num_channels, hidden_dim, kernel_size=1)
④Transformer无位置信息,为其加入位置编码,固定位置编码大小为[256*25*34],保持维度一致
# 模型定义
self.row_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
self.col_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
# 前向传播
pos = torch.cat([self.col_embed[:W].unsqueeze(0).repeat(H, 1, 1),
self.row_embed[:H].unsqueeze(1).repeat(1, W, 1),], dim=-1).flatten(0, 1).unsqueeze(1)
提出了二维编码图片来加入位置向量:
针对256维向量,前128维代表x位置编码,后128维代表y的位置编码
# 使用二维编码 编码位置向量N_steps = args.hidden_dim // 2 # N_steps:128
# 初始化一个128维向量
dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device)
dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
# 除
pos_x = x_embed[:, :, :, None] / dim_t
pos_y = y_embed[:, :, :, None] / dim_t
使用stack(与cat的不同):为达到sin和cos拼接
⑤相加后作为输入需要拉直,将h与w拉直变为一个数值,变为[850*256],850为序列长度,256为head dimension
相加:
# tensor和pos位置编码相加操作
def with_pos_embed(self, tensor, pos: Optional[Tensor]):return tensor if pos is None else tensor + pos
# 拉直
h = self.transformer(pos + h.flatten(2).permute(2, 0, 1),self.query_pos.unsqueeze(1))
⑥进入Transformer Encoder层,输入为[850,256],输出也为[850*256],在DETR中使用了6个Encoder进行叠加
# 定义的有关Transformer的输入参数
def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,num_decoder_layers=6, dim_feedforward=2048, dropout=0.1,activation="relu", normalize_before=False,return_intermediate_dec=False):
# 进入Transformer进行一系列操作
# 最终得到100*256
self.transformer = nn.Transformer(hidden_dim, nheads,num_encoder_layers,num_decoder_layers)
⑦进入Transformer Decoder层,进行框的输出,将输入1和输入2反复做自注意力操作,得到[100*256]的特征;在DETR中使用了6个Decoder进行叠加
# 前向传播时叠加两个输入
h = self.transformer(pos + h.flatten(2).permute(2, 0, 1),self.query_pos.unsqueeze(1))
输入1:创新点object queries,它是一个learnable positional embedding,维度[100*256],其中的256是与encoder中的256相互对应,便于一起做乘法,100代表模型最终为100输出(条件)
# object queries设置为100 最终出100个框
self.query_pos = nn.Parameter(torch.rand(100, hidden_dim))
细节:但是在第一层Decoder中没有做object queries自注意力机制,为了移除冗余框
输入2:图像端得出的全局特征,维度[850*256]
⑧ 将特征给全连接层,全连接层做物体类别的预测和出框的预测:
类别若是COCO则为91类:
self.linear_class = nn.Linear(hidden_dim, num_classes + 1)
框为4个值(x、y、w、h):
self.linear_bbox = nn.Linear(hidden_dim, 4)
⑨将得到的100个框与GT框进行匈牙利匹配
logits, bboxes = detr(inputs)
实验:
与Faster-RCNN对比:
训练策略的改变对模型提升效果很大,DETR对大物体检测效果较好,但小物体处理效果一般
Transformer Encoder:
class TransformerEncoder(nn.Module):def __init__(self, encoder_layer, num_layers, norm=None):super().__init__()# 克隆layers 跳_get_clonesself.layers = _get_clones(encoder_layer, num_layers)self.num_layers = num_layersself.norm = normdef forward(self, src,mask: Optional[Tensor] = None,src_key_padding_mask: Optional[Tensor] = None,pos: Optional[Tensor] = None):# 传入输入output = srcfor layer in self.layers:output = layer(output, src_mask=mask,src_key_padding_mask=src_key_padding_mask, pos=pos)if self.norm is not None:output = self.norm(output)return output
Encoder主要学习的是全局特征,尽可能让物体和物体之间分得开
自注意力的可视化,使用Transformer Encoder让图片里的物体分的很开,在此基础上做目标检测和分割相对而言就会简单很多
随着Transformer编码器层数增加,学到的全局特征越多,性能一直在提升,但带来了参数增长和速度变慢
Transformer Decoder:
class TransformerDecoder(nn.Module):def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False):super().__init__()self.layers = _get_clones(decoder_layer, num_layers)self.num_layers = num_layersself.norm = normself.return_intermediate = return_intermediatedef forward(self, tgt, memory,tgt_mask: Optional[Tensor] = None,memory_mask: Optional[Tensor] = None,tgt_key_padding_mask: Optional[Tensor] = None,memory_key_padding_mask: Optional[Tensor] = None,pos: Optional[Tensor] = None,query_pos: Optional[Tensor] = None):output = tgtintermediate = []for layer in self.layers:output = layer(output, memory, tgt_mask=tgt_mask,memory_mask=memory_mask,tgt_key_padding_mask=tgt_key_padding_mask,memory_key_padding_mask=memory_key_padding_mask,pos=pos, query_pos=query_pos)if self.return_intermediate:intermediate.append(self.norm(output))if self.norm is not None:output = self.norm(output)if self.return_intermediate:intermediate.pop()intermediate.append(output)if self.return_intermediate:return torch.stack(intermediate)return output.unsqueeze(0)
Decoder将注意力分给学习边缘,更好的区分物体和解决遮挡问题
Object Queries:
每一个正方形代表一个object queries,绿色的点代表小的Bounding Box,红色的点代表大的横向的Bounding Box,蓝色的点代表大的纵向的Bounding Box
object queries 与anchor类似:
anchor:提前定义好一些Bounding Box,最后将预测和提前订好的Bounding Box做对比
object queries:可学习;类似于问问题的“人”,用图片自己的方式去问,得到答案,而答案就是对应的Bounding Box,而未找到答案就无结果
每次学习后看到一张图片都会问左下角是否看到一些小物体,中间是否看到大的横向物体
每次学习后看到一张图片都会问右边是否看到一些小物体,中间是否看到大的横向或纵向物体
总结:
优点:
提出了一个全新的用于目标检测的DETR框架
利用了Transformer和二分图匹配,使框架是一个端到端可学习网络
在COCO数据集和全景分割上达到了很好的效果
自注意力带来的全局信息使之在大物体上效果更好
缺点:
训练时间长
不好优化
小物体性能差
运行效果:
相关文章:
DETR:End-to-End Object Detection with Transformers
【DETR 论文精读【论文精读】-哔哩哔哩】 https://b23.tv/Iy9k4O2 【DETR源码解读4-哔哩哔哩】 https://b23.tv/Qp1uH5v 摘要: 将目标检测看作一个集合预测的问题 任务:给定一张图片,预测一组框,每个框需要得到坐标信息和包含的…...
【C++/Qt 】使用QCustomplot类打造一款数学函数图像生成工具(支持latex公式渲染+Python连接AI大模型)
✨✨ Rqtz 个人主页 : 点击✨✨ 🌈Qt系列专栏:点击 软件介绍 基于Qt的开源项目QCustomplot类的一款在线的数学函数图像生成工具,涉及到了数学的latex公式渲染,如何将latex语法转换为Python的函数,和如何在Qt中使用QCustomplot类进…...
Hackathon靶机系列Hackathon2
扫描ip: 获得靶机的ip:192.168.108.134 扫描端口: 获得80端口,7223的ssh和一个ftp服务器服务器中存在两个文件: 先看ftp: 默认用户名为ftp: 下载两个文件: 和 打开flag1.txt: 获得…...
Mybatis 复习
1 什么是MyBatis MyBatis是一个优秀的持久层框架,它对JDBC操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、 结果集检索等JDBC繁杂的过程代码 。…...
BurpSuite安装教程(详细!!附带下载链接)
声明 学习内容来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍🏻作者简介:致…...
Istio_05_Istio架构
Istio_05_Istio架构 ArchitectureControl PlanePilotCitadelGalley Data PlaneSidecarIstio-proxyPilot-agentMetadta Exchange Ambient Architecture 如: Istio的架构(控制面、数据面) Gateway: Istio数据面的出/入口网关 Gateway分为: Ingress-gateway、Egress-gateway外部访…...
R语言结构方程模型(SEM)在生态学领域中的应用
目录 专题一、R/Rstudio简介及入门 专题二、结构方程模型(SEM)介绍 专题三:R语言SEM分析入门:lavaan VS piecewiseSEM 专题四:SEM全局估计(lavaan)在生态学领域高阶应用 专题五࿱…...
node.js基础学习-fs模块-文件操作(六)
一、前言 fs模块是 Node.js 内置的文件系统(File System)模块,它提供了一系列用于与文件系统进行交互的方法。通过fs模块,可以对文件或目录进行读取、写入、删除、重命名、查询状态等操作,这使得 Node.js 能够很好地处…...
EXCEL截取某一列从第一个字符开始到特定字符结束的字符串到新的一列
使用EXCEL中的公式进行特定截取 假设列A是一组产品的编码,我们需要的数据是“-”之前的字段。 我们需要在B1单元格输入公式“LEFT(A1,SEARCH("-",A1)-1)”然后选中B1至B4单元格,按“CTRLD”向下填充,就可以得出其它几行“-”之前的…...
JVM的垃圾回收算法有哪些
标记清除算法 标记清除算法,是将垃圾回收分为2个阶段,分别是标记和清除 根据可达性分析算法得出的垃圾进行标记对这些标记为可回收的内容进行垃圾回收 优点:标记和清除速度较快缺点:碎片化较为严重,内存不连贯的 标记整理算法 优缺点同标记…...
看华为,引入IPD的正确路径
目录 前言 引发重视 作者简介 前言 华为将 IPD 的引入过程归结为三步: 先僵化、后优化、再固化。 如果只是单纯模仿,在不清楚底层逻辑的情况下, 就开始走先僵化的流程,去搞削足适履式的引入。 开始执行后,你就…...
2024142读书笔记|《别无归处是归处》——一壶酒,一竿身,世上如侬有几人
2024142读书笔记|《别无归处是归处》——一壶酒,一竿身,世上如侬有几人 《别无归处是归处:吴镇的“渔父”画题(文人画的真性)》作者朱良志。诗词与古画并存的一本书,古画是比较偏复古黯淡微黄及墨色的&…...
think php处理 异步 url 请求 记录
1、需求 某网站 需要 AI生成音乐,生成mp3文件的时候需要等待,需要程序中实时监听mp3文件是否生成 2、用的开发框架 为php 3、文件结构 配置路由设置 Route::group(/music, function () {Route::post(/musicLyrics, AiMusic/musicLyrics);//Ai生成歌词流式…...
PostgreSQL详细安装教程
#安装PostgreSQL的yum仓库 sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm#安装PostgreSQL 15版本 sudo yum install -y postgresql15-server#初始化数据库(若要自定义数据库存储目录…...
电子电气架构 --- 车载网关GW连接外部IP Tester
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...
开发一套ERP 第八弹 RUst 插入数据
更全面的报错,方便检查错误在哪里,现代高级语言越来越智能 还是得看下原文档怎么操作的 src 目录为crate 的根目录 想在crate 中模块相互引入需要在 main 中声明,各个模块,然后才能在各个模块中相互引入和使用 原始工程引入,避免直接使用 lib.rs 回合cargo 中的一些 工程管理出…...
RFdiffusion Diffuser类解读
Diffuser 类是一个封装类,调用EuclideanDiffuser和IGSO3类,用于执行扩散模型的核心功能,主要针对分子或蛋白质结构的旋转(SO(3) 群上的扩散)和位移(欧几里得空间中的扩散)。 源代码: class Diffuser:# wrapper for yielding diffused coordinatesdef __init__(self,T…...
【pdf密码】为什么我的PDF文件不能复制文字?
大家现在接触PDF文件越来越多,有的时候在网上下载的PDF文件打开之后,发现选中文字之后无法复制。甚至其他功能也都无法使用,这是怎么回事?该怎么办? 当我们发现文件打开之后,编辑功能无法使用,很…...
C#学写了一个程序记录日志的方法(Log类)
1.错误和警告信息单独生产文本进行记录; 2.日志到一定内存阈值可以打包压缩,单独存储起来,修改字段MaxLogFileSizeForCompress的值即可; 3.Log类调用举例:Log.Txt(JB.信息,“日志记录内容”,"通道1"); usi…...
Android Framework禁止弹出当前VOLTE不可用的提示窗口
文章目录 VoLTE简介VoLTE 的优势 当前VOLTE不可用的弹窗弹窗代码定位屏蔽弹出窗口 VoLTE简介 VoLTE(Voice over LTE)是一种基于4G LTE网络的语音通话技术。它允许用户在4G网络上进行高质量的语音通话和视频通话,而不需要回落到2G或3G网络。V…...
Maven Surefire 插件简介
Maven Surefire 插件是 Maven 构建系统中的一个关键组件,专门用于在构建生命周期中执行单元测试。 它通常与 Maven 构建生命周期的测试阶段绑定,确保所有单元测试在项目编译后和打包前被执行。 最新版本 Maven Surefire 插件的最新版本为 3.5.2。 使…...
vue3-新增API组件
shallowRef 创建一个响应式数据,但只对顶层属性进行响应式处理,只跟踪引用值的变化,不关心值内部的属性变化 import {shallowRef} from "vue" import UserInfo from "/components/UserInfo.vue";let name shallowRef("vue&quo…...
Linux随记(十三)
一、jstack随记 运行cmd cd C:\icp-agent\jdk_min\bin 执行 jstack PID > thread_dump.txt (查看PID:tasklist |findstr javaw 查看第二列) thread_dump.txt 取给研发二、让普通用户test,有权限使用docker指令 1、 查看当前用…...
AI数据分析工具(一)
Looker Studio(谷歌)-免费 优点 免费使用:对于中小型企业和个人用户来说,没有任何费用压力,可以免费享受到数据可视化和报表创建的功能。与Google服务集成:特别适合使用Google产品生态的企业,…...
dhcp服务
安装dhcp-libs和dhcp-common软件包是配置DHCP服务器的前提,但仅仅安装这两个软件包并不能直接开启DHCP服务器。您还需要进行以下步骤来完整配置和启动DHCP服务器: 安装DHCP服务器软件包: 除了dhcp-libs和dhcp-common,您还需要安装…...
RSA算法和AES算法,哪种更安全
目录 一、RSA (非对称加密算法) 二、AES (对称加密算法) 三、对比总结 四、更安全的选择 五、结合使用:RSA AES RSA 和 AES 是两种不同类型的加密算法,适用于不同的场景,因此它们的安全性不能直接比较,而是取决于具体的应用…...
反向代理模块开发
1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求,然后将请求转发给内部网络上的服务器,将从服务器上得到的结果返回给客户端,此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说,反向代理就相当于…...
(微信小程序)基于Spring Boot的校园失物招领平台的设计与实现(vue3+uniapp+mysql)
💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...
1-7 GD32函数指针应用
前言: 本博客仅在应用函数指针与回调函数相关的知识,通过实践巩固所学知识,也是对相关知识点的回顾。 函数指针与回调函数:1-6 GD32函数指针与回调函数-CSDN博客 目录 前言: 1.0 程序架构思想 2.0 构建串口结构体 …...
前端js面试知识点思维导图(脑图)
如果看着不清晰可以去https://download.csdn.net/download/m0_73761441/90058523访问下载,无需积分 使用百度脑图制作,可以一键导入下面的文本生成自己的脑图 js相关面试题、知识点 数据类型 1. 数据类型分类?分别包含ÿ…...
使用 F5 TTS 文字转音频
F5 TTS 支持 ZeroShot 音频克隆,只有将需要音频传给模型,模型既可以生成以对应声音生成的音频,F5 最强大的地方就是可以使用定制的人声。F5 使用了 DIT 架构进行训练,结构如下: 本地使用 F5 TTS F5 使用很简单&#x…...
【笔记】自动驾驶预测与决策规划_Part8_数据驱动的规划方法
文章目录 0. 前言1.生成模型1.1 Diffusion-ES1. Diffusion-ES算法介绍2. Diffusion-ES算法具体流程Diffusion Model 是什么?Diffusion-ES: Evolutionary StrategiesDiffusion-ES MethodDiffusion-ES Mapping Language instructions to reward functions with LLM pr…...
多视图几何中向量叉乘的矩阵转换 Matrix Transformation for Cross Product in MVG
Title: 多视图几何中向量叉乘的矩阵转换 Matrix Transformation for Cross Product in MVG 文章目录 I. 向量叉乘的矩阵转换恒等式II. 符号计算 Maxima 程序推导III. 推论和关联公式的说明1. 推论2. 应用于对极几何中基本矩阵推导3. 应用于基本矩阵与单应矩阵关系4. 与刚体运动…...
面向多用户场景的恢复机制驱动的无线组密钥生成协议
中文标题:面向多用户场景的恢复机制驱动的无线组密钥生成协议 英文标题:A Recovery Mechanism-driven Wireless Group Key Generation Protocol for Multi-User Scenarios 作者信息: Huaicong Zhang, Yawen Huang, Jiabao Yu, Boqian Liu, …...
ROS2教程 - 2 环境安装
更好的阅读体验:https://www.foooor.com 2 环境安装 下面以 ROS2 的 humble 版本为例,介绍 ROS2 的安装。 ROS1 只能在 ubuntu 系统上安装,ROS2全面支持三种平台:Ubuntu、MAC OS X、Windows10,下面在 Ubuntu22.04 …...
力扣200 岛屿数量 Java版本
文章目录 题目描述代码 题目描述 给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 …...
每日速记10道java面试题03
其他资料 每日速记10道java面试题01-CSDN博客 每日速记10道java面试题02-CSDN博客 目录 一、你使用过java的反射机制吗?如何应用反射? 二、什么是泛型?泛型的作用是什么? 三、java的泛型擦除是什么? 四、Java 中…...
力扣刷题TOP101:6.BM7 链表中环的入口结点
目录: 目的 思路 复杂度 记忆秘诀 python代码 目的 {1,2},{3,4,5}, 3 是环入口。 思路 这个任务是找到带环链表的环入口。可以看作是上一题龟兔赛跑(Floyd 判圈算法)的延续版:乌龟愤愤不平地举报兔子跑得太快,偷偷…...
智慧防汛平台在城市生命线安全建设中的应用
随着城市化进程的加快,城市基础设施的复杂性和互联性不断增强,城市生命线的安全管理面临前所未有的挑战。智慧防汛平台作为城市生命线安全建设的重要组成部分,通过现代信息技术提升城市防汛应急管理的智能化水平,保障城市安全。 …...
高德应用OceanBase云数据库的升级选型与迁移干货
业务背景 高德,DAU已在亿级,时时刻刻都持续不断地产生着庞大的数据。随着数据量的迅猛增长,对现有的业务数据存储能力构成日益严峻的挑战。 以我所在部门中的某一大型服务为例,其存储在XDB中的数据量往往达到数百TB之巨…...
Flink cdc同步增量数据timestamp字段相差八小时(分析|解决)不是粘贴复制的!
问题 我使用flink cdc同步mysql到mysql遇到了timestamp字段缺少八小时的问题。很少无语,flink ,cdc,debezium时区都设置了,没有任何效果! 分析 问题出现在mysql binlog身上!!! 因为默认mysql会使用UTC来…...
用shell脚本写一个通用的监听程序异常并重启脚本
进来服务器的程序php-fpm时常在并发下时常挂掉,而且时常在凌晨2点以后,通过排查是因为php配置需要调整并发,同时,为了不影响我休息(以前老师说:能用机器和程序解决问题的坚决不用人去操作,这样才…...
使用 Go 语言中的 Context 取消协程执行
使用 Go 语言中的 Context 取消协程执行 在 Go 语言中,协程(goroutine)是一种轻量级的线程,非常适合处理并发任务。然而,如何优雅地取消正在运行的协程是一个常见的问题。本文将通过一个具体的例子来展示如何使用 con…...
使用经典的Java,还是拥抱新兴的Rust?
在当代互联网时代的企业级开发中,技术栈的选择往往牵动着每个团队的神经。随着Rust语言的崛起,许多开发团队开始重新思考:是继续坚持使用经典的Java,还是拥抱新兴的Rust?这个问题背后,折射出的是对技术演进…...
《算法导论》英文版前言To the teacher第3段研习录:题海战术有没有?
【英文版】 We have included 957 exercises and 158 problems. Each section ends with exercises, and each chapter ends with problems. The exercises are generally short questions that test basic mastery of the material. Some are simple self-check thought exer…...
XELA - uSkin 三轴触觉传感器:为机器人赋予敏锐触感
XELA Robotics 的 uSkin 触觉传感器以其创新性在机器人技术中备受关注。它凭借高密度设计和三轴力测量能力,大幅提升了机器人的触觉感知能力,这种技术不但增强了机器人的智能化和柔性,还为不同行业的应用创造了广泛的可能性。其中在机器人灵巧…...
k8s常用命令总结
以下是 Kubernetes 所有常用命令的详细总结,涵盖了 kubectl 的各个方面,包括基本操作、资源管理、调试、监控等。每个命令都附有简要说明和示例。 1. 基本命令 查看 Kubernetes 版本 kubectl version 查看集群信息 kubectl cluster-info 查看当前上…...
即时通讯| IM+RTC在AI技术加持下的社交体验
即时通讯作为互联网的重要应用之一,见证了中国互联网30年发展的辉煌历程。 它从最初的文字交流,发展到如今的语音、视频通话,甚至是虚拟现实社交,已经渗透到生活的社交、娱乐、商务等方方面面,成为现代社会不可或缺的一…...
评估人工智能生成答案准确性
目录 评估人工智能生成答案准确性 评估人工智能生成答案准确性 在评估人工智能(AI)系统生成的答案准确性时,我们主要关注两个方面:事实相似性和语义相似性。这两个方面的加权平均分数被用来衡量系统回答的准确性。 事实相似性: 事实相似性通过F1分数来计算。F1分数是精确…...
scala的守卫语句格式
import scala.io.StdIn object test49{//从控制台读入一个数字a,使用(StdIn.readInt)//如果a>0并且a<3,打印[0-3]//如果a>4并且a<8,打印[4-8]//否则:打印未匹配 // def main(args: Array[String]): Unit { // val aStdIn.readInt()//等…...