猫狗识别无法准确识别图片概率

刚接触深度学习,一开始照着帖子做了猫狗大战的demo,想用VGG16框架做个,现在目前代码跑通了,但是不知道为什么达不到效果,根本无法识别猫狗

from cProfile import label
from tkinter.tix import IMAGE
import numpy as np
import os
import random
import torch
import torch.nn.functional as F
import torchvision
import torch.utils.data as data
import shutil
import os.path
import torch.utils.data as data
import torchvision.transforms as transforms
from PIL import Image
from torch.utils.data import Dataset, DataLoader
import torch
from torch.autograd import Variable

IMAGE_SIZE =86
Transpose = torch.transpose
device = "cuda" if torch.cuda.is_available() else "cpu"
rootPath = os.getcwd()#得到当前的工作地址

dataTransform = transforms.Compose([
transforms.Resize(IMAGE_SIZE), # 将图像按比例缩放至合适尺寸
transforms.CenterCrop((IMAGE_SIZE, IMAGE_SIZE)), # 从图像中心裁剪合适大小的图像
transforms.ToTensor() # 转换成Tensor形式,并且数值归一化到[0.0, 1.0],同时将H×W×C的数据转置成C×H×W,这一点很关键
])

class StationType(data.Dataset):

def __init__(self, mode, pictureDataset):          # 默认构造函数,传入数据集类别(训练或测试),以及数据集路径
    self.mode = mode
    self.list_img = []     # 新建一个image list,用于存放图片路径,注意是图片路径
               
    self.list_label = []   # 新建一个label list,用于存放图片对应猫或狗的标签,其中数值0表示猫,1表示狗
    print(self.list_label)               
    self.data_size = 0                  # 记录数据集大小
    self.transform = dataTransform      # 转换关系

    if self.mode == 'train':            # 训练集模式下,需要提取图片的路径和标签
        pictureDataset = pictureDataset + '/train_data/'           # 训练集路径在"dir"/train/
        for file in os.listdir(pictureDataset):    # 遍历dir文件夹
            self.list_img.append(pictureDataset + file)        # 将图片路径和文件名添加至image list
            self.data_size += 1                     # 数据集增1
            name = file.split(sep='.')              # 分割文件名,"cat.0.jpg"将分割成"cat",".","jpg"3个元素

            # label采用one-hot编码,"1,0"表示猫,"0,1"表示狗,任何情况只有一个位置为"1",在采用CrossEntropyLoss()计算Loss情况下,label只需要输入"1"的索引,即猫应输入0,狗应输入1
            if name[0] == 'cat':
                
                self.list_label.append(0)         # 图片为猫,label为0
                print(0)
            else:
            
                self.list_label.append(1)         # 图片为狗,label为1,注意:list_img和list_label中的内容是一一配对的
                print(1)
    elif self.mode == 'test':           # 测试集模式下,只需要提取图片路径就行
        work = pictureDataset + '/test_data/'            # 测试集路径为"dir"/test/
        for file in os.listdir(pictureDataset):
            self.list_img.append(work + file)    # 添加图片路径至image list
            self.data_size += 1
            self.list_label.append(2)       # 添加2作为label,实际未用到,也无意义
    else:
        print('Undefined Dataset!')



def __getitem__(self, item):            # 重载data.Dataset父类方法,获取数据集中数据内容
    if self.mode == 'train':                                        # 训练集模式下需要读取数据集的image和label
        img = Image.open(self.list_img[item])                       # 打开图片
        label = self.list_label[item]                               # 获取image对应的label
        return self.transform(img), torch.LongTensor([label])       # 将image和label转换成PyTorch形式并返回
    elif self.mode == 'test':                                       # 测试集只需读取image
        img = Image.open(self.list_img[item])
        return self.transform(img)                                  # 只返回image
    else:
        print('None')

def __len__(self):
    return self.data_size               # 返回数据集大小

class vgg16Model(torch.nn.Module):
def init(self):
super(vgg16Model, self).init()

    #池化层,按最大池化 kernel_size池化大小  stride步长 padding边界填充
    self.max_pool1 = torch.nn.MaxPool2d(kernel_size=2, stride=2,padding=1)
    self.max_pool2 = torch.nn.MaxPool2d(kernel_size=2, stride=2,padding=1)
    self.max_pool3 = torch.nn.MaxPool2d(kernel_size=2, stride=2,padding=1)
    self.max_pool4 = torch.nn.MaxPool2d(kernel_size=2, stride=2,padding=1)
    self.max_pool5 = torch.nn.MaxPool2d(kernel_size=2, stride=2,padding=1)

    #self.conv1 = paddle.nn.Conv2D(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1)
    
    #卷积层 in_channels输入通道 out_channels输出通道(及创建的这层神经元的格式),kernel_size卷积核大小,padding边界填充
    #请注意保持上层out_channels和in_channels的一致性
    self.conv1 = torch.nn.Conv2d(in_channels=3,out_channels=64,kernel_size=3,stride=1,padding=1)    
    self.conv2 = torch.nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,stride=1,padding=1)
    self.conv3 = torch.nn.Conv2d(in_channels=64,out_channels=128,kernel_size=3,stride=1,padding=1)
    self.conv4 = torch.nn.Conv2d(in_channels=128,out_channels=128,kernel_size=3,stride=1,padding=1)
    self.conv5 = torch.nn.Conv2d(in_channels=128,out_channels=256,kernel_size=3,stride=1,padding=1)
    self.conv6 = torch.nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,stride=1,padding=1)
    self.conv7 = torch.nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,stride=1,padding=1)
    self.conv8 = torch.nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1)
    self.conv9 = torch.nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,stride=1,padding=1)
    self.conv10 = torch.nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,stride=1,padding=1)
    self.conv11 = torch.nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,stride=1,padding=1)
    self.conv12 = torch.nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,stride=1,padding=1)
    self.conv13 = torch.nn.Conv2d(in_channels=512,out_channels=512,kernel_size=3,stride=1,padding=1)

    #全连接层 输入是尺寸大小,输出尺寸大小(及神经元个数),在输入前用 paddle.flatten对上一层展开
    self.fc1=torch.nn.Linear(8192,4096)
    self.fc2=torch.nn.Linear(4096,4096)
    self.fc3=torch.nn.Linear(4096,2)
def forward(self, x):
    x = self.conv1(x)
    x = F.relu(x)
    x = self.conv2(x)
    x = F.relu(x)
    x = self.max_pool1(x)

    x = self.conv3(x)
    x = F.relu(x)
    x = self.conv4(x)
    x = F.relu(x)
    x = self.max_pool2(x)

    x = self.conv5(x)
    x = F.relu(x)
    x = self.conv6(x)
    x = F.relu(x)
    x = self.conv7(x)
    x = F.relu(x)
    x = self.max_pool3(x)

    x = self.conv8(x)
    x = F.relu(x)
    x = self.conv9(x)
    x = F.relu(x)
    x = self.conv10(x)
    x = F.relu(x)
    x = self.max_pool4(x)

    x = self.conv11(x)
    x = F.relu(x)
    x = self.conv12(x)
    x = F.relu(x)
    x = self.conv13(x)
    x = F.relu(x)
    x = self.max_pool5(x)
    #print(3)
       
    x = torch.flatten(x,start_dim=1)
    print(x.size())
    x = self.fc1(x)
    x = self.fc2(x)
    x = self.fc3(x)
    x = F.softmax(x,dim=1)
   
    return x

dataset_dir = './pictureDataset/' # 数据集路径

model_cp = './model/' # 网络参数保存位置
workers = 10 # PyTorch读取数据线程数量
batch_size = 5 # batch_size大小
lr = 0.0001 # 学习率
nepoch = 10

device = torch.device("cuda:0" if (torch.cuda.is_available()) else "cpu")
print(device)

def train():
datafile = StationType('train', dataset_dir)
print(datafile) # 实例化一个数据集
dataloader = DataLoader(datafile, batch_size=5, shuffle=False, num_workers=0, drop_last=True) # 用PyTorch的DataLoader类封装,实现数据集顺序打乱,多线程读取,一次取多个数据等效果

print('Dataset loaded! length of train set is {0}'.format(len(datafile)))

model = vgg16Model()                       # 实例化一个网络
model = model.to(device)               # 网络送入GPU,即采用GPU计算,如果没有GPU加速,可以去掉".cuda()"
# model = model
# model = nn.DataParallel(model)
model.train()                       # 网络设定为训练模式,有两种模式可选,.train()和.eval(),训练模式和评估模式,区别就是训练模式采用了dropout策略,可以放置网络过拟合


optimizer = torch.optim.Adam(model.parameters(), lr=lr)         # 实例化一个优化器,即调整网络参数,优化方式为adam方法

criterion = torch.nn.CrossEntropyLoss()                         # 定义loss计算方法,cross entropy,交叉熵,可以理解为两者数值越接近其值越小

cnt = 0             # 训练图片数量
for epoch in range(nepoch):
    # 读取数据集中数据进行训练,因为dataloader的batch_size设置为16,所以每次读取的数据量为5,即img包含了5个图像,label有5个
    for img, label in dataloader:                                           # 循环读取封装后的数据集,其实就是调用了数据集中的__getitem__()方法,只是返回数据格式进行了一次封装
        img, label = Variable(img).to(device), Variable(label).to(device)           # 将数据放置在PyTorch的Variable节点中,并送入GPU中作为网络计算起点
        print("epoch:",epoch)
        out = model(img)                                                    # 计算网络输出值,就是输入网络一个图像数据,输出猫和狗的概率,调用了网络中的forward()方法
        loss = criterion(out, label.squeeze())      # 计算损失,也就是网络输出值和实际label的差异,显然差异越小说明网络拟合效果越好,此处需要注意的是第二个参数,必须是一个1维Tensor
        loss.backward()                             # 误差反向传播,采用求导的方式,计算网络中每个节点参数的梯度,显然梯度越大说明参数设置不合理,需要调整
        optimizer.step()                            # 优化采用设定的优化方法对网络中的各个参数进行调整
        optimizer.zero_grad()                       # 清除优化器中的梯度以便下一次计算,因为优化器默认会保留,不清除的话,每次计算梯度都回累加
        cnt += 1

        print('Epoch:{0},Frame:{1}, train_loss {2}'.format(epoch, cnt*batch_size, loss/batch_size))          # 打印一个batch size的训练结果

torch.save(model.state_dict(), '{0}/model.pth'.format(model_cp))            # 训练所有数据后,保存网络的参数

if name == 'main':
train()

os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

dataset_dir = './pictureDataset/test_data/' # 数据集路径
model_file = './model/model.pth' # 模型保存路径
N = 10

device = torch.device("cuda:0" if (torch.cuda.is_available()) else "cpu")
#开始训练
def test():

# setting model
model = vgg16Model()                                       # 实例化一个网络
model.to(device)                                       # 送入GPU,利用GPU计算
model.load_state_dict(torch.load(model_file))       # 加载训练好的模型参数
model.eval()                                        # 设定为评估模式,即计算过程中不要dropout

# get data
files = random.sample(os.listdir(dataset_dir), N)   # 随机获取N个测试图像
imgs = []           # img
imgs_data = []      # img data
for file in files:
    img = Image.open(dataset_dir + file)            # 打开图像
    img_data = catdogdemo.dataTransform(img).to(device)           # 转换成torch tensor数据   ++

    imgs.append(img)                                # 图像list
    imgs_data.append(img_data)                      # tensor list
imgs_data = torch.stack(imgs_data)                  # tensor list合成一个4D tensor

# calculation
out = model(imgs_data)                              # 对每个图像进行网络计算

out = F.softmax(out, dim=1)                         # 输出概率化
out = out.data.cpu().numpy()                        # 转成numpy数据
print(out)
# pring results         显示结果
for idx in range(N):
    plt.figure()
    if out[idx, 0] > out[idx, 1]:
        plt.suptitle('cat:{:.1%},dog:{:.1%}'.format(out[idx, 0], out[idx, 1]))
    else:
        plt.suptitle('dog:{:.1%},cat:{:.1%}'.format(out[idx, 1], out[idx, 0]))
    plt.imshow(imgs[idx])
plt.show()

if name == 'main':
test()

现在运行倒是没什么问题,只不过从测试集里面不论是哪张图片,猫的概率都是79,狗的概率都是21,完全相同,一点变化都没有
实在是不知道怎么办5555555
正常识别猫狗概率就可以了

你训练数据集了吗?loss数据多少?
你这没有使用预训练模型,nepoch = 10有点小了吧