Python 訓練營打卡 Day 40-訓練和測試的規范寫法

一.單通道圖片的規范寫法

以之前的MNIST數據集為例
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader , Dataset # DataLoader 是 PyTorch 中用于加載數據的工具
from torchvision import datasets, transforms # torchvision 是一個用于計算機視覺的庫,datasets 和 transforms 是其中的模塊
import matplotlib.pyplot as plt
import warnings
# 忽略警告信息
warnings.filterwarnings("ignore")
# 設置隨機種子,確保結果可復現
torch.manual_seed(42)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用設備: {device}")# 1. 數據預處理
transform = transforms.Compose([transforms.ToTensor(),  # 轉換為張量并歸一化到[0,1]transforms.Normalize((0.1307,), (0.3081,))  # MNIST數據集的均值和標準差
])# 2. 加載MNIST數據集
train_dataset = datasets.MNIST(root='./data',train=True,download=True,transform=transform
)test_dataset = datasets.MNIST(root='./data',train=False,transform=transform
)# 3. 創建數據加載器
batch_size = 64  # 每批處理64個樣本
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 4. 定義模型、損失函數和優化器
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten()  # 將28x28的圖像展平為784維向量self.layer1 = nn.Linear(784, 128)  # 第一層:784個輸入,128個神經元self.relu = nn.ReLU()  # 激活函數self.layer2 = nn.Linear(128, 10)  # 第二層:128個輸入,10個輸出(對應10個數字類別)def forward(self, x):x = self.flatten(x)  # 展平圖像x = self.layer1(x)   # 第一層線性變換x = self.relu(x)     # 應用ReLU激活函數x = self.layer2(x)   # 第二層線性變換,輸出logitsreturn x# 初始化模型
model = MLP()
model = model.to(device)  # 將模型移至GPU(如果可用)# from torchsummary import summary  # 導入torchsummary庫
# print("\n模型結構信息:")
# summary(model, input_size=(1, 28, 28))  # 輸入尺寸為MNIST圖像尺寸criterion = nn.CrossEntropyLoss()  # 交叉熵損失函數,適用于多分類問題
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam優化器# 5. 訓練模型(記錄每個 iteration 的損失)
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):model.train()  # 設置為訓練模式# 新增:記錄每個 iteration 的損失all_iter_losses = []  # 存儲所有 batch 的損失iter_indices = []     # 存儲 iteration 序號(從1開始)for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):# enumerate() 是 Python 內置函數,用于遍歷可迭代對象(如列表、元組)并同時獲取索引和值。# batch_idx:當前批次的索引(從 0 開始)# (data, target):當前批次的樣本數據和對應的標簽,是一個元組,這是因為dataloader內置的getitem方法返回的是一個元組,包含數據和標簽。# 只需要記住這種固定寫法即可data, target = data.to(device), target.to(device)  # 移至GPU(如果可用)optimizer.zero_grad()  # 梯度清零output = model(data)  # 前向傳播loss = criterion(output, target)  # 計算損失loss.backward()  # 反向傳播optimizer.step()  # 更新參數# 記錄當前 iteration 的損失(注意:這里直接使用單 batch 損失,而非累加平均)iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1)  # iteration 序號從1開始# 統計準確率和損失running_loss += loss.item() #將loss轉化為標量值并且累加到running_loss中,計算總損失_, predicted = output.max(1) # output:是模型的輸出(logits),形狀為 [batch_size, 10](MNIST 有 10 個類別)# 獲取預測結果,max(1) 返回每行(即每個樣本)的最大值和對應的索引,這里我們只需要索引total += target.size(0) # target.size(0) 返回當前批次的樣本數量,即 batch_size,累加所有批次的樣本數,最終等于訓練集的總樣本數correct += predicted.eq(target).sum().item() # 返回一個布爾張量,表示預測是否正確,sum() 計算正確預測的數量,item() 將結果轉換為 Python 數字# 每100個批次打印一次訓練信息(可選:同時打印單 batch 損失)if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 單Batch損失: {iter_loss:.4f} | 累計平均損失: {running_loss/(batch_idx+1):.4f}')# 測試、打印 epoch 結果epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totalepoch_test_loss, epoch_test_acc = test(model, test_loader, criterion, device)print(f'Epoch {epoch+1}/{epochs} 完成 | 訓練準確率: {epoch_train_acc:.2f}% | 測試準確率: {epoch_test_acc:.2f}%')# 繪制所有 iteration 的損失曲線plot_iter_losses(all_iter_losses, iter_indices)# 保留原 epoch 級曲線(可選)# plot_metrics(train_losses, test_losses, train_accuracies, test_accuracies, epochs)return epoch_test_acc  # 返回最終測試準確率# 6. 測試模型(不變)
def test(model, test_loader, criterion, device):model.eval()  # 設置為評估模式test_loss = 0correct = 0total = 0with torch.no_grad():  # 不計算梯度,節省內存和計算資源for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()avg_loss = test_loss / len(test_loader)accuracy = 100. * correct / totalreturn avg_loss, accuracy  # 返回損失和準確率# 7. 繪制每個 iteration 的損失曲線
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序號)')plt.ylabel('損失值')plt.title('每個 Iteration 的訓練損失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 8. 執行訓練和測試(設置 epochs=2 驗證效果)
epochs = 2  
print("開始訓練模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, device, epochs)
print(f"訓練完成!最終測試準確率: {final_accuracy:.2f}%")

在PyTorch中處理張量(Tensor)時,以下是關于展平(Flatten)、維度調整(如view/reshape)等操作的關鍵點,這些操作通常不會影響第一個維度(即批量維度`batch_size`):

圖像任務中張量形狀

輸入張量的形狀通常為:`(batch_size, channels, height, width)`
例如:`(batch_size, 3, 28, 28)` ?
其中,?`batch_size` 代表一次輸入的樣本數量

NLP任務中的張量形狀

輸入張量的形狀通常為:`(batch_size, sequence_length)`

此時,`batch_size` 同樣是第一個維度

1.Flatten操作

功能:將張量展開為一維數組,但保留批量維度
示例:

  • 輸入形狀:`(batch_size, 3, 28, 28)`(圖像數據)
  • Flatten后形狀:`(batch_size, 3×28×28)` = `(batch_size, 2352)` ?
  • 說明:第一個維度`batch_size`不變,后面的所有維度被展平為一個維度
2.view/reshape操作

功能:調整張量維度,但必須顯示保留或指定批量維度
示例:

  • 輸入形狀:輸入形狀:`(batch_size, 3, 28, 28)`
  • 調整為:調整為:`(batch_size, -1)` ?
  • ?結果:展平為兩個維度,保留`batch_size`,第二個維度自動計算為`3×28×28=2352`
總結
  • 批量維度不變性:無論進行flatten、view還是reshape操作,第一個維度`batch_size`通常保持不變
  • 動態維度指定:使用`-1`讓PyTorch自動計算該維度的大小,但需確保其他維度的指定合理,避免形狀不匹配錯誤

二.彩色圖像的規范寫法

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 設置中文字體支持
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解決負號顯示問題# 1. 數據預處理
transform = transforms.Compose([transforms.ToTensor(),                # 轉換為張量transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 標準化處理
])# 2. 加載CIFAR-10數據集
train_dataset = datasets.CIFAR10(root='./data',train=True,download=True,transform=transform
)test_dataset = datasets.CIFAR10(root='./data',train=False,transform=transform
)# 3. 創建數據加載器
batch_size = 64
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 4. 定義MLP模型(適應CIFAR-10的輸入尺寸)
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten()  # 將3x32x32的圖像展平為3072維向量self.layer1 = nn.Linear(3072, 512)  # 第一層:3072個輸入,512個神經元self.relu1 = nn.ReLU()self.dropout1 = nn.Dropout(0.2)  # 添加Dropout防止過擬合self.layer2 = nn.Linear(512, 256)  # 第二層:512個輸入,256個神經元self.relu2 = nn.ReLU()self.dropout2 = nn.Dropout(0.2)self.layer3 = nn.Linear(256, 10)  # 輸出層:10個類別def forward(self, x):# 第一步:將輸入圖像展平為一維向量x = self.flatten(x)  # 輸入尺寸: [batch_size, 3, 32, 32] → [batch_size, 3072]# 第一層全連接 + 激活 + Dropoutx = self.layer1(x)   # 線性變換: [batch_size, 3072] → [batch_size, 512]x = self.relu1(x)    # 應用ReLU激活函數x = self.dropout1(x) # 訓練時隨機丟棄部分神經元輸出# 第二層全連接 + 激活 + Dropoutx = self.layer2(x)   # 線性變換: [batch_size, 512] → [batch_size, 256]x = self.relu2(x)    # 應用ReLU激活函數x = self.dropout2(x) # 訓練時隨機丟棄部分神經元輸出# 第三層(輸出層)全連接x = self.layer3(x)   # 線性變換: [batch_size, 256] → [batch_size, 10]return x  # 返回未經過Softmax的logits# 檢查GPU是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 初始化模型
model = MLP()
model = model.to(device)  # 將模型移至GPU(如果可用)criterion = nn.CrossEntropyLoss()  # 交叉熵損失函數
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam優化器# 5. 訓練模型(記錄每個 iteration 的損失)
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):model.train()  # 設置為訓練模式# 記錄每個 iteration 的損失all_iter_losses = []  # 存儲所有 batch 的損失iter_indices = []     # 存儲 iteration 序號for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device)  # 移至GPUoptimizer.zero_grad()  # 梯度清零output = model(data)  # 前向傳播loss = criterion(output, target)  # 計算損失loss.backward()  # 反向傳播optimizer.step()  # 更新參數# 記錄當前 iteration 的損失iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1)# 統計準確率和損失running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()# 每100個批次打印一次訓練信息if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 單Batch損失: {iter_loss:.4f} | 累計平均損失: {running_loss/(batch_idx+1):.4f}')# 計算當前epoch的平均訓練損失和準確率epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / total# 測試階段model.eval()  # 設置為評估模式test_loss = 0correct_test = 0total_test = 0with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total_test += target.size(0)correct_test += predicted.eq(target).sum().item()epoch_test_loss = test_loss / len(test_loader)epoch_test_acc = 100. * correct_test / total_testprint(f'Epoch {epoch+1}/{epochs} 完成 | 訓練準確率: {epoch_train_acc:.2f}% | 測試準確率: {epoch_test_acc:.2f}%')# 繪制所有 iteration 的損失曲線plot_iter_losses(all_iter_losses, iter_indices)return epoch_test_acc  # 返回最終測試準確率# 6. 繪制每個 iteration 的損失曲線
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序號)')plt.ylabel('損失值')plt.title('每個 Iteration 的訓練損失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 7. 執行訓練和測試
epochs = 20  # 增加訓練輪次以獲得更好效果
print("開始訓練模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, device, epochs)
print(f"訓練完成!最終測試準確率: {final_accuracy:.2f}%")# # 保存模型
# torch.save(model.state_dict(), 'cifar10_mlp_model.pth')
# # print("模型已保存為: cifar10_mlp_model.pth")

彩色的通道也是在第一步被直接展平,其他代碼一致

由于深度mlp的參數過多,為了避免過擬合在這里引入了dropout這個操作,他可以在訓練階段隨機丟棄一些神經元,避免過擬合情況。dropout的取值也是超參數,在測試階段,由于開啟了eval模式,會自動關閉dropout

MLP(多層感知機)在圖像任務上表現較差(即使增加深度和輪次也只能達到 50-55% 準確率),主要原因與圖像數據的空間特性和MLP 的結構缺陷密切相關

  • ?MLP 的每一層都是全連接層,輸入圖像會被展平為一維向量(如 CIFAR-10 的 32x32x3 圖像展平為 3072 維向量)。圖像中相鄰像素通常具有強相關性(如邊緣、紋理),但 MLP 將所有像素視為獨立特征,無法利用局部空間結構。例如,識別 “汽車輪胎” 需要鄰近像素的組合信息,而 MLP 需通過大量參數單獨學習每個像素的關聯,效率極低
  • ?深層 MLP 的參數規模呈指數級增長,容易過擬合

@浙大疏錦行

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

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

相關文章

Java 枚舉(Enum)的使用說明

在 Java 中,枚舉(Enum)是一種特殊的數據類型,用于定義一組固定的命名常量。它比傳統的常量(如 public static final)更安全、更靈活,且支持面向對象特性。以下是枚舉的詳細用法: 1. …

Docker部署Nginx-UI

使用如下命令拉取運行nginx-ui軟件 docker run -dit \ --namenginx-ui \ --restartalways \ -e TZAsia/Shanghai \ -v /mnt/user/appdata/nginx:/etc/nginx \ -v /mnt/user/appdata/nginx-ui:/etc/nginx-ui \ -v /var/run/docker.sock:/var/run/docker.sock \ -…

OkHttp 3.0源碼解析:從設計理念到核心實現

本文通過深入分析OkHttp 3.0源碼,揭示其高效HTTP客戶端的實現奧秘,包含核心設計理念、關鍵組件解析、完整工作流程及實用技巧。 一、引言:為什么選擇OkHttp? 在Android和Java生態中,OkHttp已成為HTTP客戶端的標準選擇…

洛谷P12170 [藍橋杯 2025 省 Python B] 攻擊次數

題目傳送門 思路 首先定義一個數 n n n ,初值為 2025 2025 2025,從第一回合開始,三個英雄持續攻擊,攻擊方式為: 第一個英雄: 每回合攻擊 5 5 5

百度之星2021——BD202104 萌新

輸入格式: 本題有多組測試數據。 第一行一個數 T (1 ≤ T ≤ 1000) 表示一共有 T 組數據。對于每一組數據,輸入一行兩個數 a,b (1 ≤ a,b ≤ 1000000000)。 輸出格式: 對每組數據,輸出一行兩個數分別表示最小與最大的 c&#xff0…

R語言ICU患者死亡率預測實戰

【圖書推薦】《R語言醫學數據分析實踐》-CSDN博客 《R語言醫學數據分析實踐 李丹 宋立桓 蔡偉祺 清華大學出版社9787302673484》【摘要 書評 試讀】- 京東圖書 (jd.com) 預測ICU患者死亡率對比較藥物的療效、比較護理的有效性、比較手術的有效性有重要意義,利用機…

leetcode240-搜索二維矩陣

leetcode 240 思路 1. 矩陣特性 首先,利用矩陣的特性是解題的關鍵: 每行的元素遞增每列的元素遞增 這意味著,如果我們在矩陣中從右上角或左下角開始搜索,可以有效縮小搜索范圍 2. 從右上角開始搜索 將搜索的起點定位在矩陣…

Linux相關概念和易錯知識點(42)(TCP的連接管理、可靠性、面臨復雜網絡的處理)

目錄 1.TCP的連接管理機制(1)三次握手①握手過程②對握手過程的理解 (2)四次揮手(3)握手和揮手的觸發(4)狀態切換①揮手過程中狀態的切換②握手過程中狀態的切換 2.TCP的可靠性&…

【web應用】若依框架:若依框架中的頁面跳轉簡介

文章目錄 ?前言1. 后端控制器跳轉2. 前端路由跳轉3. 菜單配置跳轉4. 權限控制跳轉5. 常見跳轉路徑 ?一、主目錄頁面跳轉?二、菜單目錄跳轉?總結 標題詳情作者JosieBook頭銜CSDN博客專家資格、阿里云社區專家博主、軟件設計工程師博客內容開源、框架、軟件工程、全棧&#x…

MS9292+MS9332 HD/DVI轉VGA轉換器+HD環出帶音頻

MS9292MS9332是一款HD/DVI轉VGA轉換器HD環出帶音頻的視頻轉換方案。支持HD/DVI輸入,VGA輸出和HD環出,HD/DVI輸入最高支持1920120060Hz,VGA輸出最高支持1920120060Hz,HD環出最高支持4K30Hz。該方案已實現量產,并提供完善…

C++初階-list的模擬實現(難度較高)

1.list(容器,不是類)模擬實現基本結構 這個實現是和源碼的實現不同的,不要進行強制類型轉換了,很麻煩。我們把定義放在.h文件中,在.cpp中放測試代碼。 注:這個基本結構之后會改變,…

【ROS】Nav2源碼之nav2_behavior_tree-行為樹節點列表

1、行為樹節點分類 在 Nav2(Navigation2)的行為樹框架中,行為樹節點插件按照功能分為 Action(動作節點)、Condition(條件節點)、Control(控制節點) 和 Decorator(裝飾節點) 四類。 1.1 動作節點 Action 執行具體的機器人操作或任務,直接與硬件、傳感器或外部系統…

【iOS】cell的復用以及自定義cell

【iOS】cell的復用以及自定義cell 文章目錄 【iOS】cell的復用以及自定義cell前言cell的復用手動(非注冊)自動(注冊) 自定義cell 前言 cell的復用及自定義cell是UITableView或UICollectionView的一個重要優化機制,當用戶滾動視圖…

深度學習之模型壓縮三駕馬車:基于ResNet18的模型剪枝實戰(2)

前言 《深度學習之模型壓縮三駕馬車:基于ResNet18的模型剪枝實戰(1)》里面我只是提到了對conv1層進行剪枝,只是為了驗證這個剪枝的整個過程,但是后面也有提到:僅裁剪 conv1層的影響極大,原因如…

傳輸層協議:UDP

目錄 1、概念 2、報文結構 3、核心特性 3.1 無連接 3.2 不可靠交付 3.3 面向數據報 3.4 輕量級&高效 3.5 支持廣播和組播 4、典型應用場景 5、優缺點分析 6、與TCP的區別 1、概念 UDP(User Datagram Protocol,用戶數據報協議&#xff09…

JVM虛擬機:內存結構、垃圾回收、性能優化

1、JVM虛擬機的簡介 Java 虛擬機(Java Virtual Machine 簡稱:JVM)是運行所有 Java 程序的抽象計算機,是 Java 語言的運行環境,實現了 Java 程序的跨平臺特性。JVM 屏蔽了與具體操作系統平臺相關的信息,使得 Java 程序只需生成在 JVM 上運行的目標代碼(字節碼),就可以…

c++ 面試題(1)-----深度優先搜索(DFS)實現

操作系統:ubuntu22.04 IDE:Visual Studio Code 編程語言:C11 題目描述 地上有一個 m 行 n 列的方格,從坐標 [0,0] 起始。一個機器人可以從某一格移動到上下左右四個格子,但不能進入行坐標和列坐標的數位之和大于 k 的格子。 例…

【匯編逆向系列】七、函數調用包含多個參數之浮點型- XMM0-3寄存器

目錄 1. 匯編代碼 1.1 debug編譯 1.2 release編譯 2. 匯編分析 2.1 浮點參數傳遞規則 2.2 棧幀rsp的變化時序 2.3 參數的訪問邏輯 2.4 返回值XMM0寄存器 3. 匯編轉化 3.1 Debug編譯 3.2 Release 編譯 3.3 C語言轉化 1. 匯編代碼 上一節介紹了整型的函數傳參&#x…

華為云Flexus+DeepSeek征文 | 從零到一:用Flexus云服務打造低延遲聯網搜索Agent

作者簡介 我是摘星,一名專注于云計算和AI技術的開發者。本次通過華為云MaaS平臺體驗DeepSeek系列模型,將實際使用經驗分享給大家,希望能幫助開發者快速掌握華為云AI服務的核心能力。 目錄 作者簡介 前言 1. 項目背景與技術選型 1.1 項目…

【多智能體】受木偶戲啟發實現多智能體協作編排

😊你好,我是小航,一個正在變禿、變強的文藝傾年。 🔔本專欄《人工智能》旨在記錄最新的科研前沿,包括大模型、具身智能、智能體等相關領域,期待與你一同探索、學習、進步,一起卷起來叭&#xff…