貓狗分類CNN
貓狗分類CNN
實驗環境
編譯器 :win10+python3.7.4+pycharm2018
庫: anaconda+pytorch+tensorflow+tensorboardX
硬體 gpu(可以沒有)
效能:
accuracy:準確度大概穩定在0.6左右。這是在二分類的情況下。如果測試自己的圖片,也就是存既不是貓也不是狗的概率的話,肯惡搞準確度會更低。
loss:約為0.02
Ⅰ、解決方法
一、資料集的預處理
1.訓練集
1.1.1 初始化:提取路徑和標籤
這個問題是kaggle競賽的一個賽題。所以資料集也是由官方提供的。訓練集內容如下圖
我們可以看到,它的命名規則是 分類.序號.jpg
所以我們就只要建立兩個list,一個存路徑,一個存標籤
self.list_img = []
self.list_label = [] # 0:cat,1:dog
然後開啟訓練集,迴圈遍歷裡面的圖片
dir = train_path + '/' #train_path為訓練集資料夾 for file in os.listdir(dir): self.list_img.append(dir + file) self.data_size += 1 name = file.split(sep='.') #以'.'為界限,分割檔名 # one-hot if name[0] == 'cat': self.list_label.append(0) else: self.list_label.append(1)
採用one-hot編碼,這樣對後期計算損失函式比較友好。
1.1.2 處理圖片
思路:開啟圖片-->重新設定圖片大小-->轉換圖片為tensor的形式-->返回tensor和標籤
img = Image.open(self.list_img[item]) #item為選中的圖片序號 img = img.resize((IMAGE_H, IMAGE_W)) #重新設定圖片大小 img = np.array(img)[:, :, :3] label = self.list_label[item] return self.transform(img), torch.LongTensor([label])
其中transform函式的方法是
transforms.ToTensor()
2.測試集
1.2.1初始化:
這是大賽提供的測試集。叫測試集或許不太準確,因為他沒有打標籤。姑且叫他測試集好了。
初始化的思路比訓練集要簡單,因為沒有標籤,所以只要遍歷資料夾然後把路徑存起來。
dir = test_path + '/'
for file in os.listdir(dir):
self.list_img.append(dir + file)
self.data_size += 1
1.2.2 處理圖片
和訓練集差不多,因為沒有標籤所以只需要返回圖片就行
img = Image.open(self.list_img[item])
img = img.resize((IMAGE_H, IMAGE_W))
img = np.array(img)[:, :, :3]
return self.transform(img)
二、模型搭建
傷透心,別人程式碼隨便搭的網路都比我的效果好。果然,網路的搭建還是要有經驗。
有人說可以修改預訓練好的模型來再處理。看了好久,感覺搭了之後視覺化就不太會用了。作為新手操作不了,所以還是選擇用這樣的方法來做
def __init__(self):
super(myNet, self).__init__()
self.conv1 = torch.nn.Conv2d(3, 16, 3, padding=1)
self.conv2 = torch.nn.Conv2d(16, 16, 3, padding=1)
self.fc1 = nn.Linear(50*50*16, 128)
self.fc2 = nn.Linear(128, 64)
self.fc3 = nn.Linear(64, 2)
def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = x.view(x.size()[0], -1)
x=self.fc1(x)
x = F.relu(x)
x=self.fc2(x)
x = F.relu(x)
x = self.fc3(x)
return F.softmax(x, dim=1)
三、訓練
1.引數
訓練就是普普通通的呼叫啦,然後一些引數什麼的都寫在開頭,可以根據自己的電腦效能改一改,我的初始引數如下
writer = SummaryWriter('./runs') #視覺化儲存位置
save_model_path = './model/myModel.pth' # 模型儲存位置
workers = 10 # PyTorch讀取資料執行緒數量
batch_size = 32 # batch_size大小
lr = 0.0001 # 學習率
2.loss和準確度
因為是要有迭代的曲線。所以loss和準確度都是採用最近訓練的結果來計算的。我是以一個batch_size作為節點計算一次。
其中loss是交叉熵計演算法
for img, label in dataloader:
img, label = Variable(img).cuda(), Variable(label).cuda()
out = model(img)
loss = criterion(out, label.squeeze())
loss.backward()
optimizer.step()
optimizer.zero_grad()
cnt += 1
_, preds = torch.max(out.data, 1)
acc = float(torch.sum(preds==label.squeeze()))
print('epoch:{},acc:{:.4f}, loss: {:.4f}'.format(cnt, acc/out.size()[0],loss/batch_size))
3.結果
具體的曲線實現和展示,在視覺化部分說明
四、測試
1.test
測試方法就是隨機從測試集中提取一個圖片,然後輸出結果。
2.testMyImg
這個測試就是可以測試自己的圖片的。
與test的不同點在於,test測試的都是大賽給的資料集,所以內容不是貓就是狗。但是testMyImg是輸入自己的圖片,所以可能既沒有貓,也沒有狗。所以我設定了一個閾值VPT,只有可能性超過VPT才會判定。
可以根據自己的需求修改
VPT=0.5
注意!!因為設定的三通道,所以圖片格式為jpg
3.結果
1.test結果
2.testMyImg
3.我將整個網路結構都可視化了。具體方法在視覺化部分說明
Ⅱ 視覺化
一、工具
本來想用qypt來做一個介面,在裡面視覺化輸出的。但是中間出的叉子比較多。還涉及到多執行緒,速度太慢了。無意中發現了tensorboardX。發現太好用了!對於我這種還沒入門的新手,需要的功能還特別簡單。上手特!別!快!
tensorboardX是tensorflow下的一個視覺化工具。所以要用tensorboardX的話,要同時安裝tensorflow和tensorboardX。anaconda下安裝就行了,推薦使用豆瓣源
二、程式碼詳解
我是在訓練裡視覺化loss和accracy曲線。然後測試裡可視化了cnn網路結構和權重以及卷積核
開頭定義了儲存位置,可以根據自己的需求修改
writer = SummaryWriter('./runs') #視覺化儲存位置
1.loss和accracy曲線
用的是tensorboard的add_scalar
writer.add_scalar('loss', loss/out.size()[0], cnt)
writer.add_scalar('accuracy', acc/out.size()[0],cnt)
2.cnn網路結構視覺化
writer.add_graph(model, (img,)) # 記錄神經網路結構
3.權重、卷積核可視化
權重視覺化
for name, param in model.named_parameters():
if 'conv' in name and 'weight' in name:
in_channels = param.size()[1]
k_w, k_h = param.size()[3], param.size()[2] # 卷積核的尺寸
kernel_all = param.view(-1, 1, k_w, k_h) # 每個通道的卷積核
kernel_grid =utils.make_grid(kernel_all, normalize=True, scale_each=True, nrow=in_channels)
writer.add_image(f'{name}_all', kernel_grid, global_step=0)
卷積核特徵值視覺化(根據自己的網路結構編寫)
for name, layer in model._modules.items():
if not('conv' in name):
break
showImg=layer(showImg)
showImg=F.relu(showImg)
showImg=F.max_pool2d(showImg,2)
#
x1 = showImg.transpose(0, 1)
img_grid = utils.make_grid(x1, normalize=True, scale_each=True, nrow=4) # normalize進行歸一化處理
writer.add_image(f'{name}_feature_maps', img_grid, global_step=0)
4.其它
原圖儲存(以test為例,testMyImg也差不多)
writer.add_image('img',datafile.__getitem__(index),)
結果儲存
writer.add_text('test\' result',str)
三、使用方法
可以在命令列操作 ,輸入tensorboard =視覺化檔案所在位置
tensorboard --logdir=runs
注意!!!!!
runs檔案內容每次都會新增,而不是覆蓋。如果覺得資料有干擾的話,建議每次執行之前,把上一次的runs檔案刪掉