CV - 目标检测

news2025/4/7 15:06:43

物体检测

目标检测和图片分类的区别:

图像分类(Image Classification)

目的:图像分类的目的是识别出图像中主要物体的类别。它试图回答“图像是什么?”的问题。
输出:通常输出是一个标签或一组概率值,表示图像属于各个预定义类别的可能性。例如,对于一张包含猫的图片,分类器可能会输出“猫”这个标签。
应用场景:适用于只需要了解图像整体内容的场景,如识别照片中的动物种类、区分不同的风景类型等。

目标检测(Object Detection)

目的:目标检测不仅需要识别图像中所有感兴趣物体的类别,还需要确定每个物体在图像中的具体位置。它试图回答“图像中有什么?它们在哪里?”的问题。
输出:除了给出物体的类别外,还会输出物体所在的边界框(bounding box),即用矩形框标记出每个物体的位置。例如,在自动驾驶场景下,系统不仅要能识别出行人、车辆等物体,还要精确地定位它们的位置以便做出安全决策。
应用场景:适合于需要知道图像内特定对象位置的情况,比如视频监控、自动驾驶汽车、医学影像分析等领域。

边缘框

  • 一个边缘框可以通过 4 个数字定义
    • (左上 x,左上 y,右下 x,右下 y)
    • (左上 x,左上 y,宽,高)
      在这里插入图片描述

目标检测数据集

  • 每行表示一个物体
    • 图片文件名,物体类别,边缘框
  • COCO (cocodataset.org)
    • 80 物体,330K 图片,1.5M 物体

总结

  • 物体检测识别图片里的多个物体的类别和位置
  • 位置通常用边缘框表示。

边缘框实现

%matplotlib inline
import torch
from d2l import torch as d2l

d2l.set_figsize()
img = d2l.plt.imread('../img/catdog.jpg')
d2l.plt.imshow(img);

在这里插入图片描述
定义在这两种表示法之间进行转换的函数

#@save
def box_corner_to_center(boxes):
    """从(左上,右下)转换到(中间,宽度,高度)"""
    x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2
    w = x2 - x1
    h = y2 - y1
    boxes = torch.stack((cx, cy, w, h), axis=-1)
    return boxes

#@save
def box_center_to_corner(boxes):
    """从(中间,宽度,高度)转换到(左上,右下)"""
    cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    x1 = cx - 0.5 * w
    y1 = cy - 0.5 * h
    x2 = cx + 0.5 * w
    y2 = cy + 0.5 * h
    boxes = torch.stack((x1, y1, x2, y2), axis=-1)
    return boxes

定义图像中狗和猫的边界框

# bbox是边界框的英文缩写
dog_bbox, cat_bbox = [60.0, 45.0, 378.0, 516.0], [400.0, 112.0, 655.0, 493.0]

boxes = torch.tensor((dog_bbox, cat_bbox))
box_center_to_corner(box_corner_to_center(boxes)) == boxes

在这里插入图片描述
将边界框在图中画出

#@save
def bbox_to_rect(bbox, color):
    # 将边界框(左上x,左上y,右下x,右下y)格式转换成matplotlib格式:
    # ((左上x,左上y),宽,高)
    return d2l.plt.Rectangle(
        xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0], height=bbox[3]-bbox[1],
        fill=False, edgecolor=color, linewidth=2)

fig = d2l.plt.imshow(img)
fig.axes.add_patch(bbox_to_rect(dog_bbox, 'blue'))
fig.axes.add_patch(bbox_to_rect(cat_bbox, 'red'));

在这里插入图片描述

数据集

李沐老师收集并标记了一个小型数据集,下面首先是下载该数据集:

%matplotlib inline
import os
import pandas as pd
import torch
import torchvision
from d2l import torch as d2l

#@save
d2l.DATA_HUB['banana-detection'] = (
    d2l.DATA_URL + 'banana-detection.zip',
    '5de26c8fce5ccdea9f91267273464dc968d20d72')

读取香蕉检测数据集

#@save
def read_data_bananas(is_train=True):
    """读取香蕉检测数据集中的图像和标签"""
    data_dir = d2l.download_extract('banana-detection')
    csv_fname = os.path.join(data_dir, 'bananas_train' if is_train
                             else 'bananas_val', 'label.csv')
    csv_data = pd.read_csv(csv_fname)
    csv_data = csv_data.set_index('img_name')
    images, targets = [], []
    for img_name, target in csv_data.iterrows():
        images.append(torchvision.io.read_image(
            os.path.join(data_dir, 'bananas_train' if is_train else
                         'bananas_val', 'images', f'{img_name}')))
        # 这里的target包含(类别,左上角x,左上角y,右下角x,右下角y),
        # 其中所有图像都具有相同的香蕉类(索引为0)
        targets.append(list(target))
    return images, torch.tensor(targets).unsqueeze(1) / 256

创建一个自定义 Dataseet 实例:

#@save
class BananasDataset(torch.utils.data.Dataset):
    """一个用于加载香蕉检测数据集的自定义数据集"""
    def __init__(self, is_train):
        self.features, self.labels = read_data_bananas(is_train)
        print('read ' + str(len(self.features)) + (f' training examples' if
              is_train else f' validation examples'))

    def __getitem__(self, idx):
        return (self.features[idx].float(), self.labels[idx])

    def __len__(self):
        return len(self.features)

为训练集和测试集返回两个数据加载器实例

#@save
def load_data_bananas(batch_size):
    """加载香蕉检测数据集"""
    train_iter = torch.utils.data.DataLoader(BananasDataset(is_train=True),
                                             batch_size, shuffle=True)
    val_iter = torch.utils.data.DataLoader(BananasDataset(is_train=False),
                                           batch_size)
    return train_iter, val_iter

读取一个小批量,并打印其中的图像和标签的形状

batch_size, edge_size = 32, 256
train_iter, _ = load_data_bananas(batch_size)
batch = next(iter(train_iter))
batch[0].shape, batch[1].shape

在这里插入图片描述
演示:

imgs = (batch[0][0:10].permute(0, 2, 3, 1)) / 255
axes = d2l.show_images(imgs, 2, 5, scale=2)
for ax, label in zip(axes, batch[1][0:10]):
    d2l.show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w'])

在这里插入图片描述

QA 思考

Q1:如果在工业检测中数据集非常小(近百张),除了进行数据增强外,还有什么更好的方法吗?
A1:迁移学习:找一个非常好的,在一个比较大的目标检测数据集上训练的比较好的模型,然后拿过来进行微调。近百张其实也不算小的了,只是说模型训练出来不是很好。数据增强的话,对图像进行处理,对应的框也必须要相应的变化一下,这是比较麻烦的点。

后记

自己实现了一遍,然后也是使用的李沐老师在课件中提供的狗猫图片:

import torch
from matplotlib import pyplot as plt
from PIL import Image

def set_image_display_size():
    plt.figure(figsize=(8, 6))

def load_image(img_path):
    return Image.open(img_path)

def show_single_image(img):
    plt.imshow(img)
    plt.axis('on')  # 显示坐标轴
    plt.show()

def box_corner_to_center(boxes):
    x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2
    w = x2 - x1
    h = y2 - y1
    boxes = torch.stack((cx, cy, w, h), axis=-1)
    return boxes

def box_center_to_corner(boxes):
    # 这里向左和向上都是减小的
    cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    x1 = cx - 0.5 * w
    y1 = cy - 0.5 * h
    x2 = cx + 0.5 * w
    y2 = cy + 0.5 * h
    boxes = torch.stack((x1, y1, x2, y2), axis=-1)
    return boxes

def bbox_to_rect(bbox, color):
    # 将边界框(左上x, 左上y, 右下x, 右下y)格式转换成matplotlib格式:
    # ((左上x, 左上y), 宽, 高)
    return plt.Rectangle(
        xy=(bbox[0], bbox[1]), width=bbox[2] - bbox[0], height=bbox[3] - bbox[1],
        fill=False, edgecolor=color, linewidth=2)

if __name__ == "__main__":
    # 设置图像显示大小
    set_image_display_size()

    # 加载图像
    img_path = '../image/catdog.jpg'  # 确保路径正确
    img = load_image(img_path)
    show_single_image(img)

    # dog, cat 边界框
    dog_bbox, cat_bbox = [60.0, 45.0, 378.0, 516.0], [400.0, 112.0, 655.0, 493.0]

    # 转换为张量并测试转换函数是否正确
    boxes = torch.tensor((dog_bbox, cat_bbox))
    converted_boxes = box_center_to_corner(box_corner_to_center(boxes))
    # torch.allclose,判断两个张量是否在一定容差范围内相等。
    print("转换是否一致:", torch.allclose(converted_boxes, boxes))

    # 显示图像并绘制边界框,imshow 将 img 显示在画布上
    fig = plt.imshow(img)
    # add_patch 是 matplotlib 中用于在坐标轴上添加图形元素(如矩形、圆形等)的函数
    fig.axes.add_patch(bbox_to_rect(dog_bbox, 'blue'))  # 狗的边界框
    fig.axes.add_patch(bbox_to_rect(cat_bbox, 'red'))  # 猫的边界框
    plt.show()

我在colab上跑了一下下面的代码,发现可以,下载不了的可能需要一点 “魔法”

import hashlib
import os
import tarfile
import zipfile
import pandas as pd
import requests
import torch
import torchvision

from matplotlib import pyplot as plt

"""
    这段代码本身并没有包含训练过程。它只是加载了已经标注好的香蕉检测数据集,并可视化了图像及其对应的边界框。
    这些边界框信息是预先标注好的(存储在 CSV 文件中),而不是通过模型训练得到的。
    
    read_data_bananas 函数读取数据集中的图像和标签:
        图像存储在文件夹中(如 bananas_train/images/)。
        标签存储在 CSV 文件中(如 bananas_train/label.csv)。
        每个标签包括图像名称、目标类别(香蕉类别的索引为 0)、以及边界框坐标。
        
    zip 结构类似如下:
            banana-detection/
        ├── bananas_train/
        │   ├── images/
        │   │   ├── image1.jpg
        │   │   ├── image2.jpg
        │   │   └── ...
        │   └── label.csv  # 包含每张图像的标注信息(即边界框和类别)
        └── bananas_val/
            ├── images/
            │   ├── image1.jpg
            │   ├── image2.jpg
            │   └── ...
            └── label.csv
"""
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'

DATA_HUB['banana-detection'] = (
    DATA_URL + 'banana-detection.zip',
    '5de26c8fce5ccdea9f91267273464dc968d20d72')


def download(name, cache_dir=os.path.join('..', 'data')):
    """下载一个DATA_HUB中的文件,返回本地文件名"""
    # assert 条件, 错误信息
    assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}"
    """
        url:文件的下载地址。 http://d2l-data.s3-accelerate.amazonaws.com/banana-detection.zip
        sha1_hash:文件内容的 SHA-1 校验值,用于验证文件完整性。5de26c8fce5ccdea9f91267273464dc968d20d72
    """
    url, sha1_hash = DATA_HUB[name]
    """
        递归创建目录:包括所有必要的父目录。
        避免重复创建导致的错误:如果目录已经存在,不会抛出异常。
    """
    os.makedirs(cache_dir, exist_ok=True)
    """
        url.split('/')[-1]:提取 URL 路径的最后一部分(通常是文件名)。
        os.path.join(cache_dir, ...):将缓存目录和文件名组合成完整的本地文件路径。
    """
    fname = os.path.join(cache_dir, url.split('/')[-1])  # fname = ../data/banana-detection.zip
    if os.path.exists(fname):  # 文件存在,进入校验流程
        # 创建一个 SHA-1 哈希对象,用于计算文件的哈希值。
        sha1 = hashlib.sha1()
        # 以二进制模式读取文件
        with open(fname, 'rb') as f:
            while True:
                # 每次读取 1MB 数据(1048576 字节),更新哈希对象。
                data = f.read(1048576)
                # 为空,退出循环
                if not data:
                    break
                # 将读取的数据块逐步添加到哈希计算中
                sha1.update(data)
        """
            计算哈希值:
                调用 sha1.hexdigest() 获取最终的 SHA-1 哈希值(40 个字符的十六进制字符串)。
            校验哈希值:
                将计算得到的哈希值与预期的哈希值 sha1_hash 进行比较。
                如果两者相等,说明文件完整且未被篡改,直接返回文件路径(命中缓存)。
                否则,继续执行下载逻辑。
        """
        if sha1.hexdigest() == sha1_hash:
            return fname  # 命中缓存
    print(f'正在从{url}下载{fname}...')
    """
        使用 requests.get 方法发送 HTTP 请求,从远程服务器下载文件。
        参数说明:
            stream=True:以流式方式下载文件,避免一次性加载整个文件到内存中。
            verify=True:启用 SSL 证书验证,确保安全连接。
    """
    r = requests.get(url, stream=True, verify=True)
    """
        打开本地文件 fname,以二进制写入模式('wb')创建或覆盖文件。
            将下载的内容 r.content 写入文件。
            下载完成后,关闭文件。
    """
    with open(fname, 'wb') as f:
        f.write(r.content)
    return fname


def download_extract(name, folder=None):
    """下载并解压zip/tar文件"""
    fname = download(name)  # 下载文件的完整路径
    """
        os.path.dirname(fname):提取文件所在的目录路径(即父目录)。
            例如,如果 fname 是 '../data/example.zip',则 base_dir 是 '../data'。
        os.path.splitext(fname):将文件路径拆分为文件名和扩展名。
            例如,如果 fname 是 '../data/example.zip',则 data_dir 是 '../data/example',ext 是 '.zip'。
    """
    base_dir = os.path.dirname(fname)
    data_dir, ext = os.path.splitext(fname)
    if ext == '.zip':
        fp = zipfile.ZipFile(fname, 'r')
    elif ext in ('.tar', '.gz'):
        fp = tarfile.open(fname, 'r')
    else:
        assert False, '只有zip/tar/gz 文件可以被解压缩'
    # 解压文件到指定的目录 base_dir
    fp.extractall(base_dir)
    """
        如果 folder 参数存在:
            返回 os.path.join(base_dir, folder),即解压后目录下的指定子目录。
        如果 folder 参数不存在:
            返回 data_dir,即解压后的默认目录。
    """
    return os.path.join(base_dir, folder) if folder else data_dir


def read_data_bananas(is_train=True):
    """读取香蕉检测数据集中的图像和标签"""
    data_dir = download_extract('banana-detection')
    """
        根据 is_train 参数,确定加载训练集还是验证集的标注文件:
            如果 is_train=True,加载 'bananas_train/label.csv'。
            如果 is_train=False,加载 'bananas_val/label.csv'。
        使用 pandas 库的 read_csv 方法读取 CSV 文件内容。
        将 img_name 列设置为索引列(方便后续按图像名称访问数据)。
    """
    csv_fname = os.path.join(data_dir, 'bananas_train' if is_train
    else 'bananas_val', 'label.csv')  # for example: ../data/banana-detection/banana_train/label.csv
    csv_data = pd.read_csv(csv_fname)  # 读取 csv 文件
    # 将 img_name 列设置为索引列
    csv_data = csv_data.set_index('img_name')
    """
        images:用于存储读取的图像数据。
        targets:用于存储每张图像对应的标注信息。
    """
    images, targets = [], []
    """
        img_name:当前行的索引值(即图像名称)。
        target:当前行的数据(即标注信息)。
    """
    for img_name, target in csv_data.iterrows():
        images.append(torchvision.io.read_image(
            os.path.join(data_dir, 'bananas_train' if is_train else
            'bananas_val', 'images', f'{img_name}')))
        # 这里的target包含(类别,左上角x,左上角y,右下角x,右下角y),
        # 其中所有图像都具有相同的香蕉类(索引为0)
        targets.append(list(target))
    """
        images:图像数据列表。
        torch.tensor(targets).unsqueeze(1) / 256:
        将 targets 转换为 PyTorch 张量。
        使用 unsqueeze(1) 在维度 1 上增加一个维度,使其形状变为 (N, 1, 5),其中 N 是样本数量,5 是每个标注信息的长度。
        所有边界框坐标除以 256,进行归一化处理(假设图像大小为 256x256)。
    """
    return images, torch.tensor(targets).unsqueeze(1) / 256


class BananasDataset(torch.utils.data.Dataset):
    """一个用于加载香蕉检测数据集的自定义数据集"""

    def __init__(self, is_train):
        self.features, self.labels = read_data_bananas(is_train)
        print('read ' + str(len(self.features)) + (f' training examples' if
                                                   is_train else f' validation examples'))
        # such as : read 1000 training examples

    def __getitem__(self, idx):
        return self.features[idx].float(), self.labels[idx]

    def __len__(self):
        return len(self.features)


def load_data_bananas(batch_size):
    """加载香蕉检测数据集"""
    train_iter = torch.utils.data.DataLoader(BananasDataset(is_train=True),
                                             batch_size, shuffle=True)
    val_iter = torch.utils.data.DataLoader(BananasDataset(is_train=False),
                                           batch_size)
    return train_iter, val_iter


def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):
    figsize = (num_cols * scale, num_rows * scale)
    """
        _:表示整个图形对象(这里用下划线忽略)
        axes:表示所有子图的数组
    """
    _, axes = plt.subplots(num_rows, num_cols, figsize=figsize)
    axes = axes.flatten()
    for i, (ax, img) in enumerate(zip(axes, imgs)):
        if torch.is_tensor(img):
            ax.imshow(img.numpy())
        else:
            ax.imshow(img)
        ax.axes.get_xaxis().set_visible(False)
        ax.axes.get_yaxis().set_visible(False)
        if titles:
            ax.set_title(titles[i])
    return axes


def bbox_to_rect(bbox, color):
    """将边界框(左上x,左上y,右下x,右下y)格式转换成matplotlib格式:
    ((左上x,左上y),宽,高)"""
    return plt.Rectangle(
        xy=(bbox[0], bbox[1]), width=bbox[2] - bbox[0], height=bbox[3] - bbox[1],
        fill=False, edgecolor=color, linewidth=2)


# 定义一个名为 numpy 的函数,它能够将 PyTorch 张量转换为 NumPy 数组,并且自动处理张量的梯度信息
numpy = lambda x, *args, **kwargs: x.detach().numpy(*args, **kwargs)


def show_bboxes(axes, bboxes, labels=None, colors=None):
    """显示所有边界框"""
    """
        功能:将输入对象转换为列表形式。
        如果 obj 是 None,返回默认值 default_values。
        如果 obj 不是列表或元组,则将其包装成单元素列表。
        否则,直接返回 obj。
        作用:确保 labels 和 colors 参数始终是列表形式,以便后续迭代操作。
    """

    def _make_list(obj, default_values=None):
        if obj is None:
            obj = default_values
        elif not isinstance(obj, (list, tuple)):
            obj = [obj]
        return obj

    """
        将 labels 转换为列表形式。如果未提供标签,则返回空列表。
        将 colors 转换为列表形式。如果未提供颜色,则使用默认颜色列表 ['b', 'g', 'r', 'm', 'c'](蓝色、绿色、红色、洋红色、青色)。
    """
    labels = _make_list(labels)
    colors = _make_list(colors, ['b', 'g', 'r', 'm', 'c'])
    """
        遍历 bboxes 列表中的每个边界框 bbox。
        根据索引 i,从 colors 列表中循环选择颜色(防止颜色不足时重复使用)。
        调用 bbox_to_rect 函数,将边界框坐标转换为 Matplotlib 的矩形对象。
        假设 bbox_to_rect 是一个已定义的函数,用于将边界框坐标转换为 matplotlib.patches.Rectangle 对象。
        numpy(bbox):将边界框数据转换为 NumPy 数组(假设 bbox 是 PyTorch 张量)。
        使用 axes.add_patch(rect) 将矩形添加到绘图区域中。
    """
    for i, bbox in enumerate(bboxes):
        color = colors[i % len(colors)]
        rect = bbox_to_rect(numpy(bbox), color)
        axes.add_patch(rect)
        """
            检查是否提供了标签,并且当前索引 i 在标签范围内。
            根据边界框颜色选择标签文字的颜色:
            如果边界框颜色为白色('w'),标签文字颜色为黑色('k')。
            否则,标签文字颜色为白色('w')。
            使用 axes.text 方法,在边界框的左上角位置添加标签文本。
            rect.xy[0] 和 rect.xy[1]:矩形左上角的 x 和 y 坐标。
            va='center' 和 ha='center':设置文本垂直和水平居中对齐。
            fontsize=9:设置字体大小为 9。
            color=text_color:设置文本颜色。
            bbox=dict(facecolor=color, lw=0):为文本添加背景框,背景颜色与边界框一致,边框宽度为 0。
        """
        if labels and len(labels) > i:
            text_color = 'k' if color == 'w' else 'w'
            axes.text(rect.xy[0], rect.xy[1], labels[i],
                      va='center', ha='center', fontsize=9, color=text_color,
                      bbox=dict(facecolor=color, lw=0))


if __name__ == "__main__":
    batch_size, edge_size = 32, 256
    train_iter, _ = load_data_bananas(batch_size)
    """
        使用 iter(train_iter) 创建一个迭代器对象。
        调用 next() 获取迭代器的第一个批次的数据。
    """
    batch = next(iter(train_iter))
    """
        torch.Size([32, 3, 256, 256]):表示 32 张 RGB 图像,每张图像大小为 256x256。
        torch.Size([32, num_boxes, 5]):表示每张图像有 num_boxes 个边界框,每个边界框包含 5 个值(类别 + 坐标)。    
    """
    print(batch[0].shape, batch[1].shape)
    """
    功能:
        batch[0][0:10]:从 batch[0] 中提取前 10 张图像。
        .permute(0, 2, 3, 1):调整张量的维度顺序,将 (N, C, H, W) 转换为 (N, H, W, C),即从 PyTorch 的默认格式转换为适合显示的格式。
        / 255:将像素值归一化到 [0, 1] 范围(假设原始像素值范围是 [0, 255])。
    结果:
        imgs 是一个形状为 (10, 256, 256, 3) 的张量,表示 10 张归一化的 RGB 图像。
    """
    imgs = (batch[0][0:10].permute(0, 2, 3, 1)) / 255
    axes = show_images(imgs, 2, 5, scale=2)
    for ax, label in zip(axes, batch[1][0:10]):
        """
            label[0][1:5]:提取第一个边界框的坐标信息([x_min, y_min, x_max, y_max])。
            * edge_size:将归一化的坐标值还原为原始像素坐标。
            show_bboxes(ax, ...):在子图 ax 上绘制边界框,颜色为白色 ('w')。
        """
        show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w'])
    plt.show()
"""
归一化是为了模型训练:确保输入数据在合理的范围内,加速收敛并提高稳定性。
还原是为了可视化:将数据转换回原始范围,以便人类可以直观地理解图像和标注信息。
"""

在这里插入图片描述

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

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

相关文章

node-modules-inspector 可视化node_modules

1、node_modules 每个vue的项目都有很多的依赖,有的是dev的,有的是生产的。 2、使用命令pnpx node-modules-inspector pnpx node-modules-inspector 3、node_modules可视化 4、在线体验 Node Modules Inspector 5、github地址 https://github.com/a…

远程服务器下载llama模型

适用于有防火墙不能直接从HF上下载的情况 然后,你可以克隆 Llama-3.1-8B-Instruct 模型: git clone https://你的用户名:你的访问令牌hf-mirror.com/meta-llama/Llama-3.1-8B-Instruct用户名,令牌来自huggingface官网 注意:要提…

2011-2019年各省地方财政金融监管支出数据

2011-2019年各省地方财政金融监管支出数据 1、时间:2007-2019年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区、年份、地方财政金融监管支出 4、范围:31省 5、指标说明:地方财政在金融监管方面的支出…

Java大厂面试题 -- JVM 优化进阶之路:从原理到实战的深度剖析(2)

最近佳作推荐: Java大厂面试题 – 深度揭秘 JVM 优化:六道面试题与行业巨头实战解析(1)(New) 开源架构与人工智能的融合:开启技术新纪元(New) 开源架构的自动化测试策略优…

存储引擎 / 事务 / 索引

1. 存储引擎 MySQL 中特有的术语。 (Oracle 有,但不叫这个名字) 是一种表存储 / 组织数据的方式 不同的存储引擎,表存储数据的方式不同 1.1 查看存储引擎 命令: show engines \g(或大写:G…

RabbitMQ运维

RabbitMQ运维 一.集群1.简单介绍2.集群的作用 二.搭建集群1.多机多节点搭建步骤 2.单机单节点搭建步骤 3.宕机演示 三.仲裁队列1.简单介绍2.Raft协议Raft基本概念主节点选举选举过程 3.仲裁队列的使用 四.HAProxy负载均衡1.安装HAProxy2.HAProxy的使用 一.集群 1.简单介绍 Ra…

Ansible 实战:Roles,运维的 “魔法函数”

一、介绍 你现在已经学过tasks和handlers,那么,最好的playbook组织方式是什么呢?答案很简单:使用roles!roles基于一种已知的文件结构,能够自动加载特定的vars_files、tasks以及handlers。通过roles对内容进…

关于JVM和OS中的指令重排以及JIT优化

关于JVM和OS中的指令重排以及JIT优化 前言: 这东西应该很重要才对,可是大多数博客都是以讹传讹,全是错误,尤其是JVM会对字节码进行重排都出来了,明明自己测一测就出来的东西,写出来误人子弟… 研究了两天&…

在CPU服务器上部署Ollama和Dify的过程记录

在本指南中,我将详细介绍如何在CPU服务器上安装和配置Ollama模型服务和Dify平台,以及如何利用Docker实现这些服务的高效部署和迁移。本文分为三大部分:Ollama部署、Dify环境配置和Docker环境管理,适合需要在本地或私有环境中运行A…

【计网】TCP 协议详解 与 常见面试题

三次握手、四次挥手的常见面试题 不用死记,只需要清楚三次握手,四次挥手的流程,回答的时候心里要记住,假设网络是不可靠的 问题(1):为什么关闭连接时需要四次挥手,而建立连接却只要三次握手? 关…

7.4 SVD 的几何背景

一、SVD 的几何解释 SVD 将矩阵分解成三个矩阵的乘积: ( 正交矩阵 ) ( 对角矩阵 ) ( 正交矩阵 ) (\pmb{正交矩阵})\times(\pmb{对角矩阵})(\pmb{正交矩阵}) (正交矩阵)(对角矩阵)(正交矩阵),用几何语言表述其几何背景: ( 旋转 ) ( 伸缩 )…

C++的多态-上

目录 多态的概念 多态的定义及实现 1.虚函数 2. 多态的实现 2.1.多态构成条件 2.2.虚函数重写的两个例外 (1)协变(基类与派生类虚函数返回值类型不同) (2)析构函数的重写(基类与派生类析构函数的名字不同) 2.3.多态的实现 2.4.多态在析构函数中的应用 2.5.多态构成条…

内存与显存:从同根生到殊途异路的科技演进

在现代计算机的世界里,内存和显存是两个不可或缺的硬件组件。它们看似功能相近,却在发展历程中逐渐分道扬镳,各自服务于不同的计算需求。今天,我们将从一根内存条和一块显卡入手,深入探讨内存与显存的异同,…

手搓多模态-04 归一化介绍

在机器学习中,归一化是一个非常重要的工具,它能帮助我们加速训练的速度。在我们前面的SiglipVisionTransformer 中,也有用到归一化层,如下代码所示: class SiglipVisionTransformer(nn.Module): ##视觉模型的第二层&am…

【C++】第八节—string类(上)——详解+代码示例

hello,又见面了! 云边有个稻草人-CSDN博客 C_云边有个稻草人的博客-CSDN博客——C专栏(质量分高达97!) 菜鸟进化中。。。 目录 一、为什么要学习string类? 1.1 C语言中的字符串 1.2 面试题(暂不做讲解) …

Java 数组与 ArrayList 核心区别解析:从源码到实战!!!

🌟 Java 数组与 ArrayList 核心区别解析:从源码到实战 💡 Java 开发者必读! 数组(Array)和 ArrayList 是 Java 中最常用的数据存储结构,但它们的底层设计、性能表现和适用场景差异显著。本文通…

【易飞】易飞批量选择品号处理方法,工作效率提升300%

开窗选择品号方式要么手动输入,要么以什么开头、包含、从A物料到B物料查询后返回的有规律的品号。对于没有规律且大量品号的处理方式是否有便捷的方法呢? 尤其在通常在查询多阶材料清单,查询库存明细表,整批变更元件等如品号无规律情况下,只能一个个选择,无法通过EXCEL方…

【最新版】啦啦外卖v64系统独立版源码+全部小程序APP端+安装教程

一.系统介绍 啦啦外卖跑腿平台独立版,使用的都知道该系统功能非常强大,应该说是目前外卖平台功能最全的一套系统。主要是功能非常多,拿来即用,包括客户端小程序、配送端小程序、商户端小程序,还有对应四个端的APP源码…

iproute2 工具集使用详解

目录 一、iproute2 核心命令:ip二、常用功能详解1. 管理网络接口(link 对象)2. 管理 IP 地址(address 对象)3. 管理路由表(route 对象)4. 管理 ARP 和邻居缓存(neigh 对象&#xff0…

AD(Altium Designer)更换PCB文件的器件封装

一、确定是否拥有想换的器件PCB封装 1.1 打开现有的原理图 1.2 确定是否拥有想换的器件PCB文件 1.2.1 如果有 按照1.3进行切换器件PCB封装 1.2.2 如果没有 按照如下链接进行添加 AD(Altium Designer)已有封装库的基础上添加器件封装-CSDN博客https://blog.csdn.net/XU15…