卷积神经网络| 猫狗系列【AlexNet】

首先,搭建网络:

AlexNet神经网络原理图:

net代码:【根据网络图来搭建网络,不会的看看相关视频会好理解一些】

import torchfrom torch import nnimport torch.nn.functional as Fclass MyAlexNet(nn.Module):    def __init__(self):        super(MyAlexNet, self).__init__()#继承        self.c1 = nn.Conv2d(in_channels=3, out_channels=48, kernel_size=11, stride=4, padding=2)#搭建第一层网络,输入通道3层,输出通道48,核11        self.ReLU = nn.ReLU()#激活函数        self.c2 = nn.Conv2d(in_channels=48, out_channels=128, kernel_size=5, stride=1, padding=2)#上面输出48,下面输入也是48,输出125,卷积核5        self.s2 = nn.MaxPool2d(2)#池化层        self.c3 = nn.Conv2d(in_channels=128, out_channels=192, kernel_size=3, stride=1, padding=1)        self.s3 = nn.MaxPool2d(2)        self.c4 = nn.Conv2d(in_channels=192, out_channels=192, kernel_size=3, stride=1, padding=1)        self.c5 = nn.Conv2d(in_channels=192, out_channels=128, kernel_size=3, stride=1, padding=1)        self.s5 = nn.MaxPool2d(kernel_size=3, stride=2)        self.flatten = nn.Flatten()#平展层        self.f6 = nn.Linear(4608, 2048)        self.f7 = nn.Linear(2048, 2048)        self.f8 = nn.Linear(2048, 1000)        self.f9 = nn.Linear(1000, 2)#输出二分类网络    def forward(self, x):        x = self.ReLU(self.c1(x))        x = self.ReLU(self.c2(x))        x = self.s2(x)#池化层        x = self.ReLU(self.c3(x))        x = self.s3(x)        x = self.ReLU(self.c4(x))        x = self.ReLU(self.c5(x))        x = self.s5(x)        x = self.flatten(x)#平展层        x = self.f6(x)        x = F.dropout(x, p=0.5)#防止过拟合,有50%的网络随机失效        x = self.f7(x)        x = F.dropout(x, p=0.5)        x = self.f8(x)        x = F.dropout(x, p=0.5)        x = self.f9(x)        return xif __name__ == '__mian__':    x = torch.rand([1, 3, 224, 224])#张量形式数组    model = MyAlexNet()    y = model(x)

测试一下这个网络:

划分数据集:(8:2)(spilit_data

import osfrom shutil import copyimport randomdef mkfile(file):    if not os.path.exists(file):        os.makedirs(file)# 获取data文件夹下所有文件夹名(即需要分类的类名)file_path = 'D:/Users/Twilight/PycharmProjects/AlexNet/data_name'flower_class = [cla for cla in os.listdir(file_path)]# 创建 训练集train 文件夹,并由类名在其目录下创建5个子目录mkfile('data/train')for cla in flower_class:    mkfile('data/train/' + cla)# 创建 验证集val 文件夹,并由类名在其目录下创建子目录mkfile('data/val')for cla in flower_class:    mkfile('data/val/' + cla)# 划分比例,训练集 : 验证集 = 8:2split_rate = 0.2# 遍历所有类别的全部图像并按比例分成训练集和验证集for cla in flower_class:    cla_path = file_path + '/' + cla + '/'  # 某一类别的子目录    images = os.listdir(cla_path)  # iamges 列表存储了该目录下所有图像的名称    num = len(images)    eval_index = random.sample(images, k=int(num * split_rate))  # 从images列表中随机抽取 k 个图像名称    for index, image in enumerate(images):        # eval_index 中保存验证集val的图像名称        if image in eval_index:            image_path = cla_path + image            new_path = 'data/val/' + cla            copy(image_path, new_path)  # 将选中的图像复制到新路径        # 其余的图像保存在训练集train中        else:            image_path = cla_path + image            new_path = 'data/train/' + cla            copy(image_path, new_path)        print("\r[{}] processing [{}/{}]".format(cla, index + 1, num), end="")  # processing bar    print()print("processing done!")

生成的新的文件夹:

由于数据集量太大,划分完了我还删了很多图片,我的data里面只有1000张,训练集猫狗分别400,测试集猫狗分别100。【跑不动根本跑不动】

训练代码:(train)

import torchfrom torch import nnfrom net import MyAlexNetimport numpy as npfrom torch.optim import lr_schedulerimport osfrom torchvision import transformsfrom torchvision.datasets import ImageFolderfrom torch.utils.data import DataLoaderimport matplotlib.pyplot as plt# 解决中文显示问题(乱码)plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = FalseROOT_TRAIN = r'D:/Users/Twilight/PycharmProjects/AlexNet/data/train'#数据集路径训练集ROOT_TEST = r'D:/Users/Twilight/PycharmProjects/AlexNet/data/val'# 将图像的像素值归一化到【-1, 1】之间normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])#train_transform = transforms.Compose([#训练集    transforms.Resize((224, 224)),#224*224    transforms.RandomVerticalFlip(),#随机垂直    transforms.ToTensor(),#转化为张量    normalize])#归一化val_transform = transforms.Compose([#验证集    transforms.Resize((224, 224)),    transforms.ToTensor(),    normalize])train_dataset = ImageFolder(ROOT_TRAIN, transform=train_transform)val_dataset = ImageFolder(ROOT_TEST, transform=val_transform)train_dataloader = DataLoader(train_dataset, batch_size=4, shuffle=True)#批次32,打乱val_dataloader = DataLoader(val_dataset, batch_size=4, shuffle=True)device = 'cuda' if torch.cuda.is_available() else 'cpu'#数据导入显卡里面model = MyAlexNet().to(device)#把数据送到神经网络中,然后输到显卡里面# 定义一个损失函数loss_fn = nn.CrossEntropyLoss()# 定义一个优化器optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)#随机梯度下降法,把模型参数传给优化器,学习率0.01# 学习率每隔10轮变为原来的0.5lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)# 定义训练函数def train(dataloader, model, loss_fn, optimizer):#数据,模型,学习率,优化器传入    loss, current, n = 0.0, 0.0, 0#指示器    for batch, (x, y) in enumerate(dataloader):        image, y = x.to(device), y.to(device)        output = model(image)#进行训练        cur_loss = loss_fn(output, y)#看误差        _, pred = torch.max(output, axis=1)#_代表不关心返回的最大值是多少。只需要得到pred        cur_acc = torch.sum(y==pred) / output.shape[0]#算精确率        # 反向传播        optimizer.zero_grad()#梯度降为0        cur_loss.backward()#反向传播        optimizer.step()#更新梯度        loss += cur_loss.item()#Loss值累加起来(一轮很多批次)        current += cur_acc.item()#准确度加起来        n = n+1#轮    train_loss = loss / n#计算这一轮学习的学习率(每一批的)    train_acc = current / n    print('train_loss' + str(train_loss))    print('train_acc' + str(train_acc))#训练精确的    return train_loss, train_acc#返回后面可视化用# 定义一个验证函数def val(dataloader, model, loss_fn):    # 将模型转化为验证模型    model.eval()    loss, current, n = 0.0, 0.0, 0    with torch.no_grad():        for batch, (x, y) in enumerate(dataloader):            image, y = x.to(device), y.to(device)            output = model(image)            cur_loss = loss_fn(output, y)            _, pred = torch.max(output, axis=1)            cur_acc = torch.sum(y == pred) / output.shape[0]            loss += cur_loss.item()            current += cur_acc.item()            n = n + 1    val_loss = loss / n    val_acc = current / n    print('val_loss' + str(val_loss))    print('val_acc' + str(val_acc))    return val_loss, val_acc# 定义画图函数def matplot_loss(train_loss, val_loss):    plt.plot(train_loss, label='train_loss')    plt.plot(val_loss, label='val_loss')    plt.legend(loc='best')    plt.ylabel('loss')    plt.xlabel('epoch')    plt.title("训练集和验证集loss值对比图")    plt.show(block=True)def matplot_acc(train_acc, val_acc):    plt.plot(train_acc, label='train_acc')    plt.plot(val_acc, label='val_acc')    plt.legend(loc='best')    plt.ylabel('acc')    plt.xlabel('epoch')    plt.title("训练集和验证集acc值对比图")    plt.show(block=True)# 开始训练loss_train = []acc_train = []loss_val = []acc_val = []epoch = 20 #20轮min_acc = 0for t in range(epoch):    lr_scheduler.step()#每十步分析一下学习率    print(f"epoch{t+1}\n-----------")    train_loss, train_acc = train(train_dataloader, model, loss_fn, optimizer)    val_loss, val_acc = val(val_dataloader, model, loss_fn)    loss_train.append(train_loss)#写到集合里头    acc_train.append(train_acc)    loss_val.append(val_loss)    acc_val.append(val_acc)    # 保存最好的模型权重    if val_acc >min_acc:#如果模型精确度大于0        folder = 'save_model'        if not os.path.exists(folder):#如果文件夹不存在            os.mkdir('save_model')#生成        min_acc = val_acc        print(f"save best model, 第{t+1}轮")        torch.save(model.state_dict(), 'save_model/best_model.pth')    # 保存最后一轮的权重文件    if t == epoch-1:        torch.save(model.state_dict(), 'save_model/last_model.pth')matplot_loss(loss_train, loss_val)matplot_acc(acc_train, acc_val)print('Done!')

最好的模型保存,嘻嘻。

生成的loss、acc图​:​

(效果其实是非常不好的,因为数据量太少了哈哈,然后参数某些地方也可以再调一下)

测试代码(test)

import torchfrom net import MyAlexNetfrom torch.autograd import Variablefrom torchvision import datasets, transformsfrom torchvision.transforms import ToTensorfrom torchvision.transforms import ToPILImagefrom torchvision.datasets import ImageFolderfrom torch.utils.data import DataLoaderROOT_TRAIN = r'D:/Users/Twilight/PycharmProjects/AlexNet/data/train'#数据集路径训练集ROOT_TEST = r'D:/Users/Twilight/PycharmProjects/AlexNet/data/val'# 将图像的像素值归一化到【-1, 1】之间normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])train_transform = transforms.Compose([    transforms.Resize((224, 224)),    transforms.RandomVerticalFlip(),    transforms.ToTensor(),    normalize])val_transform = transforms.Compose([    transforms.Resize((224, 224)),    transforms.ToTensor(),    normalize    ])train_dataset = ImageFolder(ROOT_TRAIN, transform=train_transform)#变张量val_dataset = ImageFolder(ROOT_TEST, transform=val_transform)train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)val_dataloader = DataLoader(val_dataset, batch_size=32, shuffle=True)device = 'cuda' if torch.cuda.is_available() else 'cpu'model = MyAlexNet().to(device)# 加载模型model.load_state_dict(torch.load("D:/Users/Twilight/PycharmProjects/AlexNet/save_model/best_model.pth"))# 获取预测结果classes = [    "cat",    "dog",]# 把张量转化为照片格式,后面可视化show = ToPILImage()# 进入到验证阶段model.eval()for i in range(10):#验证前十张    x, y = val_dataset[i][0], val_dataset[i][1]    show(x).show()    x = Variable(torch.unsqueeze(x, dim=0).float(), requires_grad=True).to(device)#把值传入到显卡里面    x = torch.tensor(x).to(device)    with torch.no_grad():        pred = model(x)        predicted, actual = classes[torch.argmax(pred[0])], classes[y]        print(f'predicted:"{predicted}", Actual:"{actual}"')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天都是被迫学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值