1.遇到報錯:ValueError: optimizer got an empty parameter list
在pycharm上也是報相同的錯誤
完整代碼:

1 import torch 2 import torch.nn as nn 3 from torch.optim import SGD 4 import torch.utils.data as Data 5 from sklearn.datasets import load_boston 6 from sklearn.preprocessing import StandardScaler 7 import pandas as pd 8 import numpy as np 9 import matplotlib.pyplot as plt 10 ##讀取數據 11 boston_X,boston_y= load_boston(return_X_y=True) 12 print("boston_X.shape:",boston_X.shape) 13 plt.figure() 14 plt.hist(boston_y,bins=20) 15 plt.show() 16 ##數據標准化處理 17 ss = StandardScaler(with_mean=True,with_std=True) 18 boston_Xs= ss.fit_transform(boston_X) 19 ##將數據預處理為可以使用pytorch進行批量訓練的形式 20 ##訓練X轉化為張量 21 train_xt= torch.from_numpy(boston_Xs.astype(np.float32)) 22 ##訓練集y轉化為張量 23 train_yt = torch.from_numpy(boston_y.astype(np.float32)) 24 ##將訓練集轉化為張量后,使用TensorDataset將X和Y整理到一起 25 train_data = Data.TensorDataset(train_xt,train_yt) 26 ##定義一個數據加載器,將訓練數據集進行批量處理 27 train_loader = Data.DataLoader( 28 dataset = train_data, ##使用的數據集 29 batch_size = 128, ##批量處理樣本的大小 30 shuffle = True, ##每次迭代前打亂數據 31 num_workers = 1, ##使用兩個進程 32 ) 33 ##使用繼承Module的方式定義全連接神經網絡 34 class MLPmodel(nn.Module): 35 def _init_(self): 36 super(MLPmodel,self)._init_() 37 ##定義第一個隱藏層 38 self.hidden1 = nn.Linear( 39 in_features = 13, ##第一個隱藏層的輸入,數據的特征數 40 out_feature = 10, ##第一個隱藏層的輸出,神經元的數量 41 bias = True, 42 ) 43 self.activel = nn.ReLU() 44 ##定義第二個隱藏層 45 self.hidden2 = nn.Linear(10,10) 46 self.active2 = nn.ReLU() 47 ##定義預測回歸層 48 self.regression = nn.Linear(10,1) 49 ##定義網絡的前向傳播路徑 50 def forward(self, x): 51 x=self.hidden1(x) 52 x=self.active1(x) 53 x=self.hidden2(x) 54 x=self.active2(x) 55 output=self.regression(x) 56 ##輸出為output 57 return output 58 ##輸出網絡結構 59 mlp1 = MLPmodel() 60 print(mlp1) 61 ##對回歸模型mlp1進行訓練並輸出損失函數的變化情況,定義優化器和損失函數 62 optimizer = SGD(mlp1.parameters(),lr=0.001) 63 loss_func = nn.MSELoss() ##最小均方根誤差 64 train_loss_all = [ ] ##輸出每個批次訓練的損失函數 65 ##進行訓練,並輸出每次迭代的損失函數 66 for epoch in range(30): 67 ##對訓練數據的加載器進行迭代計算 68 for step,(b_x,b_y) in enumerate(train_loader): 69 output = mlp1(b_x).flatten() ##MLP在訓練batch上的輸出 70 train_loss = loss_func(output,b_y) ##均方根誤差 71 optimizer.zero_grad() ##每個迭代步的梯度初始化為0 72 train_loss.backward() ##損失的向后傳播,計算梯度 73 optimizer.step() ##使用梯度進行優化 74 train_loss_all.append(train_loss.item()) 75 plt.figure() 76 plt.plot(train_loss_all,"r-") 77 plt.title("Train loss per iteration") 78 plt.show()
解決:
在寫_init_的時候左右邊上一個下划線 _ ,因此報錯,但實際需要使用的代碼當中並非是這個函數,而是__init__ ,即左右兩邊是兩個下划線
此錯誤為低級錯誤,缺花費了很多時間。
2.遇到錯誤
在運行以下代碼時總是出錯
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
AttributeError: 'NoneType' object has no attribute 'shape'
原因可能是:當使用cv2的時候,1.圖片不存在(路徑不存在, 路徑包含中文無法識別) 2.讀取的圖片內容和默認讀取時參數匹配不匹配。(默認讀取的是3通道的彩色圖)例如讀取到的圖片是灰度圖,就會返回None。
在我這個運行的代碼當中,其中是第一種,其中路徑包含了中文,因此報錯,只需將中文切換為中文即可。

## 導入本章所需要的模塊 import numpy as np import pandas as pd import matplotlib.pyplot as plt import requests import cv2 import torch from torch import nn import torch.nn.functional as F from torchvision import models from torchvision import transforms from PIL import Image ## 導入預訓練好的VGG16網絡 vgg16 = models.vgg16(pretrained=True) print(vgg16) ## 讀取一張圖片,並對其進行可視化 im = Image.open("data/chap6/大象.jpg") imarray = np.asarray(im) / 255.0 plt.figure() plt.imshow(imarray) plt.show() imarray.shape ## 對一張圖像處理為vgg16網絡可以處理的形式 data_transforms = transforms.Compose([ transforms.Resize((224,224)),# 重置圖像分辨率 transforms.ToTensor(),# 轉化為張量並歸一化至[0-1] transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) input_im = data_transforms(im).unsqueeze(0) print("input_im.shape:",input_im.shape) ## 使用鈎子獲取分類層的2個特征 ## 定義一個輔助函數,來獲取指定層名稱的特征 activation = {} ## 保存不同層的輸出 def get_activation(name): def hook(model, input, output): activation[name] = output.detach() return hook ## 獲取中間的卷積后的圖像特征 vgg16.eval() ## 第四層,經過第一次最大值池化 vgg16.features[4].register_forward_hook(get_activation("maxpool1")) _ = vgg16(input_im) maxpool1 = activation["maxpool1"] print("獲取特征的尺寸為:",maxpool1.shape) ## 對中間層進行可視化,可視化64個特征映射 plt.figure(figsize=(11,6)) for ii in range(maxpool1.shape[1]): ## 可視化每張手寫體 plt.subplot(6,11,ii+1) plt.imshow(maxpool1.data.numpy()[0,ii,:,:],cmap="gray") plt.axis("off") plt.subplots_adjust(wspace=0.1, hspace=0.1) plt.show() ## 獲取更深層次的卷積后的圖像特征 vgg16.eval() vgg16.features[21].register_forward_hook(get_activation("layer21_conv")) _ = vgg16(input_im) layer21_conv = activation["layer21_conv"] print("獲取特征的尺寸為:",layer21_conv.shape) ## 對中間層進行可視化,只可視化前72個特征映射 plt.figure(figsize=(12,6)) for ii in range(72): ## 可視化每張手寫體 plt.subplot(6,12,ii+1) plt.imshow(layer21_conv.data.numpy()[0,ii,:,:],cmap="gray") plt.axis("off") plt.subplots_adjust(wspace=0.1, hspace=0.1) plt.show() ## 獲取vgg模型訓練時對應的1000類的類別標簽 LABELS_URL = "https://s3.amazonaws.com/outcome-blog/imagenet/labels.json" # 從網頁鏈接中獲取類別標簽 response = requests.get(LABELS_URL) labels = {int(key): value for key, value in response.json().items()} ## 使用VGG16網絡預測圖像的種類 vgg16.eval() im_pre = vgg16(input_im) ## 計算預測top-5的可能性 softmax = nn.Softmax(dim=1) im_pre_prob = softmax(im_pre) prob,prelab = torch.topk(im_pre_prob,5) prob = prob.data.numpy().flatten() prelab = prelab.numpy().flatten() for ii,lab in enumerate(prelab): print("index: ", lab ," label: ",labels[lab]," ||",prob[ii]) # African elephant 非洲大象 # tusker 長牙動物 # Indian elephant 印度象,亞洲象屬maximus # water buffalo 水牛 # Weimaraner 威馬 ## 定義一個萌購輸出最后的卷機層輸出和梯度的新的網絡 class MyVgg16(nn.Module): def __init__(self): super(MyVgg16, self).__init__() # 使用預訓練好的VGG16模型 self.vgg = models.vgg16(pretrained=True) # 切分vgg6模型,便於獲取卷積層的輸出 self.features_conv = self.vgg.features[:30] # 使用原始的最大值池化層 self.max_pool = self.vgg.features[30] self.avgpool = self.vgg.avgpool # 使用vgg16的分類層 self.classifier = self.vgg.classifier # 生成梯度占位符 self.gradients = None # 獲取地圖的鈎子函數 def activations_hook(self, grad): self.gradients = grad def forward(self, x): x = self.features_conv(x) # 注冊鈎子 h = x.register_hook(self.activations_hook) # 對卷積后的輸出使用最大值池化 x = self.max_pool(x) x = self.avgpool(x) x = x.view((1, -1)) x = self.classifier(x) return x # 獲取梯度的方法 def get_activations_gradient(self): return self.gradients # 獲取卷機層輸出的方法 def get_activations(self, x): return self.features_conv(x) # 初始化網絡 vggcam = MyVgg16() # 設置網絡的模式 vggcam.eval() ## 計算網絡對圖像的預測值 im_pre = vggcam(input_im) ## 計算預測top-5的可能性 softmax = nn.Softmax(dim=1) im_pre_prob = softmax(im_pre) prob, prelab = torch.topk(im_pre_prob, 5) prob = prob.data.numpy().flatten() prelab = prelab.numpy().flatten() for ii, lab in enumerate(prelab): print("index: ", lab, " label: ", labels[lab], " ||", prob[ii]) ## 這里預測結果和前面的一樣,可能性最大的是第101個編號 # 獲取相對於模型參數的輸出梯度 im_pre[:, prelab[0]].backward() # 獲取模型的梯度 gradients = vggcam.get_activations_gradient() # 計算梯度相應通道的均值 mean_gradients = torch.mean(gradients, dim=[0, 2, 3]) # 獲取圖像在相應卷積層輸出的卷積特征 activations = vggcam.get_activations(input_im).detach() # m每個通道乘以相應的梯度均值 for i in range(len(mean_gradients)): activations[:, i, :, :] *= mean_gradients[i] # 計算所有通道的均值輸出得到熱力圖 heatmap = torch.mean(activations, dim=1).squeeze() # 使用relu函數作用於熱力圖 heatmap = F.relu(heatmap) # 對熱力圖進行標准化 heatmap /= torch.max(heatmap) heatmap = heatmap.numpy() # 可視化熱力圖 plt.matshow(heatmap) ## 將Grad-CAM熱力圖融合到原始圖像上 img = cv2.imread("data/chap6/aliphone.jpg") #im = Image.open("data/chap6/大象.jpg") print("大象img的尺寸為:",img.shape[1], img.shape[0]) heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) heatmap = np.uint8(255 * heatmap) heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) Grad_cam_img = heatmap * 0.4 + img Grad_cam_img = Grad_cam_img / Grad_cam_img.max() ## 可視化圖像 b,g,r = cv2.split(Grad_cam_img) Grad_cam_img = cv2.merge([r,g,b]) plt.figure() plt.imshow(Grad_cam_img) plt.show() ## 可視化老虎圖像的Grad-cam im = Image.open("data/chap6/老虎.jpg") input_im = data_transforms(im).unsqueeze(0) # 初始化網絡 vggcam = MyVgg16() # 設置網絡的模式 vggcam.eval() ## 計算網絡對圖像的預測值 im_pre = vggcam(input_im) ## 計算預測top-5的可能性 softmax = nn.Softmax(dim=1) im_pre_prob = softmax(im_pre) prob, prelab = torch.topk(im_pre_prob, 5) prob = prob.data.numpy().flatten() prelab = prelab.numpy().flatten() for ii, lab in enumerate(prelab): print("index: ", lab, " label: ", labels[lab], " ||", prob[ii]) # 獲取相對於模型參數的輸出梯度 im_pre[:, prelab[0]].backward() # 獲取模型的梯度 gradients = vggcam.get_activations_gradient() # 計算梯度相應通道的均值 mean_gradients = torch.mean(gradients, dim=[0, 2, 3]) # 獲取圖像在相應卷積層輸出的卷積特征 activations = vggcam.get_activations(input_im).detach() # m每個通道乘以相應的梯度均值 for i in range(len(mean_gradients)): activations[:, i, :, :] *= mean_gradients[i] # 計算所有通道的均值輸出得到熱力圖 heatmap = torch.mean(activations, dim=1).squeeze() # 使用relu函數作用於熱力圖 heatmap = F.relu(heatmap) # 對熱力圖進行標准化 heatmap /= torch.max(heatmap) heatmap = heatmap.numpy() # 可視化熱力圖 plt.matshow(heatmap) ## 將Grad-CAM熱力圖融合到原始圖像上 img = cv2.imread("data/chap6/老虎.jpg") heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) heatmap = np.uint8(255 * heatmap) heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) Grad_cam_img = heatmap * 0.5 + img Grad_cam_img = Grad_cam_img / Grad_cam_img.max() ## 可視化圖像 b, g, r = cv2.split(Grad_cam_img) Grad_cam_img = cv2.merge([r, g, b]) plt.figure() plt.imshow(Grad_cam_img) plt.show()