計算機視覺:神經網絡實戰之手勢識別(附代碼)

第一章:計算機視覺中圖像的基礎認知
第二章:計算機視覺:卷積神經網絡(CNN)基本概念(一)
第三章:計算機視覺:卷積神經網絡(CNN)基本概念(二)
第四章:搭建一個經典的LeNet5神經網絡(附代碼)
第五章:計算機視覺:神經網絡實戰之手勢識別(附代碼)
第六章:計算機視覺:目標檢測從簡單到容易(一)(附代碼)

一、簡介

手勢識別作為計算機視覺領域的一個重要應用,通過分析圖像或視頻序列來識別特定的手勢動作。下面以0-9手勢數字識別為案例,從數據加載、預處理到模型訓練的手勢識別全流程,基于PyTorch框架構建經典卷積神經網絡。

數字圖片的存放的目錄結構:
在這里插入圖片描述
gesture是圖片的根目錄,二級子目錄分為訓練集 train和測試集test。三級目錄就是每個數字的英文單詞作為目錄名字,這也是每張圖片的歸屬標簽,三級目錄里面存放的是具體的數字圖片,比如 one 目錄下,存放166 張不同的數字 1 手勢圖片

在這里插入圖片描述在這里插入圖片描述

二、數據讀取與預處理

2.1 數據加載策略

首先定義一個函數 load_dataset,用于動態加載一個圖像數據集的路徑和對應的標簽。適用于以文件夾結構組織的數據集,其中每個子文件夾的名字代表一個類別(或標簽),并且該子文件夾內包含了屬于這個類別的所有圖像文件。

import osdef load_dataset(root_path):"""動態加載數據集路徑:param root_path: 數據集根目錄(需包含以標簽命名的子目錄):return: 路徑列表, 標簽列表"""paths, labels = [], []for label in os.listdir(root_path):# 忽略隱藏文件或目錄if label.startswith('.'):continue# 獲取每個標簽對應的子目錄路徑label_path = os.path.join(root_path, label)# 遍歷子目錄下的所有文件for file in os.listdir(label_path):# 忽略隱藏文件或目錄if file.startswith('.'):continue# 構造完整的文件路徑file_path = os.path.join(label_path, file)# 將文件路徑添加到路徑列表中paths.append(file_path)# 將對應的標簽添加到標簽列表中labels.append(label)return paths, labels

加載數據整體思路:

  • 初始化兩個空列表 paths 和 labels,分別用于存儲圖像文件的完整路徑和對應的類別標簽。

  • 使用 os.listdir(root_path) 列出根目錄下的所有項目(文件或文件夾)。

  • 對于每一個子目錄,即類別標簽,構造其完整路徑 label_path。

  • 遍歷子目錄中的所有文件,對于每個文件構造其完整路徑,并將這些路徑添加到 paths 列表中;同時,將對應的類別標簽添加到 labels 列表中。

  • 最后返回 paths 和 labels 列表。

實際調用示例

train_root = "gesture/train"
test_root = "gesture/test"
train_paths, train_labels = load_dataset(train_root)
test_paths, test_labels = load_dataset(test_root)
  • 指定訓練集(train)和測試集(test)的根目錄分別為 gesture/traingesture/test
  • 調用load_dataset函數,分別對訓練集和測試集進行處理,獲取它們的文件路徑和標簽列表。
  • train_paths 和 train_labels 分別保存了訓練集中所有圖像的路徑及其對應的類別標簽;同樣地,test_paths 和 test_labels 保存了測試集的相關信息。

2.2 標簽編碼映射

建立標簽與數字ID的雙向映射:

labels = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
label2idx = {label:idx for idx, label in enumerate(labels)}
idx2label = {idx:label for label, idx in label2idx.items()}# 轉換示例
print(label2idx["three"])  # 輸出: 3
print(idx2label[5])        # 輸出: "five"

三、數據加載

3.1 自定義數據集類

定義一個名為 GestureDataset 的自定義數據集類,該類繼承自 PyTorch 的 torch.utils.data.Dataset 類。這個類主要用于手勢識別任務中處理圖像數據集,包括圖像的讀取、轉換以及標簽的處理。

# 引入必要的工具類
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from PIL import Image
from torchvision import transforms
import torchclass GestureDataset(Dataset):"""自定義手勢識別數據集"""def __init__(self, X, y):"""初始化"""# 圖像文件路徑列表self.X = X# 對應的標簽列表self.y = ydef __getitem__(self, idx):"""實現:- 按下標來索引一個樣本"""# 獲取圖像路徑img_path = self.X[idx]# 讀取圖像img = Image.open(fp=img_path)# 統一大小img = img.resize((32, 32))# 轉張量 [C, H, W]# 轉換為PyTorch張量(范圍[0,1])img = transforms.ToTensor()(img)# 標準化到[-1,1]范圍img = transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])(img)# 讀取標簽img_label = self.y[idx]# 標簽轉 idimg_idx = label2idx.get(img_label)# 轉張量label = torch.tensor(data=img_idx, dtype=torch.long)return img, labeldef __len__(self):"""返回該數據集的樣本個數"""return len(self.X)
  • 引入必要的工具和庫,用于創建自定義的數據集 (Dataset) 和數據加載器 (DataLoader),處理圖像 (PIL.Image),應用圖像變換 (transforms) 以及張量操作 (torch)。
  • GestureDataset 類接受兩個參數:X 和 y。
    • X 是一個包含所有圖像文件路徑的列表。
    • y 是與這些圖像對應的標簽列表。
  • 實現 __getitem__ 方法:
    • 根據給定的索引 idx,返回一個樣本(即一張圖像及其對應標簽)。
    • 首先,通過提供的索引從 X 列表中獲取圖像的路徑,并使用 Image.open() 打開圖像。
    • 使用 .resize((32, 32)) 將圖像調整為統一大小。
    • 使用 transforms.ToTensor() 將圖像轉換為PyTorch張量,并將像素值縮放到[0, 1]范圍內。
    • 使用 transforms.Normalize() 對張量進行標準化處理,使每個通道的像素值均值為0.5,標準差也為0.5,從而將像素值映射到[-1, 1]范圍內。
    • 獲取該圖像的標簽 img_label,并將其轉換為整數索引 img_idx。
    • 最后,將標簽轉換為PyTorch張量類型,并返回圖像張量和標簽張量。
  • 實現 __len__ 方法:此方法返回數據集中樣本的數量,即圖像路徑列表 X 的長度。

為什么要將圖像轉換為PyTorch張量?

從圖像到張量:深度學習模型通常接受張量作為輸入,而不是原始的圖像格式(如PIL Image或NumPy數組)。因此,需要將讀取的圖像轉換為張量格式。

為什么要將像素值縮放到[0, 1]范圍內?

數值范圍調整:原始圖像的像素值通常位于[0, 255]范圍內(對于8位圖像),這意味著每個像素的值是一個介于0到255之間的整數。然而,大多數現代神經網絡期望輸入數據的數值范圍在[0, 1]或[-1, 1]之間。通過使用ToTensor(),每個像素值除以255,從而將其縮放到[0, 1]范圍。

為什么要對張量進行標準化處理?

transforms.Normalize(mean, std)歸一化是另一個重要的預處理步驟,它涉及到對數據進行均值和標準差的標準化處理。這一步驟有助于加速模型的收斂過程,并可能提高模型的性能。

  • 加快收斂速度:通過對輸入數據進行標準化處理,可以使得損失函數表面更加平滑,從而幫助梯度下降算法更快地找到最優解。這是因為當輸入特征具有相似的尺度時,優化算法能夠更有效地更新權重。
  • 提升模型表現:標準化后的輸入可以使不同特征(在這個場景中指的是圖像的不同通道)具有相同的尺度,避免某些特征因為尺度過大或過小而對模型的學習產生不成比例的影響。這對于深層網絡尤為重要,因為它有助于防止梯度消失或爆炸的問題。
  • 具體參數說明:
    mean=[0.5, 0.5, 0.5] 和 std=[0.5, 0.5, 0.5] 分別表示三個通道(通常是RGB圖像的紅、綠、藍通道)的平均值和標準差。這些值用于將輸入張量的每個元素標準化到接近正態分布的形式,即均值為0,方差為1。具體來說,這里的設置會將像素值從[0, 1]范圍映射到[-1, 1]范圍。
  • 計算公式:對于每個像素值 x,經過標準化后的新值為 (x - mean) / std。根據上面的例子,如果一個像素值原來是0.75(已經通過ToTensor()轉換到了[0, 1]范圍),那么標準化后的值將是 (0.75 - 0.5) / 0.5 = 0.5。

transforms.ToTensor()transforms.Normalize() 這兩個操作是為了確保輸入到神經網絡的數據具有一致的尺度和分布,這樣不僅有助于提高模型訓練的效率,還可能改善最終模型的表現。這是因為在良好的初始化條件下,模型能夠更穩定和高效地學習輸入數據中的模式。

3.2 數據加載器配置

使用自定義的數據集類 GestureDataset 來創建訓練集和測試集的數據加載器 DataLoader,以便于后續的模型訓練和評估。

# 訓練集加載器
train_dataset = GestureDataset(X=train_paths, y=train_labels)
train_dataloader = DataLoader(dataset=train_dataset, shuffle=True, batch_size=16)
# 測試集加載器
test_dataset = GestureDataset(X=test_paths, y=test_labels)
test_dataloader = DataLoader(dataset=test_dataset, shuffle=False, batch_size=32)# 測試
for X, y in test_dataloader:print(X.shape)print(y.shape)break
  • GestureDataset(X=train_paths, y=train_labels):
    • 這里實例化了 GestureDataset 類,傳入兩個參數:X=train_paths 和 y=train_labels。
    • train_paths 是一個包含所有訓練圖像路徑的列表。
    • train_labels 是與這些圖像對應的標簽列表。
    • 通過這種方式,train_dataset 對象可以訪問每個樣本(圖像及其標簽),并對其進行必要的預處理(如調整大小、轉換為張量等)。
  • DataLoader(dataset=train_dataset, shuffle=True, batch_size=16):
    • 使用 PyTorch 的 DataLoader 創建了一個數據加載器 train_dataloader。
    • dataset=train_dataset: 指定了要加載的數據集對象。
    • shuffle=True: 表示在每個epoch開始時,將數據集中的樣本順序打亂。這對于訓練集來說非常重要,因為它可以幫助模型更好地泛化,避免模型學習到數據順序的相關性。對于測試集,通常不需要打亂順序,因為我們更關注模型在未見過的數據上的表現,而不是訓練過程中的隨機性。
    • batch_size=16: 設置了每個批次的大小為16,即每次迭代時從數據集中取出16個樣本進行訓練。選擇合適的批量大小對于訓練效率和模型性能都很關鍵,但也需要考慮內存限制。

四、卷積神經網絡構建

4.1 網絡架構設計

基于改進版LeNet-5卷積神經網絡實現,LeNet-5網絡在上一篇《搭建一個經典的LeNet5神經網絡》中有詳細介紹。

定義一個名為 GestureNet 的神經網絡類,該類繼承自 PyTorch 的 nn.Module。這個網絡設計用于手勢識別任務。

import torch.nn as nnclass GestureNet(nn.Module):# 定義了 GestureNet 類并初始化了父類 nn.Module。# 參數 in_channels 默認設置為3,通常代表輸入圖像的通道數(如RGB圖像)。# num_classes 參數指定了模型最終輸出的類別數量,默認設置為10,適用于一個包含10個類別的分類任務。def __init__(self, in_channels=3, num_classes=10):super().__init__()# 特征提取器self.features = nn.Sequential(nn.Conv2d(in_channels, 6, kernel_size=5),nn.ReLU(inplace=True),nn.MaxPool2d(2, 2),nn.Conv2d(6, 16, kernel_size=5),nn.ReLU(inplace=True),nn.MaxPool2d(2, 2))# 分類器self.classifier = nn.Sequential(nn.Flatten(),nn.Linear(16*5*5, 120),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(120, 84),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(84, num_classes))def forward(self, x):x = self.features(x)x = self.classifier(x)return x

代碼解釋:

  • self.features = nn.Sequential(...): 功能:這部分負責從輸入圖像中提取有用的特征。
    • 第一層是一個卷積層 (nn.Conv2d),它將輸入通道數轉換為6個輸出通道,使用5x5大小的卷積核。
    • 接著是一個ReLU激活函數 (nn.ReLU),這里使用了 inplace=True 來節省內存,直接在原地修改輸入張量而不是創建新的張量。
    • 然后是最大池化層 (nn.MaxPool2d),它使用2x2的窗口大小進行下采樣,這有助于減少數據維度同時保留主要特征。
    • 接下來的第二層卷積層 (nn.Conv2d) 將通道數從6增加到16,同樣使用5x5的卷積核。
    • 最后再經過ReLU激活函數和最大池化層處理。
  • self.classifier = nn.Sequential(...):功能:這部分將特征提取器提取的特征映射到具體的類別上,完成分類任務。
    • 首先通過 nn.Flatten() 層將多維的特征圖展平成一維向量。假設輸入圖像大小為32x32,經過兩次池化操作后,特征圖大小變為8x8(考慮邊緣丟失),再乘以16個通道,因此這里的 16 x 5 x 5 可能需要根據實際的輸入尺寸調整為正確的值(可能是 16 x 8 x 8 或者其他值,取決于你的輸入尺寸和網絡的具體配置)。
    • 然后是一個全連接層 (nn.Linear),將展平后的特征映射到120維的空間。
    • 使用ReLU激活函數和Dropout (nn.Dropout),后者用于防止過擬合,此處的丟棄概率為0.5。
    • 接下來是另一個全連接層,將特征維度減少到84。
    • 再次應用ReLU激活函數和Dropout。
    • 最終,最后一個全連接層將特征映射到指定的類別數量 (num_classes)。
  • forward(self, x):這個方法定義了數據如何從前向后流經網絡。
    • 輸入 x 首先通過特征提取器 self.features 提取特征。
    • 然后這些特征被送入分類器 self.classifier 進行分類處理。
    • 最終返回分類結果。

上面是構建了一個簡單的卷積神經網絡用于手勢識別,包括特征提取和分類兩個階段,并且在分類階段引入了Dropout來提高模型的泛化能力。

4.2 網絡維度變化

輸入圖像32x32的完整計算過程:

輸出尺寸參數計算
Input3×32×32-
Conv1(5x5)6×28×28(5×5×3+1)×6 = 456
MaxPool16×14×14-
Conv2(5x5)16×10×10(5×5×6+1)×16 = 2416
MaxPool216×5×5-
Flatten400-
FC1120(400+1)×120 = 48120
FC284(120+1)×84 = 10164
Output10(84+1)×10 = 850

總參數量: 456 + 2416 + 48120 + 10164 + 850 = 61,706

五、模型訓練與優化

5.1 訓練配置

設置一個用于訓練神經網絡的基本環境,包括設備選擇、模型實例化、優化器配置、損失函數定義以及學習率調度器的配置。

# 這行代碼檢查系統是否支持CUDA(即是否有可用的NVIDIA GPU),如果有,則將device變量設置為 "cuda",否則設置為 "cpu"。
# 確保模型的參數和運算都在選定的設備上進行,以充分利用硬件資源。
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = GestureNet().to(device)
# 使用Adam優化算法來更新模型參數。Adam是一種常用的自適應學習率優化算法,適用于大多數深度學習任務。
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-4)
# 定義交叉熵損失函數,這是分類問題中最常用的損失函數之一,特別適合于多分類任務。
loss_fn = nn.CrossEntropyLoss()
# 配置了一個學習率調度器 ReduceLROnPlateau,它可以根據某個監控指標的表現動態調整學習率。
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=3)

參數解釋:

  • model.parameters():提供模型的所有可學習參數給優化器。
  • lr=0.001:設定初始學習率為0.001。
  • weight_decay=1e-4:加入L2正則化,防止過擬合。這里的權重衰減系數設為0.0001。
  • optimizer:要調整的學習率所屬的優化器。
  • 'min':模式設定為最小化監控指標(如驗證損失)。如果監控指標停止下降,就會觸發學習率的降低。
  • patience=3:容忍度設為3,意味著如果連續3個epoch監控指標都沒有改善,就會降低學習率。

利用Adam優化器和交叉熵損失函數進行有效的訓練,并通過學習率調度器根據訓練情況自動調整學習率,從而可能提高模型的最終性能。

5.2 訓練循環實現

定義一個名為 train_epoch 的函數,用于執行一個epoch的模型訓練。通過遍歷提供的數據加載器(loader),對模型進行前向傳播、計算損失、反向傳播以及參數更新。

def train_epoch(model, loader, optimizer, loss_fn):# 設置模型為訓練模式model.train()# 初始化變量 total_loss 用于累積整個epoch中的所有批次損失。這有助于最后計算平均損失。total_loss = 0# 使用 for 循環遍歷數據加載器 loader 提供的所有批次數據 (inputs, labels)。for inputs, labels in loader:# 將輸入數據和標簽都移動到指定的設備(CPU或GPU)上,以便與模型保持一致。inputs, labels = inputs.to(device), labels.to(device)"""清空梯度:optimizer.zero_grad() 清除之前的梯度信息,因為PyTorch默認會累加梯度。前向傳播:outputs = model(inputs) 執行一次前向傳播,獲取模型的預測輸出。計算損失:loss = loss_fn(outputs, labels) 根據預測輸出和真實標簽計算損失。反向傳播:loss.backward() 執行反向傳播,計算每個參數的梯度。更新權重:optimizer.step() 使用計算出的梯度來更新模型的權重。"""optimizer.zero_grad()outputs = model(inputs)loss = loss_fn(outputs, labels)loss.backward()optimizer.step()# loss.item() 獲取當前批次的標量損失值。# inputs.size(0) 獲取當前批次的樣本數量。# 將當前批次的損失乘以批次大小并累加到 total_loss 中,這樣做是為了計算整個數據集上的平均損失。total_loss += loss.item() * inputs.size(0)# 返回整個epoch的平均損失,即總損失除以數據集中樣本的數量。return total_loss / len(loader.dataset)

該函數接受四個參數:

  • model: 要訓練的神經網絡模型。
  • loader: 數據加載器,提供批次的數據和標簽。
  • optimizer: 優化器,用于更新模型的權重。
  • loss_fn: 損失函數,用于評估模型預測值與真實標簽之間的誤差。

定義一個名為 validate 的函數,用于在驗證集或測試集上評估模型的性能。通過計算平均損失和分類準確率來衡量模型的表現。

def validate(model, loader, loss_fn):# 設置模型為推理模式model.eval()# total_loss: 用于累積整個數據集上的所有批次損失。total_loss = 0# correct: 記錄預測正確的樣本數,用于計算準確率。correct = 0# 使用 torch.no_grad() 上下文管理器,在這個塊內的所有操作都不會被追蹤用于自動求導。# 這對于推理階段非常有用,因為它減少了內存消耗并加快了計算速度,因為不需要計算梯度。with torch.no_grad():# 遍歷數據加載器提供的所有批次數據 (inputs, labels)。for inputs, labels in loader:# 將輸入數據和標簽都移動到指定的設備(CPU或GPU)上,以便與模型保持一致。inputs, labels = inputs.to(device), labels.to(device)# 執行一次前向傳播,獲取模型的預測輸出 outputs。outputs = model(inputs)# 根據預測輸出和真實標簽計算損失 loss。loss = loss_fn(outputs, labels)# 將當前批次的損失乘以批次大小并累加到 total_loss 中,這樣做是為了最后計算整個數據集上的平均損失。total_loss += loss.item() * inputs.size(0)# 獲取每個輸入的最大得分對應的類別索引(即模型的預測類別)。_, predicted = torch.max(outputs, 1)# 比較預測類別 predicted 和真實標簽 labels,統計預測正確的樣本數,并將其累加到 correct 變量中。correct += (predicted == labels).sum().item()# 計算整個數據集上的平均損失:total_loss 除以數據集中的樣本總數 len(loader.dataset)。# 計算分類準確率:正確預測的樣本數 correct 除以數據集中的樣本總數 len(loader.dataset)。# 最終返回這兩個指標作為函數的結果,分別是平均損失和準確率。return total_loss / len(loader.dataset), correct / len(loader.dataset)

該函數接受三個參數:

  • model: 要評估的神經網絡模型。
  • loader: 數據加載器,提供批次的數據和標簽(通常為驗證集或測試集)。
  • loss_fn: 損失函數,用于評估模型預測值與真實標簽之間的誤差。

validate方法評估模型在驗證集或測試集上的表現,通過計算平均損失和準確率來量化模型的性能。這種評估對于監控模型的學習進度、調優超參數以及決定何時停止訓練非常重要。使用 torch.no_grad() 和 model.eval() 確保了在推理過程中不會進行不必要的梯度計算和參數更新,從而提高了效率和準確性。

5.3 完整訓練流程

這段代碼實現一個簡單的訓練循環,用于在一個數據集上訓練神經網絡模型,并在每個epoch后使用驗證集評估模型性能。同時保存最佳模型。

# 初始化一個變量 best_acc,用于記錄目前為止在驗證集上獲得的最佳準確率。初始值設為0。
best_acc = 0
# 循環執行總共50個epoch的訓練。你可以根據需要調整這個數字。
for epoch in range(50):# 執行一個epoch的訓練和驗證train_loss = train_epoch(model, train_dataloader, optimizer, loss_fn)val_loss, val_acc = validate(model, test_dataloader, loss_fn)# 學習率調度scheduler.step(val_loss)print(f"Epoch {epoch+1:02d}: "f"Train Loss: {train_loss:.4f} | "f"Val Loss: {val_loss:.4f} | "f"Accuracy: {val_acc:.2%}")# 保存最佳模型參數if val_acc > best_acc:best_acc = val_acctorch.save(model.state_dict(), "best_model.pth")

輸出內容:

Epoch 01: Train Loss: 2.2930 | Val Loss: 2.1288 | Accuracy: 36.00%
Epoch 02: Train Loss: 1.6239 | Val Loss: 0.9157 | Accuracy: 73.75%
Epoch 03: Train Loss: 1.0185 | Val Loss: 0.5172 | Accuracy: 86.00%
Epoch 04: Train Loss: 0.7497 | Val Loss: 0.3426 | Accuracy: 88.25%
Epoch 05: Train Loss: 0.5869 | Val Loss: 0.2387 | Accuracy: 93.00%
Epoch 06: Train Loss: 0.4685 | Val Loss: 0.2408 | Accuracy: 91.75%
Epoch 07: Train Loss: 0.3958 | Val Loss: 0.1606 | Accuracy: 94.75%
Epoch 08: Train Loss: 0.3526 | Val Loss: 0.1398 | Accuracy: 96.25%
Epoch 09: Train Loss: 0.2660 | Val Loss: 0.1457 | Accuracy: 95.00%
Epoch 10: Train Loss: 0.2468 | Val Loss: 0.1102 | Accuracy: 96.25%
Epoch 11: Train Loss: 0.2453 | Val Loss: 0.1406 | Accuracy: 94.75%
Epoch 12: Train Loss: 0.2144 | Val Loss: 0.1584 | Accuracy: 93.75%
Epoch 13: Train Loss: 0.2132 | Val Loss: 0.1025 | Accuracy: 96.00%
Epoch 14: Train Loss: 0.1924 | Val Loss: 0.0857 | Accuracy: 97.75%
Epoch 15: Train Loss: 0.1701 | Val Loss: 0.1847 | Accuracy: 93.50%
Epoch 16: Train Loss: 0.1622 | Val Loss: 0.0780 | Accuracy: 97.25%
Epoch 17: Train Loss: 0.1204 | Val Loss: 0.1193 | Accuracy: 95.00%
Epoch 18: Train Loss: 0.1181 | Val Loss: 0.0955 | Accuracy: 96.75%
Epoch 19: Train Loss: 0.1312 | Val Loss: 0.0799 | Accuracy: 97.75%
Epoch 20: Train Loss: 0.1139 | Val Loss: 0.1064 | Accuracy: 96.50%
Epoch 21: Train Loss: 0.0857 | Val Loss: 0.0972 | Accuracy: 96.75%
Epoch 22: Train Loss: 0.0808 | Val Loss: 0.0980 | Accuracy: 97.00%
Epoch 23: Train Loss: 0.0966 | Val Loss: 0.0870 | Accuracy: 96.75%
Epoch 24: Train Loss: 0.0744 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 25: Train Loss: 0.0722 | Val Loss: 0.0854 | Accuracy: 96.50%
Epoch 26: Train Loss: 0.0947 | Val Loss: 0.0844 | Accuracy: 96.50%
Epoch 27: Train Loss: 0.0698 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 28: Train Loss: 0.0873 | Val Loss: 0.0858 | Accuracy: 96.50%
Epoch 29: Train Loss: 0.0797 | Val Loss: 0.0857 | Accuracy: 96.50%
Epoch 30: Train Loss: 0.0622 | Val Loss: 0.0857 | Accuracy: 96.50%
Epoch 31: Train Loss: 0.0728 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 32: Train Loss: 0.0841 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 33: Train Loss: 0.0644 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 34: Train Loss: 0.0755 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 35: Train Loss: 0.0797 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 36: Train Loss: 0.0677 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 37: Train Loss: 0.0667 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 38: Train Loss: 0.0902 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 39: Train Loss: 0.0715 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 40: Train Loss: 0.0727 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 41: Train Loss: 0.0750 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 42: Train Loss: 0.0813 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 43: Train Loss: 0.0780 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 44: Train Loss: 0.0847 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 45: Train Loss: 0.0767 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 46: Train Loss: 0.0732 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 47: Train Loss: 0.0634 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 48: Train Loss: 0.0750 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 49: Train Loss: 0.0665 | Val Loss: 0.0856 | Accuracy: 96.50%
Epoch 50: Train Loss: 0.0736 | Val Loss: 0.0856 | Accuracy: 96.50%

訓練階段:調用 train_epoch 函數對模型進行一個epoch的訓練,并返回該epoch的平均訓練損失 train_loss。

驗證階段:調用 validate 函數評估模型在驗證集上的表現,返回驗證損失 val_loss 和分類準確率 val_acc。注意這里使用的是 test_loader,通常應使用 val_loader 來代表驗證集加載器,以避免直接在測試集上進行驗證。

scheduler.step(val_loss)根據驗證集上的損失 val_loss 調整學習率。這里使用的是 ReduceLROnPlateau 調度器,當監測的指標(這里是驗證損失)停止改善時,會自動降低學習率,幫助模型跳出局部最優解或加速收斂。

打印出當前epoch的信息,包括:

  • 當前是第幾個epoch ({epoch+1:02d} 確保輸出兩位數,例如01, 02…50)。
  • 訓練損失 train_loss,保留四位小數。
  • 驗證損失 val_loss,保留四位小數。
  • 分類準確率 val_acc,以百分比形式顯示,并保留兩位小數。

六、圖像預測

定義一個名為 predict 的函數,用于對單個圖像進行預測。

加載一個預訓練的模型,對輸入圖像進行必要的預處理,然后使用該模型預測圖像的類別,并返回預測的標簽。

predict函數接受兩個參數:

  • image_path: 輸入圖像的路徑。
  • model_path: 預訓練模型的路徑,默認為 “best_model.pth”。
def predict(image_path, model_path="best_model.pth"):# 加載模型model = GestureNet()# 加載保存的最佳模型參數(權重)到模型中。model.load_state_dict(torch.load(model_path))# 將模型設置為評估模式,確保在推理時正確處理如 Dropout 和 Batch Normalization 等層的行為。model.eval()# 打開指定路徑的圖像,并通過 .convert('RGB') 確保其格式為 RGB。image = Image.open(image_path).convert('RGB')# 創建一系列圖像變換操作,包括調整大小、轉換為張量以及標準化處理。transform = transforms.Compose([transforms.Resize((32, 32)), # 將圖像調整為 32x32 像素大小。transforms.ToTensor(), # 將圖像轉換為 PyTorch 張量,并將像素值從 [0, 255] 縮放到 [0, 1]。transforms.Normalize([0.5]*3, [0.5]*3) # 對每個通道應用均值和標準差為 0.5 的標準化處理,使數據分布接近正態分布。])# 通過 transform(image) 應用上述變換,# 并使用 .unsqueeze(0) 在維度0處增加一個新的維度,以適應模型輸入的要求(即模擬一個批次的輸入)。# 這一步是因為大多數深度學習模型期望輸入是一個四維張量(批次大小,通道數,高度,寬度),即使只有一個樣本也需要指定批次大小。tensor_img = transform(image).unsqueeze(0)# 禁用梯度計算:使用 torch.no_grad() 上下文管理器,在推理過程中禁用梯度計算,減少內存占用并加快計算速度。with torch.no_grad():# 前向傳播:執行一次前向傳播,獲取模型輸出 output。output = model(tensor_img)# 獲取預測結果:使用 torch.max(output, 1) 獲取輸出中最大值的索引(即預測的類別),_ 用來忽略最大值本身,只保留索引。_, predicted = torch.max(output, 1)# 返回預測標簽:通過 idx2label[predicted.item()] 將預測的類別索引轉換為對應的標簽名稱。return idx2label[predicted.item()]# 使用示例
print(predict("../gesture/train/four/IMG_1122.JPG"))  # 輸出: "four"

七、 訓練模式和推理模式

模型為訓練模式和推理模式,有什么區別?

在深度學習中,模型通常有兩種運行模式:訓練模式(Training Mode)推理模式(Inference Mode 或 Evaluation Mode)。這兩種模式在行為上有一些關鍵的區別,主要是因為某些層或操作在訓練和推理時需要不同的處理方式。以下是它們之間的主要區別:

7.1 訓練模式

  1. Dropout 層

    • 在訓練模式下,Dropout 層會隨機“丟棄”一些神經元(即設置其輸出為零),以防止過擬合并增強模型的泛化能力。
    • 這種機制有助于避免模型對特定特征過度依賴。
  2. Batch Normalization

    • 在訓練過程中,Batch Normalization 會使用當前批次的數據來計算均值和方差,并對輸入進行歸一化。
    • 同時,它還會更新運行時的平均均值和方差,這些值會在推理階段使用。
  3. 梯度計算與參數更新

    • 在訓練模式下,模型不僅執行前向傳播,還會通過反向傳播計算損失函數關于模型參數的梯度,并根據優化算法更新這些參數。
  4. 數據增強

    • 在訓練模式下,通常會對輸入數據應用數據增強技術(如隨機裁剪、翻轉等),以增加數據集的多樣性,從而提高模型的泛化能力。

7.2 推理模式

  1. Dropout 層

    • 在推理模式下,Dropout 層不會丟棄任何神經元;相反,所有神經元都會參與計算,但它們的輸出會被縮放(通常是乘以保留概率)。這是因為我們希望模型能夠利用全部的信息來做預測。
  2. Batch Normalization

    • 在推理模式下,Batch Normalization 使用的是在整個訓練過程中累積得到的運行時均值和方差來進行歸一化,而不是當前批次的統計數據。
    • 這樣做的目的是為了保證推理時的一致性,因為推理時可能每次只處理少量樣本甚至單個樣本。
  3. 梯度計算與參數更新

    • 在推理模式下,不涉及梯度計算和參數更新。模型只是簡單地執行前向傳播以生成預測結果。
  4. 數據增強

    • 在推理模式下,通常不會應用數據增強技術,因為我們希望基于原始輸入數據做出最準確的預測。

7.3 如何切換模式

  • 在 PyTorch 中,可以通過調用 model.train() 將模型設置為訓練模式,通過調用 model.eval() 將模型設置為推理模式(也稱為評估模式)。

  • 切換到相應模式非常重要,特別是在驗證集或測試集上評估模型性能時,確保模型處于 eval 模式可以避免不必要的 Dropout 或 Batch Normalization 行為影響結果。

理解這兩種模式的區別對于正確地訓練和評估深度學習模型至關重要,尤其是在涉及到 Dropout、Batch Normalization 等技術的應用場景中。正確設置模型的工作模式可以顯著影響最終模型的性能和穩定性。

八、結語

以上展現手勢識別系統的構建過程,涵蓋數據管理、模型設計、訓練優化等關鍵環節。可根據實際需求調整網絡深度、數據增強策略等參數。


計算機視覺:計算機視覺之手勢識別圖片

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/71391.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/71391.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/71391.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

win11安裝wsl報錯:無法解析服務器的名稱或地址(啟用wsl2)

1. 啟用wsl報錯如下 # 查看可安裝的 wsl --install wsl --list --online此原因是因為沒有開啟DNS的原因,所以需要我們手動開啟DNS。 2. 按照如下配置即可 Google的DNS(8.8.8.8和8.8.4.4) 全國通用DNS地址 (114.114.114.114) 3. 運行以下命令來重啟 WSL…

開源模型應用落地-DeepSeek-R1-Distill-Qwen-7B-LoRA微調-LLaMA-Factory-單機單卡-V100(一)

一、前言 如今,大語言模型領域熱鬧非凡,各種模型不斷涌現。DeepSeek-R1-Distill-Qwen-7B 模型憑借其出色的效果和性能,吸引了眾多開發者的目光。而 LLaMa-Factory 作為強大的微調工具,能讓模型更好地滿足個性化需求。 在本篇中&am…

k8s-對接NFS存儲

一、前提條件 1、NFS_Server 部署好了。 2、網絡可達。 二、 使用方式 1、CSI **項目地址 https://github.com/kubernetes-csi/csi-driver-nfs#readme Install NFS CSI driver v4.10.0 version on a kubernetes cluster If you have already installed Helm, you can a…

【動態路由】系統Web URL資源整合系列(后端技術實現)【nodejs實現】

需求說明 軟件功能需求:反向代理功能(描述:apollo、eureka控、apisix、sentinel、普米、kibana、timetask、grafana、hbase、skywalking-ui、pinpoint、cmak界面、kafka-map、nacos、gateway、elasticsearch、 oa-portal 業務應用等多個web資…

Git 修改或刪除某次提交信息

Git 修改或刪除某次提交信息 情況一:未推送到遠程倉庫修改提交信息刪除提交信息(替換為空信息)修改歷史提交信息刪除歷史提交信息 情況二:已推送到遠程倉庫修改最新提交信息并推送到遠程倉庫修改歷史提交信息并推送到遠程倉庫 情況…

DeepSeek崛起:如何在云端快速部署你的專屬AI助手

在2025年春節的科技盛宴上,DeepSeek因其在AI領域的卓越表現成為焦點,其開源的推理模型DeepSeek-R1擅長處理多種復雜任務,支持多語言處理,并通過搜索引擎獲取實時信息。DeepSeek因其先進的自然語言處理技術、廣泛的知識庫和高性價比…

DeepSeek部署到本地(解決ollama模型下載失敗問題)

一、下載ollama軟件安裝 1、下載ollama軟件 Ollama 下載完成后可以直接進行安裝(外網,速度可能會有點慢) 2、修改安裝目錄 進去下載的目錄,使用cmd打開終端輸入OllamaSetup.exe /DIRE:\MySoftware\Ollama 輸入完成后會自動打開…

GPT1 大模型

GPT1 大模型 模型架構訓練過程 GPT-1 : 采用傳統的語言模型方法進行預訓練,擅長處理自然語言生成任務(NLG)OpenAI 在 2018 年 6 月推出 1.17 億個參數的 GPT-1 (Generative Pre-training , 生成式預訓練) 數據集 : 數據來源 : BooksCorpus…

?1.HTML、CSS 和 JavaScript 是什么?

?? HTML、CSS 和 JavaScript 是構建網頁的三大核心技術,它們相互協作,讓網頁呈現出豐富的內容、精美的樣式和交互功能。以下為你詳細介紹: 🦋1. HTML(超文本標記語言) 定義:HTML 是一種用于描…

x86平臺基于Qt+opengl優化ffmpeg軟解碼1080P視頻渲染效率

一般的在arm嵌入式平臺,大多數板子都要硬解碼硬件渲染的框架,使用即可。 在x86下比較麻煩了。 優化的思路一共有以下幾個方面, 1. 軟解碼變成硬解碼 2. 將YUV轉QImage的操作轉移到GPU 3. QWidget渲染QImage變成opengGL渲染AVFrame 這三點…

ocr智能票據識別系統|自動化票據識別集成方案

在企業日常運營中,對大量票據實現數字化管理是一項耗時且容易出錯的任務。隨著技術的進步,OCR(光學字符識別)智能票據識別系統的出現為企業提供了一個高效、準確的解決方案,不僅簡化了財務流程,還大幅提升了…

docker批量pull/save/load/tag/push鏡像shell腳本

目錄 注意: 腳本內容 執行效果 注意: 以下腳本為shell腳本通過docker/nerdctl進行鏡像獨立打包鏡像的相關操作腳本內倉庫信息和鏡像存取路徑需自行更改需自行創建images.txt并填寫值,并且與腳本位于同級目錄下 [rootmaster01 sulibao]# l…

利用Java爬蟲精準獲取商品銷量詳情:實戰案例指南

在電商領域,商品銷量數據是衡量產品受歡迎程度和市場表現的關鍵指標。精準獲取商品銷量詳情不僅能幫助商家優化產品策略,還能為市場研究和數據分析提供豐富的數據資源。本文將詳細介紹如何利用Java爬蟲技術精準獲取商品銷量詳情,并分享關鍵技…

30 款 Windows 和 Mac 下的復制粘貼軟件對比

在日常電腦操作中,復制粘貼是極為高頻的操作,一款好用的復制粘貼軟件能極大提升工作效率。以下為你詳細介紹 30 款 Windows 和 Mac 下的復制粘貼軟件,并對比它們的優缺點,同時附上官網下載地址,方便大家獲取軟件。 Pa…

【Linux】Linux 文件系統——有關 inode 不足的案例

??大家好,我是練小杰,今天周二了,明天星期三,還有三天就是星期五了,堅持住啊各位!!!😆 本文是對之前Linux文件權限中的inode號進行實例討論,看到博客有錯誤…

WPF快速創建DeepSeek本地自己的客戶端-基礎思路版本

開發工具:VS 2015 開發環境:.Net 4.0 使用技術:WPF 本篇文章內容: 本地部署DeepSeek以后一般使用網頁工具(如Chatbox)或者DOS窗口與其對話。本篇文章使用WPF創建一個基礎版的對話工具。 一、搭建本地DeepS…

VSCode本地python包“無法解析導入”

問題現象 在使用 VSCode 編寫 Python 代碼時,雖然程序能正常運行,但遇到“無法解析導入”的問題,導致代碼無法高亮。 解決方法 配置 python.autoComplete.extraPaths 打開 VSCode 設置(CtrlShiftP -> Preferences: Open Wo…

目標檢測IoU閾值全解析:YOLO/DETR模型中的精度-召回率博弈與工程實踐指南

一、技術原理與數學本質 IoU計算公式: IoU \frac{Area\ of\ Overlap}{Area\ of\ Union} \frac{A ∩ B}{A ∪ B}閾值選擇悖論: 高閾值(0.6-0.75):減少誤檢(FP↓)但增加漏檢(FN↑…

藍橋杯備考:二分算法之木材加工

P2440 木材加工 - 洛谷 這種題我們就是把答案枚舉出來,然后對答案進行二分,然后再進行判斷 比如我們這道題,我們枚舉切割的長度,然后由于切割長度越長切割段數越少 切割長度越短,切割段數越多的性質,我們…

Mongodb數據管理

Mongodb數據管理 1.登錄數據庫,查看默認的庫 [rootdb51~]# mongo> show databases; admin 0.000GB config 0.000GB local 0.000GB> use admin switched to db admin > show tables system.version > admin庫:admin 是 MongoDB 的管理…