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()