Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1323|回复: 10

王栋:公式识别系统

[复制链接]

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
发表于 2025-3-14 20:20:21 | 显示全部楼层 |阅读模式
1.学习神经网络的基本知识
2.学习卷积和池化以及全连接算法的具体含义

2.找一个yolo2的代码,逐句的实验,具体流程

(1)正推:由输入一步一步得到输出,每一步都要看到结果
(2)反推:反推更新网络数据。
回复

使用道具 举报

5

主题

16

帖子

115

积分

注册会员

Rank: 2

积分
115
发表于 2025-4-24 14:29:02 | 显示全部楼层
本帖最后由 王栋 于 2025-4-24 14:38 编辑

import torch  # 深度学习框架
import torch.nn as nn  # 神经网络模块
import torchvision  # 计算机视觉工具包
import cv2  # OpenCV库
import numpy as np  # 数值计算库

# ====================== 1. 数据准备 ======================
# 流水线操作(预处理部分)
transform = torchvision.transforms.Compose([  # 把多个打包成一个
    torchvision.transforms.ToTensor(),# 转换为张量
    torchvision.transforms.Lambda(lambda x: x.repeat(3, 1, 1)),#变为三通道
    torchvision.transforms.Resize((416, 416))#缩放到416*416像素
])

# 加载 MNIST 数据集
train_dataset = torchvision.datasets.MNIST(#训练集
    root='./data', #数据集路径
    train=True, #保存为训练集
    download=True, #没有就自动下载
    transform=transform)#应用上面的流程
test_dataset = torchvision.datasets.MNIST(#测试集
    root='./data',
    train=False,
    transform=transform)

# 将分类标签转换为检测标签(动态计算边界框)
#这个函数把MNIST的分类标签(0-9的数字)转成目标检测需要的边界框格式
def convert_to_detection_labels(dataset):
    new_labels = []
    for img, label in dataset:
        h, w = img.shape[1], img.shape[2]  # PyTorch 张量格式为 [C, H, W]
        
        # 动态计算边界框参数(示例为 YOLO 格式)
        x_center = w / 2 / w   # 归一化到 [0,1]
        y_center = h / 2 / h
        width = 0.8            # 目标宽度占图像宽度的 80%
        height = 0.8           # 目标高度占图像高度的 80%
        
        # 创建边界框(格式需与模型匹配)
        box = [label if isinstance(label, int) else label.item(), x_center, y_center, width, height]
        new_labels.append(torch.tensor(box, dtype=torch.float32))
    return new_labels

train_labels = convert_to_detection_labels(train_dataset) #训练集
test_labels = convert_to_detection_labels(test_dataset)   #测试集
回复

使用道具 举报

5

主题

16

帖子

115

积分

注册会员

Rank: 2

积分
115
发表于 2025-4-24 16:04:32 | 显示全部楼层
# ====================== 3. 简化版YOLOv2模型 ======================
class SimpleYOLO(nn.Module):
    def __init__(self, num_classes=10, anchors = torch.tensor([[1.3221, 1.7314]])):
         #锚框的宽高比例(宽度是高度的1.3221倍)
        #锚框:模型可以快速适应不同大小的目标,而不需要从零开始预测边界框的绝对尺寸
        super().__init__()## 必须调用父类初始化
        self.num_classes = num_classes# 类别数量(MNIST有10个数字)
        self.anchors = torch.tensor(anchors)# 预定义的锚框尺寸(这里只有1种)
        
        # 简化网络结构
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, 3, padding=1),#输入3通道,输出16通道,3x3卷积,边缘填充1
            nn.LeakyReLU(0.1),# 激活函数
            nn.MaxPool2d(2, 2),#最大池化
            nn.Conv2d(16, 32, 3, padding=1),#输入16通道,输出32通道,3x3卷积,边缘填充1
            nn.LeakyReLU(0.1),# 激活函数
            nn.MaxPool2d(2, 2),#最大池化
            nn.Conv2d(32, 64, 3, padding=1),#输入32通道,输出64通道,3x3卷积,边缘填充1
            nn.LeakyReLU(0.1),# 激活函数
            nn.MaxPool2d(2, 2),#最大池化
            nn.Conv2d(64, 128, 3, padding=1),#输入64通道,输出128通道,3x3卷积,边缘填充1
            nn.LeakyReLU(0.1),# 激活函数
            nn.MaxPool2d(2, 2)#最大池化
        )
        
        # 检测层 用于预测结果
        self.detection = nn.Conv2d(128, len(anchors)*(5+num_classes), 1)
        ## 输出通道数 = 锚框数量 × (5个边界框参数 + 类别数量)
        ## 5个边界框参数:x_center, y_center, width, height, confidence

    def forward(self, x):#向前传播的过程
        x = self.features(x)## 通过特征提取层(输出形状:[batch, 128, 26, 26])#经过四次池化,每次都减半,416变为26
        output = self.detection(x) ##通过检测层(输出形状:[batch, 1*(5+10), 26, 26]
        #调整输出形状
        batch_size,_, h, w = output.shape #获取高度,批次大小,宽度
        output = output.view(batch_size, len(self.anchors), 5+self.num_classes, h, w) #调整为:[batch, 锚框数量, (5参数+10类别), 高度, 宽度]
        output = output.permute(0, 1, 3, 4, 2) ## 调整维度顺序,变为:[batch, 锚框数量, 高度, 宽度, (5参数+10类别)]
        return output

# ====================== 4. 简化版损失函数 ======================
def calculate_iou(pred_boxes, target_boxes):
    """计算IoU"""
    # 将坐标中心坐标 → 左上角+右下角 #预测框
    pred_boxes = pred_boxes.clone() #克隆张量
    pred_boxes[:, 0] = pred_boxes[:, 0] - pred_boxes[:, 2]/2 #左上角x坐标
    pred_boxes[:, 1] = pred_boxes[:, 1] - pred_boxes[:, 3]/2 #左上角y坐标
    pred_boxes[:, 2] = pred_boxes[:, 0] + pred_boxes[:, 2]   #右上角x坐标
    pred_boxes[:, 3] = pred_boxes[:, 1] + pred_boxes[:, 3]   #右上角y坐标

     #目标框
    target_boxes = target_boxes.clone() #同上
    target_boxes[:, 0] = target_boxes[:, 0] - target_boxes[:, 2]/2
    target_boxes[:, 1] = target_boxes[:, 1] - target_boxes[:, 3]/2
    target_boxes[:, 2] = target_boxes[:, 0] + target_boxes[:, 2]
    target_boxes[:, 3] = target_boxes[:, 1] + target_boxes[:, 3]

    # 计算交集区域 计算预测框和目标框的交集区域面积
    inter_x1 = torch.max(pred_boxes[:, 0], target_boxes[:, 0])#torch.max():逐元素比较,取较大值
    inter_y1 = torch.max(pred_boxes[:, 1], target_boxes[:, 1])
    inter_x2 = torch.min(pred_boxes[:, 2], target_boxes[:, 2])#torch.min():逐元素比较,取较小值
    inter_y2 = torch.min(pred_boxes[:, 3], target_boxes[:, 3])
   
    inter_area = torch.clamp(inter_x2 - inter_x1, min=0) * torch.clamp(inter_y2 - inter_y1, min=0)
    #交集区域的宽度 = inter_x2 - inter_x1,高度 = inter_y2 - inter_y1,面积 = 宽度 × 高度
    # 计算并集面积
    pred_area = (pred_boxes[:, 2] - pred_boxes[:, 0]) * (pred_boxes[:, 3] - pred_boxes[:, 1])
    target_area = (target_boxes[:, 2] - target_boxes[:, 0]) * (target_boxes[:, 3] - target_boxes[:, 1])
    union_area = pred_area + target_area - inter_area
    return inter_area / union_area
回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 00:26:57 | 显示全部楼层

目录:
1.YOLO2的工作流程
2.YOLO2的数据集的格式和下载
3.YOLO2网络的直观表示
4.YOLO2网络的训练过程

回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 08:28:33 | 显示全部楼层

1.YOLO2的大体工作流程
包含训练和测量两大步
YOLO2的训练的数据为图片和标签(含有图片中物品位置坐标和种类)
YOLO2的输入为图片,输出为标签
2.YOLO2的数据下载
比较常用的是VOC数据集
数据集下载https://openxlab.org.cn/datasets ... AL_VOC2012/cli/main
下载到数据集后,其架构如下
OpenDataLab_PASCAL_VOC2012
|--dsdl
||--dsdl_SemSeg_full.zip
||--dsdl_Det_full.zip
|--raw
||--VOCtrainval_11-May-2012.tar
||--VOCdevkit_18-May-2011.tar
||--VOC2012test.tar
|--sample
||--image  #内部为原始图片
||--metafile.yaml
||--README.md
其中原始数据都在raw文件夹中,如解压缩VOC2012test.tar,就会生成VOC2012文件夹,里面包含annotations 、 imageSets和 JPEGImages三个文件夹,
其中annotations 就记录了标记文件,以xml格式存储,如其中一个xml写着:<name>person</name><bndbox><xmin>119</xmin>
                        <ymin>76</ymin><xmax>184</xmax><ymax>311</ymax></bndbox>记录着在一个图片的x 119-184 y:76-311的矩形框中有一个人。
JPEGImages记录着所有的原始文件

annotations文件中的xml文件格式读取并不方便,需要编制专门算法提取,针对这个问题,数据库专门提供了另外一种格式的数据json,放在dsdl文件夹中,格式如下
  {
          "bbox": [
            53.0,
            87.0,
            418.0,
            333.0
          ],
          "category": "horse",
          "pose": "Left",
          "truncated": 0,
          "difficult": 0
        },


回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 14:33:10 | 显示全部楼层
2.数据库加载
TorchVision 预期的VOC数据集格式:
./data/  # 你指定的`root`路径
└── VOCdevkit/
    └── VOC2012/  # 年份由`year`参数指定(如2012)
        ├── Annotations/       # 存放XML标注文件(每个图片对应一个)
        ├── JPEGImages/         # 存放原始图片(.jpg)
        ├── ImageSets/
        │   └── Main/           # 包含数据划分文件(如train.txt, val.txt)
        └── Segmentation/       # 分割任务相关(检测任务可忽略)

比较常用的是VOC数据集
数据集下载https://openxlab.org.cn/datasets ... AL_VOC2012/cli/main
下载到数据集后,其架构如下
OpenDataLab_PASCAL_VOC2012
|--dsdl
||--dsdl_SemSeg_full.zip
||--dsdl_Det_full.zip
|--raw
||--VOCtrainval_11-May-2012.tar
||--VOCdevkit_18-May-2011.tar
||--VOC2012test.tar
|--sample
||--image  #内部为原始图片
||--metafile.yaml
||--README.md
其中原始数据都在raw文件夹中,如解压缩VOCtrainval_11-May-2012.tar.tar,就会得到 VOCdevkit文件夹
回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 15:09:00 | 显示全部楼层
数据读取练习
  1. import torch
  2. import torchvision
  3. from torchvision.transforms import ToTensor
  4. import matplotlib.pyplot as plt
  5. import matplotlib.patches as patches

  6. # 加载数据集
  7. transform = ToTensor()
  8. train_dataset = torchvision.datasets.VOCDetection(
  9.     root='./raw',
  10.     year='2012',
  11.     image_set='train',
  12.     download=False,
  13.     transform=transform
  14. )

  15. # 显示前5个样本
  16. for i in range(5):
  17.     image, target = train_dataset[i]
  18.     image = image.permute(1, 2, 0).numpy()  # Tensor → H,W,C
  19.    
  20.     fig, ax = plt.subplots(1)
  21.     ax.imshow(image)
  22.    
  23.     for obj in target['annotation']['object']:
  24.         name = obj['name']
  25.         bbox = obj['bndbox']
  26.         xmin, ymin = int(bbox['xmin']), int(bbox['ymin'])
  27.         xmax, ymax = int(bbox['xmax']), int(bbox['ymax'])
  28.         
  29.         rect = patches.Rectangle(
  30.             (xmin, ymin), xmax-xmin, ymax-ymin,
  31.             linewidth=1, edgecolor='r', facecolor='none'
  32.         )
  33.         ax.add_patch(rect)
  34.         ax.text(xmin, ymin, name, color='white', backgroundcolor='r')
  35.    
  36.     plt.axis('off')
  37.     plt.show()
复制代码
回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 15:18:49 | 显示全部楼层
yolo2要求使用416*416格式的图片,因此为了上述代码中的transform = ToTensor()需要进一步调整为:
    transform = torchvision.transforms.Compose([  # 把多个打包成一个
        torchvision.transforms.ToTensor(),# 转换为张量
        torchvision.transforms.Resize((416, 416))#缩放到416*416像素
    ])
修改后直接运行观察结果,发现图片标注的框不再准确,这是因为:
torchvision.datasets.VOCDetection 中,transform 仅对图像(image)进行处理,而标注(annotations)不会自动调整。您需要手动同步更新标注中的边界框坐标(如 xmin, ymin, xmax, ymax)以匹配变换后的图像尺寸
回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 15:33:57 | 显示全部楼层
调整后的代码如下所示
  1. import torch
  2. import torchvision
  3. from torchvision.transforms import ToTensor
  4. import matplotlib.pyplot as plt
  5. import matplotlib.patches as patches

  6. # 加载数据集
  7. transform = torchvision.transforms.Compose([  # 把多个打包成一个
  8.         torchvision.transforms.ToTensor(),# 转换为张量
  9.         torchvision.transforms.Resize((416, 416))#缩放到416*416像素
  10.     ])
  11. train_dataset = torchvision.datasets.VOCDetection(
  12.     root='./raw',
  13.     year='2012',
  14.     image_set='train',
  15.     download=False,
  16.     transform=transform
  17. )


  18. def adjust_bbox(bbox, original_size, new_size):
  19.     """
  20.     根据图像缩放比例调整边界框坐标
  21.     Args:
  22.         bbox: 原始边界框 dict {'xmin': '100', 'ymin': '200', 'xmax': '300', 'ymax': '400'}
  23.         original_size: 原始图像尺寸 (width, height)
  24.         new_size: 变换后尺寸 (new_width, new_height)
  25.     Returns:
  26.         调整后的边界框坐标 [xmin, ymin, xmax, ymax]
  27.     """
  28.     width_scale = new_size[0] / original_size[0]
  29.     height_scale = new_size[1] / original_size[1]
  30.    
  31.     new_bbox = {
  32.         'xmin': int(float(bbox['xmin']) * width_scale),
  33.         'ymin': int(float(bbox['ymin']) * height_scale),
  34.         'xmax': int(float(bbox['xmax']) * width_scale),
  35.         'ymax': int(float(bbox['ymax']) * height_scale)
  36.         }
  37.     return new_bbox

  38. # 显示前5个样本
  39. for i in range(5):
  40.     image, target = train_dataset[i]
  41.     image = image.permute(1, 2, 0).numpy()  # Tensor → H,W,C
  42.    
  43.     fig, ax = plt.subplots(1)
  44.     ax.imshow(image)


  45.     # 原始图像尺寸(从标注中获取)
  46.     original_width = int(target['annotation']['size']['width'])
  47.     original_height = int(target['annotation']['size']['height'])
  48.     original_size = (original_width, original_height)

  49.     # 调整所有边界框
  50.     new_size = (416, 416)  # 与Resize参数一致
  51.     for obj in target['annotation']['object']:
  52.         obj['bndbox'] = adjust_bbox(obj['bndbox'], original_size, new_size)


  53.         
  54.     for obj in target['annotation']['object']:
  55.         name = obj['name']
  56.         bbox = obj['bndbox']
  57.         xmin, ymin = bbox['xmin'], bbox['ymin']
  58.         xmax, ymax = bbox['xmax'], bbox['ymax']
  59.         
  60.         rect = patches.Rectangle(
  61.             (xmin, ymin), xmax-xmin, ymax-ymin,
  62.             linewidth=1, edgecolor='r', facecolor='none'
  63.         )
  64.         ax.add_patch(rect)
  65.         ax.text(xmin, ymin, name, color='white', backgroundcolor='r')
  66.    
  67.     plt.axis('off')
  68.     plt.show()
复制代码
回复

使用道具 举报

399

主题

1251

帖子

4020

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4020
 楼主| 发表于 2025-4-25 15:45:54 | 显示全部楼层
train_labels = convert_to_detection_labels(train_dataset) #训练集
将原始数据集 train_dataset 中的标注信息(如类别标签、边界框坐标等)转换为目标检测模型可识别的标准化标签格式。


# 原始标注示例
original_anno = {
    "image_id": 1,
    "annotations": [
        {"bbox": [10,20,100,200], "category_id": 3},
        {"bbox": [50,60,80,120], "category_id": 5}
    ]
}

# 转换后可能得到
train_labels = {
    "boxes": torch.tensor([[10,20,100,200], [50,60,80,120]]),
    "labels": torch.tensor([3,5]),
    "image_id": torch.tensor(1)
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2025-6-8 07:26 , Processed in 0.040777 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表