基于torch.nn.functional.conv2d实现CNN

在我们之前的实验中,我们一直用torch.nn.Conv2D来实现卷积神经网络,但是torch.nn.Conv2D在实现中是以torch.nn.functional.conv2d为基础的,这两者的区别是什么呢?

torch.nn.Conv2D

源码如下:

torch.nn.Conv2d

CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')

可以发现,函数参数包括输入的通道数、输出的通道数、卷积核大小等。在输入中,我们不需要输入卷积核的权重,但是如果在实验中,我们需要用自己的卷积核,那么这种方式就不适用了。

torch.nn.functional.conv2d

源码如下:

torch.nn.functional

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) → Tensor

参数的具体意义:

input代表输入图像的大小(minibatch,in_channels,H,W),是一个四维tensor

filters代表卷积核的大小(out_channels,in_channe/groups,H,W),是一个四维tensor

bias代表每一个channel的bias,是一个维数等于out_channels的tensor

stride是一个数或者一个二元组(SH,SW),代表纵向和横向的步长

padding是一个数或者一个二元组(PH,PW ),代表纵向和横向的填充值

dilation是一个数,代表卷积核内部每个元素之间间隔元素的数目(不常用,默认为0)

groups是一个数,代表分组卷积时分的组数,特别的当groups = in_channel时,就是在做逐层卷积(depth-wise conv).

二者区别

torch.nn.Conv2D是一个类,而torch.nn.functional.conv2d是一个函数,在Sequential里面只能放nn.xxx,而nn.functional.xxx是不能放入Sequential里面的。

nn.Module 实现的 layer 是由 class Layer(nn.Module) 定义的特殊类,nn.functional 中的函数是纯函数,由 def function(input) 定义。

nn.functional.xxx 需要自己定义 weight,每次调用时都需要手动传入 weight,而 nn.xxx 则不用。

如果需要自己定义卷积核,那么就只能使用nn.functional.conv2d。但是在使用时,需要注意BatchNormalization和Dropout的使用方式。参考以下链接

接下来我们使用torch.nn.functional.conv2d来定义CNN实现Mnist数据集的识别,CNN定义如下所示:

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv_1_weight = nn.Parameter(torch.randn(16,1,3,3))
        self.bias_1_weight = nn.Parameter(torch.randn(16))
        self.bn1 = nn.BatchNorm2d(16)

        self.conv_2_weight = nn.Parameter(torch.randn(32,16,3,3))
        self.bias_2_weight = nn.Parameter(torch.randn(32))
        self.bn2 = nn.BatchNorm2d(32)

        self.Linear_weight = nn.Parameter(torch.randn(10,32*32*32))
        self.bias_weight = nn.Parameter(torch.randn(10))
    def forward(self,x):
        x = F.conv2d(x,self.conv_1_weight,self.bias_1_weight,stride=1,padding=1)
        x = F.relu(self.bn1(x),inplace=True)
        x = F.conv2d(x,self.conv_2_weight,self.bias_2_weight,stride=1,padding=1)
        x = F.relu(self.bn2(x),inplace=True)
        x = x.view(-1,32*32*32)
        x = F.linear(x,self.Linear_weight,self.bias_weight)
        return x

实验结果如下所示,最终的模型准确率为97%:

Epoch:  29 | Train Loss: 0.1965 | Test Accuracy: 0.97
Epoch:  29 | Train Loss: 0.1152 | Test Accuracy: 0.97
Epoch:  29 | Train Loss: 0.0702 | Test Accuracy: 0.97
Epoch:  29 | Train Loss: 0.0971 | Test Accuracy: 0.97
Epoch:  29 | Train Loss: 0.1620 | Test Accuracy: 0.97

全部代码如下所示:

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from data import Getdata
from torch import optim

data_train_loader,data_test_loader = Getdata()
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv_1_weight = nn.Parameter(torch.randn(16,1,3,3))
        self.bias_1_weight = nn.Parameter(torch.randn(16))
        self.bn1 = nn.BatchNorm2d(16)

        self.conv_2_weight = nn.Parameter(torch.randn(32,16,3,3))
        self.bias_2_weight = nn.Parameter(torch.randn(32))
        self.bn2 = nn.BatchNorm2d(32)

        self.Linear_weight = nn.Parameter(torch.randn(10,32*32*32))
        self.bias_weight = nn.Parameter(torch.randn(10))
    def forward(self,x):
        x = F.conv2d(x,self.conv_1_weight,self.bias_1_weight,stride=1,padding=1)
        x = F.relu(self.bn1(x),inplace=True)
        x = F.conv2d(x,self.conv_2_weight,self.bias_2_weight,stride=1,padding=1)
        x = F.relu(self.bn2(x),inplace=True)
        x = x.view(-1,32*32*32)
        x = F.linear(x,self.Linear_weight,self.bias_weight)
        return x
model = CNN()

optimizer = torch.optim.Adam(model.parameters(),lr=1e-3)
loss_func = nn.CrossEntropyLoss()
epoch = 30

for i in range(epoch):
    for step,(train_x,train_y) in enumerate(data_train_loader):
        model.train()
        output = model(train_x)
        loss = loss_func(output,train_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if step % 50 == 0:
            model.eval()
            with torch.no_grad():
                test_acc = 0
                num = 0
                for s,(test_x,test_y) in enumerate(data_test_loader):
                    output = model(test_x)
                    output = output.int()
                    pred_y = torch.max((output),dim=1)[1]
                    test_acc += test_y.eq_(pred_y).sum().item()
                    num += test_y.size(0)
            print('Epoch: ',i,'| Train Loss: %.4f'% loss.item(),'| Test Accuracy: %.2f' % float(test_acc / num))


努力加油a啊

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
解释这段代码import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import Dataset, DataLoader from sklearn.metrics import accuracy_score import jieba from CLDNN2 import CLDNN from CLDNNtest import CLDNNtest # 定义超参数 MAX_LENGTH = 100 # 输入序列的最大长度 VOCAB_SIZE = 35091 # 词汇表大小 EMBEDDING_SIZE = 128 # 词向量的维度 NUM_FILTERS = 100 # 卷积核数量 FILTER_SIZES = [2, 3, 4] # 卷积核尺寸 class SentimentDataset(Dataset): def __init__(self, texts, labels): self.texts = texts self.labels = labels def __len__(self): return len(self.texts) def __getitem__(self, index): text = self.texts[index] label = self.labels[index] return text, label class CNNClassifier(nn.Module): def __init__(self, vocab_size, embedding_size, num_filters, filter_sizes, output_size, dropout): super().__init__() self.embedding = nn.Embedding(vocab_size, embedding_size) # self.convs = nn.ModuleList([ # nn.Conv2d(1, num_filters, (fs, embedding_size)) for fs in filter_sizes # ]) self.convs = nn.Sequential( nn.Conv2d(1, num_filters, (2, 2)), # nn.MaxPool2d(2), nn.ReLU(inplace=True), nn.Conv2d(num_filters, num_filters, (3, 3)), nn.ReLU(inplace=True), nn.Conv2d(num_filters, num_filters, (4, 4)), nn.MaxPool2d(2), nn.ReLU(inplace=True), nn.Dropout(dropout) ) self.fc = nn.Sequential( nn.Linear(286700, 300), nn.Linear(300, output_size) ) # self.dropout = nn.Dropout(dropout) def forward(self, text): # text: batch_size * seq_len embedded = self.embedding(text) # batch_size * seq_len * embedding_size # print(embedded.shape) embedded = embedded.unsqueeze(1) # batch_size * 1 * seq_len * embedding_size x = self.convs(embedded) print(x.shape) # print(embedded.shape) # conved = [F.relu(conv(embedded)).squeeze(3)
06-08

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

starlet_kiss

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

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

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

打赏作者

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

抵扣说明:

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

余额充值