貓狗分類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文件刪掉


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM