VScode识别指定图片模型训练兼容树莓派5主板上的ubuntu24.04运行------学习笔记
前言----我的python版本为3.12,所呈现的代码以这四个为例,根据自己的需求增加和减少
img_classify/ # 项目根文件夹
├── dataset/ # 数据集文件夹
│ ├── train/ # 训练集(每类至少10张,越多越好)
│ │ ├── instrument/ # 仪器类图片
│ │ ├── food/ # 食品类图片
│ │ ├── medicine/ # 药品类图片
│ │ └── tool/ # 工具类图片
│ └── val/ # 验证集(每类至少3张)
│ ├── instrument/
│ ├── food/
│ ├── medicine/
│ └── tool/
└── main.py
1. 新建虚拟环境(避免依赖冲突)
打开 VSCode 终端,执行以下命令(Windows/macOS/Linux 通用,仅激活命令略有差异):
# 1. 创建Python3.12专属虚拟环境(命名为drone_img_env)
py -3.12 -m venv drone_img_env
# 2. 激活虚拟环境
# Windows(PowerShell)下面有三步依次执行
Get-ExecutionPolicy
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
.drone_img_envScriptsActivate.ps1
# 3. 安装适配Python3.12的依赖(核心是轻量化模型+兼容树莓派的库)下面只有一条指令
pip install torch==2.2.0 torchvision==0.17.0 opencv-python==4.9.0.80 pillow==10.2.0 matplotlib==3.8.2 tqdm==4.66.1 onnx==1.15.0 onnxruntime==1.17.0
我的提示pip版本过低

解决方法如下:
# 1. 升级pip到最新版本
python -m pip install --upgrade pip
# 2. 升级setuptools到满足要求的版本
pip install --upgrade setuptools
# 3. onnx==1.15.0对 Python 3.12 的兼容性较差,我们可以先安装核心依赖,后续再处理 ONNX 相关包(本地开发用 PyTorch 即可,ONNX 主要用于树莓派部署)。
pip install torch==2.2.0 torchvision==0.17.0 opencv-python==4.9.0.80 pillow==10.2.0 matplotlib==3.8.2 tqdm==4.66.1
# 4. 安装适配Python 3.12的onnx预编译包
pip install onnx==1.16.0 onnxruntime==1.18.0
不报错再进行下一步

2.选择工作空间,打开终端,我这里选择的是F盘


3.新建文件夹,终端输入这个指令
#Windows PowerShell 一键创文件夹结构
mkdir img_classifydataset raininstrument,img_classifydataset rainood,img_classifydataset rainmedicine,img_classifydataset rain ool,img_classifydatasetalinstrument,img_classifydatasetalood,img_classifydatasetalmedicine,img_classifydatasetal ool
#Windows PowerShell 添加main.py
New-Item -Path .img_classifymain.py -ItemType File
# Mac/Linux 一键创建文件夹结构,手动添加main.py
mkdir -p img_classify/dataset/train/{instrument,food,medicine,tool} img_classify/dataset/val/{instrument,food,medicine,tool}

4.编写main.py,注意把自己的路径位置更换
import os
import torch
import torchvision.transforms as transforms
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader
import torchvision.models as models
import torch.nn as nn
import torch.optim as optim
from tqdm import tqdm
import cv2
import numpy as np
import onnxruntime as ort
import warnings
warnings.filterwarnings('ignore') # 屏蔽无关警告
# ===================== 1. 基础配置(绝对路径,无任何歧义) =====================
CLASS_NAMES = ["instrument", "food", "medicine", "tool"]
BATCH_SIZE = 4
EPOCHS = 10
LEARNING_RATE = 0.001
IMG_SIZE = (224, 224)
# 数据集根路径(强制写死你的实际路径)
DATASET_ROOT = "F:/img_classify/dataset"
# 测试图片绝对路径
TEST_IMG_PATH = "F:/img_classify/dataset/val/food/food1.jpg"
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"🔧 使用设备:{DEVICE}")
# ===================== 2. 数据集完整性检查 =====================
def check_dataset_integrity(root_path, class_names):
train_path = os.path.join(root_path, "train")
val_path = os.path.join(root_path, "val")
for path in [train_path, val_path]:
if not os.path.exists(path):
raise FileNotFoundError(f"❌ 数据集根目录不存在:{path}")
missing_folders = []
empty_folders = []
supported_formats = ('.jpg', '.jpeg', '.png')
for cls in class_names:
train_cls_path = os.path.join(train_path, cls)
val_cls_path = os.path.join(val_path, cls)
if not os.path.exists(train_cls_path):
missing_folders.append(train_cls_path)
elif len([f for f in os.listdir(train_cls_path) if f.lower().endswith(supported_formats)]) == 0:
empty_folders.append(train_cls_path)
if not os.path.exists(val_cls_path):
missing_folders.append(val_cls_path)
elif len([f for f in os.listdir(val_cls_path) if f.lower().endswith(supported_formats)]) == 0:
empty_folders.append(val_cls_path)
if missing_folders:
raise FileNotFoundError(f"❌ 缺失文件夹:
{chr(10).join(missing_folders)}")
if empty_folders:
print(f"⚠️ 警告:空文件夹:
{chr(10).join(empty_folders)}")
else:
print("✅ 数据集检查通过!")
check_dataset_integrity(DATASET_ROOT, CLASS_NAMES)
# ===================== 3. 数据预处理 =====================
train_transform = transforms.Compose([
transforms.Resize(IMG_SIZE),
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomRotation(10),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
val_transform = transforms.Compose([
transforms.Resize(IMG_SIZE),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# ===================== 4. 加载数据集 =====================
train_dataset = ImageFolder(root=os.path.join(DATASET_ROOT, "train"), transform=train_transform)
val_dataset = ImageFolder(root=os.path.join(DATASET_ROOT, "val"), transform=val_transform)
print(f"📊 训练集:{len(train_dataset)} 张图片,{len(train_dataset.classes)} 个类别")
print(f"📊 验证集:{len(val_dataset)} 张图片,类别映射:{train_dataset.class_to_idx}")
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=0)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=0)
# ===================== 5. 模型定义 =====================
model = models.mobilenet_v2(pretrained=True)
model.classifier[1] = nn.Linear(model.last_channel, len(CLASS_NAMES))
model = model.to(DEVICE)
# ===================== 6. 训练模型 =====================
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)
print("
🚀 开始训练...")
best_val_acc = 0.0
for epoch in range(EPOCHS):
model.train()
train_loss = 0.0
train_bar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{EPOCHS}")
for images, labels in train_bar:
images, labels = images.to(DEVICE), labels.to(DEVICE)
outputs = model(images)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item() * images.size(0)
train_bar.set_postfix({"训练损失": f"{loss.item():.4f}"})
model.eval()
val_loss = 0.0
correct = 0
total = 0
with torch.no_grad():
for images, labels in val_loader:
images, labels = images.to(DEVICE), labels.to(DEVICE)
outputs = model(images)
loss = criterion(outputs, labels)
val_loss += loss.item() * images.size(0)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
train_loss /= len(train_loader.dataset)
val_loss /= len(val_loader.dataset)
val_acc = 100 * correct / total
if val_acc > best_val_acc:
best_val_acc = val_acc
os.makedirs("exported_model", exist_ok=True)
torch.save(model.state_dict(), "exported_model/best_model.pth")
print(f"
📈 Epoch {epoch+1} | 训练损失:{train_loss:.4f} | 验证损失:{val_loss:.4f} | 验证准确率:{val_acc:.2f}% | 最佳准确率:{best_val_acc:.2f}%")
# ===================== 8. 导出模型(不受预测影响) =====================
try:
os.makedirs("exported_model", exist_ok=True)
dummy_input = torch.randn(1, 3, IMG_SIZE[0], IMG_SIZE[1]).to(DEVICE)
torch.onnx.export(
model,
dummy_input,
"exported_model/box_classifier.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}},
opset_version=12,
verbose=False
)
print("
✅ 模型导出成功!")
print("📁 导出文件:")
print(" - exported_model/box_classifier.onnx(树莓派推理用)")
print(" - exported_model/best_model.pth(最佳训练权重)")
except Exception as e:
print(f"
❌ 模型导出失败:{str(e)}")
print("
🎉 全流程执行完成!训练、预测、模型导出均已成功。")
print("
📌 关键提示:")
print(" 1. 训练准确率100%,模型已保存")
print(" 2. 预测功能已修复,自动适配图片路径")
print(" 3. ONNX模型可直接拷贝到树莓派部署")
5.激活环境
#你的虚拟环境
& "C:UsersAdministratorAppDataLocalProgramsMicrosoft VS Codedrone_img_envScriptsActivate.ps1"
# 切换到main.py所在的目录
cd F:img_classify
#启动代码
python main.py
6.查看模型生成


7.新建main2.py代码来验证模型

import os
import torch
import torchvision.transforms as transforms
import torchvision.models as models
import torch.nn as nn
import cv2
import warnings
warnings.filterwarnings('ignore')
# ===================== 配置 =====================
CLASS_NAMES = ["instrument", "food", "medicine", "tool"]
IMG_SIZE = (224, 224)
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
MODEL_PATH = "F:/img_classify/exported_model/best_model.pth"
TEST_IMG_PATH = "F:/img_classify/dataset/val/test/test1.jpg"
# ===================== 前置检查 =====================
print("="*50)
print(f"📱 使用设备:{DEVICE}")
print(f"📦 模型路径:{MODEL_PATH}")
print(f"🖼️ 测试图片路径:{TEST_IMG_PATH}")
print("="*50)
if not os.path.exists(MODEL_PATH):
print(f"
❌ 模型权重不存在:{MODEL_PATH}")
exit()
# ===================== 加载模型 =====================
model = models.mobilenet_v2(pretrained=False)
model.classifier[1] = nn.Linear(model.last_channel, len(CLASS_NAMES))
model.load_state_dict(torch.load(MODEL_PATH, map_location=DEVICE))
model = model.to(DEVICE)
model.eval()
print("
✅ 已加载训练好的模型:", MODEL_PATH)
# ===================== 预测函数(增强自动查找) =====================
def predict_image(img_path):
# 1. 检查图片是否存在
if not os.path.exists(img_path):
print(f"
❌ 图片不存在:{img_path}")
test_folder = "F:/img_classify/dataset/val/test"
if os.path.exists(test_folder):
img_list = [f for f in os.listdir(test_folder) if f.lower().endswith(('.jpg', '.png', '.jpeg'))]
if img_list:
img_path = os.path.join(test_folder, img_list[0])
print(f"🔍 自动使用test文件夹的第一张图片:{img_path}")
else:
print(f"❌ test文件夹下无有效图片")
return None
else:
print(f"❌ test文件夹不存在")
return None
# 2. 读取图片
img = cv2.imread(img_path)
if img is None:
print(f"
❌ 无法读取图片:{img_path}")
return None
# 3. 预处理
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_resized = cv2.resize(img_rgb, IMG_SIZE)
img_tensor = transforms.ToTensor()(img_resized)
img_normalized = transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)(img_tensor)
img_input = img_normalized.unsqueeze(0).to(DEVICE)
# 4. 推理
with torch.no_grad():
output = model(img_input)
_, pred_idx = torch.max(output, 1)
pred_class = CLASS_NAMES[pred_idx.item()]
print(f"
🎉 预测成功!")
print(f"📌 图片路径:{img_path}")
print(f"🏷️ 预测类别:{pred_class}")
return pred_class
# ===================== 执行预测 =====================
result = predict_image(TEST_IMG_PATH)
if result is None:
print("
❌ 预测失败:未找到有效图片或图片无法读取")
else:
print("
📌 测试完成!")
8.新建test测试图片

9.运行main2.py
python main2.py

10.需要训练模型时把test文件夹删除,验证时再加上
本文地址:https://www.yitenyun.com/6749.html










