YOLOv8源码逐行解读(yolov8.yaml)(更新中)

news2025/2/25 15:08:25

本人也是刚接触YOLO不久的菜鸟一个,写博客主要是记录自己的学习过程,如果有写的不对的地方欢迎大家批评指正!

yolov8.yaml 官方下载地址:https://github.com/ultralytics/ultralytics/tree/main/ultralytics/models/v8

# Ultralytics YOLO 🚀, GPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

nc:数据集类别数。scales:不同尺寸的模型大小根据scales进行缩放。

本文使用的结构图来自RangeKing(github)

Backbone部分:

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9

  # [from, repeats, module, args] 

from:本层的来源,也就是输入。-1表示将上层的输出作为本层的输入。

repeats:本层的重复次数。

module:本层的名称。

args:本层的参数。

第0层: - [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2

-1代表将上层的输入作为本层的输入。第0层的输入是640*640*3的图像。

Conv代表卷积层,相应的参数:64代表输出通道数,3代表卷积核大小k,2代表stride步长。

这里给出Conv的代码供参考


def autopad(k, p=None, d=1):  # kernel, padding, dilation
    # Pad to 'same' shape outputs
    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p

class Conv(nn.Module):
    # Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)
    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        return self.act(self.conv(x))

可以从代码中看出,当k=3时,p=1

所以第0层的卷积f_in=640, c_out=64, k=3, s=2, p=1

输出的特征图大小计算公式:f_out = ((f_in - k + 2*p ) / s ) 向下取整 +1

计算出卷积后的特征图大小:640-3+2=639,639/2向下取整=319,319+1=320

所以经过此层,输出的特征图尺寸为320*320*64,长宽为初始图片的1/2。

第1层: - [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4

本层和上一层是一样的操作(128代表输出通道数,3代表卷积核大小k,2代表stride步长),卷积后的特征图尺寸为160*160*128(320-3+2=319,319/2向下取整=159,159+1=160),长宽为初始图片的1/4。

第2层:  - [-1, 3, C2f, [128, True]]

本层是C2f模块,先给出C2f的源码:

class C2f(nn.Module):
    # CSP Bottleneck with 2 convolutions
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        self.c = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))

    def forward(self, x):
        y = list(self.cv1(x).chunk(2, 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

    def forward_split(self, x):
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

class Bottleneck(nn.Module):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):  # ch_in, ch_out, shortcut, groups, kernels, expand
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, k[0], 1)
        self.cv2 = Conv(c_, c2, k[1], 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))

结合RangeKing绘制的YOLOv8网络结构图理解:

(代码有点复杂,之后补上这一块的解释)

3代表本层重复3次。128代表输出通道数,True表示Bottleneck有shortcut。

经过这层之后,特征图尺寸依旧是160*160*128。

 第3层: - [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8

进行卷积操作256代表输出通道数,3代表卷积核大小k,2代表stride步长,输出特征图尺寸为80*80*256(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样),特征图的长宽已经变成输入图像的1/8。

第4层:  - [-1, 6, C2f, [256, True]]

6代表本层重复6次。256代表输出通道数,True表示Bottleneck有shortcut。

经过这层之后,特征图尺寸依旧是80*80*256。

第5层:  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16

进行卷积操作512代表输出通道数,3代表卷积核大小k,2代表stride步长,输出特征图尺寸为40*40*512(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样),特征图的长宽已经变成输入图像的1/16。

第6层:  - [-1, 6, C2f, [512, True]]

6代表本层重复6次。512代表输出通道数,True表示Bottleneck有shortcut。

经过这层之后,特征图尺寸依旧是40*40*512。

第7层:  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32

进行卷积操作1024代表输出通道数,3代表卷积核大小k,2代表stride步长,输出特征图尺寸为20*20*1024(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样),特征图的长宽已经变成输入图像的1/32。

第8层:  - [-1, 3, C2f, [1024, True]]

3代表本层重复3次。1024代表输出通道数,True表示Bottleneck有shortcut。

经过这层之后,特征图尺寸依旧是20*20*1024。

第9层:  - [-1, 1, SPPF, [1024, 5]]  # 9

class SPPF(nn.Module):
    # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
    def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_ * 4, c2, 1, 1)
        self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)

    def forward(self, x):
        x = self.cv1(x)
        y1 = self.m(x)
        y2 = self.m(y1)
        return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))

本层是快速空间金字塔池化层(SPPF)。1024代表输出通道数,5代表池化核大小k。结合模块结构图和代码可以看出,最后concat得到的特征图尺寸是20*20*(512*4),经过一次Conv得到20*20*1024。

Head部分:

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 12

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 4], 1, Concat, [1]]  # cat backbone P3
  - [-1, 3, C2f, [256]]  # 15 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large)

  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)

第10层:  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]

torch.nn.Upsample(size=None, scale_factor=None, mode='nearest', align_corners=None)

本层是上采样层。-1代表将上层的输出作为本层的输入。None代表上采样的size(输出尺寸)不指定。2代表scale_factor=2,表示输出的尺寸是输入尺寸的2倍。nearest代表使用的上采样算法为最近邻插值算法。经过这层之后,特征图的长和宽变成原来的两倍,通道数不变,所以最终尺寸为40*40*1024。

第11层:  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4

本层是concat层,[-1, 6]代表将上层和第6层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是40*40*1024,第6层的输出是40*40*512,最终本层的输出尺寸为40*40*1536。

第12层:  - [-1, 3, C2f, [512]]  # 12

3代表本层重复3次。512代表输出通道数。与Backbone中C2f不同的是,此处的C2f的bottleneck模块的shortcut=False

经过这层之后,特征图尺寸变为40*40*512。

第13层:  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]

本层也是上采样层(参考第10层)。经过这层之后,特征图的长和宽变成原来的两倍,通道数不变,所以最终尺寸为80*80*512。

第14层:  - [[-1, 4], 1, Concat, [1]]  # cat backbone P3

本层是concat层,[-1, 4]代表将上层和第4层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是80*80*512,第6层的输出是80*80*256,最终本层的输出尺寸为80*80*768。

第15层:  - [-1, 3, C2f, [256]]  # 15 (P3/8-small)

3代表本层重复3次。256代表输出通道数。

经过这层之后,特征图尺寸变为80*80*256,特征图的长宽已经变成输入图像的1/8。

第16层:  - [-1, 1, Conv, [256, 3, 2]]

进行卷积操作256代表输出通道数,3代表卷积核大小k,2代表stride步长,输出特征图尺寸为40*40*256(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样)。

第17层:  - [[-1, 12], 1, Concat, [1]]  # cat head P4

本层是concat层,[-1, 12]代表将上层和第12层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是40*40*256,第12层的输出是40*40*512,最终本层的输出尺寸为40*40*768。

第18层:  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium)

3代表本层重复3次。512代表输出通道数。

经过这层之后,特征图尺寸变为40*40*512,特征图的长宽已经变成输入图像的1/16。

第19层:  - [-1, 1, Conv, [512, 3, 2]]

进行卷积操作512代表输出通道数,3代表卷积核大小k,2代表stride步长,输出特征图尺寸为20*20*512(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样)。

第20层:  - [[-1, 9], 1, Concat, [1]]  # cat head P5

本层是concat层,[-1, 9]代表将上层和第9层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是20*20*512,第9层的输出是20*20*1024,最终本层的输出尺寸为20*20*1536。

第21层:  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large)

3代表本层重复3次。1024代表输出通道数。

经过这层之后,特征图尺寸变为20*20*1024,特征图的长宽已经变成输入图像的1/32。

第22层:  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)

本层是Detect层,[15, 18, 21]代表将第15、18、21层的输出(分别是80*80*256、40*40*512、20*20*1024)作为本层的输入。nc是数据集的类别数。

class Detect(nn.Module):
    # YOLOv8 Detect head for detection models
    dynamic = False  # force grid reconstruction
    export = False  # export mode
    shape = None
    anchors = torch.empty(0)  # init
    strides = torch.empty(0)  # init

    def __init__(self, nc=80, ch=()):  # detection layer
        super().__init__()
        self.nc = nc  # number of classes
        self.nl = len(ch)  # number of detection layers
        self.reg_max = 16  # DFL channels (ch[0] // 16 to scale 4/8/12/16/20 for n/s/m/l/x)
        self.no = nc + self.reg_max * 4  # number of outputs per anchor
        self.stride = torch.zeros(self.nl)  # strides computed during build

        c2, c3 = max((16, ch[0] // 4, self.reg_max * 4)), max(ch[0], self.nc)  # channels
        self.cv2 = nn.ModuleList(
            nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch)
        self.cv3 = nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
        self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity()

    def forward(self, x):
        shape = x[0].shape  # BCHW
        for i in range(self.nl):
            x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
        if self.training:
            return x
        elif self.dynamic or self.shape != shape:
            self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
            self.shape = shape

        if self.export and self.format == 'edgetpu':  # FlexSplitV ops issue
            x_cat = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2)
            box = x_cat[:, :self.reg_max * 4]
            cls = x_cat[:, self.reg_max * 4:]
        else:
            box, cls = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2).split((self.reg_max * 4, self.nc), 1)
        dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides
        y = torch.cat((dbox, cls.sigmoid()), 1)
        return y if self.export else (y, x)

    def bias_init(self):
        # Initialize Detect() biases, WARNING: requires stride availability
        m = self  # self.model[-1]  # Detect() module
        # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1
        # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum())  # nominal class frequency
        for a, b, s in zip(m.cv2, m.cv3, m.stride):  # from
            a[-1].bias.data[:] = 1.0  # box
            b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2)  # cls (.01 objects, 80 classes, 640 img)

class DFL(nn.Module):
    # Integral module of Distribution Focal Loss (DFL) proposed in Generalized Focal Loss https://ieeexplore.ieee.org/document/9792391
    def __init__(self, c1=16):
        super().__init__()
        self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False)
        x = torch.arange(c1, dtype=torch.float)
        self.conv.weight.data[:] = nn.Parameter(x.view(1, c1, 1, 1))
        self.c1 = c1

    def forward(self, x):
        b, c, a = x.shape  # batch, channels, anchors
        return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a)
        # return self.conv(x.view(b, self.c1, 4, a).softmax(1)).view(b, 4, a)

以上是对yolov8模型结构的一个大概的梳理,有一些模块的细节本人了解的也没有很清楚,所以就没有对全部代码进行解释。希望我的文章对你有帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/427626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

工业机器人三大主流行业浮动去毛刺应用深度详解

工业机器人是一种能够自动执行各种工业任务的机器人,它的使用不仅能将工人从繁重或有害的体力劳动中解放出来,解决当前劳动力短缺问题,而且能够提高生产效率和产品质量,增强企业整体竞争力,被广泛地应用于工业各个生产…

软件测试岗,4 轮面试成功拿下字节 Offer..........

一共经历了四轮面试:技术4面+HR面。 特整理出所涉及的全部知识点,并复盘了完整面试题及答案,分享给大家,希望能够帮到一些计划面试字节的朋友。 一、测试基础理论类 怎么编写案例?软件测试的两种方法测试结束的标准…

SpringBoot解析指定Yaml配置文件

再来个文章目录 文章目录前言1、自定义配置文件2、配置对象类3、YamlPropertiesSourceFactory下面还有投票,帮忙投个票👍 前言 最近在看某个开源项目代码并准备参与其中,代码过了一遍后发现多个自定义的配置文件用来装载业务配置代替数据库…

打造最小VR头显,软件开发商Bigscreen缘何跨进VR硬件市场?

今年2月,Bigscreen推出了一款非常轻薄的PC VR头显:Beyond。该头显的特点是采用两块1英寸Micro OLED屏幕(RGB Stripe排列),可带来双眼5K分辨率,28 PPD,75Hz/90Hz刷新率和90x93FOV。目前Beyond虽还…

Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核)

Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核) 文章目录Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核)1.出厂源码编译1 修改顶层 …

Matlab simulink上手控制仿真学习笔记3-常用模块S Function及使用案例

讲得真的十分细致!个人感觉看完前4节就差不多了。 今天记录的是S Function。 内容比较多,加个目录: S Function前置工作1.1 parameter.m1.2 plant.mfunction [sys,x0,str,ts,simStateCompliance] plant(t,x,u,flag,pa)function [sys,x0,str…

三电技术(电池(BMS)、电驱(MCU)、电控(VCU))

三电技术 1、概述 三电技术不仅是新能源汽车的核心技术,也是基础性技术。 三电是指电池,电驱(电机),电控,简称 BMC。 2、电池 为了区分新能源汽车上的低压电池将其称为动力电池,“动力电池“也是行业术语。动力电…

毫无废话,四个小案例手把手教你Vue2基础轻松入门_学习笔记

四个小案例手把手教你Vue2基础轻松入门_学习笔记 本文将通过四个小案例介绍Vue2学习 根据 黑马程序员vue前端基础教程-4个小时带你快速入门vue 教程。 因教程中的网络项目和综合项目难度不高,且内容仅为综合使用,本笔记不另介绍。 * 源自教程&#xff0c…

【Linux】网络编程之套接字 --TCP

目录🌈前言🌸1、TCP相关API🍡1.1、socket函数🍢1.2、bind函数🍧1.3、listen函数🍨1.4、accept函数🍰1.5、connect函数🌺2、TCP网络编程🍡2.1、简单TCP通信程序 -- 多进程…

【redis】验证redis是否正常运行以及报错解决方案

Redis 出现 “(error) NOAUTH Authentication required.” 错误,意味着客户端尝试向 Redis 服务器发送命令,但未提供身份验证或提供的身份验证信息不正确。这通常是由于 Redis 实例开启了密码认证机制导致的。 为了解决该问题,可以尝试以下…

代码随想录算法训练营第六天|242 有效的字母异位词 349 两个数组的交集 202 快乐数 1 两数之和

文章目录哈希表242 有效的字母异位词思路代码总结349 两个数组的交集思路代码总结202 快乐数思路代码总结1 两数之和思路代码总结哈希表 哈希碰撞:拉链法(链表)线性探测法(顺序向后) std::unordered_map, std::unorde…

LinuxGUI自动化测试框架搭建(四)-Hyper-V上安装Ubuntu操作系统

(四)-Hyper-V上安装Ubuntu操作系统 1 Ubuntu下载1.1 下载地址1.2 下载说明2 Hyper-V上安装Ubuntu2.1 创建虚拟机2.2 安装Ubuntu系统3 设置虚拟你网络4 关闭虚拟机检查点并移除DVD驱动器5 启动虚拟机6 配置Ubuntu网络7 网络测试1 Ubuntu下载 1.1 下载地址 官网地址:https://…

(十五)排序算法-归并排序

1 基本介绍 1.1 概述 归并排序(Merge Sort)是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。 将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数&…

华为浮动路由和BFD配置

拓扑图 电脑配置 pc1:192.168.10.1/24 pc2:192.168.20.1/24 AR1路由器配置 配置4个接口的地址 ge0/0/0:192.168.10.254/24 ge0/0/1:192.168.20.254/24 ge0/0/2:12.1.1.1/30 ge4/0/0:13.1.1.1/30 <Huawei>system-view Enter system view, return user view with CtrlZ…

机器学习笔记之正则化(五)Dropout

机器学习笔记之正则化——Dropout引言引子&#xff1a;题目描述(正则化相关)正确答案&#xff1a;ABCD\mathcal A\mathcal B\mathcal C\mathcal DABCD题目解析回顾&#xff1a;集成学习方法&#xff1a;Bagging\text{Bagging}BaggingDropout\text{Dropout}Dropout方法深度神经网…

黑马程序员微服务技术栈教程 - 1. SpringCloud 微服务治理

教程链接&#xff1a;https://www.bilibili.com/video/BV1LQ4y127n4 黑马的资料下载链接&#xff1a;https://pan.baidu.com/s/1zRmwSvSvoDkWh0-MynwERA&pwd1234 目录认识微服务单体架构分布式架构微服务微服务结构微服务技术对比SpringCloud总结 &#x1f380;服务拆分及远…

刷题day54:柱形图中最大矩形

题意描述&#xff1a; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 暴力方法&#xff1a; class Solution { public:int largestRectangleArea(ve…

软考第四章 局域网与城域网

局域网与城域网 传统局域网&#xff08;LAN&#xff09;是分组广播式网络&#xff0c;这是与分组交换式的广域网的主要区别。广播技术中&#xff0c;所有工作站都连接到共享的传输介质上&#xff0c;共享信道的分配技术是局域网的核心技术&#xff0c;而这一技术又与网络的拓扑…

故障分析 | 从一则错误日志到 MySQL 认证机制与 bug 的深入分析

作者&#xff1a;李锡超 一个爱笑的江苏苏宁银行 数据库工程师&#xff0c;主要负责数据库日常运维、自动化建设、DMP平台运维。擅长MySQL、Python、Oracle&#xff0c;爱好骑行、研究技术。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;原创内容未经授权不得…

Redis的MoreKey和BigKey问题

文章目录1、MoreKey案例2、BigKey案例1、MoreKey案例 大批量往Redis里面插入200w测试数据key 在Linux Bash下面执行&#xff0c;插入200w数据 for((i1;i<200*10000;i)); do echo "set k$i v$i">>/root/redisTest.txt;done;使用命令 tail -10 redisTest.t…