CNN中input,output的计算推导

最近在研究facebook推出的深度学习框架pytorch,在使用CNN对非常经典的MNIST数据集进行卷积运算时遇到了些问题,就是自己手动使用公式进行推导时,总是在最后一步的全连接层矩阵运算时出错在这里插入图片描述

  • 开始也是比较的郁闷,为什么按照Stanford University CS231n上介绍的运算公式总是推算不对呢
  • 较劲的我又重新的返回来查看了这么一个非常简单的入门级别代码:
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        # 使用序列工具快速构建
        self.conv1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=5,stride=1, padding=2),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=5,stride=1,padding=2),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2))
        self.fc = nn.Linear(7*7*32, 10)

    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        out = out.view(out.size(0), -1)  # reshape
        out = self.fc(out)
        return out

然后我又开始在验算纸继续按照公式又运算了一遍:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
按照上面的代码公式可以总结为:

	W(out)=[W(in)+2p-F]/S+1
	H(out)=[H(in)+2p-F]/S+1

其中W(out),H(out)为输出维度,
W(in),H(in)为输入维度
p为padding
F为kernel_size

  • 结合这上面的公式对MNIST数据集的一张图片进行手动运算,原图像的维度为28*28
    计算:
    进行着第一步卷积之后的图像[28+22-5]/1+1
    可以看出此时的运算结果还为28 (可以自己的运算一遍进行验证)

  • 我们知道在进行卷积运算之后,是需要结合着pool的,也就是通常所说的池化,或者说降维,这里呢就介绍MaxPool

  • nn.MaxPool2d())

  • 看这其中的参数,个人认为这就是对输出数据进行折半处理咱们第一步开始进行验证自己的猜测
    如果猜测的正确的话,我们在进行四层卷积运算之后MNIST数据对应输出应该是

  • 14x14x16

  • 7x7x32

  • 3x3x64

  • 1x1x128
    验证:

import torch
import torch.nn as nn
import torchvision
from torch import optim
import torchvision.datasets as normal_datasets
import torchvision.transforms as transforms
from torch.autograd import Variable
num_epochs = 5 # 批次
batch_size = 100 # 批次数据
learning_rate = 0.001  # 学习率
# 将数据处理成Variable, 如果有GPU, 可以转成cuda形式
def get_variable(x):
    x = Variable(x)
    return x.cuda() if torch.cuda.is_available() else x
# 从torchvision.datasets中加载一些常用数据集
train_dataset = normal_datasets.MNIST(
    root='./MNIST_Model/',  # 数据集保存路径
    train=True,  # 是否作为训练集
    transform=transforms.ToTensor(),  # 数据如何处理, 可以自己自定义
    download=True)  # 路径下没有的话, 可以下载
# 见数据加载器和batch
test_dataset = normal_datasets.MNIST(root='./MNIST_Model/',
                                     train=False,
                                     transform=transforms.ToTensor())

train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                                          batch_size=batch_size,
                                          shuffle=False)

# 两层卷积
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        # 使用序列工具快速构建
        self.conv1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=5,stride=1, padding=2),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=5,stride=1,padding=2),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2))
        self.conv3=nn.Sequential(
            nn.Conv2d(32,64,kernel_size=5,stride=1,padding=2),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2))
        self.conv4=nn.Sequential(nn.Conv2d(64,128,kernel_size=5,stride=1,padding=2),
                                 nn.BatchNorm2d(128),
                                 nn.ReLU(),
                                 nn.MaxPool2d(2))
        self.fc = nn.Linear(1*1*128, 10)
    def forward(self, x):
        out = self.conv1(x)
        print(out.shape)
        out = self.conv2(out)
        print(out.shape)
        out=self.conv3(out)
        print(out.shape)
        out=self.conv4(out)
        print(out.shape)
        out = out.view(out.size(0), -1)  # reshape
        out = self.fc(out)
        return out
cnn = CNN()
if torch.cuda.is_available():
    cnn = cnn.cuda()

# 选择损失函数和优化方法
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(cnn.parameters(), lr=learning_rate)
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        images = get_variable(images)
        labels = get_variable(labels)

        outputs = cnn(images)
        loss = loss_func(outputs, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if (i + 1) % 100 == 0:
            print('Epoch [%d/%d], Iter [%d/%d] Loss: %.4f'
                  % (epoch + 1, num_epochs, i + 1, len(train_dataset) // batch_size, loss.item()))

在这里插入图片描述
此时可以看到确实是我们猜想的那样
*总结:
上述都是个人理解,如有不正确的地方欢迎提出,一同进步

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陶陶name

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

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

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

打赏作者

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

抵扣说明:

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

余额充值