增加了数据增强离线的程序(可扩充数据集),将图片压缩从32*32,调整为224*224.

This commit is contained in:
zhanghuan
2025-09-15 17:26:14 +08:00
parent d73331010c
commit 264d01e9b9
5 changed files with 80 additions and 14 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ class FoodClassifierApp:
self.root.geometry("1400x800")
# 食物类别(根据您的数据集)
self.food_classes = ["回锅肉", "西红柿鸡蛋","麻辣小面"]
self.food_classes = ['回锅肉', '炒细面', '西红柿鸡蛋', '麻辣小面']
# 设备设置
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+50
View File
@@ -0,0 +1,50 @@
import os
import random
from PIL import Image
from torchvision import transforms
# 原始数据目录
input_root = "../dataset/train"
# 增强后保存目录
output_root = "../dataset/train_aug"
# 每类目标张数
target_num = 500
# 定义数据增强
transform = transforms.Compose([
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomRotation(15),
transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.02),
transforms.RandomResizedCrop(size=(224, 224), scale=(0.8, 1.0)),
])
os.makedirs(output_root, exist_ok=True)
# 遍历每个类别文件夹
for class_name in os.listdir(input_root):
input_dir = os.path.join(input_root, class_name)
output_dir = os.path.join(output_root, class_name)
os.makedirs(output_dir, exist_ok=True)
# 读取类别下所有图片路径
img_files = [f for f in os.listdir(input_dir) if f.lower().endswith(('.jpg', '.png', '.jpeg'))]
img_paths = [os.path.join(input_dir, f) for f in img_files]
print(f"类别 {class_name} 原始图片数: {len(img_paths)}")
count = 0
while count < target_num:
img_path = random.choice(img_paths)
img = Image.open(img_path).convert("RGB")
# 生成增强图
aug_img = transform(img)
# 保存
save_path = os.path.join(output_dir, f"aug_{count:03d}.jpg")
aug_img.save(save_path)
count += 1
print(f"类别 {class_name} 已扩充到 {target_num} 张,保存于 {output_dir}")
print("✅ 数据增强完成!")
+13 -8
View File
@@ -17,9 +17,9 @@ class FoodCNN(nn.Module):
super(FoodCNN, self).__init__()
self.use_internal_preprocess = use_internal_preprocess
# 图片预处理变换(仅在推理时使用)
# 图片预处理变换(仅在推理时使用)32)改为(224
self.preprocess = transforms.Compose([
transforms.Resize((32, 32),interpolation=transforms.InterpolationMode.BILINEAR),
transforms.Resize((224, 224),interpolation=transforms.InterpolationMode.BILINEAR),
transforms.ToTensor(),
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
])
@@ -49,7 +49,8 @@ class FoodCNN(nn.Module):
self.dropout3 = nn.Dropout2d(0.25)
# 全连接层
self.fc1 = nn.Linear(128 * 4 * 4, 512)
# self.fc1 = nn.Linear(128 * 4 * 4, 512)
self.fc1 = nn.Linear(128 * 28 * 28, 512)
self.dropout4 = nn.Dropout(0.5)
self.fc2 = nn.Linear(512, settings.NUM_CLASSES)
@@ -76,8 +77,9 @@ class FoodCNN(nn.Module):
tensor = tensor.unsqueeze(0)
# 使用与移动端相同的插值方法缩放到32x32
tensor = F.interpolate(tensor, size=(32, 32), mode='bilinear', align_corners=False)
# tensor = F.interpolate(tensor, size=(32, 32), mode='bilinear', align_corners=False)
tensor = F.interpolate(tensor, size=(224, 224), mode='bilinear', align_corners=False)
# ImageNet标准化
mean = torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1)
std = torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1)
@@ -100,7 +102,8 @@ class FoodCNN(nn.Module):
# x = x.float() / 255.0
# 缩放到 32x32
x = F.interpolate(x, size=(32, 32), mode='bilinear', align_corners=False)
# x = F.interpolate(x, size=(32, 32), mode='bilinear', align_corners=False)
x = F.interpolate(x, size=(224, 224), mode='bilinear', align_corners=False)
# 缩放到 32x32 - 使用 align_corners=True 来匹配 PIL 的默认行为
# x = F.interpolate(x, size=(32, 32), mode='bilinear', align_corners=True)
@@ -140,8 +143,10 @@ class FoodCNN(nn.Module):
x = self.dropout3(x)
# 展平
x = x.view(-1, 128 * 4 * 4)
# x = x.view(-1, 128 * 4 * 4)
x = x.view(-1, 128 * 28 * 28)
# x = x.view(-1, 65536)
# 全连接层
x = F.relu(self.fc1(x))
x = self.dropout4(x)
+2 -1
View File
@@ -15,7 +15,7 @@ VAL_DATA_DIR = os.path.join(DATASET_DIR, 'val')
TEST_DATA_DIR = os.path.join(DATASET_DIR, 'test')
# 模型保存路径
MODEL_DIR = os.path.join(BASE_DIR, 'model', '12')
MODEL_DIR = os.path.join(BASE_DIR, 'model', '15')
BEST_MODEL_PATH = os.path.join(MODEL_DIR, 'best_food_model.pth')
TRAINING_CURVES_PATH = os.path.join(MODEL_DIR, 'training_curves.png')
TRAINING_RESULTS_PATH = os.path.join(MODEL_DIR, 'training_results.txt')
@@ -26,6 +26,7 @@ INFERENCE_BEST_MODEL_PATH = BEST_MODEL_PATH
# 训练参数
NUM_EPOCHS = 100
BATCH_SIZE = 32
# BATCH_SIZE = 128
LEARNING_RATE = 0.001
WEIGHT_DECAY = 1e-4
+14 -4
View File
@@ -30,17 +30,27 @@ print(f"使用设备: {device}")
# 数据预处理 - 必须包含Resize以保证batch中tensor尺寸一致,只有Normalize由模型内部完成
# 把3232换成224224
# transform_train = transforms.Compose([
# transforms.Resize((224, 224)),
# transforms.RandomHorizontalFlip(p=0.5),
# transforms.RandomRotation(10),
# transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
# transforms.ToTensor(),
# # 注意:只有Normalize由模型内部处理
# ])
transform_train = transforms.Compose([
transforms.Resize((32, 32)), # 必须保留,确保batch中tensor尺寸一致
transforms.Resize((224, 224)),
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomRotation(10),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.02),
transforms.ToTensor(),
# 注意:只有Normalize由模型内部处理
])
# 把缩放成32*32,修改为224*224
transform_test = transforms.Compose([
transforms.Resize((32, 32)), # 必须保留,确保batch中tensor尺寸一致
transforms.Resize((224, 224)), # 必须保留,确保batch中tensor尺寸一致
transforms.ToTensor(),
# 注意:只有Normalize由模型内部处理
])
@@ -129,7 +139,7 @@ def test(model, test_loader, device, class_names):
})
print(f'\n测试集总体准确率: {100.*correct/total:.2f}%')
for i in range(3):
for i in range(settings.NUM_CLASSES):
if class_total[i] > 0:
print(f'{class_names[i]} 准确率: {100.*class_correct[i]/class_total[i]:.2f}%')