一、數據準備
1.1定義
????????數據準備(Data Preparation)?是數據分析與機器學習流程中的核心環節,指將原始數據轉換為適合分析或建模的結構化格式的過程。
1.2組成
? ? ? ? 數據準備主要由兩個部分組成,一個是劃分數據集,一個是構建加載器。
二、構建數據類
2.1Dataset類
2.1.1基本介紹?
???????? Dataset是一個抽象類,自定義的數據類都要繼承于它。它定義了數據集必須實現的方法。
這里必須的方法就有兩個:
(1)__len__:獲取數據集的大小;
(2)__getitem__?:通過索引訪問數據集的樣本;
還有一個初始化方法:
__init__:初始化數據,將需要加載的數據放在這里。
2.1.2三個方法的大致實現方式
(1)__init__:
def __init__(self,data,labels):self.data = dataself.labels = labels
注意:?
左側self.data是屬性:存儲在對象的內存空間中,生命周期與對象相同(只要對象存在就可用)。
右側data是參數:它們是函數調用時傳入的臨時變量生命周期僅限于__init__方法執行期間。
(2)__len__:
def __len__(self):return len(self.data)
(3)__getitem__:
def __getitem__():sample = self.data[index]label = self.labels[index]return sample,label
注意:返回的是一個元組?
2.1.3完整定義數據類
步驟:
(1)自定義類繼承基類Dataset;
(2)實現len,getitem方法;
(3)通過__init__加載外部數據。
(4)創建函數,打印查看結果。
代碼示例:
import torch
from torch import optim
import torch.nn as nn
from torch.utils.data import Dataset
class mydataset(Dataset):#繼承def __init__(self,data,labels):self.data = dataself.labels = labelsdef __len__(self):return len(self.data)def __getitem__(self, index):index = min(max(index,0),len(self.data)-1)sample = self.data[index]label = self.labels[index]return sample,labeldef test():x = torch.randn(20,1,dtype=torch.float,requires_grad=True)y = torch.randn(20,1,dtype=torch.float)dataset = mydataset(x,y)print(dataset[0])model = nn.Linear(1,1)criterion = nn.MSELoss()optimizer = optim.Adam(model.parameters(),lr = 0.01)for epoch in range(20):y_pred = model(x)loss = criterion(y,y_pred)optimizer.zero_grad()loss.backward()optimizer.step()print(model.weight,model.bias)if __name__ == '__main__':test()
代碼解釋:
這段代碼實現了一個簡單的線性回歸模型訓練演示,主要作用是展示PyTorch的基本工作流程。具體來說:
-
創建隨機數據:
-
生成20個隨機數作為輸入特征?
x
-
生成20個隨機數作為目標值?
y
-
-
構建數據集:
-
使用自定義的?
mydataset
?類封裝數據 -
實現數據集的長度和索引訪問功能
-
-
定義線性模型:
-
創建最簡單的神經網絡:單層線性層 (
nn.Linear(1,1)
) -
相當于數學中的?
y = wx + b
-
-
配置訓練組件:
-
損失函數:均方誤差 (
MSELoss
) -
優化器:Adam算法
-
-
執行訓練循環:
-
重復20次訓練過程:
-
模型預測 (
y_pred = model(x)
) -
計算預測值與真實值的差異 (
loss
) -
反向傳播計算梯度 (
loss.backward()
) -
優化器更新參數 (
optimizer.step()
)
-
-
-
輸出結果:
-
打印訓練后的權重?
w
?和偏置?b
-
結果:
(tensor([0.4495], grad_fn=<SelectBackward0>), tensor([-0.4830]))
Parameter containing:
tensor([[-0.3186]], requires_grad=True) Parameter containing:
tensor([0.7820], requires_grad=True)
2.2TensorDataset類
TensorDataset實行起來比Dataset自定義更簡單些,它適用于數據已經是張量的形式。
直接調用TensorDataset就行
代碼示例:
import torch
from torch.utils.data import TensorDataset
def tensordataset():features = torch.randn(12,3)labels = torch.randint(0,2,(12,))dataset = TensorDataset(features,labels)print(dataset[1])print(len(dataset))if __name__ == '__main__':# test()tensordataset()
結果:
(tensor([ 1.9409, -1.8119, ?0.3687]), tensor(1))
12
三、數據加載器
3.1簡單定義
????????數據加載器主要是用來加載數據集中的批量樣本,有時候我們并不需要一股腦的把所有的數據樣本都加載到模型中進行訓練。
3.2數據加載器的作用
數據加載器是一個迭代器,要將里面的樣本取出的話需要用到枚舉法。
主要功能:
(1)批量加載數據;
(2)打亂數據;
(3)多線程加載。
3.3創建dataloder
dataloader = DataLoader(dataset,batch_size = 10,shuffle = True,num_workers = 2 #使用兩個子進程加載數據
)
枚舉:
?enumerate返回枚舉對象,生成由索引和值組成的元組。
-
enumerate(dataloader)
:-
dataloader
?是一個 PyTorch 的 DataLoader 對象 -
enumerate()
?函數會給每次迭代添加一個索引(從0開始)
-
-
batch_index
:-
當前批次的索引號(第幾個批次)
-
從0開始計數
-
-
(samples, labels)
:-
解包 DataLoader 返回的一個批次的數據
-
samples
: 當前批次的輸入數據(特征) -
labels
: 當前批次對應的標簽
-
-
打印內容:
-
print(batch_index)
: 打印當前批次的序號 -
print(samples)
: 打印當前批次的所有樣本數據 -
print(labels)
: 打印當前批次的所有標簽
-
for batch_index,(samples,labels) in enumerate(dataloader):print(batch_index)print(samples)print(labels)
3.4相關案例
數據加載器一般是在數據準備后用,它不是放在類里面的,或者是放在循環中。
代碼示例:
import torchfrom torch.utils.data import TensorDataset,DataLoader
def test():x = torch.randn(21,3,dtype=torch.float,requires_grad=True)y = torch.randn(21,1)dataset = TensorDataset(x,y)dataloader = DataLoader(dataset, batch_size=7, shuffle=True)for i, (batch_x, batch_y) in enumerate(dataloader):print(batch_x, batch_y)break
if __name__ == '__main__':test()
代碼解釋:
-
創建隨機數據:
-
x
:21個樣本,每個樣本有3個特征(21×3的隨機浮點數張量) -
y
:21個對應的標簽(21×1的隨機浮點數張量)
-
-
封裝數據集:
-
使用
TensorDataset
將特征x
和標簽y
組合成一個數據集
-
-
創建數據加載器:
-
使用
DataLoader
將數據集分成每批7個樣本 -
shuffle=True
表示每次迭代前打亂數據順序
-
-
分批獲取數據:
-
遍歷數據加載器獲取批次數據
-
break
語句確保只打印第一個批次的數據
-
關鍵輸出:
當運行代碼時,會打印出第一個批次(7個樣本)的數據:
batch_x (7×3張量): [[特征1, 特征2, 特征3],[特征1, 特征2, 特征3],...]batch_y (7×1張量): [標簽1], [標簽2], ...
結果:
tensor([[-1.0268, -0.8619, -1.6537],
? ? ? ? [ 1.3707, -0.4312, ?0.0943],
? ? ? ? [ 0.3188, ?0.9837, -0.5358],
? ? ? ? [ 0.5535, ?0.5231, -0.0356],
? ? ? ? [ 1.3922, ?0.7636, ?0.3401],
? ? ? ? [ 1.0909, ?0.9076, ?0.1129],
? ? ? ? [ 0.8337, ?0.7352, -1.0355]], grad_fn=<StackBackward0>) tensor([[ 0.6652],
? ? ? ? [ 2.3144],
? ? ? ? [ 1.6643],
? ? ? ? [ 0.8918],
? ? ? ? [-0.4568],
? ? ? ? [ 0.9112],
? ? ? ? [-0.5561]])
四、數據集加載案例
4.1加載csv數據集
注意文件路徑的輸入,可以輸入絕對路徑。
可以選擇用自定義類的方式讀取文件,也可以用TensorDataset讀取文件,但是要注意后者所有數據必須全部轉為張量。
(1)自定義類
import torch
from torch.utils.data import Dataset,DataLoader
import pandas as pd
class mycsv(Dataset):def __init__(self,filepath):df = pd.read_csv(filepath)df = df.drop(['學號','姓名'],axis=1)data = torch.tensor(df.values)self.data = data[:,:-1] #除了最后一列的所有行self.label = data[:,-1] #所有行的最后一列def __len__(self):return len(self.data)def __getitem__(self, idx):idx = min(max(idx,0),len(self.data)-1)return self.data[idx],self.label[idx]def test():csv_path = r'E:\AI\課件\深度學習\圖片資料\大數據答辯成績表.csv'dataset = mycsv(csv_path)print(dataset[0])dataloder = DataLoader(dataset,batch_size=3,shuffle=True)#批量加載3條數據內容for i,(data,label) in enumerate(dataloder):print(i,data,label)break
if __name__ == '__main__':test()
結果:
(tensor([16, 16, 21, 22]), tensor(75))
0 tensor([[15, 15, 20, 21],
? ? ? ? [15, 16, 22, 22],
? ? ? ? [16, 16, 21, 20]]) tensor([71, 75, 73])
(2)TensorDataset
'''
(1)讀取數據
(2)數據處理
(3)轉換張量
(4)TensorDataset
(5)返回
'''
def buid_dataset(filepath):df = pd.read_csv(filepath)df = df.drop(['學號','姓名'],axis=1)data = df.iloc[:,:-1]labels = df.iloc[:,-1]x = torch.tensor(data.values,dtype=torch.float)y = torch.tensor(labels.values)dataset = TensorDataset(x,y)return dataset'''
(1)讀取文件路徑
(2)數據集引入
(3)數據加載器
(4)枚舉查看結果
'''
def test01():filepath = r'E:\AI\課件\深度學習\圖片資料\大數據答辯成績表.csv'dataset = buid_dataset(filepath)dataloader = DataLoader(dataset,batch_size=7,shuffle=True)for i,(data,label) in enumerate(dataloader):print(i,data,label)if __name__ == '__main__':# test()test01()
結果:
0 tensor([[15., 15., 21., 20.],
? ? ? ? [16., 16., 25., 19.],
? ? ? ? [18., 20., 29., 29.],
? ? ? ? [18., 18., 25., 27.],
? ? ? ? [15., 16., 23., 21.],
? ? ? ? [17., 20., 27., 26.],
? ? ? ? [18., 20., 27., 27.]]) tensor([71, 76, 96, 88, 75, 90, 92])
1 tensor([[19., 19., 27., 25.],
? ? ? ? [15., 16., 21., 20.],
? ? ? ? [18., 18., 22., 23.],
? ? ? ? [16., 16., 21., 22.],
? ? ? ? [14., 16., 22., 21.],
? ? ? ? [14., 16., 22., 24.],
? ? ? ? [17., 16., 21., 22.]]) tensor([90, 72, 81, 75, 73, 76, 76])
2 tensor([[15., 15., 20., 22.],
? ? ? ? [15., 15., 20., 21.],
? ? ? ? [15., 15., 20., 21.],
? ? ? ? [16., 16., 23., 19.],
? ? ? ? [18., 18., 24., 23.],
? ? ? ? [18., 20., 28., 28.],
? ? ? ? [19., 19., 28., 28.]]) tensor([72, 71, 71, 74, 83, 94, 94])
3 tensor([[14., 16., 22., 22.],
? ? ? ? [19., 19., 28., 27.],
? ? ? ? [15., 15., 21., 20.],
? ? ? ? [15., 16., 23., 21.],
? ? ? ? [17., 16., 20., 21.],
? ? ? ? [17., 16., 24., 24.],
? ? ? ? [15., 15., 21., 20.]]) tensor([74, 93, 71, 75, 74, 81, 71])
4 tensor([[17., 16., 21., 22.],
? ? ? ? [18., 16., 20., 22.],
? ? ? ? [18., 18., 25., 24.],
? ? ? ? [15., 15., 20., 21.],
? ? ? ? [15., 16., 22., 22.],
? ? ? ? [14., 16., 22., 21.],
? ? ? ? [18., 16., 20., 22.]]) tensor([76, 76, 85, 71, 75, 73, 76])
5 tensor([[15., 15., 21., 20.],
? ? ? ? [15., 16., 23., 22.],
? ? ? ? [19., 19., 28., 24.],
? ? ? ? [15., 16., 23., 21.],
? ? ? ? [16., 16., 23., 19.],
? ? ? ? [15., 16., 21., 20.],
? ? ? ? [17., 16., 22., 23.]]) tensor([71, 76, 90, 75, 74, 72, 78])
6 tensor([[15., 15., 20., 22.],
? ? ? ? [16., 16., 21., 20.],
? ? ? ? [16., 16., 21., 22.]]) tensor([72, 73, 75])
?
4.2加載圖片數據集
? ? ? ? 這里主要介紹imageFolder構造函數的方法:
import torch
from torchvision import datasets, transforms
import os
from torch.utils.data import DataLoader
from matplotlib import pyplot as plttorch.manual_seed(42)def load():path = os.path.join(os.path.dirname(__file__), 'dataset')print(path)transform = transforms.Compose([transforms.Resize((112, 112)),transforms.ToTensor()])dataset = datasets.ImageFolder(path, transform=transform)dataloader = DataLoader(dataset, batch_size=1, shuffle=True)for x,y in dataloader:x = x.squeeze(0).permute(1, 2, 0).numpy()plt.imshow(x)plt.show()print(y[0])breakif __name__ == '__main__':load()
4.3加載官方數據集
? ? ? ? pytorch框架中有一些經典的官方數據集,我們舉例以cifar-10為例。
????????CIFAR10: 包含 10 個類別的 60,000 張 32x32 彩色圖像,每個類別 6,000 張圖像。?其中訓練集50,000張,測試集10,000張。
? ? ? ? 下載官方數據集要引入torchvision中的transforms,datasets。
? ? ? ? API:from torchvision import transforms,datasets
代碼示例:
def test():transform = transforms.Compose([transforms.ToTensor(),])# 訓練數據集data_train = datasets.CIFAR10(root="./data",train=True,download=True,transform=transform,)trainloader = DataLoader(data_train, batch_size=4, shuffle=True, num_workers=2)for x, y in trainloader:print(x.shape)print(y)break# 測試數據集data_test = datasets.CIFAR10(root="./data",train=False,download=True,transform=transform,)testloader = DataLoader(data_test, batch_size=4, shuffle=False, num_workers=2)for x, y in testloader:print(x.shape)print(y)breakif __name__ == '__main__':test()
代碼解釋:
-
datasets.CIFAR10
參數:root="./data"
:數據存儲路徑。train=True
:加載訓練集(50,000 張圖像)。download=True
:若數據不存在,則自動下載。transform=transform
:應用前面定義的預處理。
-
DataLoader
參數:batch_size=4
:每次加載 4 張圖像和標簽。shuffle=True
:每個 epoch 前打亂數據,增強訓練隨機性。num_workers=2
:使用 2 個子進程并行加載數據(提高效率)
這段代碼的核心功能是:
- 數據加載:通過
torchvision.datasets
下載 CIFAR-10 數據集,并使用DataLoader
批量加載。 - 數據格式展示:
- 輸入:
[batch_size, channels, height, width]
的張量。 - 標簽:類別索引(0-9)的張量。
- 輸入:
- 驗證數據結構:通過打印第一批數據,確認數據格式是否符合預期。
五、激活函數
5.1基本概念
? ? ? ? 如果在隱層不使用激活函數,神經網絡表現為線性模型,整個網絡就是線性模型,無法捕捉數據中的非線性關系。 這時候做回歸比較好,做分類的效果不太好。
? ? ? ?非線性可視化:A Neural Network Playground
????????該網址可以查看激活函數對分類和回歸的效果,更直觀觀察結果。
????????激活函數的作用是在隱藏層引入非線性,使得神經網絡能夠學習和表示復雜的函數關系,使網絡具備非線性能力,增強其表達能力。
5.2分類
5.2.1sigmoid函數
? ? ? ? sigmoid函數適合運用于二分類問題中,它將神經網絡的輸出值處理后,將值壓縮到0-1之間,適合處理概率問題。
? ? ? ? 缺點:
(1)出現梯度消失的情況;
(2)信息丟失:輸入100和輸入10000,他們的結果都是映射到0-1之間;
(3)計算量大,設計指數運算。
sigmoid的計算公式:
5.2.2tanh函數
? ? ? ? tanh(雙曲正切)也是常見的激活函數,用于處理分類問題,它的輸出范圍為(-1,1),當輸入為0時,它的輸出也為0。
缺點:
(1)在sigmoid的基礎上改進了些,但也涉及梯度消失問題;
(2)計算成本大,也設計指數運算。
計算公式:
5.2.3ReLU函數
? ? ? ? ReLU(修正線性單元),它的計算簡單,緩解了梯度消失問題,因為ReLU的正半求導區恒為1,梯度不會變小,負半區輸入小于等于0,這會導致部分神經元死亡,從而降低模型的表達能力,但是也有好處,稀疏激活,這樣可以減少冗余信息。
計算公式:
5.2.4LeakyReLU函數
? ? ? ? LeakyLeLU是ReLU的改進版本,主要是為了解決ReLU的神經元死亡問題。它的計算還是比較簡單快捷的。
缺點:
(1)參數選擇,α是一超參數,選擇一個合適的α值需要反復測試;
(2)參數設置不對可能會導致激活值過低。
計算公式:
注意:ReLU(Rectified Linear Unit)和LeakyReLU(Leaky Rectified Linear Unit)既可用于線性回歸,也可用于分類任務,它們本身不是特定于某種任務,而是神經網絡中的激活函數。
5.2.5softmax函數
? ? ? ? softmax函數是用于分類問題的輸出層,將輸出結果轉換為概率分布,使輸出的各個類別的概率之和為1。softmax只是對向量的值做了改變,但它的位置不變。
特點:
(1)將輸出值轉換為0-1之間的概率分布;
(2)概率最大的類別更接近1,其他接近于0;
(3)運用于分類。
計算公式:
5.3合適的選擇
激活函數的應用,主要是應用在隱藏層或者輸出層。
隱藏層:優先選擇ReLU,然后是LeakyReLU,避免sigmoid,嘗試tanh
輸出層:
(1)二分類:sigmoid
(2)多分類:softmax
六、小結
? ? ? ? 主要學習了數據準備的構建數據類和數據加載器,主要是熟練運用操作。其次是熟悉激活函數,記住特征。