SVHN02baseline學習

順著文檔理解代碼,加備注

import os, sys, glob, shutil, json

os.environ["CUDA_VISIBLE_DEVICES"]= '0'

import cv2

from PILimport Image

import numpyas np

from tqdmimport tqdm, tqdm_notebook

import torch

torch.manual_seed(0)

torch.backends.cudnn.deterministic= False

torch.backends.cudnn.benchmark= True

import torchvision.modelsas models

import torchvision.transformsas transforms

import torchvision.datasetsas datasets

import torch.nnas nn

import torch.nn.functionalas F

import torch.optimas optim

from torch.autogradimport Variable

from torch.utils.data.datasetimport Dataset

#定義好讀取圖像的Dataset的類

#屬性img_path, img_label, transform,方法__getitem__,__len__

class SVHNDataset(object):

? ? def __init__(self,img_path,img_label,transform=None):

? ? ? ? self.img_path= img_path

? ? ? ? self.img_label= img_label

? ? ? ? if transform is not None:

? ? ? ? ? ? self.transform= transform

? ? ? ? else:

? ? ? ? ? ? self.transform= None

? ? #返回index的圖像和標簽

? ? def __getitem__(self,index):

? ? ? ? img= Image.open(self.img_path[index]).convert('RGB')

if self.transformis? not None :

? ? ? ? ? ? img= self.transform(img)

# 設置最?的字符?度為5個

? ? ? ? lbl= np.array(self.img_label[index],dtype= np.int)

#組合標簽時用list隨意加入元素——np.array類型——張量

? ? ? ? lbl= list(lbl)+ (5-len(lbl))* [10]

return img,torch.from_numpy(np.array(lbl[:5]))

def __len__(self):

? ? ? ? return len(self.img_path)

#定義訓練和驗證數(shù)據(jù)的Dataset

def getDataSet():

? ? # 訓練數(shù)據(jù)的Dataset

? ? #查找符合特定規(guī)則的文件路徑名,獲取所有的匹配路徑(用完全的路徑別用../)

? ? train_path= glob.glob(r'D:/competition/tianchi/cv/SVHN/input/mchar_train/mchar_train/*.png')

train_path.sort()

train_json= json.load(open('D:/competition/tianchi/cv/SVHN/input/train.json'))

#json格式:"000000.png": {"height": [219, 219], "label": [1, 9], "left": [246, 323], "top": [77, 81], "width": [81, 96]},

? ? #train_json[x]是dict,索引:D2['name'] = 'Bob'

? ? train_label= [train_json[x]['label']for xin train_json]

print(len(train_path),len(train_label))

#dataloader對dataset封裝以批量迭代讀取,圖像和標簽讀取成SVHNDataset類,數(shù)據(jù)擴充,

? ? #數(shù)據(jù)加載器。組合數(shù)據(jù)集和采樣器,并在數(shù)據(jù)集上提供單進程或多進程迭代器。

? ? train_loader= torch.utils.data.DataLoader(

SVHNDataset(train_path, train_label,#(input, target)

? ? transforms.Compose([#將多種變換組合在一起

? ? ? ? transforms.Resize((64,128)),#指定大小,縮放到固定尺?

? ? ? ? transforms.RandomCrop((60,120)),#在一個隨機的位置進行裁

? ? ? ? transforms.ColorJitter(0.3,0.3,0.2),#隨機改變圖像的亮度對比度和飽和度

? ? ? ? transforms.RandomRotation(5),# 加?隨機旋轉

#convert a PIL image to tensor (HWC) in range [0,255] then to a torch.Tensor(CHW) in the range [0.0,1.0]

? ? ? ? transforms.ToTensor(),# 將圖?轉換為pytorch 的tesntor

#用給定的均值和標準差分別對每個通道的數(shù)據(jù)進行正則化。均值(M1,…,Mn),給定標準差(S1,…,Sn)

#output[channel] = (input[channel] - mean[channel]) / std[channel],如((0,1)-0.5)/0.5=(-1,1)

? ? ? ? transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225])

])),

batch_size=40,#每個batch加載多少個樣本

? ? #shuffle=True,? ? #在每個epoch重新打亂數(shù)據(jù),默認false

? ? #num_workers=10,? #用多少個子進程加載數(shù)據(jù)

? ? )

#驗證數(shù)據(jù)的dataset

? ? val_path= glob.glob('D:/competition/tianchi/cv/SVHN/input/mchar_val/mchar_val/*.png')

val_path.sort()

val_json= json.load(open('D:/competition/tianchi/cv/SVHN/input/val.json'))

val_label= [val_json[x]['label']for xin val_json]

print(len(val_path),len(val_label))

val_loader= torch.utils.data.DataLoader(

SVHNDataset(val_path, val_label,

transforms.Compose([

transforms.Resize((60,120)),

# transforms.ColorJitter(0.3, 0.3, 0.2),

# transforms.RandomRotation(5),

? ? ? ? transforms.ToTensor(),

transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225])

])),

batch_size=40,

shuffle=False,

num_workers=10,)

return train_loader,val_loader

#output

train_loader,val_loader= getDataSet()#輸出應當為30000 30000 10000 10000

#構建CNN模型

class SVHN_model_1(nn.Module):

? ? #super指代父類,繼承的時候,調用含super的各個的基類__init__函數(shù)

? ? def __init__(self):

? ? ? ? super(SVHN_model_1,self).__init__()

#cnn提取特征模塊

? ? ? ? #一個有序的容器,神經網(wǎng)絡模塊將按照在傳入構造器的順序依次被添加到計算圖中執(zhí)行,同時以神經網(wǎng)絡模塊為元素的有序字典也可以作為傳入?yún)?shù)。

? ? ? ? self.cnn= nn.Sequential(

nn.Conv2d(3,16,kernel_size=(3,3),stride=(2,2)),

nn.ReLU(),

nn.MaxPool2d(2),

nn.Conv2d(16,32,kernel_size=(3,3),stride=(2,2)),

nn.ReLU(),

nn.MaxPool2d(2),

)

#對傳入數(shù)據(jù)應用線性變換:y = A x+ b,(每個輸入樣本的大小,出大小,bias=False則圖層不會學習附加偏差。)

? ? ? ? self.fc1= nn.Linear(32 * 3 * 7,11)

self.fc2= nn.Linear(32 * 3 * 7,11)

self.fc3= nn.Linear(32 * 3 * 7,11)

self.fc4= nn.Linear(32 * 3 * 7,11)

self.fc5= nn.Linear(32 * 3 * 7,11)

self.fc6= nn.Linear(32 * 3 * 7,11)

#輸出經過所有神經網(wǎng)絡層的結果

? ? def forward(self,img):

? ? ? ? feat= self.cnn(img)#nn.Sequential

? ? ? ? #將一個多行的Tensor,拼接成一行

? ? ? ? feat= feat.view(feat.shape[0],-1)

#并聯(lián)6全連接,進行分類

? ? ? ? c1= self.fc1(feat)

c2= self.fc2(feat)

c3= self.fc3(feat)

c4= self.fc4(feat)

c5= self.fc5(feat)

c6= self.fc6(feat)

return c1, c2, c3, c4, c5, c6

#model已經經過了cnn,有forward()方法出6個并聯(lián)全連接結果

model1= SVHN_model_1()

#使用在imageNet數(shù)據(jù)集上的與訓練模型

class SVHN_model_2(nn.Module):

? ? def __init__(self):

? ? ? ? #??

? ? ? ? super(SVHN_model_2,self).__init__()

model_conv= models.resnet18(pretrained=True)

#平均池化:輸出特征的個數(shù)等于輸入平面的個數(shù),都為1*1的tensor,strides,paddings等參數(shù)都自適應好了

? ? ? ? model_conv.avgpool= nn.AdaptiveAvgPool2d(1)

#迭代器:model.modules()會遍歷model中所有的子層,而model.children()僅會遍歷當前層[[1, 2], 3]--[1, 2], 3。

? ? ? ? model_conv= nn.Sequential(*list(model_conv.children())[:-1])

self.cnn= model_conv

self.fc1= nn.Linear(512,11)

self.fc2= nn.Linear(512,11)

self.fc3= nn.Linear(512,11)

self.fc4= nn.Linear(512,11)

self.fc5= nn.Linear(512,11)

#與model1一樣

? ? def forward(self,img):

? ? ? ? feat= self.cnn(img)

# print(feat.shape)

? ? ? ? feat= feat.view(feat.shape[0],-1)

c1= self.fc1(feat)

c2= self.fc2(feat)

c3= self.fc3(feat)

c4= self.fc4(feat)

c5= self.fc5(feat)

return c1, c2, c3, c4, c5

model2= SVHN_model_2()

#訓練數(shù)據(jù)

def trainData(train_loader,model):

? ? #s=nn.Softmax(dim=1)一列的和為1–NLLLoss --i=torch.log(s(input))

? ? #nn.NLLLoss(i,target) 把上面的輸出與Label對應的那個值拿出來,再去掉負號,再求均值。

? ? criterion= nn.CrossEntropyLoss()#二分類損失函數(shù),是上面三步的綜合

? ? #優(yōu)化器對象Optimizer,用來保存當前的狀態(tài),并能夠根據(jù)計算得到的梯度來更新參數(shù)。

? ? optimizer= torch.optim.Adam(model.parameters(),0.005)

loss_plot= []

c0_plot= []

#epoch訓練過程

? ? for epochin range(1):

? ? ? ? for datain train_loader:

? ? ? ? ? ? c0, c1, c2, c3, c4, c5= model(data[0])

data[1]= data[1].long()

loss= criterion(c0, data[1][:,0])+\

criterion(c1, data[1][:,1])+\

criterion(c2, data[1][:,2])+\

criterion(c3, data[1][:,3])+\

criterion(c4, data[1][:,4])

#報錯下面的data[1][:, 5]不存在

? ? ? ? ? ? ? ? ? #criterion(c5, data[1][:, 5])

? ? ? ? ? ? loss/= 5

? ? ? ? ? ? optimizer.zero_grad()

loss.backward()

optimizer.step()

loss_plot.append(loss.item())

c0_plot.append((c0.argmax(1)==data[1][:,0].sum().item()*1.0/c0.shape[0]))

print(epoch)

#trainData(train_loader,model1)

#每次epoch訓練的過程

def train(train_loader,model,criterion,optimizer,epoch):

? ? # 切換模型為訓練模式

? ? model.train()

#enumerate()將一個可遍歷的數(shù)據(jù)對象組合為一個索引序列,同時列出下標和數(shù)據(jù)

? ? for i, datain enumerate(train_loader):

? ? ? ? c0, c1, c2, c3, c4, c5= model(data[0])

data[1]= data[1].long()

loss= criterion(c0, data[1][:,0])+ \

criterion(c1, data[1][:,1])+ \

criterion(c2, data[1][:,2])+ \

criterion(c3, data[1][:,3])+ \

criterion(c4, data[1][:,4])

# criterion(c5, data[1][:, 5])

? ? ? ? loss/= 5

? ? ? ? optimizer.zero_grad()#把模型中參數(shù)的梯度設為0

? ? ? ? loss.backward()#反向傳播(grad_fn就是Tensor專門保存其進行過的數(shù)學運算

? ? ? ? optimizer.step()#模型更新

def validate(val_loader,model,criterion):

? ? # 切換模型為預測模型

? ? model.eval()

val_loss= []

# 不記錄模型梯度信息

? ? with torch.no_grad():

? ? ? ? for i, datain enumerate(val_loader):

? ? ? ? ? ? c0, c1, c2, c3, c4, c5= model(data[0])

loss= criterion(c0, data[1][:,0])+ \

criterion(c1, data[1][:,1])+ \

criterion(c2, data[1][:,2])+ \

criterion(c3, data[1][:,3])+ \

criterion(c4, data[1][:,4])+ \

criterion(c5, data[1][:,5])

loss/= 6

? ? ? ? ? ? #不記錄模型梯度信息

? ? ? ? ? ? val_loss.append(loss.item())

return np.mean(val_loss)

def valCal(train_loader,val_loader,model):

? ? criterion= nn.CrossEntropyLoss()

optimizer= torch.optim.Adam(model.parameters(),0.001)

best_loss= 1000.0

? ? for epochin range(3):

? ? ? ? print('Epoch: ', epoch)

#每一次epoch都對訓練集和VAL在同一個模型進行計算

? ? ? ? train(train_loader,model, criterion, optimizer, epoch)

print('train_over')

val_loss= validate(val_loader,model, criterion)

print('val_over')

# 記錄下驗證集精度

? ? ? ? if val_loss< best_loss:

? ? ? ? ? ? best_loss= val_loss

torch.save(model.state_dict(),'./model.pt')

valCal(train_loader,val_loader,model1)

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容