【機器學習】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.pswp.cn/web/73854.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73854.shtml
英文地址,請注明出處:http://en.pswp.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;但在…