(ML) 解決 RuntimeError: { NSLocalizedDescription = “The size of the output layer ‘xxxx’ in the neural network does not match the number of classes in the classifier.”; }

YEN HUNG CHENG
11 min readJun 11, 2023

--

Photo by Andrew Neel on Unsplash

我根據一篇文章學習了如何使用PyTorch Lightning和CoreML,在Apple神經網路引擎中實現加速運算。然而,在按照文章進行實作時遇到了一些錯誤。

文章的目標:利用 PyTorch Lightning 訓練一個 400 種鳥類的分類器,並能夠在 Macbook 與 iPhone 上進行推理,且整體訓練過程也會在 Macbook Air M1 上進行訓練,但按照文章進行環境配置及訓練模型後,在最後推理會遇到以下幾種錯誤

Error message 1

Cuda error(環境適配錯誤)

按照文章適配環境時,若是先安裝 pytorch 再安裝 pytorch_lightning 的話,pytorch_lightning 會將原本安裝好的 pytorch, cuda cudnn 版本對應打亂,解決方法,可以先安裝 pytorch_lightning,再執行安裝指定的 pytorch, cuda, cudnn 版本即可解決。

Error message 2

KeyError: ‘class index’

下載的 bird_data 中的 bird.csv 中的 class id 改為 class index 即可解決

Error message 3

TypeError: Accuracy.__new__() missing 1 required positional argument: ‘task’

打開 py_utils/module.py ,將 Accuracy() 改為 Accuracy(num_classes=class_num, task=’multiclass’) ,並且關閉所有頁面,重開 jupyter notebook

#         self.train_acc = Accuracy()
self.train_acc = Accuracy(num_classes=class_num, task='multiclass')

self.val_loss = nn.CrossEntropyLoss()
# self.val_acc = Accuracy()
self.val_acc = Accuracy(num_classes=class_num, task='multiclass')

Error message 4 (本篇重點)

RuntimeError: { NSLocalizedDescription = “The size of the output layer ‘var_324’ in the neural network does not match the number of classes in the classifier.”; }

Inference on Pytorch 是正常可以使用的,不過將模型轉換為 CoreML 時,並 Inference on Mac 時,會出現 神經網絡中輸出層 ‘var_324’ 的大小與分類器中的類數不匹配的問題,所以我就開始不斷找尋問題的解答。

模型測試

首先先將模型加入任一的 Xcode 專案中

點選 Preview 後,將任一照片拉入其中

出現 Unexpected Error 錯誤

正常情況下會出現以下結果

模型可視化測試

使用 Netron 可視化模型

再次回想一下 error message 神經網絡中輸出層 ‘var_324’ 的大小與分類器中的類數不匹配 ,這時我的想法是明明訓練模型時,我在使用 PyTorch 訓練時的輸出是 400 ,為何還是出現了類數不匹配的問題?

官方模型可視化

下載任一同為圖像分類的模型進行可視化,Ex: Resnet50、MobileNetV2、SqueezeNet

Resnet50.mlmodel

嘗試改變模型輸入與輸出名稱

打開 pt2ct.py 進行修改

import torch
from py_utils.module import Model
import coremltools as ct

if __name__ == '__main__':
model = Model.load_from_checkpoint(
"best_model/birds-epoch=00-val_loss=0.64.ckpt.ckpt")
X = torch.rand(1, 3, 112, 112)

image_input = ct.ImageType(name="image",
shape=X.shape,
scale=1/255.0)

model.to_torchscript(file_path="best_model/model_trace.pt", method='trace',
example_inputs=X)

traced_model = torch.jit.trace(torch.load('best_model/model_trace.pt'), X)

output = ct.TensorType(name="classLabelProbs")

model = ct.convert(
traced_model,
inputs=[image_input],
outputs=[output],
classifier_config=ct.ClassifierConfig('data/bird_data/labelname.txt'),
compute_units=ct.ComputeUnit.ALL,
)


model.save("best_model/bird3.mlmodel")

再次將模型可視化

Input 名稱與 Output 名稱已經變為與官方模型相同名稱,但是還是會出現一樣的 error message ,只是現在錯誤的名稱變為 classLabelProbs 而已,還有唯一不同的地方是沒有 softmax

解決問題

最後我在 Xcode 的 bird3.mlmodel 模型的 General 的 Class Labels 發現了一個問題,也就是在 Class Labels 會顯示你訓練的標籤數量,在這顯示了 515 種標籤類別,但在教學文章中表示為 400 種分類

這時候我計算將從 kaggle 下載的 dataset 的資料數量,我才發現原來真的有 515 種的鳥類資料

array = []

with open('data/bird_data/labelname.txt', 'r') as file:
for line in file:
line = line.strip() # 去除行尾的換行符號
array.append(line)

print(len(array)) # 515

最終我將 trainer_lightning.py 中的 400 改為 515

if __name__ == '__main__':

data_paths = ['best_model', 'data']

for path in data_paths:
if not os.path.exists(path):
os.mkdir(path)

data_df = pd.read_csv('data/bird_data/birds.csv')

data = DataModule(128, data_df)
# 將 400 改為 515
model = Model(515)

並且在 module.py 加入 softmax 進行訓練

    def forward(self, x):
out = self.model(x)
# 加入 softmax
out = F.softmax(out, dim=1)
return out

訓練後的模型轉換為 CoreML model 進行可視化

innerProduct 維度變為 515 x 512

但是這會有一個小問題,也就是在 pytorch 中的 softmax 轉換後,會轉換成 softmaxND

在 Xcode 進行測試

最終成功解決問題,最終發現是訓練資料的數量,跟最終輸出的維度對不上才會出現類似的問題,甚至在轉換 CoreML 時,也必須給定每筆資料的標籤才能順利轉換。

Similar Error Message

(pytorch) 將 yolov5 轉換成 CoreML 出現相似的問題

(pytorch) 將 yolov7 轉換成 CoreML 出現相似的問題

(keras) 進行二元分類的模型,模型最後轉換成 CoreML 出現相似的問題

(keras) 訓練 LSTM 下一個字符/單詞預測器,轉換為 CoreML 出現相似的問題

--

--