pytorch argmax_一起无聊地用PyTorch刷爆sklearn的内置数据集吧(`?ω?′)
我們都知道sklearn有一個datasets的子庫,里面有許多可以直接調(diào)取的小型數(shù)據(jù)集。我們可以通過PyTorch來在這些數(shù)據(jù)集上做訓練和預測。
只是無聊。測試速度。如果你是一個剛剛上手pytorch的新手玩家,你也可以通過這個來刷刷題,練練手。
看看從數(shù)據(jù)集的調(diào)用,網(wǎng)絡的建立到訓練評估你要花多長時間。本文并沒有什么技術含量,只是單純?yōu)榱耸煜ぁD阃耆梢远酥槐Х冗吅冗吚肞yTorch消解“無聊”的weekend
波士頓房價預測
使用線性層在波士頓房價數(shù)據(jù)集上建立模型先導入相關庫,因為數(shù)據(jù)量小,我們可以一次性學習一整個數(shù)據(jù)集,所以此處我們就不構(gòu)建數(shù)據(jù)加載器了。
from sklearn.datasets import load_bostonimport torch.nn as nnimport torchimport matplotlib.pyplot as pltimport pandas as pd?X, y = load_boston(return_X_y=True)# X.shape : (506, 13)# y.shape : (506,)# type : <class 'numpy.ndarray'>然后構(gòu)建線性層類LR:
class LR(nn.Module):def __init__(self, input_dim, output_dim):super(LR, self).__init__()self.fc = nn.Sequential(nn.Linear(input_dim, 64),nn.Linear(64, 128),nn.Linear(128, 32),)?self.regression = nn.Linear(32, 1)?def forward(self, x):out = self.fc(x)out = self.regression(out)return out接下來,記得把輸入數(shù)據(jù)轉(zhuǎn)換成tensor,并獲取訓練需要的對象:
# 數(shù)據(jù)類型轉(zhuǎn)換X_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.float32)?# 網(wǎng)絡實例化net = LR(input_dim=13, output_dim=1)# 獲取損失函數(shù)loss_func = nn.MSELoss()# 獲取優(yōu)化器對象optimizer = torch.optim.Adam(net.parameters(), lr=0.0001)?loss_all = []最后訓練網(wǎng)絡,并做數(shù)據(jù)可視化:
# 開始訓練for epoch in range(25):# 前向傳播output = net(X_t)# 計算損失loss = loss_func(output.flatten(), y_t.flatten())# 梯度清空optimizer.zero_grad()# 反向傳播loss.backward()# 更新網(wǎng)絡optimizer.step()?loss_all.append(loss.item())?data = pd.DataFrame({"loss" : loss_all}, columns=["loss"])data["loss"].plot(x="iteration", y="loss")plt.show()out:
手寫數(shù)字集識別
手寫數(shù)字集,這個你可以認為是小型的MNIST,MNIST是28*28的,而sklearn中提供的是8*8,而且給了1797條,用來玩夠了。
我會無聊地使用線性層,卷積層,循環(huán)層分別搭建網(wǎng)絡來預測這個小型手寫數(shù)字集。
先導入需要使用的手寫數(shù)字集,并觀察形狀:
from sklearn.datasets import load_digitsfrom sklearn.metrics import accuracy_scoreimport matplotlib.pyplot as pltimport numpy as npimport pandas as pdimport torch.nn as nnimport torchimport torch.utils.data as Datafrom random import shuffle?X, y = load_digits(return_X_y=True)# X.shape:(1797, 64)# y.shape:(1797,)# type : <class 'numpy.ndarray'>?# 構(gòu)建數(shù)據(jù)加載器?img = X[0].reshape([8, 8])plt.imshow(img, cmap=plt.cm.gray)plt.show()out:
定義數(shù)據(jù)加載器:
# 原數(shù)據(jù)可能會把相近的類別放在一起,所以分割數(shù)據(jù)前最好要打亂choose_index = np.arange(X.shape[0])shuffle(choose_index)?# 轉(zhuǎn)換為tensorX_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.int64)?# 將數(shù)據(jù)和標簽整合在一起train_data = Data.TensorDataset(X_t[choose_index[:1300]],y_t[choose_index[:1300]])test_data = Data.TensorDataset(X_t[choose_index[1300:]],y_t[choose_index[1300:]])?# 構(gòu)建數(shù)據(jù)加載器train_loader = Data.DataLoader(dataset=train_data,batch_size=64,shuffle=True,num_workers=0)?test_loader = Data.DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0)我們測試一下loader,并可視化一個batch中的第一張圖片及其對應的標簽,看看loader是否正常工作:
for batch in train_loader:img = batch[0][1]label = batch[1][1]?img = img.data.numpy().reshape([8,8])plt.imshow(img, cmap=plt.cm.gray)plt.title(f"label={label}")breakplt.show()out:
下面嘗試使用線性算子、卷積算子,循環(huán)神經(jīng)網(wǎng)絡來建立模型線性層的效果
先使用線性層預測,首先定義網(wǎng)絡:
# 定義網(wǎng)絡class LinearLayerClassifier(nn.Module):def __init__(self, input_dim, output_dim):super(LinearLayerClassifier, self).__init__()self.linear_layer = nn.Sequential(nn.Linear(input_dim, 128),nn.Tanh(),nn.Linear(128, 256),nn.Tanh(),nn.Linear(256, 128),nn.Tanh(),nn.Linear(128, 64),nn.Tanh(),)?self.output = nn.Sequential(nn.Linear(64, output_dim),nn.Tanh(),)?def forward(self, x):out = self.linear_layer(x)out = self.output(out)# 最后對結(jié)果softmax一下softmax_result = nn.functional.softmax(out, dim=1)return softmax_result然后獲取訓練需要的對象:
# 網(wǎng)絡實例化net = LinearLayerClassifier(input_dim=64, output_dim=10)# 獲取優(yōu)化器optimizer = torch.optim.RMSprop(net.parameters(), lr=0.001)# 獲取損失函數(shù)loss_func = nn.CrossEntropyLoss(reduction="mean")# 記錄損失train_loss, train_acc = [], []test_loss, test_acc = [], []訓練并做數(shù)據(jù)可視化:
# 開始訓練for epoch in range(8):# 遍歷生成器net.train()epoch_loss, epoch_acc = [], [] # 記錄當前epoch的loss和accuracyfor batch in train_loader:data, label = batch# 前向傳播output = net(data)# 預測標簽predict_label = torch.argmax(output, dim=1)# 計算損失loss = loss_func(output, label)# 梯度清空optimizer.zero_grad()# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()?# 記錄訓練結(jié)果epoch_loss.append(loss.item())epoch_acc.append(accuracy_score(predict_label, label))?train_loss.append(np.mean(epoch_loss))train_acc.append(np.mean(epoch_acc))?# 遍歷測試集net.eval()epoch_loss, epoch_acc = [], []for batch in test_loader:data, label = batchoutput = net(data)predict_label = torch.argmax(output, dim=1)loss = loss_func(output, label)epoch_loss.append(loss.item())epoch_acc.append(accuracy_score(predict_label, label))?test_loss.append(np.mean(epoch_loss))test_acc.append(np.mean(epoch_acc))?# 可視化數(shù)據(jù)label_name = ["train_loss", "test_loss", "train_acc", "test_acc"]for index, name in enumerate([train_loss, test_loss, train_acc, test_acc]):plt.plot(name, "o-", label=label_name[index])?plt.legend()plt.grid(True)plt.show()out:
模型最終收斂了,但是顯然很不穩(wěn)定CNN算子的效果
由于卷積和后續(xù)的循環(huán)神經(jīng)網(wǎng)絡都需要基于各自類型的數(shù)據(jù)維度,CNN的基本輸入數(shù)據(jù)維度為[B, C, H, W],RNN的基本輸入維度為[B, time_step, embedding_dim]。所以我們需要重構(gòu)數(shù)據(jù)加載器。其實重構(gòu)很簡單,我們只要修改X的維度即可:
X, y = load_digits(return_X_y=True)# X.shape:(1797, 64)# y.shape:(1797,)# type : <class 'numpy.ndarray'>?X = [x.reshape([1, 8, 8]).tolist() for x in X]?# 原數(shù)據(jù)可能會把相近的類別放在一起,所以分割數(shù)據(jù)前最好要打亂choose_index = np.arange(1797)shuffle(choose_index)?# 轉(zhuǎn)換成tensorX_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.int64)?# 將數(shù)據(jù)和標簽整合在一起train_data = Data.TensorDataset(X_t[choose_index[:1300]], y_t[choose_index[:1300]])test_data = Data.TensorDataset(X_t[choose_index[1300:]], y_t[choose_index[1300:]])?# 構(gòu)建數(shù)據(jù)加載器train_loader = Data.DataLoader(dataset=train_data,batch_size=64,shuffle=True,num_workers=0)?test_loader = Data.DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0)其實上面只改了一行代碼(第六行)接下來搭建網(wǎng)絡類:
# 定義網(wǎng)絡class CNNClassifier(nn.Module):def __init__(self, input_channels, output_dim):super(CNNClassifier, self).__init__()self.conv = nn.Sequential(nn.Conv2d(in_channels=input_channels,out_channels=16,kernel_size=3,stride=1,padding=1), # [B, 16, 8, 8]nn.Tanh(),nn.Conv2d(16, 32, 3, 2, 1), # [B, 32, 4, 4]nn.Tanh(),nn.Conv2d(32, 16, 3, 2, 1), # [B, 16, 2, 2]nn.Tanh(),nn.Conv2d(16, 8, 3, 1, 1) # [B, 8, 2, 2])?self.output = nn.Linear(32, 10)?def forward(self, x):out = self.conv(x)# out : [B, 8, 2, 2]out = self.output(out.flatten(start_dim=1))out = nn.functional.softmax(out, dim=1)return out接下來的訓練和各種對象的獲取和上面線性算子的過程一致,除了網(wǎng)絡實例化:
# 網(wǎng)絡實例化net = CNNClassifier(input_channels=1, output_dim=10)out:
效果看起來沒有線性算子好,因為處理的圖片還是很小的且通道數(shù)只有一,等到處理的圖片較大,且有多個顏色通道時,卷積算子的優(yōu)勢就會體現(xiàn)得比較明顯了。RNN算子的效果
此處的RNN的cell就使用GRU算子。首先還是修改數(shù)據(jù)輸入維度,和CNN相比,RNN的數(shù)據(jù)維度少了通道這一維,所以我們在數(shù)據(jù)加載器這一步,我們只要改一步:
X = [x.reshape([8, 8]).tolist() for x in X]定義RNN網(wǎng)絡,我們使用GRU算子:
# 定義網(wǎng)絡class RNNClassifier(nn.Module):def __init__(self, input_size, hidden_size, n_layers=1):super(RNNClassifier, self).__init__()self.gru = nn.GRU(input_size=input_size,hidden_size=hidden_size,num_layers=n_layers,batch_first=True)self.output = nn.Linear(hidden_size, 10)?def forward(self, embedding):# embedding : [B, 8, 8]outputs, hidden = self.gru(embedding)# outputs : [B, 8, 32]# hidden : [1, B, 32]out = outputs[:,-1,:]out = self.output(out).softmax(dim=1)return out然后最后的還是和上面一樣,除了網(wǎng)絡實例化:
# 網(wǎng)絡實例化net = RNNClassifier(input_size=8, hidden_size=64)out:
鳶尾花數(shù)據(jù)集分類
該數(shù)據(jù)集為三分類數(shù)據(jù)集。每條數(shù)據(jù)有4個特征。
先導入需要的庫,并導入數(shù)據(jù)集:
import torchfrom torch import nnfrom sklearn.datasets import load_irisfrom sklearn.metrics import accuracy_score, classification_reportimport numpy as npimport matplotlib.pyplot as plt?X, y = load_iris(return_X_y=True)# X.shape = (150,4)# y.shape = (150,)sample_num = X.shape[0]由于原本的數(shù)據(jù)集中標簽相同的數(shù)據(jù)是放在一起的,所以我們在使用前需要先打亂數(shù)據(jù):
# 分割獲取訓練集和測試集index = np.arange(sample_num)np.random.shuffle(index)split_ratio = 0.8 # 訓練集的比例offline = int(split_ratio * sample_num) # 劃分的索引界線# 訓練集train_X = torch.tensor(X[index[:offline]], dtype=torch.float32)train_y = torch.tensor(y[index[:offline]], dtype=torch.int64)# 測試集test_X = torch.tensor(X[index[offline:]], dtype=torch.float32)test_y = torch.tensor(y[index[offline:]], dtype=torch.int64)然后定義我們的網(wǎng)絡,此時還是使用簡單的MLP:
# 定義網(wǎng)絡class MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.fc = nn.Sequential(nn.Linear(4, 32),nn.ReLU(),nn.Linear(32, 64),nn.ReLU(),nn.Linear(64, 3),nn.Tanh())?def forward(self, x):out = self.fc(x)return out.softmax(dim=1)接下來我們實例化網(wǎng)絡并獲取訓練需要的損失函數(shù)與優(yōu)化器對象,繼而開始訓練。由于數(shù)據(jù)量很小,所以我們直接一次性使用整個訓練集做前饋:
# 網(wǎng)絡實例化net = MyNet()# 獲取損失函數(shù)和優(yōu)化器loss_func = nn.CrossEntropyLoss()optimizer = torch.optim.RMSprop(net.parameters(), lr=1e-3)?losses = []acc = []?# 開始訓練net.train()for epoch in range(20):# 前向傳播output = net(train_X)# 計算預測標簽值pre_label = torch.argmax(output, dim=1)# 計算損失loss = loss_func(output, train_y)# 梯度清空optimizer.zero_grad()# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()# 記錄訓練過程losses.append(loss.item())acc.append(accuracy_score(pre_label, train_y))?# 可視化訓練過程plt.style.use("seaborn")plt.plot(losses, label="loss")plt.plot(acc, label="acc")plt.legend()plt.show()out:
out:
precision recall f1-score support?0 1.00 1.00 1.00 121 1.00 1.00 1.00 112 1.00 1.00 1.00 7?micro avg 1.00 1.00 1.00 30macro avg 1.00 1.00 1.00 30weighted avg 1.00 1.00 1.00 30由于數(shù)據(jù)量太小了,所以訓練結(jié)果會因為隨機化分割數(shù)據(jù)集的結(jié)果而有較大的區(qū)別癌癥數(shù)據(jù)集分類
該數(shù)據(jù)集任務為二分類,輸出是否為癌癥患者。該數(shù)據(jù)的每條有30個特征。
引入庫和數(shù)據(jù)集:
from sklearn.datasets import load_breast_cancerfrom sklearn.metrics import accuracy_score, classification_reportimport torchfrom torch import nnimport matplotlib.pyplot as pltimport numpy as np?X, y = load_breast_cancer(return_X_y=True)# X.shape = (569, 30)# y.shape = (569, )將數(shù)據(jù)轉(zhuǎn)化為tensor,并打亂,切分:
index = np.arange(X.shape[0])np.random.shuffle(index)?X_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.int64)?train_X, train_y = X_t[index[:500]], y_t[index[:500]]test_X, test_y = X_t[index[500:]], y_t[index[500:]]分類器網(wǎng)絡定義成一個簡單的MLP:
class cancerClassifier(nn.Module):def __init__(self, input_dim, output_dim):super(cancerClassifier, self).__init__()self.fc = nn.Sequential(nn.Linear(input_dim, 64),nn.ReLU(),nn.Linear(64, 128),nn.ReLU(),nn.Linear(128, 64),nn.ReLU(),nn.Linear(64, 32),nn.ReLU(),nn.Linear(32, 16),nn.ReLU(),nn.Linear(16, 8),nn.ReLU(),nn.Linear(8, 2),nn.Tanh())?def forward(self, x):out = self.fc(x)return out.softmax(dim=1)實例化網(wǎng)絡、獲取優(yōu)化器、訓練、可視化、測試網(wǎng)絡:
# 網(wǎng)絡實例化net = cancerClassifier(input_dim=30,output_dim=2)?# 獲取優(yōu)化器optimizer = torch.optim.RMSprop(net.parameters(), lr=1e-4)?train_loss, train_acc = [], []?for epoch in range(20):output = net(train_X)pre_label = torch.argmax(output, dim=1)loss = nn.functional.cross_entropy(output, train_y, reduction="mean")optimizer.zero_grad()loss.backward()optimizer.step()?train_loss.append(loss.item())train_acc.append(accuracy_score(pre_label, train_y))?plt.style.use("seaborn")plt.plot(train_loss, label="loss")plt.plot(train_acc, label="acc")plt.legend()plt.show()?# 在測試集上檢測結(jié)果net.eval()output = net(test_X)pre_label = torch.argmax(output, dim=1)print(classification_report(pre_label, test_y))out:
這個模型好像很不穩(wěn)定,隨著初始數(shù)據(jù)隨機劃分的結(jié)果不同,網(wǎng)絡acc有時會收斂到65%,有時會收斂到90%,若有更好的網(wǎng)絡方案,歡迎在評論區(qū)提出。to be continued...
總結(jié)
以上是生活随笔為你收集整理的pytorch argmax_一起无聊地用PyTorch刷爆sklearn的内置数据集吧(`?ω?′)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件开发规范和标准_社交APP,社交直播
- 下一篇: python抽奖概率设计_辞职转行不如学