【圖像分類】——來來來,干了這碗EfficientNet實戰(zhàn)(Pytorch)
目錄

摘要
新建項目
導(dǎo)入所需要的庫
設(shè)置全局參數(shù)
圖像預(yù)處理
讀取數(shù)據(jù)
設(shè)置模型
設(shè)置訓(xùn)練和驗證
測試
完整代碼:
摘要
EfficientNet是谷歌2019年提出的分類模型,自從提出以后這個模型,各大競賽平臺常常能看到他的身影,成了霸榜的神器。下圖是EfficientNet—B0模型的網(wǎng)絡(luò)結(jié)構(gòu)。
k對應(yīng)的卷積核的大小,經(jīng)過1×1的卷積,然后channel放大4倍,再經(jīng)過depthwise conv3×3的卷積,然后經(jīng)過SE模塊后,再經(jīng)過1×1的卷積,把channel恢復(fù)到輸入的大小,最后和上層的輸入融合。
本文簡單介紹一下EfficientNet的網(wǎng)絡(luò)結(jié)構(gòu),主要實戰(zhàn)為主,下面講講如何使用EfficientNet實現(xiàn)貓狗分類,由于本文使用的Loss函數(shù)是CrossEntropyLoss,所以只需更改類別的個數(shù)就可以實現(xiàn)多分類。
新建項目
新建一個圖像分類的項目,data里面放數(shù)據(jù)集,dataset文件夾中自定義數(shù)據(jù)的讀取方法,這次我不采用默認的讀取方式,太簡單沒啥意思。然后再新建train.py和test.py
在項目的根目錄新建train.py,然后在里面寫訓(xùn)練代碼。
導(dǎo)入所需要的庫
首先檢查有沒有安裝EfficientNet的庫,如果沒有安裝則執(zhí)行pip install efficientnet_pytorch安裝EfficientNet庫,安裝后再導(dǎo)入。
import torch.optim as optim import torch import torch.nn as nn import torch.nn.parallel import torch.optim import torch.utils.data import torch.utils.data.distributed import torchvision.transforms as transforms from dataset.dataset import DogCat from torch.autograd import Variable from efficientnet_pytorch import EfficientNet #pip install efficientnet_pytorch
設(shè)置全局參數(shù)
設(shè)置BatchSize、學(xué)習(xí)率和epochs,判斷是否有cuda環(huán)境,如果沒有設(shè)置為cpu。
# 設(shè)置全局參數(shù)
modellr = 1e-4
BATCH_SIZE = 64
EPOCHS = 20
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
圖像預(yù)處理
在做圖像與處理時,train數(shù)據(jù)集的transform和驗證集的transform分開做,train的圖像處理出了resize和歸一化之外,還可以設(shè)置圖像的增強,比如旋轉(zhuǎn)、隨機擦除等一系列的操作,驗證集則不需要做圖像增強,另外不要盲目的做增強,不合理的增強手段很可能會帶來負作用,甚至出現(xiàn)Loss不收斂的情況。
# 數(shù)據(jù)預(yù)處理
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
transform_test = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
讀取數(shù)據(jù)
數(shù)據(jù)集地址:鏈接:https://pan.baidu.com/s/1ZM8vDWEzgscJMnBrZfvQGw?提取碼:48c3
將其下載后解壓放到data文件夾中。數(shù)據(jù)的目錄如下圖:
然后我們在dataset文件夾下面新建?__init__.py和dataset.py,在dataset.py文件夾寫入下面的代碼:
# coding:utf8 import os from PIL import Image from torch.utils import data from torchvision import transforms as T from sklearn.model_selection import train_test_split class DogCat(data.Dataset): def __init__(self, root, transforms=None, train=True, test=False): """ 主要目標: 獲取所有圖片的地址,并根據(jù)訓(xùn)練,驗證,測試劃分數(shù)據(jù) """ self.test = test self.transforms = transforms imgs = [os.path.join(root, img) for img in os.listdir(root)] if self.test: imgs = sorted(imgs, key=lambda x: int(x.split('.')[-2].split('/')[-1])) else: imgs = sorted(imgs, key=lambda x: int(x.split('.')[-2])) if self.test: self.imgs = imgs else: trainval_files, val_files = train_test_split(imgs, test_size=0.3, random_state=42) if train: self.imgs = trainval_files else: self.imgs = val_files def __getitem__(self, index): """ 一次返回一張圖片的數(shù)據(jù) """ img_path = self.imgs[index] if self.test: label =-1 else: label = 1 if 'dog' in img_path.split('/')[-1] else 0 data = Image.open(img_path) data = self.transforms(data) return data, label def __len__(self): return len(self.imgs)
然后我們在train.py調(diào)用DogCat讀取數(shù)據(jù)
dataset_train = DogCat('data/train', transforms=transform, train=True) dataset_test = DogCat("data/train", transforms=transform_test, train=False) # 讀取數(shù)據(jù) print(dataset_train.imgs) # 導(dǎo)入數(shù)據(jù) train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True) test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=False)
設(shè)置模型
使用CrossEntropyLoss作為loss,模型采用efficientnet-B3。更改最后一層的全連接,將類別設(shè)置為2,然后將模型放到DEVICE。優(yōu)化器選用Adam。
# 實例化模型并且移動到GPU criterion = nn.CrossEntropyLoss() model_ft = EfficientNet.from_pretrained('efficientnet-b3') num_ftrs = model_ft._fc.in_features model_ft._fc = nn.Linear(num_ftrs, 2) model_ft.to(DEVICE) # 選擇簡單暴力的Adam優(yōu)化器,學(xué)習(xí)率調(diào)低 optimizer = optim.Adam(model_ft.parameters(), lr=modellr) def adjust_learning_rate(optimizer, epoch): """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" modellrnew = modellr * (0.1 ** (epoch // 50)) print("lr:", modellrnew) for param_group in optimizer.param_groups: param_group['lr'] = modellrnew
設(shè)置訓(xùn)練和驗證
# 定義訓(xùn)練過程 def train(model, device, train_loader, optimizer, epoch): model.train() sum_loss = 0 total_num = len(train_loader.dataset) print(total_num, len(train_loader)) for batch_idx, (data, target) in enumerate(train_loader): data, target = Variable(data).to(device), Variable(target).to(device) output = model(data) loss = criterion(output, target) optimizer.zero_grad() loss.backward() optimizer.step() print_loss = loss.data.item() sum_loss += print_loss if (batch_idx + 1) % 50 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, (batch_idx + 1) * len(data), len(train_loader.dataset), 100. * (batch_idx + 1) / len(train_loader), loss.item())) ave_loss = sum_loss / len(train_loader) print('epoch:{},loss:{}'.format(epoch, ave_loss)) # 驗證過程 def val(model, device, test_loader): model.eval() test_loss = 0 correct = 0 total_num = len(test_loader.dataset) print(total_num, len(test_loader)) with torch.no_grad(): for data, target in test_loader: data, target = Variable(data).to(device), Variable(target).to(device) output = model(data) loss = criterion(output, target) _, pred = torch.max(output.data, 1) correct += torch.sum(pred == target) print_loss = loss.data.item() test_loss += print_loss correct = correct.data.item() acc = correct / total_num avgloss = test_loss / len(test_loader) print('\nVal set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( avgloss, correct, len(test_loader.dataset), 100 * acc)) # 訓(xùn)練 for epoch in range(1, EPOCHS + 1): adjust_learning_rate(optimizer, epoch) train(model_ft, DEVICE, train_loader, optimizer, epoch) val(model_ft, DEVICE, test_loader) torch.save(model_ft, 'model.pth')
完成上面的代碼后就可以開始訓(xùn)練,點擊run開始訓(xùn)練,如下圖:
由于我們使用了預(yù)訓(xùn)練模型,所以收斂速度很快。
測試
我介紹兩種常用的測試方式,第一種是通用的,通過自己手動加載數(shù)據(jù)集然后做預(yù)測,具體操作如下:
測試集存放的目錄如下圖:
第一步 定義類別,這個類別的順序和訓(xùn)練時的類別順序?qū)?yīng),一定不要改變順序!!!!我們在訓(xùn)練時,cat類別是0,dog類別是1,所以我定義classes為(cat,dog)。
第二步 定義transforms,transforms和驗證集的transforms一樣即可,別做數(shù)據(jù)增強。
第三步 加載model,并將模型放在DEVICE里,
第四步 讀取圖片并預(yù)測圖片的類別,在這里注意,讀取圖片用PIL庫的Image。不要用cv2,transforms不支持。
import torch.utils.data.distributed import torchvision.transforms as transforms import torchvision.datasets as datasets from PIL import Image from torch.autograd import Variable import os classes = ('cat', 'dog') transform_test = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = torch.load("model.pth") model.eval() model.to(DEVICE) path='data/test/' testList=os.listdir(path) for file in testList: img=Image.open(path+file) img=transform_test(img) img.unsqueeze_(0) img = Variable(img).to(DEVICE) out=model(img) # Predict _, pred = torch.max(out.data, 1) print('Image Name:{},predict:{}'.format(file,classes[pred.data.item()]))
運行結(jié)果:
第二種使用我們剛才定義的dataset.py加載測試集。代碼如下:
import torch.utils.data.distributed import torchvision.transforms as transforms from dataset.dataset import DogCat from torch.autograd import Variable classes = ('cat', 'dog') transform_test = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = torch.load("model.pth") model.eval() model.to(DEVICE) dataset_test =DogCat('data/test/', transform_test,test=True) print(len(dataset_test)) # 對應(yīng)文件夾的label for index in range(len(dataset_test)): item = dataset_test[index] img, label = item img.unsqueeze_(0) data = Variable(img).to(DEVICE) output = model(data) _, pred = torch.max(output.data, 1) print('Image Name:{},predict:{}'.format(dataset_test.imgs[index], classes[pred.data.item()])) index += 1
完整代碼:
train.py
import torch.optim as optim import torch import torch.nn as nn import torch.nn.parallel import torch.optim import torch.utils.data import torch.utils.data.distributed import torchvision.transforms as transforms from dataset.dataset import DogCat from torch.autograd import Variable from efficientnet_pytorch import EfficientNet #pip install efficientnet_pytorch # 設(shè)置全局參數(shù) modellr = 1e-4 BATCH_SIZE = 32 EPOCHS = 10 DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 數(shù)據(jù)預(yù)處理 transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) transform_test = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) dataset_train = DogCat('data/train', transforms=transform, train=True) dataset_test = DogCat("data/train", transforms=transform_test, train=False) # 讀取數(shù)據(jù) print(dataset_train.imgs) # 導(dǎo)入數(shù)據(jù) train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True) test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=False) # 實例化模型并且移動到GPU criterion = nn.CrossEntropyLoss() model_ft = EfficientNet.from_pretrained('efficientnet-b3') num_ftrs = model_ft._fc.in_features model_ft._fc = nn.Linear(num_ftrs, 2) model_ft.to(DEVICE) # 選擇簡單暴力的Adam優(yōu)化器,學(xué)習(xí)率調(diào)低 optimizer = optim.Adam(model_ft.parameters(), lr=modellr) def adjust_learning_rate(optimizer, epoch): """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" modellrnew = modellr * (0.1 ** (epoch // 50)) print("lr:", modellrnew) for param_group in optimizer.param_groups: param_group['lr'] = modellrnew # 定義訓(xùn)練過程 def train(model, device, train_loader, optimizer, epoch): model.train() sum_loss = 0 total_num = len(train_loader.dataset) print(total_num, len(train_loader)) for batch_idx, (data, target) in enumerate(train_loader): data, target = Variable(data).to(device), Variable(target).to(device) output = model(data) loss = criterion(output, target) optimizer.zero_grad() loss.backward() optimizer.step() print_loss = loss.data.item() sum_loss += print_loss if (batch_idx + 1) % 50 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, (batch_idx + 1) * len(data), len(train_loader.dataset), 100. * (batch_idx + 1) / len(train_loader), loss.item())) ave_loss = sum_loss / len(train_loader) print('epoch:{},loss:{}'.format(epoch, ave_loss)) # 驗證過程 def val(model, device, test_loader): model.eval() test_loss = 0 correct = 0 total_num = len(test_loader.dataset) print(total_num, len(test_loader)) with torch.no_grad(): for data, target in test_loader: data, target = Variable(data).to(device), Variable(target).to(device) output = model(data) loss = criterion(output, target) _, pred = torch.max(output.data, 1) correct += torch.sum(pred == target) print_loss = loss.data.item() test_loss += print_loss correct = correct.data.item() acc = correct / total_num avgloss = test_loss / len(test_loader) print('\nVal set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( avgloss, correct, len(test_loader.dataset), 100 * acc)) # 訓(xùn)練 for epoch in range(1, EPOCHS + 1): adjust_learning_rate(optimizer, epoch) train(model_ft, DEVICE, train_loader, optimizer, epoch) val(model_ft, DEVICE, test_loader) torch.save(model_ft, 'model.pth')
test1.py
import torch.utils.data.distributed import torchvision.transforms as transforms import torchvision.datasets as datasets from PIL import Image from torch.autograd import Variable import os classes = ('cat', 'dog') transform_test = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = torch.load("model.pth") model.eval() model.to(DEVICE) path='data/test/' testList=os.listdir(path) for file in testList: img=Image.open(path+file) img=transform_test(img) img.unsqueeze_(0) img = Variable(img).to(DEVICE) out=model(img) # Predict _, pred = torch.max(out.data, 1) print('Image Name:{},predict:{}'.format(file,classes[pred.data.item()]))
test2.py
import torch.utils.data.distributed import torchvision.transforms as transforms from dataset.dataset import DogCat from torch.autograd import Variable classes = ('cat', 'dog') transform_test = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = torch.load("model.pth") model.eval() model.to(DEVICE) dataset_test =DogCat('data/test/', transform_test,test=True) print(len(dataset_test)) # 對應(yīng)文件夾的label for index in range(len(dataset_test)): item = dataset_test[index] img, label = item img.unsqueeze_(0) data = Variable(img).to(DEVICE) output = model(data) _, pred = torch.max(output.data, 1) print('Image Name:{},predict:{}'.format(dataset_test.imgs[index], classes[pred.data.item()])) index += 1
圖像分類EfficientNet實戰(zhàn).zip-深度學(xué)習(xí)文檔類資源-CSDN下載
pytorch 網(wǎng)絡(luò)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。