Day08下 - 卷积

卷积在图像处理中的作用:

  • 图片是一个二维的矩阵
  • 通过一个3×3的矩阵与原图进行相乘再相加的计算,得到一个新的图片
  • 通过设计不同的3×3矩阵内容,可以得到不同的新图片

卷积神经网络

  • 将图片(本质是矩阵)作为输入
  • 将卷积核作为待调整的参数
  • 让卷积运算作为机器学习的一部分
  • 让机器学习寻找特征,寻找过程中:
    • 将一个卷积的操作,作为另外一个卷积的输入
    • 对于一个特征矩阵,可以利用不同的卷积核,生成不同的特征矩阵
    • 将这些输入输出全部连接到一起

卷积网络组件

  • BatchNorm层

  • ReLU层

  • 线性层

  • Dropout层

张量的维度

        数据科学
  •         按维度定义和处理数据

图像展开
  • 常规图像:[N, C, H, W]
    • N个样本图像
    • C:通道数
    • H:高度
    • W:宽度
  • 图像展平:[N, C * H * W]
    • N:图像的个数
    • C * H * W:将其展成一行,可理解为将图像像素全部排成一行
  • 改变shape:
    • 不会改变像素值
    • 不会改变数据本身的信息
    • 为了对口型,方便科学计算,方便矩阵相乘

卷积操作

import numpy as np

# 图像
img = np.random.randn(64,64)

# 卷积核
kernel = np.random.randn(3,3)

# 初始尺寸
H, W = img.shape
k, k = kernel.shape
# 结果
result = np.zeros(shape=(H-k+1,W-k+1))

# 遍历 H方向
for h_idx in range(H-k+1):
    # 遍历 W 方向
    for w_idx in range(W-k+1):
        # 图像块
        img_block = img[h_idx:h_idx+k, w_idx:w_idx+k]
        result[h_idx,w_idx]=(img_block * kernel).sum()

import torch
from torch import nn

# 二维卷积:H和W两个方向做卷积
conv2d = nn.Conv2d(in_channels=3, 
                   out_channels=2, 
                   kernel_size=3,
                   stride=2,
                   padding=1)

# 模拟图像 [N, C, H, W]
X = torch.randn(1,3,5,5)

conv2d(X).shape

conv2d.weight.shape

conv2d.bias

# 批规范化层
bn = nn.BatchNorm2d(num_features=2)

bn.bias

torch.relu

import torch  
from torch import nn  
  
# 自定义一个神经网络类  
class Model(nn.Module):  
    def __init__(self, in_channels=1, n_classes=10):  
        # 调用父类的构造函数进行初始化  
        super(Model, self).__init__()  
  
        # 1. 特征抽取部分  
        # 使用 nn.Sequential 来序列化卷积层和池化层  
        self.feature_extractor = nn.Sequential(  
            # 第一个卷积层,输入通道数为 in_channels,输出通道数为 6,卷积核大小为 5x5  
            nn.Conv2d(in_channels=in_channels, out_channels=6, kernel_size=5, stride=1, padding=0),  
            # 第一个最大池化层,池化核大小为 2x2,步长为 2  
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),  
            # 第二个卷积层,输入通道数为 6(上一个卷积层的输出通道数),输出通道数为 16,卷积核大小为 5x5  
            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5, stride=1, padding=0),  
            # 第二个最大池化层,池化核大小为 2x2,步长为 2  
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0)  
        )  
  
        # 2. 分类输出部分  
        # 使用 nn.Sequential 来序列化展平层和全连接层  
        self.classifier = nn.Sequential(  
            # 展平层,从第二个维度开始展平到最后一个维度  
            nn.Flatten(start_dim=1, end_dim=-1),  
            # 第一个全连接层,输入特征数为 400(这个值取决于前面的卷积和池化层以及输入图像的大小),输出特征数为 120  
            # 注意:这里的 400 是一个假设的值,实际使用时需要根据输入图像大小和前面的层来计算  
            nn.Linear(in_features=400, out_features=120),  
            # 第二个全连接层,输入特征数为 120,输出特征数为 84  
            nn.Linear(in_features=120, out_features=84),  
            # 第三个全连接层(输出层),输入特征数为 84,输出特征数为 n_classes(分类的类别数)  
            nn.Linear(in_features=84, out_features=n_classes)  
        )  
  
    def forward(self, x):  
        # 前向传播函数  
        # 1. 先通过特征抽取部分  
        x = self.feature_extractor(x)  
        # 2. 再通过分类输出部分  
        x = self.classifier(x)  
        return x  
  
# 实例化模型,设置输入通道数为 1,分类类别数为 10(这里可以根据实际任务调整)  
model = Model(in_channels=1)  
  
# 创建一个随机输入张量,模拟一个批次的图像数据  
# 形状为 (batch_size, channels, height, width),这里设置为 (2, 1, 32, 32)  
X = torch.randn(2, 1, 32, 32)  
  
# 通过模型进行前向传播,得到预测结果  
y_pred = model(X)  
  
# 打印预测结果的形状,形状为 (batch_size, n_classes) 的张量  
print(y_pred.shape)  # 输出结果是 torch.Size([2, 10])  
  
# 打印模型结构信息  
print(model)

手势识别

1. 原始数据读取
  • 并不是把所有图像全部读进内存
  • 而是把所有图像的路径类别归纳和梳理出来
  • img_path
  • img_label
# 导入os模块,用于处理文件和目录路径  
import os  
  
# 设置训练数据集的根目录路径  
train_root = os.path.join("gesture", "train")  
# 初始化训练数据集的路径列表和标签列表  
train_paths = []  
train_labels = []  
  
# 遍历训练数据集的根目录下的每个标签文件夹  
for label in os.listdir(train_root):  
    # 获取当前标签文件夹的完整路径  
    label_root = os.path.join(train_root, label)  
    # 遍历当前标签文件夹下的每个文件  
    for file in os.listdir(label_root):  
        # 获取当前文件的完整路径  
        file_path = os.path.join(label_root, file)  
        # 将文件路径添加到训练路径列表中  
        train_paths.append(file_path)  
        # 将当前文件的标签添加到训练标签列表中  
        train_labels.append(label)  
  

  
# 设置测试数据集的根目录路径  
test_root = os.path.join("gesture", "test")  
# 初始化测试数据集的路径列表和标签列表  
test_paths = []  
test_labels = []  
  
# 遍历测试数据集的根目录下的每个标签文件夹  
for label in os.listdir(test_root):  
    # 获取当前标签文件夹的完整路径  
    label_root = os.path.join(test_root, label)  
    # 遍历当前标签文件夹下的每个文件  
    for file in os.listdir(label_root):  
        # 获取当前文件的完整路径  
        file_path = os.path.join(label_root, file)  
        # 将文件路径添加到测试路径列表中  
        test_paths.append(file_path)  
        # 将当前文件的标签添加到测试标签列表中  
        test_labels.append(label)  
  
# 构建一个包含所有可能标签的列表(这里假设了标签是"zero"到"nine")  
labels = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]  
  
# 构建一个从标签到索引的字典  
label2idx = {label: idx for idx, label in enumerate(labels)}  
# 构建一个从索引到标签的字典  
idx2label = {idx: label for label, idx in label2idx.items()}
2. 批量化打包
  • 继承 Dataset,自定义一个数据集
  • 实例化 DataLoader
# 引入必要的工具类  
from torch.utils.data import Dataset  # 从torch.utils.data模块导入Dataset类,用于创建自定义数据集  
from torch.utils.data import DataLoader  # 从torch.utils.data模块导入DataLoader类,用于包装数据集并提供数据加载功能  
from PIL import Image  # 从PIL库导入Image类,用于图像处理  
from torchvision import transforms  # 从torchvision库导入transforms模块,用于图像变换  
import torch  # 导入torch库,用于深度学习  
  
 
class GestureDataset(Dataset):  
    """  
        自定义手势识别数据集类,继承自Dataset类  
    """  
    def __init__(self, X, y):  
        """  
            初始化方法  
            :param X: 图像路径列表  
            :param y: 图像标签列表  
        """  
        self.X = X  # 存储图像路径  
        self.y = y  # 存储图像标签  
  
    def __getitem__(self, idx):  
        """  
            根据索引获取单个样本及其标签  
            :param idx: 索引  
            :return: 图像和标签  
        """  
        # 获取图像路径  
        img_path = self.X[idx]  
        # 读取图像  
        img = Image.open(fp=img_path)  # 使用PIL的Image类打开图像文件  
        # 统一大小到32x32  
        img = img.resize((32, 32))  
        # 将图像转换为张量,并归一化到[0, 1]范围  
        img = transforms.ToTensor()(img)  
        # 将图像张量归一化到[-1, 1]范围  
        img = transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])(img)  
  
        # 读取标签  
        img_label = self.y[idx]  
        # 标签转索引(这里假设label2idx是一个全局变量或需要在外部定义)  
        img_idx = label2idx.get(img_label)  # 使用字典获取标签对应的索引  
        # 将索引转换为张量,并指定数据类型为long  
        label = torch.tensor(data=img_idx, dtype=torch.long)  
  
        return img, label  # 返回图像张量和标签张量  
  
    def __len__(self):  
        """  
            返回数据集中的样本数量  
        """  
        return len(self.X)  # 返回图像路径列表的长度  
  
# 创建训练集加载器  
train_dataset = GestureDataset(X=train_paths, y=train_labels)  # 使用训练数据创建GestureDataset实例  
train_dataloader = DataLoader(dataset=train_dataset, shuffle=True, batch_size=16)  # 创建DataLoader实例,设置随机打乱和批量大小  
  
# 创建测试集加载器  
test_dataset = GestureDataset(X=test_paths, y=test_labels)  # 使用测试数据创建GestureDataset实例  
test_dataloader = DataLoader(dataset=test_dataset, shuffle=False, batch_size=32)  # 创建DataLoader实例,不设置随机打乱和设置批量大小  
  
# 测试DataLoader  
for X, y in test_dataloader:  
    print(X.shape)  # 打印图像张量的形状(批量大小, 通道数, 高度, 宽度)  
    print(y.shape)  # 打印标签张量的形状(批量大小,)  
    break  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值