pytorch argmax_一起无聊地用PyTorch刷爆sklearn的内置数据集吧(`?ω?′)
我們都知道sklearn有一個datasets的子庫,里面有許多可以直接調取的小型數據集。我們可以通過PyTorch來在這些數據集上做訓練和預測。
只是無聊。測試速度。如果你是一個剛剛上手pytorch的新手玩家,你也可以通過這個來刷刷題,練練手。
看看從數據集的調用,網絡的建立到訓練評估你要花多長時間。本文并沒有什么技術含量,只是單純為了熟悉。你完全可以端著一杯咖啡邊喝邊利用PyTorch消解“無聊”的weekend
波士頓房價預測
使用線性層在波士頓房價數據集上建立模型先導入相關庫,因為數據量小,我們可以一次性學習一整個數據集,所以此處我們就不構建數據加載器了。
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'>然后構建線性層類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接下來,記得把輸入數據轉換成tensor,并獲取訓練需要的對象:
# 數據類型轉換X_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.float32)?# 網絡實例化net = LR(input_dim=13, output_dim=1)# 獲取損失函數loss_func = nn.MSELoss()# 獲取優化器對象optimizer = torch.optim.Adam(net.parameters(), lr=0.0001)?loss_all = []最后訓練網絡,并做數據可視化:
# 開始訓練for epoch in range(25):# 前向傳播output = net(X_t)# 計算損失loss = loss_func(output.flatten(), y_t.flatten())# 梯度清空optimizer.zero_grad()# 反向傳播loss.backward()# 更新網絡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:
手寫數字集識別
手寫數字集,這個你可以認為是小型的MNIST,MNIST是28*28的,而sklearn中提供的是8*8,而且給了1797條,用來玩夠了。
我會無聊地使用線性層,卷積層,循環層分別搭建網絡來預測這個小型手寫數字集。
先導入需要使用的手寫數字集,并觀察形狀:
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'>?# 構建數據加載器?img = X[0].reshape([8, 8])plt.imshow(img, cmap=plt.cm.gray)plt.show()out:
定義數據加載器:
# 原數據可能會把相近的類別放在一起,所以分割數據前最好要打亂choose_index = np.arange(X.shape[0])shuffle(choose_index)?# 轉換為tensorX_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.int64)?# 將數據和標簽整合在一起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:]])?# 構建數據加載器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:
下面嘗試使用線性算子、卷積算子,循環神經網絡來建立模型線性層的效果
先使用線性層預測,首先定義網絡:
# 定義網絡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)# 最后對結果softmax一下softmax_result = nn.functional.softmax(out, dim=1)return softmax_result然后獲取訓練需要的對象:
# 網絡實例化net = LinearLayerClassifier(input_dim=64, output_dim=10)# 獲取優化器optimizer = torch.optim.RMSprop(net.parameters(), lr=0.001)# 獲取損失函數loss_func = nn.CrossEntropyLoss(reduction="mean")# 記錄損失train_loss, train_acc = [], []test_loss, test_acc = [], []訓練并做數據可視化:
# 開始訓練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()# 更新參數optimizer.step()?# 記錄訓練結果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))?# 可視化數據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:
模型最終收斂了,但是顯然很不穩定CNN算子的效果
由于卷積和后續的循環神經網絡都需要基于各自類型的數據維度,CNN的基本輸入數據維度為[B, C, H, W],RNN的基本輸入維度為[B, time_step, embedding_dim]。所以我們需要重構數據加載器。其實重構很簡單,我們只要修改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]?# 原數據可能會把相近的類別放在一起,所以分割數據前最好要打亂choose_index = np.arange(1797)shuffle(choose_index)?# 轉換成tensorX_t = torch.tensor(X, dtype=torch.float32)y_t = torch.tensor(y, dtype=torch.int64)?# 將數據和標簽整合在一起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:]])?# 構建數據加載器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)其實上面只改了一行代碼(第六行)接下來搭建網絡類:
# 定義網絡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接下來的訓練和各種對象的獲取和上面線性算子的過程一致,除了網絡實例化:
# 網絡實例化net = CNNClassifier(input_channels=1, output_dim=10)out:
效果看起來沒有線性算子好,因為處理的圖片還是很小的且通道數只有一,等到處理的圖片較大,且有多個顏色通道時,卷積算子的優勢就會體現得比較明顯了。RNN算子的效果
此處的RNN的cell就使用GRU算子。首先還是修改數據輸入維度,和CNN相比,RNN的數據維度少了通道這一維,所以我們在數據加載器這一步,我們只要改一步:
X = [x.reshape([8, 8]).tolist() for x in X]定義RNN網絡,我們使用GRU算子:
# 定義網絡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然后最后的還是和上面一樣,除了網絡實例化:
# 網絡實例化net = RNNClassifier(input_size=8, hidden_size=64)out:
鳶尾花數據集分類
該數據集為三分類數據集。每條數據有4個特征。
先導入需要的庫,并導入數據集:
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]由于原本的數據集中標簽相同的數據是放在一起的,所以我們在使用前需要先打亂數據:
# 分割獲取訓練集和測試集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)然后定義我們的網絡,此時還是使用簡單的MLP:
# 定義網絡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)接下來我們實例化網絡并獲取訓練需要的損失函數與優化器對象,繼而開始訓練。由于數據量很小,所以我們直接一次性使用整個訓練集做前饋:
# 網絡實例化net = MyNet()# 獲取損失函數和優化器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()# 更新參數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由于數據量太小了,所以訓練結果會因為隨機化分割數據集的結果而有較大的區別癌癥數據集分類
該數據集任務為二分類,輸出是否為癌癥患者。該數據的每條有30個特征。
引入庫和數據集:
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, )將數據轉化為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:]]分類器網絡定義成一個簡單的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)實例化網絡、獲取優化器、訓練、可視化、測試網絡:
# 網絡實例化net = cancerClassifier(input_dim=30,output_dim=2)?# 獲取優化器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()?# 在測試集上檢測結果net.eval()output = net(test_X)pre_label = torch.argmax(output, dim=1)print(classification_report(pre_label, test_y))out:
這個模型好像很不穩定,隨著初始數據隨機劃分的結果不同,網絡acc有時會收斂到65%,有時會收斂到90%,若有更好的網絡方案,歡迎在評論區提出。to be continued...
總結
以上是生活随笔為你收集整理的pytorch argmax_一起无聊地用PyTorch刷爆sklearn的内置数据集吧(`?ω?′)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件开发规范和标准_社交APP,社交直播
- 下一篇: python抽奖概率设计_辞职转行不如学