LeNet

 定义模型

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.model=nn.Sequential(
            #卷积(-1)*1*28*28 ->(-1)*6*28*28 公式:[W=(W-F+2P)/S+1] [卷积输出大小=(输入大小-卷积核大小+2倍填充)/步长+1]
            #输入输出通道根据LeNet模型直接确定为1和6 卷积核大小是人为设定为5 5*5卷积后大小不变一般是padding=2
            Conv2d(in_channels=1,out_channels=6,kernel_size=5,padding=2),Sigmoid(),
            #池化(-1)*6*28*28 -> (-1)*6*14*14 公式:[W=(W-F)/S+1] [池化输出大小=[(输入大小-卷积核大小)/步长]+1]
            #当池化窗口扫描到边缘后池化窗口大于当前被扫窗口时,存在一个参数确定是否保留当前窗口池化后的数值,一般默认保留,可以防止信息丢失。
            AvgPool2d(kernel_size=2,stride=2),
            # 卷积(-1)*6*14*14 ->(-1)*16*10*10
            Conv2d(in_channels=6,out_channels=16,kernel_size=5,padding=0),Sigmoid(),
            # 池化(-1)*16*10*10 -> (-1)*16*5*5
            AvgPool2d(kernel_size=2,stride=2),
            #拉平 (-1)*16*5*5 -> (-1)*400  备注16*5*5=400
            Flatten(),
            #全连接  (-1)*400 -> (-1)*120
            Linear(in_features=400,out_features=120),Sigmoid(),
            # 全连接  (-1)*120 -> (-1)*84
            Linear(in_features=120,out_features=84),Sigmoid(),
            # 全连接  (-1)*84 -> (-1)*10
            Linear(in_features=84,out_features=10)
        )
    def forward(self,x):
        output=self.model(x)
        return output

# lenet=LeNet()
# print(lenet)
# x=torch.ones((64,1,28,28))
# y=lenet(x)
# print(y.shape)

在整个卷积块中,与上一层相比,每一层特征的高度和宽度都减小了。 第一个卷积层使用 2 个像素的填充,来补偿 5×5 卷积核导致的特征减少。 相反,第二个卷积层没有填充,因此高度和宽度都减少了 4 个像素。 随着层叠的上升,通道的数量从输入时的 1 个,增加到第一个卷积层之后的 6 个,再到第二个卷积层之后的 16 个。 同时,每个池化层的高度和宽度都减半。最后,由每个全连接层减少维数,最终输出一个维数与结果分类数相匹配的输出。

数据预处理

import torchvision
from torch.utils.data import DataLoader


'''数据预处理'''
dataset_transform=torchvision.transforms.Compose([                          #将预处理方法打包为一个整体
    torchvision.transforms.ToTensor(),                                      #第一个预处理:把PIL图片或者numpy数组转换为张量,转换前的numpy数组通道排列顺序是【】转换为张量之后的通道排序为【batch,channel,height,width】
    torchvision.transforms.Normalize(mean=(0.5,0.5,0.5),std=(0.5,0.5,0.5))  #第二个预处理:标准化 【(输入数据-均值)/ 标准差】
                                                                            #(输入数据-0.5) / 0.5
])

训练网络的一些参数

'''设置训练网络的一些参数'''
BATCH_SIZE=256                  #批次大小
#1e-2=1 x (10)^(-2)=1/100=0.01
LEARNING_RATE=0.001             #学习率
EPOCH=1                         #训练轮数
total_train_step=0              #记录训练次数
total_val_step=0                #记录验证次数w

用于画图

'''用于画图'''
train_loss_list=[]
Val_loss_list=[]
Val_accuracy_list=[]

下载数据集

'''下载数据集'''
train_set=torchvision.datasets.CIFAR10(root='./cifar10',                    #将数据集放在同级目录下的cifar10文件夹下
                                       train=True,                          #True代表为训练数据
                                       download=True,                       #如果没有下载过数据集,会自动下载
                                       transform=dataset_transform          #数据预处理
                                       )                                    #5w张训练图片
val_set=torchvision.datasets.CIFAR10(root='./cifar10',
                                      train=False,
                                      download=True,
                                      transform=dataset_transform
                                      )

加载数据集

'''加载数据集'''
train_loader=DataLoader(
    dataset=train_set,                  #导入训练集
    batch_size=BATCH_SIZE,              #在训练集中每次随机取出BATCH_SIZE个数据
    shuffle=True                        #将数据打乱
)
val_loader=DataLoader(
    dataset=val_set,
    batch_size=BATCH_SIZE,
    shuffle=False                       #验证时打乱与否没有影响,只需要查看效果,不会影响模型参数
)                                       # 10000张验证图片

迭代器

train_data_iter=iter(train_loader)                  #返回一个迭代器 ,dataloader是一个可迭代对象,可以使用iter()进行访问
train_imgs,trian_labels=train_data_iter.next()      #可以用next()一个批次一个批次的访问可迭代对象,也可以用下面的enumerate(dataloader)形式访问

计算数据集长度

train_set_size=len(train_set)
val_set_size=len(val_set)

创建网络模型

lenet=LeNet()
# print(lenet)
lenet.to('cuda')

损失函数

'''损失函数'''
loss_function=nn.CrossEntropyLoss()

优化器

optimizer=torch.optim.Adam(lenet.parameters(),lr=LEARNING_RATE)      #将lenet可训练的所有参数都进行训练

展示一些图片

# '''尝试展示一些图片,玩玩而已'''
# import matplotlib.pyplot as plt
# import numpy as np
# #定义函数
# def imshow(img):
#     img = img / 2 + 0.5     # 反标准化 预处理时将数据进行了标准化操作,(输入数据-0.5) / 0.5,所以此处把标注化给抵消掉
#     npimg = img.numpy()     # 预处理时将图片转化为了tensor类型,此处要把数据重新转换为numpy数据形式,同时还需要进行下一行代码的转换通道顺序操作
#     plt.imshow(np.transpose(npimg, (1, 2, 0)))#此处的 1 2 0 填写规则见博客https://blog.csdn.net/qq_39413850/article/details/121699885
#     plt.show()
# #随机取出一些训练图片
# dataiter=iter(train_loader)
# val_imgs,val_labels=dataiter.next()
# #展示图片
# imshow(torchvision.utils.make_grid(val_imgs))
# #打印标签
# classes = ('plane', 'car', 'bird', 'cat',
#            'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# print(' '.join('%5s'% classes[val_labels[j]] for j in range(BATCH_SIZE)))

训练与测试

'''训练'''
for enpoch in range(EPOCH):
    print("----------Begin epoch{} ----------".format(enpoch + 1))
    sum_loss=0  #累计损失
    lenet.train()
    for idx,data in enumerate(iterable=train_loader,start=0):
        imgs, targets = data[0].to('cuda'), data[1].to('cuda')
        optimizer.zero_grad()               # 梯度清零
        outputs=lenet(imgs)                 #将图片放入lenet模型
        loss=loss_function(outputs,targets) #参数一:预测值,参数二:真实值
        loss.backward()                     #反向传播
        optimizer.step()                    #参数更新
        sum_loss+=loss.item()               #累计损失并且将损失变为一个具体的数

        if idx%390==389:                  #每隔500次打印一次
            print('iter:[%d,%5d] loss:%.3f'%(enpoch+1,idx+1,sum_loss))       #打印当前轮次,当前迭代索引,累计损失
            train_loss_list.append(sum_loss/390)                              #Train loss vs. Iters
            sum_loss=0.0                                                      #将损失清零,进行下一次迭代

    sava_path = './lenet_{}.pth'.format(enpoch)
    torch.save(lenet.state_dict(), sava_path)
    print("save model :lenet{}".format(enpoch))


# 测试
    lenet.eval()
    sum_correct=0
    total_val_loss = 0
    with torch.no_grad():
        for data in val_loader:
            imgs, targets = data
            imgs = imgs.to('cuda')
            targets = targets.to('cuda')
            outputs = lenet(imgs)                                   #shape:[batch,10]
            loss = loss_function(outputs,targets)
            total_val_loss = total_val_loss + loss.item()
            correct = (outputs.argmax(1) == targets).sum()           #sum求True的个数
            sum_correct = sum_correct+correct

    print("Val Loss:{:.2f}".format(total_val_loss))
    Val_loss_list.append(total_val_loss/78)
    print("Val Accuracy:{:.2f}%".format(100*(sum_correct)/val_set_size))
    Val_accuracy_list.append((100 * (sum_correct.item()) / val_set_size))

绘图

x1=range(0,1)
x2=range(0,1)
x3=range(0,1)

y1=train_loss_list
y2=Val_loss_list
y3=Val_accuracy_list

plt.figure()
plt.plot(x1,y1,'r.-',x2,y2,'g.-')
plt.title('Loss vs. Epoches ')
plt.xlabel('Epoches')
plt.ylabel('Train loss:red | Val loss:green')


plt.figure()
plt.plot(x3,y3,'c.-')
plt.title('Val accuracy vs. Epoches')
plt.xlabel('Epoches')
plt.ylabel('Val accuracy')

plt.show()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值