3. 手势识别(LeNet、Vgg16、ResNet50)

news2024/9/22 9:57:33

手势识别

  • Show me your code
    • 1. 模型 model.py
    • 2. LeNet 实现手势识别(详细)
      • 2.1 数据打包
      • 2.2 搭建模型
      • 2.3 训练模型
      • 2.4 结果分析
      • 2.5 推理过程
    • 3. Vgg16 手势识别
    • 4. ResNet50 手势识别

Show me your code

1. 模型 model.py

import torch
from torch import nn


class ConvBlock(nn.Module):
    """
        一层卷积:
            - 卷积层
            - 批规范化层
            - 激活层
    """
    def __init__(self, in_channels, out_channels, 
                 kernel_size=3, stride=1, padding=1):
        super().__init__()
        self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                             kernel_size=kernel_size, stride=stride,padding=padding)
        self.bn = nn.BatchNorm2d(num_features=out_channels)
        self.relu = nn.ReLU()
    
    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

class LeNet(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        # 1, 特征抽取部分
        self.feature_extractor = nn.Sequential(
            # 卷积层1
            ConvBlock(in_channels=3, 
                      out_channels=6, 
                      kernel_size=5,
                      stride=1,
                      padding=0),
            
            # 亚采样(池化)
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            
            # 卷积层2
            ConvBlock(in_channels=6, 
                      out_channels=16, 
                      kernel_size=5,
                      stride=1,
                      padding=0),
            
            # 亚采样(池化)
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            
        )
        
        # 2, 分类
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(in_features=400, out_features=120),
            nn.ReLU(),
            nn.Linear(in_features=120, out_features=84),
            nn.ReLU(),
            nn.Linear(in_features=84, out_features=num_classes)
        )
        
    def forward(self, x):
        # 1, 提取特征
        x = self.feature_extractor(x)
        # 2, 分类输出
        x = self.classifier(x)
        return x
    
class Vgg16(nn.Module):
    def __init__(self, n_classes=1000):
        super().__init__()
        # 1, 特征抽取部分
        self.feature_extractor = nn.Sequential(
            
            # stage1
            
            # 卷积1
            ConvBlock(in_channels=3, 
                      out_channels=64, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积2
            ConvBlock(in_channels=64, 
                      out_channels=64, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 池化
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            
            # stage2
            
            # 卷积1
            ConvBlock(in_channels=64, 
                      out_channels=128, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积2
            ConvBlock(in_channels=128, 
                      out_channels=128, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 池化
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            
            # stage3
            
            # 卷积1
            ConvBlock(in_channels=128, 
                      out_channels=256, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积2
            ConvBlock(in_channels=256, 
                      out_channels=256, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积3
            ConvBlock(in_channels=256, 
                      out_channels=256, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 池化
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            
            # stage4
            
            # 卷积1
            ConvBlock(in_channels=256, 
                      out_channels=512, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积2
            ConvBlock(in_channels=512, 
                      out_channels=512, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积3
            ConvBlock(in_channels=512, 
                      out_channels=512, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 池化
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
            
            
            # stage5
            
            # 卷积1
            ConvBlock(in_channels=512, 
                      out_channels=512, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积2
            ConvBlock(in_channels=512, 
                      out_channels=512, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 卷积3
            ConvBlock(in_channels=512, 
                      out_channels=512, 
                      kernel_size=3,
                      stride=1,
                      padding=1),
            # 池化
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
        )
        
        # 2, 分类
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(in_features=7 * 7 * 512, out_features=4096),
            nn.ReLU(),
            nn.Linear(in_features=4096, out_features=4096),
            nn.ReLU(),
            nn.Linear(in_features=4096, out_features=n_classes)
        )
        
    def forward(self, x):
        # 1, 提取特征
        x = self.feature_extractor(x)
        # 2, 分类输出
        x = self.classifier(x)
        return x


"""
    ResBlock
"""

class ResConvBlock(nn.Module):
    """
        虚线块,每一个大的重复逻辑块前面,第一个短接块就是这个
        实现逻辑:
            y = F(x) + Conv(x)
    """
    def __init__(self, in_channels, out_channels, stride):
        # 调用父类初始化方法
        super().__init__()
                
        # 1,核心处理逻辑
        self.stage = nn.Sequential(
            # 1  1 * 1
            nn.Conv2d(in_channels=in_channels,
                     out_channels=out_channels[0],
                     kernel_size=1,
                     stride=stride,
                     padding=0,
                     bias=False),
            nn.BatchNorm2d(num_features=out_channels[0]),
            nn.ReLU(),
            # 2  3 * 3
            nn.Conv2d(in_channels=out_channels[0],
                     out_channels=out_channels[1],
                     kernel_size=3,
                     padding=1,
                     stride=1,
                     bias=False),
            nn.BatchNorm2d(num_features=out_channels[1]),
            nn.ReLU(),
            # 3  1 * 1
            nn.Conv2d(in_channels=out_channels[1],
                     out_channels=out_channels[2],
                     kernel_size=1,
                     stride=1,
                     padding=0,
                     bias=False),
            nn.BatchNorm2d(num_features=out_channels[2]))
        
        # 2,短路层
        self.shortcut = nn.Sequential(
            nn.Conv2d(in_channels=in_channels,
                                   out_channels=out_channels[2],
                                   kernel_size=1,
                                   stride=stride,
                                   padding=0,
                                   bias=False),
            nn.BatchNorm2d(num_features=out_channels[2])
        )
        
        # 3,最后的激活
        self.relu = nn.ReLU()
    
    def forward(self, x):
        # 1,短接处理
        s = self.shortcut(x)
        
        # 2,核心处理
        h = self.stage(x)
        
        # 3,两部分相加 add
        h = h + s
        
        # 4,输出 激活
        o = self.relu(h)
        
        return o
    
class IdentityBlock(nn.Module):
    """
        实线块
            y = F(x) + x
    """
    def __init__(self, in_channels, out_channels):
        super().__init__()
        
        self.stage = nn.Sequential(
            # 1:1 x 1
            nn.Conv2d(in_channels=in_channels,
                     out_channels=out_channels[0],
                     kernel_size=1,
                     padding=0,
                     stride=1,
                     bias=False),
            nn.BatchNorm2d(num_features=out_channels[0]),
            nn.ReLU(),
            
            # 2:3 x 3
            nn.Conv2d(in_channels=out_channels[0],
                     out_channels=out_channels[1],
                     kernel_size=3,
                     padding=1,
                     stride=1,
                     bias=False),
            nn.BatchNorm2d(num_features=out_channels[1]),
            nn.ReLU(),
            
            # 3:1 x 1
            nn.Conv2d(in_channels=out_channels[1],
                     out_channels=out_channels[2],
                     kernel_size=1,
                     padding=0,
                     stride=1,
                     bias=False),
            nn.BatchNorm2d(num_features=out_channels[2])
        )
        
        self.relu = nn.ReLU()
    
    def forward(self, x):
        h = x + self.stage(x)
        o = self.relu(h)  
        return o
    
class ResNet50(nn.Module):
    """
        自定义 ResNet50
    """
    def __init__(self, n_classes=1000):
        super(ResNet50, self).__init__()
        self.stage1 = nn.Sequential(
            nn.Conv2d(in_channels=3, 
                     out_channels=64,
                     kernel_size=7,
                     padding=3,
                     stride=2,
                     bias=False),
            nn.BatchNorm2d(num_features=64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3,
                        stride=2,
                        padding=1)
        )
        self.stage2 = nn.Sequential(
            ResConvBlock(in_channels=64,
                     out_channels=(64, 64, 256),
                     stride=1),
            IdentityBlock(in_channels=256,
                         out_channels=(64, 64, 256)),
            IdentityBlock(in_channels=256,
                         out_channels=(64, 64, 256)),
        )
        
        self.stage3 = nn.Sequential(
            ResConvBlock(in_channels=256,
                      out_channels=(128, 128, 512),
                      stride=2),
            IdentityBlock(in_channels=512,
                         out_channels=(128, 128, 512)),
            IdentityBlock(in_channels=512,
                         out_channels=(128, 128, 512)),
            IdentityBlock(in_channels=512,
                         out_channels=(128, 128, 512))
        )
        
        self.stage4 = nn.Sequential(
            ResConvBlock(in_channels=512,
                      out_channels=(256, 256, 1024),
                      stride=2),
            IdentityBlock(in_channels=1024,
                         out_channels=(256, 256, 1024)),
            IdentityBlock(in_channels=1024,
                         out_channels=(256, 256, 1024)),
            IdentityBlock(in_channels=1024,
                         out_channels=(256, 256, 1024)),
            IdentityBlock(in_channels=1024,
                         out_channels=(256, 256, 1024)),
            IdentityBlock(in_channels=1024,
                         out_channels=(256, 256, 1024))
        )
        self.stage5 = nn.Sequential(
            ResConvBlock(in_channels=1024,
                      out_channels=(512, 512, 2048),
                      stride=2),
            IdentityBlock(in_channels=2048,
                         out_channels=(512, 512, 2048)),
            IdentityBlock(in_channels=2048,
                         out_channels=(512, 512, 2048))
        )
        self.pool = nn.AdaptiveAvgPool2d(output_size=(1, 1))
        
        self.fc = nn.Linear(in_features=2048,
                           out_features=n_classes)
    def forward(self, x):
        h = self.stage1(x)
        h = self.stage2(h)
        h = self.stage3(h)
        h = self.stage4(h)
        h = self.stage5(h)
        h = self.pool(h)
        h = h.view(h.size(0), -1)
        o = self.fc(h)
        return o

if __name__ == "__main__":
    model = LeNet()
    print(model)
    x = torch.randn(1, 1, 32, 32)
    y = model(x)
    print(y.shape)

2. LeNet 实现手势识别(详细)

2.1 数据打包

"""
    1,数据打包
        - [N, C, H, W]
        - 读取原始图像信息(每个图像的路径及其类别)
        - 批量化打包(Dataset,Dataloader)
"""
import os
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import numpy as np
from PIL import Image
import torch
from torch import nn
import time
from matplotlib import pyplot as plt
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

# 读取基图像的本信息
root = "gestures"

# 训练集
train_root = os.path.join(root, 'train')
img_train = []
label_train = []
for label in os.listdir(train_root):
    label_root = os.path.join(train_root, label)
    for img in os.listdir(label_root):
        img_path = os.path.join(label_root, img)
        img_train.append(img_path)
        label_train.append(label)
        
# 测试集
test_root = os.path.join(root, 'test')
img_test = []
label_test = []
for label in os.listdir(test_root):
    label_root = os.path.join(test_root, label)
    for img in os.listdir(label_root):
        img_path = os.path.join(label_root, img)
        img_test.append(img_path)
        label_test.append(label)

# 2, 标签字典
label_list = list(set(label_train))
# 原地 + 升序
label_list.sort()
# 构建标签字典
label2idx = {label: idx for idx, label in enumerate(label_list)}
idx2label = {idx: label for label, idx in label2idx.items()}


class GesturesDataset(Dataset):
    """
        自定义数据集
    """
    def __init__(self, X, y):
        self.X = X
        self.y = y
    
    def __len__(self):
        return len(self.X)
    
    def __getitem__(self,idx):
        img_path = self.X[idx]
        img_label = self.y[idx]
        
        # 1,处理图像
        # 读取图像
        img = Image.open(fp=img_path)
        # 转 为 32 * 32
        img = img.resize((32,32))
        # 转 NumPy数组
        img = np.array(img)
        # 范围 [-1, 1]
        img = img / 255
        img = (img - 0.5) / 0.5
        # 转张量
        img = torch.tensor(data=img, dtype=torch.float32)
        # 转 维度 [H, W, C] ---> [C, H, W]
        img = img.permute(dims=(2, 0, 1))
        
        
        # 2,处理标签
        label = label2idx.get(img_label)
        # 转张量
        label = torch.tensor(data=label, dtype=torch.long)
        
        
        # 返回样本
        return img, label

# 训练集加载器
train_dataset = GesturesDataset(X=img_train, y=label_train)
train_dataloader = DataLoader(dataset=train_dataset, 
                              shuffle=True, 
                              batch_size=8)
# 测试集加载器
test_dataset = GesturesDataset(X=img_test, y=label_test)
test_dataloader = DataLoader(dataset=test_dataset, 
                              shuffle=False, 
                              batch_size=32)

2.2 搭建模型

from models import LeNet
# 32 x 32 
model = LeNet()

2.3 训练模型

# 训练筹备
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model.to(device=device)
epochs = 80
lr = 1e-3
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=model.parameters(), lr=lr)

# 准确率计算
def get_acc(data_loader):
    accs = []
    model.eval()
    with torch.no_grad():
        for X, y in data_loader:
            X = X.to(device=device)
            y = y.to(device=device)
            y_pred = model(X)
            y_pred = y_pred.argmax(dim=-1)
            acc = (y_pred == y).to(torch.float32).mean().item()
            accs.append(acc)
    final_acc = round(number=sum(accs) / len(accs), ndigits=5)
    return final_acc

# 训练过程
def train():
    
    train_accs = []
    test_accs = []
    cur_test_acc = 0
    
    # 1,训练之前,检测一下准确率
    train_acc = get_acc(data_loader=train_dataloader)
    test_acc = get_acc(data_loader=test_dataloader)
    train_accs.append(train_acc)
    test_accs.append(test_acc)
    
    print(f"训练之前:train_acc: {train_acc},test_acc: {test_acc}")
    
    # 每一轮次
    for epoch in range(epochs):
        # 模型设置为 train 模式
        model.train()
        # 计时
        start_train = time.time()
        # 每一批量
        for X, y in train_dataloader:
            # 数据搬家
            X = X.to(device=device)
            y = y.to(device=device)
            # 1,正向传播
            y_pred = model(X)
            # 2,计算损失
            loss = loss_fn(y_pred, y)
            # 3,反向传播
            loss.backward()
            # 4,优化一步
            optimizer.step()
            # 5,清空梯度
            optimizer.zero_grad()
        # 计时结束
        stop_train = time.time()
        # 测试准确率
        train_acc = get_acc(data_loader=train_dataloader)
        test_acc = get_acc(data_loader=test_dataloader)
        train_accs.append(train_acc)
        test_accs.append(test_acc)
        # 保存模型
        if cur_test_acc < test_acc:
            cur_test_acc = test_acc
            # 保存最好模型
            torch.save(obj=model.state_dict(), f="lenet_best.pt")
        # 保存最后模型
        torch.save(obj=model.state_dict(), f="lenet_last.pt") 
        
        print(f"""当前是第 {epoch + 1} 轮:
                --> train_acc: {train_acc},
                --> test_acc: {test_acc},
                --> elapsed_time: {round(number=stop_train - start_train, ndigits=3)}秒""")
    return train_accs, test_accs


train_accs, test_accs = train()

当前是第 497 轮:
–> train_acc: 0.99457,
–> test_acc: 0.95536,
–> elapsed_time: 1.341秒
当前是第 498 轮:
–> train_acc: 0.99459,
–> test_acc: 0.95759,
–> elapsed_time: 1.347秒
当前是第 499 轮:
–> train_acc: 0.99339,
–> test_acc: 0.95759,
–> elapsed_time: 1.329秒
当前是第 500 轮:
–> train_acc: 0.99219,
–> test_acc: 0.95536,
–> elapsed_time: 1.308秒

2.4 结果分析

plt.plot(train_accs, label="train_acc")
plt.plot(test_accs, label="train_acc")
plt.legend()
plt.grid()
plt.xlabel(xlabel='epoch')
plt.ylabel(ylabel="acc")
plt.title(label="LeNet Training Process")

在这里插入图片描述

2.5 推理过程

# 检测设备
device = "cuda" if torch.cuda.is_available() else "cpu"

# 构建一个模型
m1 = LeNet()
m1.to(device=device)
# 加载权重
m1.load_state_dict(state_dict=torch.load(f="lenet_best.pt", map_location=device),
                   strict=False)

def infer(img_path):
    """
        输入:图像地址
        输出:预测类别
    """
    # 1,读取图像
    if not os.path.exists(img_path):
        raise FileNotFoundError("文件没找到")
    
    # 2, 判断当前局部变量中是否有model
    if "m1" not in globals() or not isinstance(globals()["m1"], LeNet):
        raise ValueError("m1模型不存在")
        
    # 3,读取图像
    img = Image.open(fp=img_path)
        
    # 4,预处理
    img = img.resize((32, 32))
    img = np.array(img)
    img = img / 255
    img = (img - 0.5) / 0.5
    
    # 5, 转张量
    img = torch.tensor(data=img, dtype=torch.float32)
    
    # 6, 转换维度
    img = img.permute(dims=(2, 0, 1))
    
    # 7, 新增一个批量维度
    img = img.unsqueeze(dim=0)
    
    # 8,数据搬家
    img = img.to(device=device)
    
    # 9,模型设为评估模式
    model.eval()
    
    # 10,无梯度环境
    with torch.no_grad():
        # 11,正向传播
        y_pred = m1(img)
        
        # 12, 解析结果
        y_pred = y_pred.argmax(dim=-1).item()
        
        # 13,标签转换
        label = idx2label.get(y_pred)
        
        # 14, 返回结果
        return label

‘G5’

3. Vgg16 手势识别

  • Vgg 最多搭建到19层,模型再深就出问题了,梯度无法回传,梯度消失了。后面被 Resnet 拯救了。

请添加图片描述

"""
    1,数据打包
        - [N, C, H, W]
        - 读取原始图像信息(每个图像的路径及其类别)
        - 批量化打包(Dataset,Dataloader)
"""
import os
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import numpy as np
from PIL import Image
import torch
from torch import nn
import time
from matplotlib import pyplot as plt
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

# 1,读取基图像的本信息
root = "gestures"

# 1,训练集
train_root = os.path.join(root, 'train')
img_train = []
label_train = []
for label in os.listdir(train_root):
    label_root = os.path.join(train_root, label)
    for img in os.listdir(label_root):
        img_path = os.path.join(label_root, img)
        img_train.append(img_path)
        label_train.append(label)
        
# 2,测试集
test_root = os.path.join(root, 'test')
img_test = []
label_test = []
for label in os.listdir(test_root):
    label_root = os.path.join(test_root, label)
    for img in os.listdir(label_root):
        img_path = os.path.join(label_root, img)
        img_test.append(img_path)
        label_test.append(label)

# 2, 标签字典
label_list = list(set(label_train))
# 原地 + 升序
label_list.sort()
# 构建标签字典
label2idx = {label: idx for idx, label in enumerate(label_list)}
idx2label = {idx: label for label, idx in label2idx.items()}

# 3,自定义数据集
class GesturesDataset(Dataset):
    """
        自定义数据集
    """
    def __init__(self, X, y):
        self.X = X
        self.y = y
    
    def __len__(self):
        return len(self.X)
    
    def __getitem__(self,idx):
        img_path = self.X[idx]
        img_label = self.y[idx]
        
        # 1,处理图像
        # 读取图像
        img = Image.open(fp=img_path)
        # 转 为 32 * 32
        img = img.resize((224,224))
        # 转 NumPy数组
        img = np.array(img)
        # 范围 [-1, 1]
        img = img / 255
        img = (img - 0.5) / 0.5
        # 转张量
        img = torch.tensor(data=img, dtype=torch.float32)
        # 转 维度 [H, W, C] ---> [C, H, W]
        img = img.permute(dims=(2, 0, 1))
        
        
        # 2,处理标签
        label = label2idx.get(img_label)
        # 转张量
        label = torch.tensor(data=label, dtype=torch.long)
        
        
        # 返回样本
        return img, label

# 训练集加载器
train_dataset = GesturesDataset(X=img_train, y=label_train)
train_dataloader = DataLoader(dataset=train_dataset, 
                              shuffle=True, 
                              batch_size=12)
                              
# 测试集加载器
test_dataset = GesturesDataset(X=img_test, y=label_test)
test_dataloader = DataLoader(dataset=test_dataset, 
                              shuffle=False, 
                              batch_size=12)
                              
from models import Vgg16
# 224 x 224
model = Vgg16(n_classes=10)

# 训练筹备
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model.to(device=device)
epochs = 10
lr = 1e-3
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=model.parameters(), lr=lr)


# 准确率计算
def get_acc(data_loader):
    accs = []
    model.eval()
    with torch.no_grad():
        for X, y in data_loader:
            X = X.to(device=device)
            y = y.to(device=device)
            y_pred = model(X)
            y_pred = y_pred.argmax(dim=-1)
            acc = (y_pred == y).to(torch.float32).mean().item()
            accs.append(acc)
    final_acc = round(number=sum(accs) / len(accs), ndigits=5)
    return final_acc

# 训练过程
def train():
    
    train_accs = []
    test_accs = []
    cur_test_acc = 0
    
    # 1,训练之前,检测一下准确率
    train_acc = get_acc(data_loader=train_dataloader)
    test_acc = get_acc(data_loader=test_dataloader)
    train_accs.append(train_acc)
    test_accs.append(test_acc)
    
    print(f"训练之前:train_acc: {train_acc},test_acc: {test_acc}")
    
    # 每一轮次
    for epoch in range(epochs):
        # 模型设置为 train 模式
        model.train()
        # 计时
        start_train = time.time()
        # 每一批量
        for X, y in train_dataloader:
            # 数据搬家
            X = X.to(device=device)
            y = y.to(device=device)
            # 1,正向传播
            y_pred = model(X)
            # 2,计算损失
            loss = loss_fn(y_pred, y)
            # 3,反向传播
            loss.backward()
            # 4,优化一步
            optimizer.step()
            # 5,清空梯度
            optimizer.zero_grad()
        # 计时结束
        stop_train = time.time()
        # 测试准确率
        train_acc = get_acc(data_loader=train_dataloader)
        test_acc = get_acc(data_loader=test_dataloader)
        train_accs.append(train_acc)
        test_accs.append(test_acc)
        # 保存模型
        if cur_test_acc < test_acc:
            cur_test_acc = test_acc
            # 保存最好模型
            torch.save(obj=model.state_dict(), f="vgg16_best.pt")
        # 保存最后模型
        torch.save(obj=model.state_dict(), f="vgg16_last.pt") 
        
        print(f"""当前是第 {epoch + 1} 轮:
                --> train_acc: {train_acc},
                --> test_acc: {test_acc},
                --> elapsed_time: {round(number=stop_train - start_train, ndigits=3)}秒""")
    return train_accs, test_accs

train_accs, test_accs = train()

训练之前:train_acc: 0.09832,test_acc: 0.11765
当前是第 1 轮:
–> train_acc: 0.66367,
–> test_acc: 0.65686,
–> elapsed_time: 18.589秒
当前是第 2 轮:
–> train_acc: 0.78897,
–> test_acc: 0.75735,
–> elapsed_time: 18.167秒
当前是第 3 轮:
–> train_acc: 0.92206,
–> test_acc: 0.89461,
–> elapsed_time: 18.214秒
当前是第 4 轮:
–> train_acc: 0.96163,
–> test_acc: 0.92892,
–> elapsed_time: 18.928秒
当前是第 5 轮:
–> train_acc: 0.97782,
–> test_acc: 0.94363,
–> elapsed_time: 18.666秒
当前是第 6 轮:
–> train_acc: 0.97242,
–> test_acc: 0.93137,
–> elapsed_time: 18.443秒
当前是第 7 轮:
–> train_acc: 0.994,
–> test_acc: 0.95343,
–> elapsed_time: 18.449秒
当前是第 8 轮:
–> train_acc: 0.9982,
–> test_acc: 0.97059,
–> elapsed_time: 18.66秒
当前是第 9 轮:
–> train_acc: 0.9982,
–> test_acc: 0.94853,
–> elapsed_time: 18.459秒
当前是第 10 轮:
–> train_acc: 0.9994,
–> test_acc: 0.96569,
–> elapsed_time: 18.508秒

plt.plot(train_accs, label="train_acc")
plt.plot(test_accs, label="train_acc")
plt.legend()
plt.grid()
plt.xlabel(xlabel='epoch')
plt.ylabel(ylabel="acc")
plt.title(label="Vgg16 Training Process")

在这里插入图片描述

4. ResNet50 手势识别

"""
    1,数据打包
        - [N, C, H, W]
        - 读取原始图像信息(每个图像的路径及其类别)
        - 批量化打包(Dataset,Dataloader)
"""
import os
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import numpy as np
from PIL import Image
import torch
from torch import nn
import time
from matplotlib import pyplot as plt
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

# 1,读取基图像的本信息
root = "gestures"

# 1,训练集
train_root = os.path.join(root, 'train')
img_train = []
label_train = []
for label in os.listdir(train_root):
    label_root = os.path.join(train_root, label)
    for img in os.listdir(label_root):
        img_path = os.path.join(label_root, img)
        img_train.append(img_path)
        label_train.append(label)
        
# 2,测试集
test_root = os.path.join(root, 'test')
img_test = []
label_test = []
for label in os.listdir(test_root):
    label_root = os.path.join(test_root, label)
    for img in os.listdir(label_root):
        img_path = os.path.join(label_root, img)
        img_test.append(img_path)
        label_test.append(label)

# 2, 标签字典
label_list = list(set(label_train))
# 原地 + 升序
label_list.sort()
# 构建标签字典
label2idx = {label: idx for idx, label in enumerate(label_list)}
idx2label = {idx: label for label, idx in label2idx.items()}


# 3,自定义数据集
class GesturesDataset(Dataset):
    """
        自定义数据集
    """
    def __init__(self, X, y):
        self.X = X
        self.y = y
    
    def __len__(self):
        return len(self.X)
    
    def __getitem__(self,idx):
        img_path = self.X[idx]
        img_label = self.y[idx]
        
        # 1,处理图像
        # 读取图像
        img = Image.open(fp=img_path)
        # 转 为 32 * 32
        img = img.resize((224, 224))
        # 转 NumPy数组
        img = np.array(img)
        # 范围 [-1, 1]
        img = img / 255
        img = (img - 0.5) / 0.5
        # 转张量
        img = torch.tensor(data=img, dtype=torch.float32)
        # 转 维度 [H, W, C] ---> [C, H, W]
        img = img.permute(dims=(2, 0, 1))
        
        
        # 2,处理标签
        label = label2idx.get(img_label)
        # 转张量
        label = torch.tensor(data=label, dtype=torch.long)
        
        
        # 返回样本
        return img, label


# 训练集加载器
train_dataset = GesturesDataset(X=img_train, y=label_train)
train_dataloader = DataLoader(dataset=train_dataset, 
                              shuffle=True, 
                              batch_size=16)
# 测试集加载器
test_dataset = GesturesDataset(X=img_test, y=label_test)
test_dataloader = DataLoader(dataset=test_dataset, 
                              shuffle=False, 
                              batch_size=16)

from models import ResNet50
# 224 x 224
model = ResNet50(n_classes=10)

# 训练筹备
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model.to(device=device)
epochs = 10
lr = 1e-3
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=model.parameters(), lr=lr)

# 准确率计算
def get_acc(data_loader):
    accs = []
    model.eval()
    with torch.no_grad():
        for X, y in data_loader:
            X = X.to(device=device)
            y = y.to(device=device)
            y_pred = model(X)
            y_pred = y_pred.argmax(dim=-1)
            acc = (y_pred == y).to(torch.float32).mean().item()
            accs.append(acc)
    final_acc = round(number=sum(accs) / len(accs), ndigits=5)
    return final_acc


# 训练过程
def train():
    
    train_accs = []
    test_accs = []
    cur_test_acc = 0
    
    # 1,训练之前,检测一下准确率
    train_acc = get_acc(data_loader=train_dataloader)
    test_acc = get_acc(data_loader=test_dataloader)
    train_accs.append(train_acc)
    test_accs.append(test_acc)
    
    print(f"训练之前:train_acc: {train_acc},test_acc: {test_acc}")
    
    # 每一轮次
    for epoch in range(epochs):
        # 模型设置为 train 模式
        model.train()
        # 计时
        start_train = time.time()
        # 每一批量
        for X, y in train_dataloader:
            # 数据搬家
            X = X.to(device=device)
            y = y.to(device=device)
            # 1,正向传播
            y_pred = model(X)
            # 2,计算损失
            loss = loss_fn(y_pred, y)
            # 3,反向传播
            loss.backward()
            # 4,优化一步
            optimizer.step()
            # 5,清空梯度
            optimizer.zero_grad()
        # 计时结束
        stop_train = time.time()
        # 测试准确率
        train_acc = get_acc(data_loader=train_dataloader)
        test_acc = get_acc(data_loader=test_dataloader)
        train_accs.append(train_acc)
        test_accs.append(test_acc)
        # 保存模型
        if cur_test_acc < test_acc:
            cur_test_acc = test_acc
            # 保存最好模型
            torch.save(obj=model.state_dict(), f="resnet50_best.pt")
        # 保存最后模型
        torch.save(obj=model.state_dict(), f="resnet50_last.pt") 
        
        print(f"""当前是第 {epoch + 1} 轮:
                --> train_acc: {train_acc},
                --> test_acc: {test_acc},
                --> elapsed_time: {round(number=stop_train - start_train, ndigits=3)}秒""")
    return train_accs, test_accs

train_accs, test_accs = train()
  • 没有训练很多轮,没耐心等他了。

训练之前:train_acc: 0.10072,test_acc: 0.09804
当前是第 1 轮:
–> train_acc: 0.20564,
–> test_acc: 0.19608,
–> elapsed_time: 8.413秒
当前是第 2 轮:
–> train_acc: 0.22542,
–> test_acc: 0.25,
–> elapsed_time: 8.083秒
当前是第 3 轮:
–> train_acc: 0.30276,
–> test_acc: 0.27451,
–> elapsed_time: 8.087秒
当前是第 4 轮:
–> train_acc: 0.43106,
–> test_acc: 0.45098,
–> elapsed_time: 8.054秒
当前是第 5 轮:
–> train_acc: 0.48681,
–> test_acc: 0.47304,
–> elapsed_time: 8.034秒
当前是第 6 轮:
–> train_acc: 0.53177,
–> test_acc: 0.52696,
–> elapsed_time: 8.025秒
当前是第 7 轮:
–> train_acc: 0.68165,
–> test_acc: 0.63971,
–> elapsed_time: 8.23秒
当前是第 8 轮:
–> train_acc: 0.71403,
–> test_acc: 0.67647,
–> elapsed_time: 8.168秒
当前是第 9 轮:
–> train_acc: 0.83153,
–> test_acc: 0.78922,
–> elapsed_time: 8.169秒
当前是第 10 轮:
–> train_acc: 0.85012,
–> test_acc: 0.7598,
–> elapsed_time: 8.161秒

  • 结果分析
plt.plot(train_accs, label="train_acc")
plt.plot(test_accs, label="train_acc")
plt.legend()
plt.grid()
plt.xlabel(xlabel='epoch')
plt.ylabel(ylabel="acc")
plt.title(label="ResNet50 Training Process")

# 参数量
n_params = 0
for param in model.parameters():
    n_params += param.numel()
n_params   # : 23528522

在这里插入图片描述

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

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

相关文章

基于单片机的智能台灯设计

摘 要 &#xff1a; 随着电子产品智能化的发展 &#xff0c; 生活中人们使用的照明工具也逐渐智能化 &#xff0c; 功能也越来越丰富 。 本文介绍了使用单片机进行可调光台灯系统的设计。 通过控制单片机输出高低电平的持续时间 &#xff0c; 从而改变 PWM 的占空比 &#…

el-tree树添加向下移动按钮,前端界面调整顺序

需求&#xff1a;树上添加向下按钮&#xff0c;再不调用接口的情况下&#xff0c;调整树的顺序结构 遇到的问题&#xff1a;第一次点击更新的&#xff0c;数据和视图是调整好的&#xff0c;再次点击页面调整顺序&#xff0c;只有数据被调整了&#xff0c;视图没有发生改变。 &…

【音视频之SDL2】bmp图片与绘制bmp

文章目录 前言BMP是什么SDL2绘制BMP的原理SDL2绘制BMP的流程SDL_LoadBMP作用函数原型参数返回值示例代码 SDL_BlitSurface作用函数原型参数返回值 示例代码效果展示总结 前言 在现代多媒体应用中&#xff0c;图像的处理和显示是非常重要的一部分。无论是在游戏开发还是在视频处…

Qt SQLite数据库编程学习总结

到此为止&#xff0c;就使用Qt进行SQLite数据库的操作&#xff0c;做一次总结 1. Qt中数据库操作的相关概念和类 Qt 数据库编程相关基本概念https://blog.csdn.net/castlooo/article/details/140497177 2.表的只读查询--QSqlQueryModel QSqlQueryModel单表查询的使用总结htt…

Nuxt.js 环境变量配置与使用

title: Nuxt.js 环境变量配置与使用 date: 2024/7/25 updated: 2024/7/25 author: cmdragon excerpt: 摘要&#xff1a;“该文探讨了Nuxt.js框架下环境变量配置的详细过程&#xff0c;涉及.env文件配置、运行时访问、安全性考量、在不同场景下的实践&#xff08;如Vue应用、…

华为OD机试 - 分配土地 (Java 2024年C卷D卷)

华为OD机试&#xff08;C卷D卷&#xff09;2024真题目录(Java & c & python) 题目描述 从前有个村庄&#xff0c;村民们喜欢在各种田地上插上小旗子&#xff0c;旗子上标识了各种不同的数字。 某天集体村民决定将覆盖相同数字的最小矩阵形的土地分配给村里做出巨大贡…

本地电脑连接阿里云

系列文章目录 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、方法1二、使用步骤1.引入库 前言 一、方法1 本地连接远程服务器的时候提示出现身份验证错误的几种解决方法 二、使用步骤 …

巴黎奥运启幕 PLM系统助力中国制造闪耀全球

2024巴黎奥运会将于法国当地时间7月26日在塞纳河畔正式开幕。即将亮相巴黎奥运会赛场的除了中国运动员之外&#xff0c;还有一批批中国制造企业为奥运会设计并制造的体育设备也将惊艳亮相&#xff0c;成为赛场上另一道亮丽的风景线。 在新时代的浪潮中&#xff0c;中国制造业坚…

大道云行,位居中国分布式存储市场挑战者象限!

近日&#xff0c;中国市场咨询机构赛迪顾问发布了《中国分布式存储市场研究报告&#xff08;2024&#xff09;》&#xff08;简称“报告”&#xff09;。报告基于对中国分布式存储市场的深入研究&#xff0c;从发展现状、厂商竞争力、未来趋势入手&#xff0c;结合新环境、新规…

【RHCE】综合真机实验(shell完成)

目录 题目&#xff1a; 需求描述 实操 一、服务端&#xff08;servera&#xff09; 1.ip配置 2.更改主机名 3.创建本地仓库 4.DNS服务 1.下载软件包和防火墙允许 2.配置主配置文件 3.配置区域文件 1.named.exam 2.named.fangxiang 4.重启服务 5.验证结果&#x…

OCDM水下通信仿真代码

一、代码介绍 MATLAB实现&#xff0c;基于OCDM水下基带通信仿真&#xff0c;对比了不同子载波激活的下OCDM水下通信性能&#xff0c;引入多径信道&#xff0c;采用相同信道估计方法,并对比了不同子载波数下的MMSE均衡效果。 信道估计方法参考论文 Robust Channel Estimation …

一款基于Cortex-M0+的单片机音频编解码 - CJC2100

USBCodec芯片可以对数字音频信号进行多种处理&#xff0c;例如增加音量、均衡调节、音效处理等。这些处理可以通过耳机的控制按钮来实现&#xff0c;让用户可以根据自己的喜好来调整音频效果。USBCodec芯片还可以控制噪声和失真的水平&#xff0c;以提供高品质的音频输出。噪声…

单证不一致清关难题 | 国际贸易综合服务平台 | 箱讯科技

什么是单证一致&#xff1f; 单证一致出口方所提供的所有单据要严格符合进口方开证银行所开信用证的要求&#xff0c;或者说出口方制作和提供的所有与本项货物买卖有关的单据&#xff0c;与进口方申请开立的信用证对单据的要求完全吻合&#xff0c;没有矛盾。 添加图片注释&am…

batch norm记录

文章目录 概要整体架构流程训练阶段推理阶段模型中使用的注意事项 概要 面试百度时候被问到了BN 内部详细的训练阶段&#xff0c;推理阶段的计算过程。没回答好&#xff0c;来记录一下 推荐一下b站up: Enzo_Mi。视频做的确实不错 bn 讲解视频 整体架构流程 训练阶段 均值和标…

多模态大模型技术白皮书 2024

不同于语言大模型只对文本进行处理&#xff0c;多模态大模型将文本、语音、图像、视频等多模态数据联合起来进行学习。多模态大模型融合了多种感知途径与表达形态&#xff0c;能够同时处理和理解来自不同感知通道&#xff08;例如视觉、听觉、语言和触觉等&#xff09;的信息&a…

构建生成工具cmake的使用(1)

ps:本文是对cmake的基础讲解&#xff0c;掌握后解决70-80%情况是足以应对的&#xff0c;后续会对cmake有进阶内容。 一 前言 CMake 是一个工具&#xff0c;帮助开发者管理和自动化软件项目的构建过程。它使用一个叫做CMakeLists.txt 的文本文件来描述项目的组织结构、编译选项…

matlab实验:实验六MATLAB 数值计算与符号运算

题目1&#xff1a;&#xff08;线性方程组数值求解&#xff09; 1&#xff0e; 用不同的方法求解下面方程&#xff1a;&#xff08;方程原式参考 P369 实验 10&#xff0c;第 1 题&#xff09; 第 1 种&#xff0c;左除和求逆函数(inv) 第 2 种 &#xff0c; 用 符 号 运 算 的…

大语言模型-对比学习-Contrastive Learning

一、对比学习概念 对比学习是一种特殊的无监督学习方法。 旨在通过拉近相关样本的距离并且推远不相关样本的距离&#xff0c;来学习数据表示。 通常使用一种高自由度、自定义的规则来生成正负样本。在模型预训练中有着广泛的应用。 二、对比学习小案例 对比学习主要分为三个…

C#使用Clipper2进行多边形合并、相交、相减、异或的示例

Clipper2库介绍 开源库介绍&#xff1a; Clipper2在Github上的地址&#xff1a;https://github.com/AngusJohnson/Clipper2 Clipper2库对简单和复杂多边形执行交集&#xff08;Intersection&#xff09;、并集&#xff08;Union&#xff09;、差分&#xff08;Difference&…

Llama 3.1超大405B!AI巨浪再掀新高潮

前沿科技速递&#x1f680; Meta公司宣布开放的Llama 3.1系列模型&#xff0c;以其惊人的128K上下文长度、对八种语言的支持以及业界领先的405B开放式最前沿AI模型&#xff0c;瞬间吸引了全球科技界的目光。该系列模型不仅在通用知识、可控性、数学、工具使用和多语言翻译等方面…