【目标检测——YOLO系列】YOLOv1 —《You Only Look Once: Unified, Real-Time Object Detection》

news2024/11/23 21:22:35

YOLOv1 —《You Only Look Once: Unified, Real-Time Object Detection》


论文地址:1506.02640] You Only Look Once: Unified, Real-Time Object Detection (arxiv.org)

代码地址:pjreddie/darknet: Convolutional Neural Networks (github.com)

1、YOLOv1概述


YOLOv1是一种end to end目标检测算法,由Joseph Redmon等人于2015年提出。它是一种基于单个神经网络的实时目标检测算法。

YOLOv1的中文名称是"你只看一次",这个名字源于算法的工作原理。相比于传统的目标检测算法,YOLOv1采用了全新的思路。**它将目标检测问题转化为一个回归问题,并将整个图像作为输入,一次性地在图像上进行目标检测和定位(单阶段检测模型)。这与传统的滑动窗口或区域提议方法不同,传统方法如RCNN系列(两阶段检测模型)**需要在图像上进行多次检测。

YOLOv1的网络结构由卷积层和全连接层组成,可以将输入图像分割成较小的网格(grid cell)。对于每个网格,YOLOv1预测多个边界框以及每个边界框中是否包含目标物体及其类别。通过对预测结果进行置信度评估和非极大值抑制,可以得到最终的目标检测结果。

相比于传统的目标检测算法,YOLOv1具有较快的检测速度可以实现实时目标检测。然而,由于网络结构的限制,YOLOv1在小目标检测和物体定位精度上可能存在一定的问题(主要因为YOLO中的一个gird cell只能预测判别一个物体,后文细说)。在后续的版本中,如YOLOv2和YOLOv3等,一些改进措施被提出来解决这些问题(比如从Faster Rcnn中引入anchor等),我们在后续文章中会对YOLO其他版本进行继续讲解。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsCvRkdZ-1685955497733)(E:\学习笔记\深度学习笔记\目标检测专栏\YOLO\yolov1.assets\image-20230605141417299.png)]

我们可以将YOLOv1网络看作一个黑盒,在推理阶段,我们将图像resize到448 * 448后输入到网络中,输出的是一个SxSx(B*5+C)的张量,该张量是关于检测框的位置信息以及检测目标的类别信息等,再经过非极大值抑制处理(关于非极大值抑制NMS,如果不理解,可以参考我们以前的内容:【目标检测】 非极大值抑制—NMS_卖报的大地主的博客-CSDN博客),得到最后的检测结果(最终的预测框位置信息、类别及其置信度信息)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6h745YOd-1685955497734)(E:\学习笔记\深度学习笔记\目标检测专栏\YOLO\yolov1.assets\image-20230605142559202.png)]


2、YOLOv1进行目标检测的详细步骤


  1. 网络输入和分割:将一幅待检测图像分割分割成S*S个网格,,比如7 * 7, 13 * 13,在原文中S=7。

  2. 边界框预测: 每个网格预测B个边界框(bounding box),在原文中B=2,**每个边界框包含5个基本参数:位置(x、y坐标)、宽度w、高度h和置信度C。**其中:(x、y)表示边界框的中心相对于其所属网格左上角的位置偏移量;宽度w、高度h表示相对于整个图像的比例;C表示边界框的置信度,confidence = Pr(object) * IOU (pred, truth), Pr(object)代表边界框中存在物体的概率,非0即1,IOU (pred, truth)代表预测框与真实标签框的交并比。

    在训练时,某物体的真实边界框的中心落在哪个网格上就由哪个网格负责预测该物体,并且在网格所生成的B个边界框中,与真实边界框的IOU最大的边界框负责预测该物体,这一部分在loss函数中有所体现。每个网格只能预测一个物体(这也是造成YOLOv1对小物体和密集型物体检测效果差的主要原因)。

  3. 类别预测: 每个网格还预测一组类别的条件概率Pr(class | object) ,即在当前边界框已包含物体的先验条件下该物体为各类别的概率,用于确定边界框中物体的类别。

    在进行推理预测时,每个边界框的类别预测概率与该边界框的置信度相乘,得到最终的类别置信度,即Pr(class | object) * Pr(object) * IOU (pred, truth) = Pr(class) * IOU (pred, truth)。根据同样的方法可以计算得到7 x 7 x 2 = 98个边界框的confidence score(当S =7, B =2时),然后根据confidence score对预测得到的98个边界框进行非极大值抑制,得到最终的检测结果。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRUHwuzf-1685955497735)(E:\学习笔记\深度学习笔记\目标检测专栏\YOLO\yolov1.assets\image-20230605152842548.png)]

  4. 网络输出: 网络的输出是一个SxSx(B*5+C)的张量,相当于每个网格都输出一个形状为B * 5+C的张量,包含B个边界框中每个边界框的位置信息和置信度信息(边界框的中心点xy坐标和宽w高h以及置信度信息),以及该网格所负责预测物体的类别概率(C个值,所属C个类别的概率,原文中C等于20,即检测20个类别)。这些位置预测结果是相对于输入图像的尺度的,因此可以通过将相对尺度乘以图像的宽度和高度来得到实际的边界框。

  5. 置信度评估和非极大值抑制: 对于每个边界框,根据其置信度和类别置信度进行综合评估。通常,可以使用阈值来筛选置信度较高的边界框,并使用非极大值抑制来消除重叠的边界框,从而得到最终的目标检测结果。

3、YOLOv1的网络结构及pytorch实现


YOLOv1的网络结构比较简单,有24个卷积层以及两个全连接层组成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MAwqdHLn-1685955497737)(E:\学习笔记\深度学习笔记\目标检测专栏\YOLO\yolov1.assets\image-20230605151335069.png)]

如下给出网络的PyTorch实现:

import torch
import torch.nn as nn
import torch.nn.functional as F

class YOLOv1(nn.Module):
    def __init__(self, num_classes, num_boxes):
        super(YOLOv1, self).__init__()
        self.num_classes = num_classes
        self.num_boxes = num_boxes

        # 网络的各层定义
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        
        self.conv2 = nn.Conv2d(64, 192, kernel_size=3, stride=1, padding=1)
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
        
        self.conv3 = nn.Conv2d(192, 128, kernel_size=1, stride=1, padding=0)
        self.conv4 = nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1)
        self.conv5 = nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=0)
        self.conv6 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1)
        self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)
        
        self.conv7 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0)
        self.conv8 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1)
        self.conv9 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0)
        self.conv10 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1)
        self.conv11 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0)
        self.conv12 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1)
        self.conv13 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0)
        self.conv14 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1)
        self.conv15 = nn.Conv2d(512, 512, kernel_size=1, stride=1, padding=0)
        self.conv16 = nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1)
        self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)
        
        self.conv17 = nn.Conv2d(1024, 512, kernel_size=1, stride=1, padding=0)
        self.conv18 = nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1)
        self.conv19 = nn.Conv2d(1024, 512, kernel_size=1, stride=1, padding=0)
        self.conv20 = nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1)
        self.conv21 = nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1)
        self.conv22 = nn.Conv2d(1024, 1024, kernel_size=3, stride=2, padding=1)
        
        self.conv23 = nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1)
        self.conv24 = nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1)
        
        self.fc1 = nn.Linear(7 * 7 * 1024, 4096)
        self.fc2 = nn.Linear(4096, 7 * 7 * (self.num_classes + 5 * self.num_boxes))
        self.softmax = nn.Softmax(dim=1)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool1(x)
        x = F.relu(self.conv2(x))
        x = self.pool2(x)
        x = F.relu(self.conv3(x))
        x = F.relu(self.conv4(x))
        x = F.relu(self.conv5(x))
        x = self.pool3(x)
        x = F.relu(self.conv6(x))
        x = F.relu(self.conv7(x))
        x = F.relu(self.conv8(x))
        x = F.relu(self.conv9(x))
        x = F.relu(self.conv10(x))
        x = F.relu(self.conv11(x))
        x = F.relu(self.conv12(x))
        x = F.relu(self.conv13(x))
        x = F.relu(self.conv14(x))
        x = F.relu(self.conv15(x))
        x = F.relu(self.conv16(x))
        x = self.pool4(x)
        x = F.relu(self.conv17(x))
        x = F.relu(self.conv18(x))
        x = F.relu(self.conv19(x))
        x = F.relu(self.conv20(x))
        x = F.relu(self.conv21(x))
        x = F.relu(self.conv22(x))
        x = F.relu(self.conv23(x))
        x = F.relu(self.conv24(x))
        x = x.view(x.size(0), -1)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        x = self.softmax(x)
        return x

4、YOLOv1的loss函数及pytorch实现


网络的Loss部分:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-baemJNCP-1685955497738)(E:\学习笔记\深度学习笔记\目标检测专栏\YOLO\yolov1.assets\image-20230605155019661.png)]

YOLOv1将检测视为回归任务,所以选用回归常用的平方和损失作为loss函数,主要由位置坐标回归误差、置信度回归误差、类别预测误差三部分组成。

  1. 位置坐标误差只统计负责检测物体的边界框的定位误差,由边界框的中心坐标定位误差和宽高定位误差组成。

  2. 置信度回归误差对负责检测物体的边界框和不负责的边界框都进行惩罚,公式中的置信度预测值为模型正向计算的输出结果中的置信度,置信度真实值为confidence = Pr(object) * IOU (pred, truth)。

  3. 类别预测误差仅对存在物体的网格(真实边界框的中心点落在该网格中)进行错误惩罚.

Note:

  • 平方和loss对各类误差一视同仁,图像中不包含物体的网格的边界框置信度等于0,容易超过包含物体网格的gradient,会导致模型训练不稳定,所以论文中采用了不同的权重因子,对定位误差和分类误差进行权衡。λcoord=5 — 增强边界框定位误差;λnoobj=5 — 削弱不包含物体的边界框置信度误差;

  • 平方和loss对大小边界框的惩罚力度一致,但我们应该使得大框的小偏差比小框中的偏差对loss训练优化的影响要小,原文中将Loss中的宽高进行了开平方根,而不是直接使用宽高,使得小框的偏差对总体误差的影响更加敏感。

YOLOv1 Loss的Pytorch实现:

import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F


class MSEWithLogitsLoss(nn.Module):
    def __init__(self, ):
        super(MSEWithLogitsLoss, self).__init__()

    def forward(self, logits, targets):
        inputs = torch.clamp(torch.sigmoid(logits), min=1e-4, max=1.0 - 1e-4)

        pos_id = (targets==1.0).float()
        neg_id = (targets==0.0).float()
        pos_loss = pos_id * (inputs - targets)**2
        neg_loss = neg_id * (inputs)**2
        loss = 5.0*pos_loss + 1.0*neg_loss

        return loss


def generate_dxdywh(gt_label, w, h, s):
    xmin, ymin, xmax, ymax = gt_label[:-1]
    # 计算边界框的中心点
    c_x = (xmax + xmin) / 2 * w
    c_y = (ymax + ymin) / 2 * h
    box_w = (xmax - xmin) * w
    box_h = (ymax - ymin) * h

    if box_w < 1e-4 or box_h < 1e-4:
        # print('Not a valid data !!!')
        return False    

    # 计算中心点所在的网格坐标
    c_x_s = c_x / s
    c_y_s = c_y / s
    grid_x = int(c_x_s)
    grid_y = int(c_y_s)
    # 计算中心点偏移量和宽高的标签
    tx = c_x_s - grid_x
    ty = c_y_s - grid_y
    tw = np.log(box_w)
    th = np.log(box_h)
    # 计算边界框位置参数的损失权重
    weight = 2.0 - (box_w / w) * (box_h / h)

    return grid_x, grid_y, tx, ty, tw, th, weight


def gt_creator(input_size, stride, label_lists=[]):
    # 必要的参数
    batch_size = len(label_lists)
    w = input_size
    h = input_size
    ws = w // stride
    hs = h // stride
    s = stride
    gt_tensor = np.zeros([batch_size, hs, ws, 1+1+4+1])

    # 制作训练标签
    for batch_index in range(batch_size):
        for gt_label in label_lists[batch_index]:
            gt_class = int(gt_label[-1])
            result = generate_dxdywh(gt_label, w, h, s)
            if result:
                grid_x, grid_y, tx, ty, tw, th, weight = result

                if grid_x < gt_tensor.shape[2] and grid_y < gt_tensor.shape[1]:
                    gt_tensor[batch_index, grid_y, grid_x, 0] = 1.0
                    gt_tensor[batch_index, grid_y, grid_x, 1] = gt_class
                    gt_tensor[batch_index, grid_y, grid_x, 2:6] = np.array([tx, ty, tw, th])
                    gt_tensor[batch_index, grid_y, grid_x, 6] = weight


    gt_tensor = gt_tensor.reshape(batch_size, -1, 1+1+4+1)

    return torch.from_numpy(gt_tensor).float()


def compute_loss(pred_conf, pred_cls, pred_txtytwth, targets):
    batch_size = pred_conf.size(0)
    # 损失函数
    conf_loss_function = MSEWithLogitsLoss()
    cls_loss_function = nn.CrossEntropyLoss(reduction='none')
    txty_loss_function = nn.BCEWithLogitsLoss(reduction='none')
    twth_loss_function = nn.MSELoss(reduction='none')

    # 预测
    pred_conf = pred_conf[:, :, 0]           # [B, HW,]
    pred_cls = pred_cls.permute(0, 2, 1)     # [B, C, HW]
    pred_txty = pred_txtytwth[:, :, :2]      # [B, HW, 2]
    pred_twth = pred_txtytwth[:, :, 2:]      # [B, HW, 2]
    
    # 标签
    gt_obj = targets[:, :, 0]                  # [B, HW,]
    gt_cls = targets[:, :, 1].long()           # [B, HW,]
    gt_txty = targets[:, :, 2:4]               # [B, HW, 2]
    gt_twth = targets[:, :, 4:6]               # [B, HW, 2]
    gt_box_scale_weight = targets[:, :, 6]     # [B, HW,]

    batch_size = pred_conf.size(0)
    # 置信度损失
    conf_loss = conf_loss_function(pred_conf, gt_obj)
    conf_loss = conf_loss.sum() / batch_size
    
    # 类别损失
    cls_loss = cls_loss_function(pred_cls, gt_cls) * gt_obj
    cls_loss = cls_loss.sum() / batch_size
    
    # 边界框txty的损失
    txty_loss = txty_loss_function(pred_txty, gt_txty).sum(-1) * gt_obj * gt_box_scale_weight
    txty_loss = txty_loss.sum() / batch_size

    # 边界框twth的损失
    twth_loss = twth_loss_function(pred_twth, gt_twth).sum(-1) * gt_obj * gt_box_scale_weight
    twth_loss = twth_loss.sum() / batch_size
    bbox_loss = txty_loss + twth_loss

    # 总的损失
    total_loss = conf_loss + cls_loss + bbox_loss

    return conf_loss, cls_loss, bbox_loss, total_loss

5、YOLOv1的不足


  • 因为YOLO中每个cell只预测两个边界框和一个物体,使得对小物体以及密集型物体检测效果差。
  • 此外,不像Faster R-CNN一样预测offset,YOLO是直接预测边界框的位置的,这就增加了训练的难度,并且识别精度弱于Faster R-CNN,但是快。
  • YOLO是根据训练数据来预测边界框的,但是当测试数据中的物体出现了训练数据中的物体没有的长宽比时,YOLO的泛化能力低。
  • 同时经过多次下采样,使得最终得到的feature的分辨率比较低,就是得到深语义的粗特征信息,忽略了细语义特征,造成定位精度下降。
  • 损失函数的设计存在缺陷,使得物体的定位误差有点儿大,尤其在不同尺寸大小的物体的处理上还有待加强。

6、其他


另外,YOLOv1中的训练过程中还是用到了Warm up、Dropout、数据增强(缩放、平移、HSV变换)等技巧,这些我们会在以后关于模型训练技巧的篇章中进行讲解。

参考链接:

  • 【精读AI论文】YOLO V1目标检测,看我就够了_哔哩哔哩_bilibili
  • 【目标检测论文阅读】YOLOv1 - 知乎 (zhihu.com)
  • yjh0410/PyTorch_YOLOv1: A new version of YOLOv1 (github.com)

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

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

相关文章

log4j 2自动配置的优先级顺序

log4j 2按照下面优先级由高到低的顺序查找使用日志的配置&#xff1a; 1、系统变量log4j2.configurationFile中指明的配置文件&#xff1b; 2、类路径上的log4j2-test.properties配置文件&#xff1b; 3、类路径上的log4j2-test.yaml 或者 log4j2-test.yml配置文件&#xff1b;…

【C++】C++中的I/O类总结——上篇

title: 【C】C-中的I/O类总结 tags: C description: ’ ’ categories: C date: 2023-06-05 00:36:59 引入 #include <iostream>int main(){std::cout<<"Hello World!"<<std::endl;}我们在学习C时&#xff0c;往往都是从上面这段程序开始的 也就…

React - Mobx

Mobx 简介 mobx是一个可以和React良好配合的集中状态管理工具&#xff0c;和Redux解决的问题相似&#xff0c;都可以独立组件进行集中状态管理 优势 简单 编写无模板的极简代码精准描述你的意图 轻松实现最优渲染 依赖自动追踪&#xff0c;实现最小渲染优化 架构自由 可…

Flutter - 一行命令解决多个pubspec.yaml文件的依赖项问题

文章目录 前言开发环境Flutter内置命令一行命令实现1. 命令使用2. 命令解释3. 命令扩展 最后 前言 项目为了模块化&#xff0c;创建了一堆Package和Plugin&#xff0c;这么做没什么问题&#xff0c;但是遇到Flutter SDK目录路径变化或者其他一些情况导致需要重新获取依赖项时就…

50+常用的广告联盟术语 (常用缩写)

广告联盟术语是指与广告联盟业务有关的行话和缩写。这些术语通常用于描述商业模型、营销策略、流量源、收益模型等方面的概念。了解广告联盟术语对于广告主、联盟会员、广告服务提供商等参与者都非常重要&#xff0c;因为它们可以帮助他们更好地理解广告联盟业务&#xff0c;提…

IDEA 2022.3.3 创建SpringBoot项目

目录 步骤01&#xff1a;快速创建项目 步骤02&#xff1a;选择依赖 步骤03&#xff1a;pom文件中版本问题 ​步骤04&#xff1a;启动测试 4.1、认识引导类 4.2、创建Controller类进行测试 可能遇到的问题及解决方案 附件1&#xff1a;pom文件源码 附件2&#xff1a;项…

华为OD机试题【食堂供餐】【2023 B卷 100分】

文章目录 &#x1f3af; 前言&#x1f3af; 题目描述&#x1f3af; 解题思路&#x1f4d9; Python代码实现&#x1f4d7; Java代码实现&#x1f4d8; C语言代码实现 &#x1f3af; 前言 &#x1f3c6; 《华为机试真题》专栏含2023年牛客网面经、华为面经试题、华为OD机试真题最…

Python使用正则表达式识别代码中的中文、英文和数字实例演示

Python 正则表达式识别代码中的中文、英文和数字 识别中文识别英文识别数字拓展 在文本处理和数据分析中&#xff0c;有时候需要从代码中提取出其中包含的中文、英文和数字信息。正则表达式是一种强大的工具&#xff0c;可以帮助我们实现这一目标。本文将分三个部分详细介绍如何…

chatgpt赋能python:Python如何倒序输出一组数

Python如何倒序输出一组数 Python是一种广泛使用的高级编程语言&#xff0c;由于其易读性和简洁性&#xff0c;Python已成为Web开发、数据分析以及人工智能等方向的首选语言。而在程序编写过程中&#xff0c;倒序输出一组数也是一个经常用到的操作。在本文中&#xff0c;我们将…

ActiveReportsJS 4.0.2 Crack ActiveReportsJS New

ActiveReportsJS - 高级 JavaScript 报告解决方案 ActiveReportsJS 是一个强大的 Web 应用程序报告工具&#xff0c;它允许开发人员和报告作者轻松地在他们的应用程序中设计和显示报告。凭借广泛的功能&#xff0c;例如向下钻取、运行时数据过滤和参数驱动的报告&#xff0c;以…

基于时间的访问控制列表(ACL)配置实验

基于时间的访问控制列表&#xff08;ACL&#xff09;配置实验 【实验目的】 掌握基于时间的ACL配置。认识给予时间的ACL的作用。验证配置。 【实验拓扑】 实验拓扑如下图所示。 设备参数如下表所示。 设备 接口 IP地址 子网掩码 默认网关 R1 S0/3/0 192.168.1.1 255…

24万字智慧城市时空信息云平台 大数据一体化 解决方案word

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除篇幅有限&#xff0c;无法完全展示&#xff0c;喜欢资料可转发评论&#xff0c;私信了解更多信息。 第二章 XX新型智慧城市总体设计 2.1 新型智慧城市核心技术 2.2 新型智慧城…

chatgpt赋能python:Python如何倒着循环:一步步教你倒序遍历序列

Python如何倒着循环&#xff1a;一步步教你倒序遍历序列 Python是一种高级编程语言&#xff0c;因其语法简单易学&#xff0c;常被用于数据分析、机器学习、自然语言处理等领域。在实际开发中&#xff0c;我们经常需要遍历序列。有时需要倒着循环序列&#xff0c;本文将详细介…

Roop:Colab脚本使用方法!

​AI领域人才辈出&#xff0c;突然就跳出一个大佬“s0md3v”&#xff0c;开源了一个单图就可以进行视频换脸的项目。 项目主页给了一张换脸动图非常有说服力&#xff0c;真是一图胜万言。 快速在本地配置一个环境&#xff0c;验证了一下&#xff0c;确实还不错。主要是&#xf…

使用ChatGPT生成思维导图(附永久免费镜像网址)

前言 思维导图&#xff08;The Mind Map&#xff09;&#xff0c;是表达发散性思维的有效图形思维工具。思维导图运用图文并重的技巧&#xff0c;把各级主题的关系用相互隶属与相关的层级图表现出来&#xff0c;把主题关键词与图像、颜色等建立记忆链接 &#xff0c;可以应用于…

Python-web开发学习笔记(3):CSS基础

&#x1f680; Python-web开发学习笔记系列往期文章&#xff1a; &#x1f343; Python-web开发学习笔记&#xff08;1&#xff09;--- HTML基础 &#x1f343; Python-web开发学习笔记&#xff08;2&#xff09;--- HTML基础 &#x1f343; Python-web开发学习笔记&#xff08…

网络层概述及提供的两种服务

1.网络层概述及提供的两种服务 笔记来源&#xff1a; 湖科大教书匠&#xff1a;网络层概述 湖科大教书匠&#xff1a;网络层提供的两种服务 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 1.1 网络层概述 网络层的主要任务是实现网络互连&#xf…

Linux 高级篇-日志管理

Linux 高级篇-日志管理 基本介绍 日志文件是重要的系统信息文件&#xff0c;其中记录了许多重要的系统事件&#xff0c;包括用户的登录信息、系统的启动信息、系统的安全信息、邮件相关信息、各种服务相关信息等。日志对于安全来说也很重要&#xff0c;它记录了系统每天发生的…

Python读写EXCEL文件常用方法

python读写excel的方式有很多&#xff0c;不同的模块在读写的讲法上稍有区别&#xff0c;这里我主要介绍几个常用的方式。 用xlrd和xlwt进行excel读写&#xff1b;用openpyxl进行excel读写&#xff1b;用pandas进行excel读写&#xff1b; 一、数据准备 为了方便演示&#xf…

在滴滴和字节干了4年测试开发,简直不要太真实…

先简单交代一下&#xff0c;某不知名211的本硕&#xff0c;18年毕业加入滴滴&#xff0c;之后跳槽到了头条&#xff0c;一直从事测试开发相关的工作。之前没有实习经历&#xff0c;算是四年的工作经验吧。 这四年之间完成了一次晋升&#xff0c;换了一家公司&#xff0c;有过开…