【Pytorch图像分类】MobilenetV2手语识别(超详细1W+)

一、简介

  • 项目使用torchvision.models自带模型:Mobilenet_v2;在约3400张手语手势图片上进行训练,准确率达到98%。
  • 训练轮数约80轮。测试集中图片100%准确率,自己拍摄的手势标准的图片准确率达到80%以上。
  • 模型轻量,2G显存可以轻松训练,推理速度很快。
  • 具备完整代码,注释完备,思路讲解

二、数据集

手语识别数据集,每个字母有一种手势表达,共26个类别。每张图片主体清晰,质量很高。

训练集:26个字母每个字母约130张图片

测试集:26个字母每个字母约100张图片

b6a810a6cdeb499ab7c60fb1ef97ece6.png

数据集源地址:Synthetic ASL Alphabet (kaggle.com)

注:源数据集的训练集每个字母有900多张图片

三、模型效果

54b4b60c9f814b0282b9b5a30b60723b.png

四、代码

(一)数据加载(loaddata.py)

1、思路

首先,我们需要导入一些必要的库:

import torch
import torchvision
from torchvision import transforms

这里,torch是PyTorch的核心库,torchvision是PyTorch的一个视觉库,它提供了很多视觉任务相关的工具,比如数据集加载器、模型和变换(transforms)。


接下来,我们定义一个函数data_load

def data_load(data_dir, test_data_dir, img_height, img_width, batch_size):
  • data_dir:训练数据集的路径。
  • test_data_dir:验证数据集的路径。
  • img_height:图像的高度。
  • img_width:图像的宽度。
  • batch_size:每个批次加载的图像数量。

定义一个随机灰度化的概率:

random_grayscale_p = 0.2

这意味着在训练过程中,有20%的概率将图像转换为灰度图,这可以帮助我们的模型更好地泛化。


接下来,我们定义训练数据加载器所需的变换:

transform_train = transforms.Compose([
    transforms.Resize((img_height, img_width)),  # 调整图像大小
    transforms.RandomGrayscale(p=random_grayscale_p),  # 随机灰度化
    transforms.ToTensor(),  # 转换为Tensor
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 标准化
])
  • Resize:将图像调整到指定的高度和宽度。
  • RandomGrayscale:以一定的概率将图像转换为灰度图。
  • ToTensor:将图像数据转换为PyTorch的Tensor格式,这是神经网络处理数据所需的格式。
  • Normalize:对图像进行标准化处理,这里我们用到了均值和标准差(0.5, 0.5, 0.5)来使数据分布在[-1, 1]之间,这有助于模型的训练。

对于验证数据加载器,我们不需要随机灰度化,所以变换稍微简单一些:

transform_val = transforms.Compose([
    transforms.Resize((img_height, img_width)),  # 调整图像大小
    transforms.ToTensor(),  # 转换为Tensor
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 标准化
])

然后,我们使用torchvision.datasets.ImageFolder来加载图像数据集。这个类会自动读取指定目录下的图像,并将它们分为不同的类别(所以目录结构很重要,见  “五、注意事项(一)目录结构”)

train_dataset = torchvision.datasets.ImageFolder(root=data_dir, transform=transform_train)
val_dataset = torchvision.datasets.ImageFolder(root=test_data_dir, transform=transform_val)

接着,我们使用torch.utils.data.DataLoader来创建数据加载器。

这个类会在训练时帮助我们有效地批量加载数据:

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

shuffle=True表示在训练过程中每个epoch都会打乱数据顺序,而验证数据不需要打乱。


最后,我们从训练数据集中获取类别名称,并将训练数据加载器、验证数据加载器和类别名称返回

class_names = train_dataset.classes
return train_loader, val_loader, class_names

这样,我们的数据加载函数就讲解完毕了。通过这个函数,我们可以方便地加载数据,为后续的模型训练做好准备。

2、完整代码

import torch
import torchvision
from torchvision import transforms

def data_load(data_dir, test_data_dir, img_height, img_width, batch_size):
    # 定义随机灰度化的概率
    random_grayscale_p = 0.2
    # 定义训练数据加载器
    transform_train = transforms.Compose([
        transforms.Resize((img_height, img_width)),  # 调整图像大小
        transforms.RandomGrayscale(p=random_grayscale_p),  # 随机灰度化
        transforms.ToTensor(),  # 转换为Tensor
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 标准化
    ])
    # 定义验证数据加载器
    transform_val = transforms.Compose([
        transforms.Resize((img_height, img_width)),  # 调整图像大小
        transforms.ToTensor(),  # 转换为Tensor
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 标准化
    ])

    train_dataset = torchvision.datasets.ImageFolder(root=data_dir, transform=transform_train)
    val_dataset = torchvision.datasets.ImageFolder(root=test_data_dir, transform=transform_val)

    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

    # 获取训练数据集的类别
    class_names = train_dataset.classes
    # 返回训练数据加载器、验证数据加载器和类别
    return train_loader, val_loader, class_names

(二)模型训练(train.py)

1、思路

我们导入了几个关键库:

import os
import torch
import torch.nn as nn
import torchvision
import time
import loaddata
  • os:用于文件和目录操作,如检查文件是否存在。
  • torch 和 torch.nn:PyTorch的核心库,用于构建和训练神经网络。
  • torchvision:提供了许多预训练模型和数据集处理工具。
  • loaddata:自定义模块,用于加载和预处理数据集。

定义模型加载函数 model_load

def model_load(class_num=26):
    # 加载预训练的mobilenet_v2模型
    mobilenet = torchvision.models.mobilenet_v2(weights=torchvision.models.MobileNet_V2_Weights.DEFAULT)
    # 修改模型的最后一层全连接层,使其输出的类别数为class_num
    mobilenet.classifier[1] = nn.Linear(in_features=mobilenet.classifier[1].in_features, out_features=class_num)
    # 返回修改后的模型
    return mobilenet
  • 加载预训练的MobileNetV2模型。
  • 修改模型的最后一层(分类器),以适应我们特定的任务,即分类class_num个数

定义训练函数train

def train(epochs):

    # 加载数据集
    train_loader, val_loader, class_names = loaddata.data_load("../dataset2/train", "../dataset2/test", 224, 224, 16)
    # 打印类别名称
    print("类别名称:", class_names)
    # 加载模型
    model = model_load(class_num=len(class_names))
    # 定义损失函数
    criterion = nn.CrossEntropyLoss()

    # 添加权重衰减
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-5)

    # 判断是否有可用的GPU
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    # 将模型移动到GPU上
    model.to(device)

    # 如果存在已有模型,则加载已有模型继续训练
    if os.path.exists("mobilenet_fv.pth"):
        model.load_state_dict(torch.load("mobilenet_fv.pth"))
        print("加载已有模型继续训练")

    best_val_accuracy = 0.0
    train_losses = []
    val_losses = []
    train_accuracies = []
    val_accuracies = []

    # 设置早停的耐心值
    patience = 5
    # 初始化耐心计数器
    patience_counter = 0

    # 遍历所有epoch
    for epoch in range(epochs):
        print("Epoch {}/{}".format(epoch + 1, epochs))
        running_loss = 0.0
        correct = 0
        total = 0
        # 遍历训练集
        for i, data in enumerate(train_loader, 0):
            inputs, labels = data[0].to(device), data[1].to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
        train_losses.append(running_loss / len(train_loader))
        train_accuracies.append(correct / total)
        print("训练损失:{:.4f},准确率:{:.4f}".format(train_losses[-1], train_accuracies[-1]))

        # 初始化验证损失、正确预测数量和总数量
        running_loss = 0.0
        correct = 0
        total = 0
        # 不计算梯度
        with torch.no_grad():
            # 遍历验证集
            for i, data in enumerate(val_loader, 0):
                # 获取输入和标签
                inputs, labels = data[0].to(device), data[1].to(device)
                # 前向传播
                outputs = model(inputs)
                # 计算损失
                loss = criterion(outputs, labels)
                # 累加损失
                running_loss += loss.item()
                # 获取预测结果
                _, predicted = torch.max(outputs.data, 1)
                # 累加总数量
                total += labels.size(0)
                # 累加正确预测数量
                correct += (predicted == labels).sum().item()
        # 计算验证损失和准确率
        val_losses.append(running_loss / len(val_loader))
        val_accuracies.append(correct / total)
        # 打印验证损失和准确率
        print("验证损失:{:.4f},准确率:{:.4f}".format(val_losses[-1], val_accuracies[-1]))

        # 如果当前准确率大于最佳准确率
        if val_accuracies[-1] > best_val_accuracy:
            # 更新最佳准确率
            best_val_accuracy = val_accuracies[-1]
            # 保存模型
            torch.save(model.state_dict(), "mobilenet_fv.pth")
            print("模型已保存")
            # 重置耐心计数器
            patience_counter = 0
        else:
            # 累加耐心计数器
            patience_counter += 1
            # 如果耐心计数器超过耐心值
            if patience_counter >= patience:
                # 打印早停法触发信息
                print("早停法触发,停止训练")
                # 跳出循环
                break

在训练函数中,我们做了以下事情:

  • 加载训练和验证数据集。
  • 设置损失函数和优化器。
  • 检查是否有GPU可用,将模型移至GPU上运行。
  • 如果有预训练模型(mobilenet_fv.pth)存在,加载并继续训练。
  • 循环遍历每个epoch,执行训练和验证过程。
  • 在每个epoch结束时,检查验证集上的准确率是否提高,如果是,则保存模型状态。

主函数调用

if __name__ == '__main__':
    train(epochs=30)

最后,我们在主函数中调用train函数,传入训练的epoch(轮数),开始整个训练过程。

2、完整代码

import os
import torch
import torch.nn as nn
import torchvision
import loaddata


# 定义一个函数,用于加载模型,参数class_num表示分类的类别数
def model_load(class_num=26):
    # 加载预训练的mobilenet_v2模型
    mobilenet = torchvision.models.mobilenet_v2(weights=torchvision.models.MobileNet_V2_Weights.DEFAULT)
    # 修改模型的最后一层全连接层,使其输出的类别数为class_num
    mobilenet.classifier[1] = nn.Linear(in_features=mobilenet.classifier[1].in_features, out_features=class_num)
    # 返回修改后的模型
    return mobilenet

# 训练过程
def train(epochs):

    # 加载数据集
    train_loader, val_loader, class_names = loaddata.data_load("../dataset2/train", "../dataset2/test", 224, 224, 16)
    # 打印类别名称
    print("类别名称:", class_names)
    # 加载模型
    model = model_load(class_num=len(class_names))
    # 定义损失函数
    criterion = nn.CrossEntropyLoss()

    # 添加权重衰减
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-5)

    # 判断是否有可用的GPU
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    # 将模型移动到GPU上
    model.to(device)

    # 如果存在已有模型,则加载已有模型继续训练
    if os.path.exists("mobilenet_fv.pth"):
        model.load_state_dict(torch.load("mobilenet_fv.pth"))
        print("加载已有模型继续训练")

    best_val_accuracy = 0.0
    train_losses = []
    val_losses = []
    train_accuracies = []
    val_accuracies = []

    # 设置早停的耐心值
    patience = 5
    # 初始化耐心计数器
    patience_counter = 0

    # 遍历所有epoch
    for epoch in range(epochs):
        print("Epoch {}/{}".format(epoch + 1, epochs))
        running_loss = 0.0
        correct = 0
        total = 0
        # 遍历训练集
        for i, data in enumerate(train_loader, 0):
            inputs, labels = data[0].to(device), data[1].to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
        train_losses.append(running_loss / len(train_loader))
        train_accuracies.append(correct / total)
        print("训练损失:{:.4f},准确率:{:.4f}".format(train_losses[-1], train_accuracies[-1]))

        # 初始化验证损失、正确预测数量和总数量
        running_loss = 0.0
        correct = 0
        total = 0
        # 不计算梯度
        with torch.no_grad():
            # 遍历验证集
            for i, data in enumerate(val_loader, 0):
                # 获取输入和标签
                inputs, labels = data[0].to(device), data[1].to(device)
                # 前向传播
                outputs = model(inputs)
                # 计算损失
                loss = criterion(outputs, labels)
                # 累加损失
                running_loss += loss.item()
                # 获取预测结果
                _, predicted = torch.max(outputs.data, 1)
                # 累加总数量
                total += labels.size(0)
                # 累加正确预测数量
                correct += (predicted == labels).sum().item()
        # 计算验证损失和准确率
        val_losses.append(running_loss / len(val_loader))
        val_accuracies.append(correct / total)
        # 打印验证损失和准确率
        print("验证损失:{:.4f},准确率:{:.4f}".format(val_losses[-1], val_accuracies[-1]))

        # 如果当前准确率大于最佳准确率
        if val_accuracies[-1] > best_val_accuracy:
            # 更新最佳准确率
            best_val_accuracy = val_accuracies[-1]
            # 保存模型
            torch.save(model.state_dict(), "mobilenet_fv.pth")
            print("模型已保存")
            # 重置耐心计数器
            patience_counter = 0
        else:
            # 累加耐心计数器
            patience_counter += 1
            # 如果耐心计数器超过耐心值
            if patience_counter >= patience:
                # 打印早停法触发信息
                print("早停法触发,停止训练")
                # 跳出循环
                break


if __name__ == '__main__':
    train(epochs=30)

(三)模型预测(classmodel.py)

1、思路

导入必要的库

import os
import torch
import torch.nn as nn
import torchvision
import time
import loaddata
  • json:用于读取JSON格式的标签文件。
  • mobilenet_v2:从torchvision.models导入预训练的MobileNetV2模型。
  • torch 和 torch.nn.functional:PyTorch库和函数。
  • ResizeComposeToTensorNormalize:用于图像预处理的torchvision.transforms中的变换。
  • PIL.Image:Python Imaging Library,用于读取和操作图像。

定义SignLanguageRecognizer

初始化函数 __init__

def __init__(self, module_file='./mobilenet_fv.pth', labels_file='./ab.json'):
    # 初始化成员变量
    self.module_file = module_file
    self.CUDA = torch.cuda.is_available()
    self.net = mobilenet_v2(num_classes=26)
    if self.CUDA:
        self.net.cuda()
    self.net.load_state_dict(torch.load(self.module_file, map_location='cuda' if self.CUDA else 'cpu'))
    self.net.eval()
    self.labels = self.load_labels(labels_file)
  • 设置模型文件路径和标签文件路径。
  • 检测是否有可用的GPU。
  • 加载一个带有26个输出类别的MobileNetV2模型。
  • 将模型移到GPU上(如果可用)。
  • 加载模型的参数。
  • 将模型设置为评估模式(eval),这是为了关闭可能影响推理速度和精度的训练相关功能,如dropout。
  • 加载标签。

加载标签函数 load_labels

def load_labels(self, file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        return json.load(file)

这个函数用于打开并读取JSON文件,返回其中的内容作为字典。


图像预处理函数 preprocess_image

@torch.no_grad()
def preprocess_image(self, image_stream):
    img = Image.open(image_stream)
    transform = Compose([
        Resize((224, 224)),
        ToTensor(),
        Normalize(mean=[0.56719673, 0.5293289, 0.48351972], std=[0.20874391, 0.21455203, 0.22451781]),
    ])
    img = transform(img)
    img = torch.unsqueeze(img, 0)
    if self.CUDA:
        img = img.cuda()
    return img
  • 调整图像大小到224x224像素。
  • 将图像转换为张量。
  • 对张量进行归一化。
  • 增加一个维度,以便适合模型输入。
  • 如果使用GPU,将图像张量移动到GPU上。

图像识别函数 recognize

@torch.no_grad()
def recognize(self, image_stream):
    img = self.preprocess_image(image_stream)
    y = self.net(img)
    y = F.softmax(y, dim=1)
    p, cls_idx = torch.max(y, dim=1)
    return y.cpu(), cls_idx.cpu()

这个函数使用预处理后的图像作为输入,经过模型预测后,返回经过softmax处理的概率分布和预测类别的索引。


获取预测结果函数 get_prediction

def get_prediction(self, image_stream):
    probs, cls = self.recognize(image_stream)
    _, cls = torch.max(probs, 1)
    p = probs[0][cls.item()]
    cls_index = str(cls.numpy()[0])
    label_name = self.labels.get(cls_index, "未知标签")
    return label_name, p.item()

这个函数调用recognize函数获取预测结果,然后从标签字典中查找对应的标签名称,并返回标签名称和最大概率。


创建实例并进行预测

recongize = SignLanguageRecognizer()
ans = recongize.get_prediction('../dataset2/test/A/fe0f9990-a4cb-4351-96df-10c2b25c63d1.rgb_0000.png')
print(ans)

这里创建了一个SignLanguageRecognizer实例,并使用给定的测试图像进行预测,最后打印出预测的标签和概率。

2、完整代码

import json
from torchvision.models import mobilenet_v2
import torch
import torch.nn.functional as F
from torchvision.transforms import Resize, Compose, ToTensor, Normalize
from PIL import Image

class SignLanguageRecognizer:
    # 初始化函数,传入模型文件和标签文件
    def __init__(self, module_file='./mobilenet_fv.pth', labels_file='./ab.json'):
        self.module_file = module_file
        # 判断是否有可用的GPU
        self.CUDA = torch.cuda.is_available()
        # 加载模型
        self.net = mobilenet_v2(num_classes=26)
        # 如果有可用的GPU,则将模型加载到GPU上
        if self.CUDA:
            self.net.cuda()
        # 加载模型参数
        self.net.load_state_dict(torch.load(self.module_file, map_location='cuda' if self.CUDA else 'cpu'))
        # 将模型设置为评估模式
        self.net.eval()
        # 加载标签
        self.labels = self.load_labels(labels_file)

    # 加载标签
    def load_labels(self, file_path):
        # 打开文件
        with open(file_path, 'r', encoding='utf-8') as file:
            # 返回json格式的文件内容
            return json.load(file)

    @torch.no_grad()  # 不计算梯度
    def preprocess_image(self, image_stream):
        # 打开图像流
        img = Image.open(image_stream)
        # 定义图像预处理操作
        transform = Compose([
            Resize((224, 224)),  # 调整图像大小为224x224
            ToTensor(),  # 将图像转换为张量
            Normalize(mean=[0.56719673, 0.5293289, 0.48351972], std=[0.20874391, 0.21455203, 0.22451781]),  # 归一化
        ])
        # 对图像进行预处理
        img = transform(img)
        # 在第0维增加一个维度
        img = torch.unsqueeze(img, 0)
        # 如果使用CUDA,则将图像移动到GPU
        if self.CUDA:
            img = img.cuda()
        # 返回预处理后的图像
        return img
    @torch.no_grad()  # 在此函数中不计算梯度
    def recognize(self, image_stream):
        # 对输入的图像进行预处理
        img = self.preprocess_image(image_stream)
        # 将预处理后的图像输入到神经网络中
        y = self.net(img)
        # 对神经网络的输出进行softmax处理
        y = F.softmax(y, dim=1)
        # 找到softmax处理后的最大值和对应的索引
        p, cls_idx = torch.max(y, dim=1)
        # 返回softmax处理后的输出和对应的索引
        return y.cpu(), cls_idx.cpu()

    def get_prediction(self, image_stream):
        # 调用recognize方法,获取图像的预测概率和类别
        probs, cls = self.recognize(image_stream)
        # 获取最大概率的类别
        _, cls = torch.max(probs, 1)
        # 获取最大概率
        p = probs[0][cls.item()]
        # 将类别转换为字符串
        cls_index = str(cls.numpy()[0])
        # 获取对应的标签名称
        label_name = self.labels.get(cls_index, "未知标签")
        # 返回标签名称和最大概率
        return label_name, p.item()

recongize=SignLanguageRecognizer()
ans=recongize.get_prediction('../dataset2/test/A/fe0f9990-a4cb-4351-96df-10c2b25c63d1.rgb_0000.png')
print(ans)

(四)标签文件(ab.json)

{
  "0": "A",
  
  "1": "B",

  "2": "C",

  "3": "D",

  "4": "E",

  "5": "F",

  "6": "G",

  "7": "H",

  "8": "I",

  "9": "J",

  "10": "K",

  "11": "L",

  "12": "M",

  "13": "N",

  "14": "O",

  "15": "P",

  "16": "Q",
  
  "17": "R",
  
  "18": "S",
  
  "19": "T",
  
  "20": "U",
  
  "21": "V",
  
  "22": "W",
  
  "23": "X",
  
  "24": "Y",
  
  "25": "Z"

}

五、注意事项

(一)目录结构

a9d5dbcd44384d618fb0e27e6533b0b3.png

1、AI文件夹 下存放:数据加载、模型训练、模型预测、标签文件

2、dataset2文件夹 下存放:test(测试集)和  train(训练集)两个目录,test和train两个目录下存放26个字母文件夹

3、AI文件夹和dataset2文件夹同级

注:1、其他文件夹不用管

        2、图中 test 只有A、B是因为之前进行测试,正式训练时应该是A到Z

(二)自己拍识别图片

1、建议横屏(因为图像会变换成224*224,有可能被裁减)

2、背景可以乱,但不要和肤色融为一体

3、手势做标准,建议找个手指长但不一样长的手拍

4、最好网上找......

手势识别是一种常见的计算机视觉任务,可以使用 PyTorch 进行实现。以下是一些实现手势识别的步骤: 1. 数据集准备:收集手势图像并将其分为训练集和测试集。手势图像可以来自公共数据集,如 MNIST 或自行收集。 2. 数据预处理:对图像进行预处理,如缩放、裁剪、归一化等。 3. 模型选择:根据任务选择合适的模型,如卷积神经网络(CNN),并根据需要进行修改。 4. 模型训练:使用训练集对模型进行训练。可以使用交叉验证等方法进行模型优化。 5. 模型测试:使用测试集对模型进行测试,评估模型的性能。 6. 模型优化:根据测试结果,对模型进行优化,如调整参数、增加训练数据等。 下面是一个使用 PyTorch 实现手势识别的简单示例代码: ```python import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms # 定义模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 10, kernel_size=5) self.conv2 = nn.Conv2d(10, 20, kernel_size=5) self.fc1 = nn.Linear(320, 50) self.fc2 = nn.Linear(50, 10) def forward(self, x): x = nn.functional.relu(nn.functional.max_pool2d(self.conv1(x), 2)) x = nn.functional.relu(nn.functional.max_pool2d(self.conv2(x), 2)) x = x.view(-1, 320) x = nn.functional.relu(self.fc1(x)) x = self.fc2(x) return nn.functional.log_softmax(x, dim=1) # 加载数据集 train_loader = torch.utils.data.DataLoader( datasets.MNIST('data', train=True, download=True, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ])), batch_size=64, shuffle=True) test_loader = torch.utils.data.DataLoader( datasets.MNIST('data', train=False, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ])), batch_size=1000, shuffle=True) # 定义优化器和损失函数 model = Net() optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5) criterion = nn.CrossEntropyLoss() # 训练模型 def train(epoch): model.train() for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() if batch_idx % 10 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) # 测试模型 def test(): model.eval() test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: output = model(data) test_loss += criterion(output, target).item() pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset))) # 运行训练和测试 for epoch in range(1, 11): train(epoch) test() ``` 该示例代码使用 MNIST 数据集,定义了一个简单的 CNN 模型,并使用交叉熵损失函数和随机梯度下降优化器进行模型训练。在每个 epoch 结束时,通过测试集评估模型的性能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值