1. 程式人生 > 實用技巧 >貓狗大戰挑戰賽

貓狗大戰挑戰賽

VGG實現貓狗分類

  1、匯入資料和解壓資料

! wget http://fenggao-image.stor.sinaapp.com/dogscats.zip! unzip dogscats.zip ! wget https://static.leiphone.com/cat_dog.rar! unrar x cat_dog.rar

  分別匯入AI研習社的資料和老師給的資料,本來想本地匯入,由於太卡,上傳了一個小時沒上傳到google網盤,網盤還一直掉線,因此放棄,下載了兩組資料。dogscats資料中的train和val分別有cat和dog的資料夾,因此選用dogscats的資料做實驗。

  2、設定transform函式,將AI研習社的test資料夾提取到同一個資料夾下,用ImageFolder提取相應路徑下的資料並設定bitch_size,考慮到VGG的輸入為224*224,所以要將圖片裁剪為224*224;提取資料長度dest_sizes,儲存類別資訊train_classes。

#組合多個函式
transform=transforms.Compose([
    transforms.CenterCrop(224),#考慮到VGG的輸入為224*224,對原始圖片進行裁剪
    #transforms.RandomHorizontalFlip(),#隨機左右翻轉
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485,0.456,0.406],std=[0.229,0.224,0.225])])
#!ls "/content/cat_dog/train"
#print(os.listdir())

#訓練時可以打亂順序增加多樣性,測試時沒有必要,所以shuffle=False
 dataset={x:datasets.ImageFolder(root=os.path.join('dogscats',x),transform=transform)forxin['train','val','test']} trainloader=torch.utils.data.DataLoader(dataset=dataset['train'],batch_size=64,shuffle=True,num_workers=6) valloader=torch.utils.data.DataLoader(dataset=dataset['val'],batch_size=64,shuffle=False,num_workers=6) testloader=torch.utils.data.DataLoader(dataset=dataset['test'],batch_size=64,shuffle=False,num_workers=6) dset_sizes={x:len(dataset[x])forxin['train','val','test']} train_classes=dataset['train'].classes

  3、下載ImageNet的json檔案,使用訓練好的VGG16模型進行預測,最後用softmax進行處理。使用json.load()來讀取imagenet檔案,將輸入資料model後再softmax,展示識別結果,由於我的batch_size設定為64,圖片也就小了點,結果也就多了點。

!wget https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json

model_vgg=models.vgg16(pretrained=True)

#找到這個結果預測的是哪個類別,最簡單的可以找向量中最大的那個值,然後找出所對應的類別:
with open('./imagenet_class_index.json') as f:
  #print(json.load(f))
  class_dict = json.load(f)
  print(class_dict)
dic_imagenet = [class_dict[str(i)][1] for i in range(len(class_dict))]

inputs_try,labels_try = inputs_try.to(device),labels_try.to(device)
model_vgg = model_vgg.to(device)
outputs_try = model_vgg(inputs_try)

print(outputs_try)
print(outputs_try.shape)

 m_softm=nn.Softmax(dim=1)  probs=m_softm(outputs_try)  vals_try,pred_try=torch.max(probs,dim=1)
 print('probsum:',torch.sum(probs,1))  print('vals_try:',vals_try)  print('pred_try:',pred_try)
 print([dic_imagenet[i]foriinpred_try.data])  imshow(torchvision.utils.make_grid(inputs_try.data.cpu()), title=[train_classes[x]forxinlabels_try.data.cpu()])

  

  4、在這裡使用nn.Linear 層將結果的1000類替換為2類,model_vgg_new.parameters()是返回一個每次生成的是Tensor型別的資料的迭代器,設定 required_grad=False凍結前面層的引數。定義優化模型和損失函式。vgg.features是取出vgg16網路中的features大層。其中vgg網路可以分為3大層,一層是(features),一層是(avgpool),最後一層是(classifier),vgg.classifiwe._modules是將取出來的網路轉為字典顯示。



print(model_vgg)

model_vgg_new=model_vgg;
forparaminmodel_vgg_new.parameters(): param.requires_grad=False model_vgg_new.classifier._modules['6']=nn.Linear(4096,2) model_vgg_new.classifier._modules['7']=torch.nn.LogSoftmax(dim=1)
model_vgg_new=model_vgg_new.to(device)
print(model_vgg_new.classifier) criterion=nn.NLLLoss() lr=0.001 #隨機梯度下降 optimizer_vgg=torch.optim.SGD(model_vgg_new.classifier[6].parameters(),lr=lr)

  5、訓練模型

def train_model(model,dataloader,size,epochs,optimizer):
  model.train()
    
  for epoch in range(epochs):
    running_loss = 0.0
    running_corrects = 0
    count = 0
    for inputs,classes in dataloader:
      inputs = inputs.to(device)
      classes = classes.to(device)
      outputs = model(inputs)
      loss = criterion(outputs,classes)           
      optimizer = optimizer
      optimizer.zero_grad()
      loss.backward()
      optimizer.step()
      _,preds = torch.max(outputs.data,1)
      # statistics
      running_loss += loss.data.item()
      running_corrects += torch.sum(preds == classes.data)
      count += len(inputs)
      print('Training: No. ', count, ' process ... total: ', size)
    epoch_loss = running_loss / size
    epoch_acc = running_corrects.data.item() / size
    print('Loss: {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))
           
# 模型訓練
train_model(model_vgg_new,trainloader,size=dset_sizes['train'], epochs=1, 
            optimizer=optimizer_vgg)

  訓練結果:

  6、測試val

def test_model(model,dataloader,size):
  model.eval()
  predictions = np.zeros(size)
  all_classes = np.zeros(size)
  all_proba = np.zeros((size,2))
  i = 0
  running_loss = 0.0
  running_corrects = 0
  for inputs,classes in dataloader:
    inputs = inputs.to(device)
    classes = classes.to(device)
    outputs = model(inputs)
    loss = criterion(outputs,classes)           
    _,preds = torch.max(outputs.data,1)
    # statistics
    running_loss += loss.data.item()
    running_corrects += torch.sum(preds == classes.data)
    predictions[i:i+len(classes)] = preds.to('cpu').numpy()
    all_classes[i:i+len(classes)] = classes.to('cpu').numpy()
    all_proba[i:i+len(classes),:] = outputs.data.to('cpu').numpy()
    i += len(classes)
    print('Testing: No. ', i, ' process ... total: ', size)        
  epoch_loss = running_loss / size
  epoch_acc = running_corrects.data.item() / size
  print('Loss: {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))
  return predictions, all_proba, all_classes
  
predictions, all_proba, all_classes = test_model(model_vgg_new,valloader,size=dset_sizes['val'])

  測試結果:

  7、測試test

predictions2,all_proba2,all_classes2=test_model(model_vgg_new,testloader,size=dset_sizes['test'])

  測試結果:此處的0.4870不能看做是test的準確率,因為test裡面沒有cat和dog的標籤,所以這個數值是不準確的。

  將圖片序號和預測結果匯入為csv檔案後再進行排序,在AI研習社的結果為:

  8、遇到問題:

  (1)匯入AI研習社下載連結後,使用unzip解壓失敗,針對.rar壓縮檔案應該使用unrar

  (2)讀取檔案時出現找不到子檔案的錯誤,但是路徑格式我確定自己沒有填寫錯誤,後來發現ImageFolder的root針對的格式是這樣的:如果路徑是cat_dog/train/1.jpg,填寫的路徑要是cat_dog才是正確答案。我匯入的大賽的資料有三個資料夾train、test、val,每個資料夾下面沒有更多的資料夾,直接是圖片,這就導致按照正確格式讀取只能將三個資料夾的資料一起讀取。通過糾結考慮只有兩個辦法:①在每個資料夾下面分別建cat和dog資料夾,才能分別讀取train、test、val;②換個下載路徑。更換下載路徑後代碼正確。

  (3)原始碼中訓練函式的引數是固定的,不利於後期的修改,尤其是optimizer沒有使用設定好的梯度下降優化函式

  

  (4)下載csv提交時,出現正確率為50%的情況。原因是我沒有意識到圖片序號的重要性,直接按照圖片在test下的順序設定了range序列,這樣的結果是不正確的。

  

  那為什麼結果是50%左右呢?由於test裡面沒有cat和dog的分類,所以分類的標籤為0,也就是說測試集中貓是正確,狗是錯誤,50%的意思是統計了貓在資料集中的數量佔比

  

  9、優化

  (1)提高訓練次數

 

  (2)優化中