【机器学习】imagenet2012 数据预处理数据预处理

【机器学习】数据预处理

  • 1. 下载/解压数据
  • 2. 数据预处理
  • 3. 加载以及训练代码
    • 3.1 使用PIL等加载代码
    • 3.2 使用OpenCV的方式来一张张加载代码
    • 3.3 h5的方式来加载大文件
  • 最后总结

这个数据大约 140个G,128w的训练集

1. 下载/解压数据

首先需要下载数据:

数据最后处理成如图的格式,每个种类的数据都放到一个相同的文件夹中去,这里的文件夹名称(种类名称)最好改成整数,方便后续处理
在这里插入图片描述

2. 数据预处理

需要对数据做如下处理

  1. 处理成模型需要的224*224长宽的数据
  2. 处理成h5/npy之类大文件格式,从而减少CPU的IO开支
import h5py
import numpy as np
import os
from tqdm import tqdm
import cv2
from concurrent.futures import ThreadPoolExecutor
from sklearn.preprocessing import LabelEncoderdef process_image(file_path, size=(224, 224)):image = cv2.imread(file_path)if image is None:print(f"无法读取图像: {file_path}")return None# 调整图像大小resized_image = cv2.resize(image, size)return resized_imagedef create_hdf5_datasets(input_dir, output_dir, images_per_file=1000, max_workers=8):# 获取所有文件的列表all_files = []for root, dirs, files in os.walk(input_dir):for file_name in files:file_path = os.path.join(root, file_name)all_files.append(file_path)# 确保输出目录存在if not os.path.exists(output_dir):os.makedirs(output_dir)# 获取所有标签并进行编码all_labels = [os.path.basename(os.path.dirname(file)) for file in all_files]label_encoder = LabelEncoder()label_encoder.fit(all_labels)file_count = 0total_files = len(all_files)# 使用多线程处理图像with ThreadPoolExecutor(max_workers=max_workers) as executor:for i in range(0, total_files, images_per_file):chunk_files = all_files[i:i + images_per_file]processed_images = list(tqdm(executor.map(process_image, chunk_files), total=len(chunk_files), desc=f"Processing chunk {file_count + 1}"))# 过滤掉 None 值processed_images = [img for img in processed_images if img is not None]# 创建标签数据(假设标签为文件夹名称)labels = [os.path.basename(os.path.dirname(file)) for file in chunk_files if cv2.imread(file) is not None]encoded_labels = label_encoder.transform(labels)# 写入 HDF5 文件output_hdf5 = os.path.join(output_dir, f'train_{file_count + 1}.hdf5')with h5py.File(output_hdf5, 'w') as f:dataset_images = f.create_dataset("images", (len(processed_images), 224, 224, 3), dtype='uint8')dataset_labels = f.create_dataset("labels", (len(encoded_labels),), dtype='int')for j, img in enumerate(processed_images):dataset_images[j] = imgdataset_labels[j] = encoded_labels[j]file_count += 1print(f"Created {output_hdf5} with {len(processed_images)} images")print(f"Total HDF5 files created: {file_count}")# 示例用法
input_directory_path = 'E:\\data\\train'  # 替换为你的目录路径  
output_directory_path = 'E:\\data\\hdf5\\train'  # 输出的目录路径
create_hdf5_datasets(input_directory_path, output_directory_path, images_per_file=50000)  # 创建多个 HDF5 文件

这里就是将图片分成若干份,每一份50000张图,主要是我电脑内存32G 无法一次性加载,所以分割了一下。

3. 加载以及训练代码

3.1 使用PIL等加载代码

这个方式是一张张的加载图片,加载后再处理成模型需要的尺寸,在一张张加载图片的时候速度较慢,会影响训练速度

# 定义自定义数据集类
class CustomDataset(torch.utils.data.Dataset):def __init__(self, csv_file, transform=None):self.data_frame = pd.read_csv(csv_file)self.transform = transformself.label_encoder = LabelEncoder()self.data_frame['label'] = self.label_encoder.fit_transform(self.data_frame['label'])  # 将标签编码为整数def __len__(self):return len(self.data_frame)def __getitem__(self, idx):img_path = self.data_frame.iloc[idx, 0] # 图像路径image = Image.open(train_file + img_path).convert('RGB')# 读取图像label = self.data_frame.iloc[idx, 1] #从表格中读取标签 ,此时标签已经被编码为整数label = torch.tensor(label, dtype=torch.long)# 将标签转换为张量if self.transform:image = self.transform(image)return image, label# 定义图像转换
transform = transforms.Compose([transforms.Resize((224, 224)),  # 调整图像大小transforms.ToTensor(),          # 转换为张量transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 归一化 mean的值和std的值是根据ImageNet数据集的均值和标准差计算得到的
])

3.2 使用OpenCV的方式来一张张加载代码

OpenCV确实能加速一点IO的速度,

import os
import pandas as pd
import cv2  # 导入 OpenCV 库
from sklearn.preprocessing import LabelEncoder
import torch
from torch.utils.data import Dataset, DataLoader, random_split
import torchvision.transforms as transforms
import torchvision.models as models
import torch.nn as nn
import torch.optim as optim
from tqdm import tqdm  # 导入 tqdm 库
import time# 定义数据路径
data_path = 'E:\\data\\ImageNet2012\\ILSVRC2012_img_train\\'# 定义自定义数据集类
class CustomDataset(torch.utils.data.Dataset):def __init__(self, csv_file, data_path, transform=None):self.data_frame = pd.read_csv(csv_file)self.data_path = data_pathself.transform = transformself.label_encoder = LabelEncoder()self.data_frame['label'] = self.label_encoder.fit_transform(self.data_frame['label'])  # 将标签编码为整数def __len__(self):return len(self.data_frame)def __getitem__(self, idx):start_time = time.time()data_load_time = time.time() - start_timeimg_name = self.data_frame.iloc[idx, 0]  # 图像相对路径img_path = os.path.join(self.data_path, img_name)  # 生成完整的图像路径image = cv2.imread(img_path)  # 使用 OpenCV 读取图像image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # 将图像从 BGR 转换为 RGBimage = cv2.resize(image, (224, 224))  # 调整图像大小label = self.data_frame.iloc[idx, 1]  # 从表格中读取标签,此时标签已经被编码为整数label = torch.tensor(label, dtype=torch.long)  # 将标签转换为张量data_to_device_time = time.time() - start_time - data_load_timeif self.transform:image = self.transform(image)forward_time = time.time() - start_time - data_load_time - data_to_device_timeprint(f"Data load time: {data_load_time:.4f}, Data to device time: {data_to_device_time:.4f}, Forward time: {forward_time:.4f}")return image, label# 定义图像转换
transform = transforms.Compose([transforms.ToTensor(),          # 转换为张量transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 归一化 mean的值和std的值是根据ImageNet数据集的均值和标准差计算得到的
])# 创建数据集
csv_file = os.path.join(data_path, 'train.csv')
dataset = CustomDataset(csv_file=csv_file, data_path=data_path, transform=transform)# 将数据集分为训练集和验证集
train_size = int(0.8 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])# 创建数据加载器
train_dataloader = DataLoader(train_dataset, batch_size=512, shuffle=True)  # 设置 shuffle 为 True
val_dataloader = DataLoader(val_dataset, batch_size=512, shuffle=False) # 加载预训练的 ResNet 模型
model = models.resnet18(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, len(dataset.data_frame['label'].unique()))  # 根据标签数量调整最后一层# 将模型移动到 GPU 上
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)# 训练函数
def train_model(model, dataloader, criterion, optimizer):model.train()running_loss = 0.0for inputs, labels in tqdm(dataloader, desc="Training"):  # 使用 tqdm 包装 dataloaderinputs, labels = inputs.to(device), labels.to(device)  # 将数据移动到 GPU 上optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item() * inputs.size(0)epoch_loss = running_loss / len(dataloader.dataset)print(f'Training Loss: {epoch_loss:.4f}')# 测试函数
def test_model(model, dataloader, criterion):model.eval()correct = 0total = 0running_loss = 0.0with torch.no_grad():for inputs, labels in tqdm(dataloader, desc="Validation"):  # 使用 tqdm 包装 dataloaderinputs, labels = inputs.to(device), labels.to(device)  # 将数据移动到 GPU 上outputs = model(inputs)loss = criterion(outputs, labels)running_loss += loss.item() * inputs.size(0)_, predicted = torch.max(outputs, 1)total += labels.size(0)correct += (predicted == labels).sum().item()accuracy = correct / totalepoch_loss = running_loss / len(dataloader.dataset)print(f'Test Loss: {epoch_loss:.4f}, Accuracy: {accuracy:.4f}')# 训练和验证循环
epochs = 25
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train_model(model, train_dataloader, criterion, optimizer)print("Validation:")test_model(model, val_dataloader, criterion)
print("Done!")

3.3 h5的方式来加载大文件

HDF5Dataset 类在初始化时只加载文件索引,而不是加载所有数据。在 getitem 方法中,它会根据索引动态加载所需的 HDF5 文件,并从中读取图像和标签。这可以确保在每次访问数据时只加载当前需要的 HDF5 文件,并在使用完成后自动从内存中移除。

import os
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from torchvision import models, transforms
from tqdm import tqdm
import h5py# 定义数据路径
train_data_path = 'E:\\data\\hdf5\\train'
val_data_path = 'E:\\data\\hdf5\\val'# 定义自定义数据集类
class HDF5Dataset(Dataset):def __init__(self, hdf5_dir, transform=None):self.hdf5_files = [os.path.join(hdf5_dir, f) for f in os.listdir(hdf5_dir) if f.endswith('.hdf5')]self.transform = transformself.file_indices = []self.load_file_indices()def load_file_indices(self):for file_idx, hdf5_file in enumerate(self.hdf5_files):with h5py.File(hdf5_file, 'r') as f:num_images = f['images'].shape[0]self.file_indices.extend([(file_idx, i) for i in range(num_images)])def __len__(self):return len(self.file_indices)def __getitem__(self, idx):file_idx, image_idx = self.file_indices[idx]hdf5_file = self.hdf5_files[file_idx]with h5py.File(hdf5_file, 'r') as f:image = f['images'][image_idx]label = f['labels'][image_idx]if self.transform:image = self.transform(image)# 将标签转换为张量label = torch.tensor(label, dtype=torch.long)return image, label# 定义图像转换
transform = transforms.Compose([transforms.ToTensor(),          # 转换为张量transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 归一化 mean的值和std的值是根据ImageNet数据集的均值和标准差计算得到的
])# 创建训练集数据集
train_dataset = HDF5Dataset(hdf5_dir=train_data_path, transform=transform)# 创建验证集数据集
val_dataset = HDF5Dataset(hdf5_dir=val_data_path, transform=transform)# 创建数据加载器
train_dataloader = DataLoader(train_dataset, batch_size=256, shuffle=True)  # 设置 shuffle 为 True
val_dataloader = DataLoader(val_dataset, batch_size=256, shuffle=False) # 加载预训练的 ResNet 模型
model = models.resnet18(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, len(set(train_dataset.file_indices)))  # 根据标签数量调整最后一层# 将模型移动到 GPU 上
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)# 训练函数
def train_model(model, dataloader, criterion, optimizer):model.train()running_loss = 0.0for inputs, labels in tqdm(dataloader, desc="Training"):  # 使用 tqdm 包装 dataloaderinputs, labels = inputs.to(device), labels.to(device)  # 将数据移动到 GPU 上optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item() * inputs.size(0)epoch_loss = running_loss / len(dataloader.dataset)print(f'Training Loss: {epoch_loss:.4f}')# 测试函数
def test_model(model, dataloader, criterion):model.eval()correct = 0total = 0running_loss = 0.0with torch.no_grad():for inputs, labels in tqdm(dataloader, desc="Validation"):  # 使用 tqdm 包装 dataloaderinputs, labels = inputs.to(device), labels.to(device)  # 将数据移动到 GPU 上outputs = model(inputs)loss = criterion(outputs, labels)running_loss += loss.item() * inputs.size(0)_, predicted = torch.max(outputs, 1)total += labels.size(0)correct += (predicted == labels).sum().item()accuracy = correct / totalepoch_loss = running_loss / len(dataloader.dataset)print(f'Test Loss: {epoch_loss:.4f}, Accuracy: {accuracy:.4f}')# 训练和验证循环
epochs = 25
model_save_path = 'model_checkpoint.pth'
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train_model(model, train_dataloader, criterion, optimizer)print("Validation:")test_model(model, val_dataloader, criterion)# 每5个循环保存一次模型,并删除之前的模型if (t + 1) % 5 == 0:if os.path.exists(model_save_path):os.remove(model_save_path)torch.save(model.state_dict(), model_save_path)print(f"Model saved at epoch {t+1}")print("Done!")

最后总结

我的电脑环境 i5 12400+4090+32G内存+固态。
但磁盘速度才几十M如果是机械盘的话应该也问题不大

然后我训练的时间最快能达到45分钟一个epoch,使用3.3章节中的代码。
提升训练速度的小技巧

  1. 不要开任务管理器,虽然开着很爽,但确实比较占用CPU的资源
  2. 不要开浏览器,浏览器中不知道运行了些什么东西会影响速度
  3. 不要开很多vscode,只保留debug的一个,能加速10分钟

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

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

相关文章

质量工程:数字化转型时代的质量体系重构

前言:质量理念的范式转移阅读原文 如果把软件开发比作建造摩天大楼: 传统测试 竣工后检查裂缝(高成本返工) 质量工程 从地基开始的全流程监理体系(设计图纸→施工工艺→建材选择→竣工验收) IEEE研究…

【全栈开发】—— Paddle OCR 文字识别 + deepseek接入(基于python 最新!!!)

所有源码都在文章中,大家不要私信来要源码,当然,评论区欢迎交流技术 目录 Paddle OCR 配置环境 示例 deepseek接入 环境配置 api 调用代码 sliconflow Paddle OCR 配置环境 清华源下载 paddlepaddle: pip install paddlepaddle …

SAIL-RK3588J 核心板技术方案——高精度装配式建筑机器人控制‌

(本方案契合《建筑机器人产业目录》政策要求) 一、方案背景与政策支持‌ ‌政策驱动‌ 2025年2月《建筑机器人产业目录》明确将‌“高精度建筑机器人控制设备”‌纳入重点补贴范围,要求定位精度≤0.5mm、支持实时质检与多机协同&#xff0c…

OpenAI API - 快速入门开发

文章目录 开发者快速入门分析图像输入使用工具扩展模型提供闪电般的 AI 体验构建代理进一步探索 模型精选模型推理模型旗舰聊天模型成本优化模型实时模型旧版 GPT 模型DALLE文本转语音转写嵌入调度工具特定模型GPT 基础模型 Libraries创建和导出 API 密钥安装官方 SDKJavaScrip…

蓝桥杯省赛 棋盘 3533 二维差分+二维前缀和

传送门 0棋盘 - 蓝桥云课 const int N 2e3 10;int n,m; int a[N][N];void insert(int x11,int y11,int x22,int y22) {a[x11][y11] ;a[x11][y22 1] --;a[x22 1][y11] --;a[x22 1][y22 1] ; }void solve() {cin >> n >> m;for (int i 1;i < m;i ){int x11…

《C++Linux编程进阶:从0实现muduo 》-第6讲.C++死锁问题如何分析调试-原子操作,互斥量,条件变量的封装

重点内容 视频讲解&#xff1a;《CLinux编程进阶&#xff1a;从0实现muduo C网络框架系列》-第6讲.C死锁问题如何分析调试-原子操作,互斥量,条件变量的封装 代码改动 lesson6代码 实现&#xff1a;base/Atomic.h 实现&#xff1a;base/Mutex.h 实现&#xff1a;base/Condit…

洛谷题单1-P5708 【深基2.习2】三角形面积-python-流程图重构

题目描述 一个三角形的三边长分别是 a a a、 b b b、 c c c&#xff0c;那么它的面积为 p ( p − a ) ( p − b ) ( p − c ) \sqrt{p(p-a)(p-b)(p-c)} p(p−a)(p−b)(p−c) ​&#xff0c;其中 p 1 2 ( a b c ) p\frac{1}{2}(abc) p21​(abc)。输入这三个数字&#xff…

matplotlib标题比x,y轴字体大,明明标题字体更大?

原始代码&#xff1a; plt.xlabel(训练轮次&#xff08;Epochs&#xff09;, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗 plt.ylabel(R值, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗…

Baklib内容中台的核心优势是什么?

智能化知识管理引擎 Baklib的智能化知识管理引擎通过多源数据整合与智能分类技术&#xff0c;实现企业知识资产的自动化归集与动态更新。系统内置的语义分析算法可自动识别文档主题&#xff0c;结合自然语言处理技术生成结构化标签体系&#xff0c;大幅降低人工标注成本。针对…

Android学习总结之ContentProvider跨应用数据共享

在 Android 开发中&#xff0c;跨应用数据共享是构建开放生态的关键需求。作为四大组件之一&#xff0c;ContentProvider通过标准化接口和安全机制&#xff0c;成为实现这一需求的核心枢纽。本文将围绕其生命周期方法、核心机制、自定义实现及最佳实践展开&#xff0c;帮助开发…

计算机底层基石:原码、反码、补码、移码深度剖析

在计算机的世界里&#xff0c;所有数据最终都以二进制的形式进行存储与运算。原码、反码、补码和移码作为二进制数据的重要编码方式&#xff0c;对计算机实现高效数据处理起着关键作用。接下来&#xff0c;我们将深入剖析这几种编码。​ 一、原码​ 1.1 定义​ 原码是最简单…

Bitnode和Bitree有什么区别 为什么Bitree前多了*

Bitnode 和 Bitree 的区别在于它们的类型定义和用途&#xff1a; Bitnode: 这是一个结构体类型&#xff0c;表示二叉树中的一个节点。 它包含三个成员&#xff1a; data&#xff1a;存储节点的数据&#xff08;这里是 char 类型&#xff09;。 lchild&#xff1a;指向左子节点…

AI 时代,我们该如何写作?

当ChatGPT/DeepSeek能在几秒钟内产出一篇文章&#xff0c;而且生成能力日益精进&#xff0c;你是否也曾思考&#xff0c;我还能做什么&#xff1f; 当2024年AI开始进入人们的视野&#xff0c;我在CSDN 上的博客也悄然发生了变化&#xff0c;以前一篇文章发布后&#xff0c;阅读…

第三卷:覆舟山决战(73-108回)正反人物群像

第三卷&#xff1a;覆舟山决战&#xff08;73-108回&#xff09;正反人物群像 核心矛盾&#xff1a;寒门称帝→权力异化→历史循环 主题&#xff1a;通过人物群像展现屠龙者成魔的必然性与制度压迫的永恒性 一、正派阵营&#xff08;理想主义残余&#xff09; 1. 檀道济&…

vscode 通过Remote-ssh远程连接服务器报错 could not establish connection to ubuntu

vscode 通过Remote-ssh插件远程连接服务器报错 could not establish connection to ubuntu&#xff0c;并且出现下面的错误打印&#xff1a; [21:00:57.307] Log Level: 2 [21:00:57.350] SSH Resolver called for "ssh-remoteubuntu", attempt 1 [21:00:57.359] r…

Nginx RTMP DASH 模块分析 (ngx_rtmp_dash_module.c)

ngx_rtmp_dash_module.c实现了一个 Nginx RTMP 模块&#xff0c;主要功能是支持通过 DASH&#xff08;动态自适应流媒体&#xff09;协议进行流媒体发布。DASH&#xff08;Dynamic Adaptive Streaming over HTTP&#xff09;是一种流行的视频流协议&#xff0c;它允许根据网络状…

飞书电子表格自建应用

背景 coze官方的插件不支持更多的飞书电子表格操作&#xff0c;因为需要自建应用 飞书创建文件夹 创建应用 开发者后台 - 飞书开放平台 添加机器人 添加权限 创建群 添加刚刚创建的机器人到群里 文件夹邀请群 创建好后&#xff0c;就可以拿到id和key 参考教程&#xff1a; 创…

LangFlow系列:LangFlow快速入门示例

本文介绍了开源AI开发工具LangFlow的快速入门方法。LangFlow作为可视化框架&#xff0c;支持通过拖拽组件构建多智能体及RAG应用&#xff0c;兼容主流大语言模型与向量数据库。文章从环境搭建、核心功能到实战案例逐步讲解&#xff0c;演示如何利用其可视化界面创建智能聊天机器…

基于龙芯3A5000处理器,全国产标准6U VPX板卡解决方案

1&#xff0c;产品功能 本产品为一款高可靠性的基于龙芯3A5000处理器以及 7A2000芯片组的标准6U VPX板卡&#xff0c;具有以太网、SATA、PCIE&#xff0c;以及显示等接口&#xff0c;产品功能框图如图1所示&#xff1a; 图1 系统框图 2&#xff0c;技术指标 序号 项目 指标…

无人机进行航空数据收集对于分析道路状况非常有用-使用无人机勘测高速公路而不阻碍交通-

无人机进行航空数据收集对于分析道路状况非常有用-使用无人机勘测高速公路而不阻碍交通- 瑞士拥有1,400 多公里长的高速公路网络。这些公路将人和货物从山谷高原运送到阿尔卑斯山的最高山口。维护这些高速公路使国家得以顺利运转。高速公路维护的重要性显而易见&#xff0c;但在…