透過「數值化分類目標」的方法可以用來將影像分類,不過如果分類目標較多而且彼此之間並沒有相互關聯性,那麼這樣的方法有可能在訓練的時候遇到無法收歛的瓶頸。因此,有時候也可以利用多個類神網路建立叢集,來進行影像分類;透過單一化訓練目標來加速訓練收歛。
在這裏我們使用「Fashion-MNIST」作為分類問題的例子;所以還是先透過「torchvision」下載所需要的資料。
#-----------
import torchvision
from torchvision import datasets
from torchvision.transforms import ToTensor
import numpy as np
train_data=datasets.FashionMNIST(root="data",
train=True,
download=True,
transform=ToTensor(),
target_transform=None)
test_data=datasets.FashionMNIST(root="data",
train=False,
download=True,
transform=ToTensor())
同樣地還是使用反饋類神經網路來進行分類,首先建立類神經網路的類別。
import torch
from torch import nn
#-----------------------
# creat neural network class
class classNeural(nn.Module):
def __init__(self,n_input,n_hidden,n_output):
super().__init__()
self.n_input=n_input
self.n_hidden=n_hidden
self.n_output=n_output
#--------
self.layer1=nn.Linear(n_input,n_hidden)
self.layer2=nn.Linear(n_hidden,n_output)
self.active=nn.Sigmoid()
#--------
def forward(self,x):
x=self.active(self.layer1(x))
return self.layer2(x)
我們使用「Fashion-MNIST」的前16筆圖形資料來建立叢集類神經網路模型。在輸入圖形資料的處理上並沒有改變,還是原來的 16 組 28*28 畫素的圖形資料。
#-------------
device=torch.device('cpu')
if(torch.cuda.is_available()):
device=torch.device('cuda')
#------------
Images=train_data.data[0:16]
Labels=train_data.targets[0:16]
nType=len(train_data.classes)
#------------
Pixels=Images.flatten(start_dim=1,end_dim=2)
nData,nPixel=Pixels.shape
X_train=((Pixels-255/2.0)/(255)).to(device)
在目標資料變數「cluster_y_train」上,必須要對映到分類目標;因為「Fashion-MNIST」總共有10的分類目標,所以要創建 10 組目標值,而且在依照分類目標的順序,將目標值設為 1,其他則為 0。
另外,利用 python 的物件序列方式,建立 10 個類神經網路「classNeural ()」所組成的叢集物件「cluster_neurals」;要特別注意的是,因為叢集物件是物件序列的形態,所以它的運算只能在「cpu」上進行;但是序列內的類神經網路物件,是由「PyTorch」所建立,因此它可以放在「gpu」來運算。
#------------
# set clustering targets
cluster_y_train=np.zeros((nType,nData,1))
for i in range(nData):
ix=Labels[i]
cluster_y_train[ix,i,0]=1.0
cluster_Y_train=torch.tensor(cluster_y_train.astype('float32')).to(device)
#------------
# set clustering neural networks
cluster_neurals=[]
for i in range(nType):
torch.manual_seed(13)
cluster_neurals.append(classNeural(28*28,10,1))
因此叢集類神經網路的訓練包含多個類神經網路的運算,訓練過程當中沒有輸出畫面,可能造成一些錯誤判斷;因此訓練迴圈過程中,可以先安裝一個簡單好用的「tqdm」程式庫來即時回映訓練進度。
pip install tqdm
因為總共有 10 組分類目標以及 10 個類神經網路;因此,依序每個類神網路放入「gpu」進行訓練迴圈執行;各別類神類網路訓練完之後,透過「load_state_dict()」函數將訓練好的類神經網路的權重,在「cpu」上存回叢集類神經網路物件序列「cluster_neurals」。
from tqdm import tqdm
#-------------
# training neural network
for ptType in tqdm(range(nType)):
Y_train=cluster_Y_train[ptType]
imgNeural=cluster_neurals[ptType]
imgNeural.to(device)
optimizer=torch.optim.AdamW(imgNeural.parameters(),lr=0.01)
loss_fn=nn.MSELoss() # MSE
for epoche in range(100):
imgNeural.train()
Y_pred=imgNeural(X_train)
loss=loss_fn(Y_pred,Y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
imgNeural.to('cpu')
cluster_neurals[ptType].load_state_dict(imgNeural.state_dict())
業集類神經網路訓練之後的結果,可以想成是各個分類的機率;因此可以透過「round()」函數來轉換成整數;列出來之後可以看到在 16 筆圖形資料,各個被分類到的目標類別的「布林值」;再利用「where()」函數找到目標位置,整合成預測結果;最後可以看到,預測的分類結果跟目標分類項目值完全一致。
import numpy as np
#------------
# predition
y_pred=np.zeros(nData).astype('int')
for ptType in range(nType):
imgNeural=cluster_neurals[ptType]
imgNeural.to(device).eval()
with torch.inference_mode():
Y_output=imgNeural(X_train)
y_output=np.round(Y_output.squeeze(dim=1).to('cpu').numpy()).astype('int')
print('cluster #',(ptType+1),':',y_output)
ix=np.where(y_output==1)
y_pred[ix]=ptType
同樣地隨機選擇影像來進行測試,也可以得到一樣的結果。
def clusterPrediction(cluster_neurals,PixelInput,device):
nData,nPixel=PixelInput.shape
y_pred=np.zeros(nData).astype('int')
for ptType in range(nType):
imgNeural=cluster_neurals[ptType]
imgNeural.to(device).eval()
with torch.inference_mode():
Y_output=imgNeural(PixelInput)
y_output=np.round(Y_output.squeeze(dim=1).to('cpu').numpy()).astype('int')
ix=np.where(y_output==1)
y_pred[ix]=ptType
return y_pred
#-------------
import random
random.seed(13)
fig=plt.figure(figsize=(9,9))
rows,cols=4,4
for i in range(rows*cols):
ix=random.randint(0,15)
#---------- handle input tensor
ImgInput=(train_data.data[ix]-255/2.0)/255
PixelInput=ImgInput.flatten().unsqueeze(dim=0).to(device)
#---------- neural network prediction
labelPred=clusterPrediction(cluster_neurals,PixelInput,device)
#---------- transfer output into label text
titlePred=train_data.classes[int(labelPred)]
titleTarget=train_data.classes[train_data.targets[ix]]
#---------- plot
fig.add_subplot(rows,cols,i+1)
plt.imshow(ImgInput.to('cpu'),cmap='gray')
strTitle=titleTarget+'->'+titlePred
plt.title(strTitle)
plt.axis(False)
plt.show()