一个完整的分类程序

#项目目录结构
|---blog
    |---DataSet
         |---dataset.py
    |---models
         |---AlexNet.py
         |---DenseNet.py
         |---GooleNet.py
         |---VGG.py
    |---pth
    |---train.py
     

以下是每个文件的具体内容:

# dataset.py
from PIL import Image
import torch
import numpy as np
import os
from torchvision import transforms


class MyDataSet(torch.utils.data.Dataset):
    def __init__(self, transform=None):  # 初始化一些需要传入的参数
        super(MyDataSet, self).__init__()
        images = []
        # 返回对应的图片和标签
        image_list = []
        label_list = []
        cwd = 'F:/openvinortest/TEST/' # 数据根目录
        classes = {'cat', 'dog'} #文件夹名称
        for index, name in enumerate(classes):
            class_path = cwd + name + '/'
            for img_name in os.listdir(class_path):
                image_list.append(class_path + img_name)
                label_list.append(index)
        print("There are %d  class" % (len(image_list)))
        # 组合文件
        temp = np.array([image_list, label_list])
        temp = temp.transpose()  # 转置
        # 对应的打乱顺序
        np.random.shuffle(temp)
        image_list = list(temp[:, 0])
        label_list = list(temp[:, 1])
        for i in range(len(image_list)):
            images.append((image_list[i], int(label_list[i])))
        self.imgs = images
        self.transform = transform

    def __getitem__(self, index):
        fn, label = self.imgs[index]
        img = Image.open(fn).convert('RGB')
        if self.transform is not None:
            img = self.transform(img)
        else:
            self.transform = transforms.Compose([transforms.Resize((227, 227)), transforms.ToTensor()])
            img = self.transform(img)
        return img, label

    def __len__(self):
        return len(self.imgs)


# 根据自己定义的那个勒MyDataset来创建数据集!注意是数据集!而不是loader迭代器
if __name__ == "__main__":
    train_data = MyDataSet()
    train_loader = torch.utils.data.DataLoader(dataset=train_data, batch_size=64, shuffle=True)
    for batch_index, data in train_loader:
        print(len(batch_index))
# AlexNet.py
import torch.nn as nn


# 图片大小227
class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=11, stride=4),  # 55*55   还是56
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),  # 27*27
            nn.Conv2d(64, 192, kernel_size=5, padding=2),  # 26 26
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),  # 13 13
            nn.Conv2d(192, 384, kernel_size=3, padding=1),  # 13 13
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),  # 13 13
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),  # 10 10
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),  # 5 5
        )
        self.classifier = nn.Sequential(
            nn.Linear(6 * 6 * 256, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 2),
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(-1, 6 * 6 * 256)
        x = self.classifier(x)
        return x
# DenseNet.py
import torch
import torch.nn as nn
import torch.nn.functional as F
from collections import OrderedDict


class _DenseLayer(nn.Sequential):
    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):
        super(_DenseLayer, self).__init__()
        self.add_module('norm1', nn.BatchNorm2d(num_input_features)),
        self.add_module('relu1', nn.ReLU(inplace=True)),
        self.add_module('conv1', nn.Conv2d(num_input_features, bn_size *
                                           growth_rate, kernel_size=1, stride=1, bias=False)),
        self.add_module('norm2', nn.BatchNorm2d(bn_size * growth_rate)),
        self.add_module('relu2', nn.ReLU(inplace=True)),
        self.add_module('conv2', nn.Conv2d(bn_size * growth_rate, growth_rate,
                                           kernel_size=3, stride=1, padding=1, bias=False)),
        self.drop_rate = drop_rate

    def forward(self, x):
        new_features = super(_DenseLayer, self).forward(x)
        if self.drop_rate > 0:
            new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)
        return torch.cat([x, new_features], 1)


class _DenseBlock(nn.Sequential):
    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):
        super(_DenseBlock, self).__init__()
        for i in range(num_layers):
            layer = _DenseLayer(num_input_features + i * growth_rate, growth_rate, bn_size, drop_rate)
            self.add_module('denselayer%d' % (i + 1), layer)


class _Transition(nn.Sequential):
    def __init__(self, num_input_features, num_output_features):
        super(_Transition, self).__init__()
        self.add_module('norm', nn.BatchNorm2d(num_input_features))
        self.add_module('relu', nn.ReLU(inplace=True))
        self.add_module('conv', nn.Conv2d(num_input_features, num_output_features, kernel_size=1, stride=1, bias=False))
        self.add_module('pool', nn.AvgPool2d(kernel_size=2, stride=2))


class DenseNet(nn.Module):
    def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16), num_init_features=64, bn_size=4, drop_rate=0,
                 num_classes=2):

        super(DenseNet, self).__init__()

        # First convolution
        self.features = nn.Sequential(OrderedDict([
            ('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)),
            ('norm0', nn.BatchNorm2d(num_init_features)),
            ('relu0', nn.ReLU(inplace=True)),
            ('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1)),
        ]))

        # Each denseblock
        num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = _DenseBlock(num_layers=num_layers, num_input_features=num_features,
                                bn_size=bn_size, growth_rate=growth_rate, drop_rate=drop_rate)
            self.features.add_module('denseblock%d' % (i + 1), block)
            num_features = num_features + num_layers * growth_rate
            if i != len(block_config) - 1:
                trans = _Transition(num_input_features=num_features, num_output_features=num_features // 2)
                self.features.add_module('transition%d' % (i + 1), trans)
                num_features = num_features // 2

        # Final batch norm
        self.features.add_module('norm5', nn.BatchNorm2d(num_features))

        # Linear layer
        self.classifier = nn.Linear(num_features, num_classes)

        # Official init from torch repo.
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal(m.weight.data)
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
            elif isinstance(m, nn.Linear):
                m.bias.data.zero_()

    def forward(self, x):
        features = self.features(x)
        out = F.relu(features, inplace=True)
        out = F.avg_pool2d(out, kernel_size=7, stride=1).view(features.size(0), -1)
        out = self.classifier(out)
        return out


def densenet121(**kwargs):
    model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 24, 16), **kwargs)
    return model


def densenet169(**kwargs):
    model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 32, 32), **kwargs)
    return model


def densenet201(**kwargs):
    model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 48, 32), **kwargs)
    return model


def densenet161(**kwargs):
    model = DenseNet(num_init_features=96, growth_rate=48, block_config=(6, 12, 36, 24), **kwargs)
    return model


if __name__ == '__main__':
    # 'DenseNet', 'densenet121', 'densenet169', 'densenet201', 'densenet161'
    # Example
    net = DenseNet()
    print(net)
# GooleNet.py
import torch
import torch.nn as nn
import torch.nn.functional as F


# 编写卷积+bn+relu模块
class BasicConv2d(nn.Module):
    def __init__(self, in_channels, out_channals, **kwargs):
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channals, **kwargs)
        self.bn = nn.BatchNorm2d(out_channals)

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        return F.relu(x)


# 编写Inception模块
class Inception(nn.Module):
    def __init__(self, in_planes,
                 n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes):
        super(Inception, self).__init__()
        # 1x1 conv branch
        self.b1 = BasicConv2d(in_planes, n1x1, kernel_size=1)
        # 1x1 conv -> 3x3 conv branch
        self.b2_1x1_a = BasicConv2d(in_planes, n3x3red, kernel_size=1)
        self.b2_3x3_b = BasicConv2d(n3x3red, n3x3, kernel_size=3, padding=1)
        # 1x1 conv -> 3x3 conv -> 3x3 conv branch
        self.b3_1x1_a = BasicConv2d(in_planes, n5x5red, kernel_size=1)
        self.b3_3x3_b = BasicConv2d(n5x5red, n5x5, kernel_size=3, padding=1)
        self.b3_3x3_c = BasicConv2d(n5x5, n5x5, kernel_size=3, padding=1)
        # 3x3 pool -> 1x1 conv branch
        self.b4_pool = nn.MaxPool2d(3, stride=1, padding=1)
        self.b4_1x1 = BasicConv2d(in_planes, pool_planes, kernel_size=1)

    def forward(self, x):
        y1 = self.b1(x)
        y2 = self.b2_3x3_b(self.b2_1x1_a(x))
        print(y2.shape)
        y3 = self.b3_3x3_c(self.b3_3x3_b(self.b3_1x1_a(x)))
        y4 = self.b4_1x1(self.b4_pool(x))
        # y的维度为[batch_size, out_channels, C_out,L_out]
        # 合并不同卷积下的特征图
        return torch.cat([y1, y2, y3, y4], 1)


class GoogLeNet(nn.Module):
    def __init__(self):
        super(GoogLeNet, self).__init__()
        self.pre_layers = BasicConv2d(3, 192, kernel_size=3, padding=1)
        self.a3 = Inception(192, 64, 96, 128, 16, 32, 32)
        self.b3 = Inception(256, 128, 128, 192, 32, 96, 64)
        self.maxpool = nn.MaxPool2d(3, stride=2, padding=1)
        self.a4 = Inception(480, 192, 96, 208, 16, 48, 64)
        self.b4 = Inception(512, 160, 112, 224, 24, 64, 64)
        self.c4 = Inception(512, 128, 128, 256, 24, 64, 64)
        self.d4 = Inception(512, 112, 144, 288, 32, 64, 64)
        self.e4 = Inception(528, 256, 160, 320, 32, 128, 128)
        self.a5 = Inception(832, 256, 160, 320, 32, 128, 128)
        self.b5 = Inception(832, 384, 192, 384, 48, 128, 128)
        self.avgpool = nn.AvgPool2d(8, stride=1)
        self.drop = nn.Dropout(0.4)
        self.linear = nn.Linear(1024, 2)

    def forward(self, x):
        out = self.pre_layers(x)
        out = self.a3(out)
        out = self.b3(out)
        out = self.maxpool(out)
        out = self.a4(out)
        out = self.b4(out)
        out = self.c4(out)
        out = self.d4(out)
        out = self.e4(out)
        out = self.maxpool(out)
        out = self.a5(out)
        out = self.b5(out)
        out = self.avgpool(out)
        out = self.drop(out)
        out = out.view(out.size(0), -1)
        out = self.linear(out)
        return out
# VGG.py
import torch.nn as nn


# 需继承torch.nn.Module类
class VGG16(nn.Module):
    def __init__(self):
        super(VGG16, self).__init__()
        # 定义卷积层和池化层,共13层卷积,5层池化
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
        )
        # 简化版全连接层
        # self.classifier = nn.Sequential(
        #     nn.Linear(4 * 4 * 512, 1024),
        #     nn.ReLU(),
        #     nn.Dropout(p=0.5),
        #     nn.Linear(1024, 1024),
        #     nn.ReLU(),
        #     nn.Dropout(p=0.5),
        #     nn.Linear(1024, 2)
        # )
        # VGG-16的全连接层
        self.classes = nn.Sequential(
            nn.Linear(7 * 7 * 512, 4096),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(4096, 2)
        )

    # 定义每次执行的计算步骤
    def forward(self, x):
        x = self.features(x)
        x = x.view(-1, 7 * 7 * 512)
        x = self.classes(x)
        return x
# train.py
import torch
import time
import cv2
import os
import random
import math
import torchvision
import torch.nn.functional as F
import torch.nn as nn
import matplotlib.pyplot as plt
from DataSet.dataset import MyDataSet
from models.DenseNet import DenseNet
from models.AlexNet import AlexNet

epochNum = 100
batchSize = 16
# 模型类实例
model = AlexNet()
# 如果GPUs可用,则将模型上需要计算的所有参数复制到GPUs上
if torch.cuda.is_available():
    model = model.cuda()
    print('支持cuda,GPU')
# loss值
loss_fn = nn.CrossEntropyLoss()
# 模型优化器
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)


def train():
    for epoch in range(1, epochNum + 1):
        train_data = MyDataSet()
        train_loader = torch.utils.data.DataLoader(dataset=train_data, batch_size=batchSize, shuffle=True,
                                                   drop_last=True)
        # 损失值
        running_loss = 0.0
        # 预测的正确数
        running_correct = 0
        for batch, data in enumerate(train_loader, 1):
            x, y = data
            if torch.cuda.is_available():
                x, y = x.cuda(), y.cuda()
            outputs = model(x)
            _, y_pred = torch.max(outputs.detach(), 1)
            # 将Varibale的梯度置零
            optimizer.zero_grad()
            # 计算损失值
            loss = loss_fn(outputs, y)
            # 反向传播求导
            loss.backward()
            # 更新所有参数
            optimizer.step()
            running_loss += loss.detach().item()
            running_correct += torch.sum(y_pred == y)
            if batch % 10 == 0:
                print('Batch {}/{},Train Loss:{:.2f},Train Acc:{:.2f}%'.format(
                    batch, 25000 / batchSize, running_loss / batch,
                           100 * running_correct.item() / (batchSize * batch)
                ))
        epoch_loss = running_loss * batchSize / 25000
        epoch_acc = 100 * running_correct.item() / 25000
        print(' Loss:{:.2f} Acc:{:.2f}%'.format(epoch_loss, epoch_acc))
        torch.save(model.state_dict(), './pth/' + str(batch) + '.pkl')


# train()


# 测试
def test():
    dst = MyDataSet()
    data_loader_test = torch.utils.data.DataLoader(dst, batch_size=1, shuffle=False)
    model.eval()
    # 加载模型
    model.load_state_dict(torch.load('./pth/2.pkl'))
    # 保存测试结果
    results = []
    count = 0
    # tqdm模块用于显示进度条
    for imgs, path in data_loader_test:
        if torch.cuda.is_available():
            X = imgs.cuda()
        outputs = model(X)
        # pred表示是哪个对象,0=cat,1=dog
        # probability表示是否个对象的概率
        probability, pred = torch.max(F.softmax(outputs, dim=1).detach(), dim=1)

        if pred == path.cuda():
            print("OK")
            count = count + 1
    print(count)


# test()
if __name__ == "__main__":
    train()
    test()

你可能感兴趣的:(一个完整的分类程序)