猫狗数据集的制作并完成对猫狗预测识别

一、猫狗数据集的制作

#在数据集制作过程中需要加载的模块
import torch
import os
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from torchvision.transforms import ToPILImage
from torch.utils.data import Dataset, DataLoader

""" 
Pytorch中数据集被抽象为一个抽象类torch.utils.data.Dataset,所有的数据集都应该继承这个类,并override以下两项:
	.__len__
	.__getitem__
"""
class Datasets(Dataset):
    mean = [0.4878, 0.4545, 0.4168]
    std = [0.2623, 0.2555, 0.2577]
    def __init__(self,path):
        #获取数据集所在的路径,注意不能把该路径设置太深
        self.path = path
        #把数据集下的所有图片的文件名列出来,返回的结果是一个列表
        self.dataset = os.listdir(self.path)
     """代表样本数量,len(obj)等价于obj.__len__()"""
    def __len__(self):
        return len(self.dataset)
 	"""__getitem__返回一条数据或一个样本,obj[index]等价于obj.__getitem__"""
    def __getitem__(self,index):
        """
        :param item:index
        :return: data,target
        """
        # 获得数据的标签
        name = self.dataset[index]
        # 数据集的文件名为i.j.jpeg, 这个标签的第i个位置如果是0表示猫,1则表示狗,第j个位置是图片的个数
        name_list = name.split(".")
        target =int(name_list[0])
   		#这里需要注意tensor(target)和Tensor(target)的区别,在one-hot编码的时候可能会出错
   		#a=[1,2,3]
   		#torch.tensor(a)------[1,2,3]
   		#torch.Tensor(a)------[1.,2.,3.]
   		target = torch.tensor(target)
        "数据预处理"
        #打开图片(路径的拼接)
        img = Image.open(os.path.join(self.path,name))
        #归一化
        img = np.array(img) / 255
        #去均值
        img = (img - self.mean) / self.std
        datasets = torch.tensor(img, dtype=torch.float32).permute(2, 0, 1)
        return datasets, target

```python
"""数据预处理中方差和均值的求解:"""
if __name__ == '__main__':
    path = r"E:/cat-dog/datasets/"
    dataset = Datasets(path= path)
    # 制作加载器,batch_size=7264,相当于把整体的训练图片打包成了一个整体,data_loader包含两坨东西(data,target)
    data_loader = DataLoader(dataset= dataset, batch_size=7246, shuffle=True)
    # 将data_loader作为一个迭代器进行运算,这里面包含了输入数据和标签,所以后面取第0个位置的数,也就是取输入数据
    data = next(iter(data_loader))[0]
    # 这里图片N(每批的数量) C(通道数) H(高)  W(宽) 几个维度,求的.0是通道层面的均值,所以dim=(0, 2, 3)
    mean = torch.mean(data, dim=(0, 2, 3))
    std = torch.std(data, dim=(0, 2, 3))

二、神经网络的搭建

import torch
import torch.nn as nn
  """
**torch.nn.Sequential**:一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行
      #1. Sequential使用实例
model = nn.Sequential(
        nn.Conv2d(1,20,5),
        nn.ReLU(),
        nn.Conv2d(20,64,5),
        nn.ReLU()
      )
      #2.Sequential with OrderedDict使用实例
model = nn.Sequential(OrderedDict([
        ('conv1', nn.Conv2d(1,20,5)),
        ('relu1', nn.ReLU()),
        ('conv2', nn.Conv2d(20,64,5)),
        ('relu2', nn.ReLU())
      ]))
      """
  
"""**使用普通方法搭建的网络**
class Net(torch.nn.Module):
	def __init__(self, n_feature, n_hidden, n_output):
		 super(Net, self).__init__()
	     self.hidden = torch.nn.Linear(n_feature, n_hidden)
	     self.predict = torch.nn.Linear(n_hidden, n_output)

	def forward(self, x):
		  x = F.relu(self.hidden(x))
		  x = self.predict(x)
		  return x
net1 = Net(1, 10, 1)
*****************************************************************
**使用nn.sequential()快速搭建网络**
net2 = torch.nn.Sequential(
    torch.nn.Linear(1, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1)
)
"""
******************************************************************
"""
print(net1)
Net (
  (hidden): Linear (1 -> 10)
  (predict): Linear (10 -> 1)
)
print(net2)
Sequential (
  (0): Linear (1 -> 10)
  (1): ReLU ()
  (2): Linear (10 -> 1)
)
"""
#在搭建网络过程中 torch.nn.Sequential与torch.nn.Module区别与选择 
#在net2中用torch.nn.Sequential会自动加入激励函数, 但是 net1 中, 激励函数实际上是在 forward() 功能中才被调用的.
class MyNetwork(nn.Module):
    def __init__(self):
        super(MyNetwork, self).__init__()
        self.line = nn.Sequential(
            nn.Linear(in_features=3 * 100 * 100, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=128),
            nn.ReLU(),
            nn.Linear(in_features=128, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=2),
        )

    def forward(self, parse):
        data = torch.reshape(parse, shape=(-1, 3 * 100 * 100))
        return self.line(data)

3.训练与测试网络

import torch
import matplotlib as plt
from torch.utils.data import DataLoader
import os
import torch.nn as nn
from MyDataset import *
from MyNet import *



class Train(object):
    def __init__(self, path, epoch, batch):
        self.path = path
        self.epoch = epoch
        self.batch = batch
        self.test_dataset = Datasets(os.path.join(self.path, "test-image"))
        self.train_dataset = Datasets(os.path.join(self.path, "train-image"))
        self.criterion = torch.nn.MSELoss()
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.net = MyNetwork().to(self.device)
        self.optimize = torch.optim.Adam(self.net.parameters())

    def dataLoader(self):
        train_data_loader = DataLoader(dataset=self.train_dataset, batch_size=self.batch, shuffle=True)
        test_data_loader = DataLoader(dataset=self.test_dataset, batch_size=self.batch, shuffle=True)
        return train_data_loader, test_data_loader
   
    def trainNet(self):
       
        train_data_loader, test_data_loader = self.dataLoader()
       
        losses = []
        accuracy = []
       
        for i in range(self.epoch):
            for j, (Input, target) in enumerate(train_data_loader):
                Input = Input.to(self.device)
                out_put = self.net(Input)
	    target = torch.zeros(target.size(0), 2).scatter_(1, target.view(-1, 1), 1).to(self.device)
	    loss = self.criterion(out_put, target)
        losses.append(loss.item())

		""" 梯度清零"""
        self.optimize.zero_grad()
        loss.backward()
        self.optimize.step()

        if j % 5 == 0:
           print("训练轮次:epoch{}/{},迭代次数:iteration{}/{}".format(i, self.epoch, j, len(train_data_loader)))
           acc = torch.mean((out_put.argmax(1)== target.argmax(1)), dtype=torch.float32)
           accuracy.append(acc.item())
           print("训练准确率为:accuracy = %s , loss值为:%s" % (acc.item(), loss.item()))
		   
		   plt.clf()
           plt.ion()
		   """加载loss曲线"""
           plt.subplot(2, 1, 1)
           plt.tight_layout(2)
           plt.plot(losses, label="loss")
           plt.legend(loc='best')

		   """加载accuracy曲线"""
           plt.subplot(2, 1, 2)
           """设置图像之间的距离"""
           plt.tight_layout(2)
           plt.plot(accuracy, label="accuracy")
           """显示图例"""
           plt.legend(loc='best')
           plt.pause(0.2)
           plt.show()
	torch.save(self.net, "models/net.pth")

    def test(self):
        train_data_loader,test_data_loader = self.dataLoader()
        for k, (In, tgt) in enumerate(test_data_loader):
            print("111111111",k)
            #In = In.to(self.device)
            """加载测试图片"""
            # 加载训练好的网络
            test_Net = torch.load('models/net.pth')

            # 这是可视化训练图片的第一步,进行反算(Input * 标准差+均值)*255
            # 这里输入In的维度是(batch, 3, 100, 100 ),std 和mean是矩阵,所以给它转换维度才能与输入做运算
            imgs = (In.cpu().data.numpy() * np.array(Datasets.std).reshape((1, 3, 1, 1)) + np.array(
                Datasets.mean).reshape((1, 3, 1, 1))) * 255
            img = np.resize(imgs, (100, 100))
            """显示测试结果"""
            if 0 < k <= self.batch:
                # plt.subplot(3, 2, k)
                # plt.tight_layout(1)
                plt.ion()
                plt.clf()
                plt.imshow(img)
                predict = test_Net(In)
                # print("predict", torch.argmax((predict[k])).item())
                predict_result = "cat" if torch.argmax(predict[k - 1]).item() == 0 else "dog"
                plt.title(predict_result)
                plt.axis('off')
                plt.pause(1)
                plt.show()
                plt.savefig("result.jpg")


if __name__ == '__main__':
    #path = r"E:/cat-dog/datasets/"
    train = Train(path= r"E:/cat-dog/datasets/", epoch=30, batch=10)
    train.trainNet()
    train.test()
发布了3 篇原创文章 · 获赞 0 · 访问量 47

猜你喜欢

转载自blog.csdn.net/weixin_41538973/article/details/104461103