加入自定义块对fashion_mnist数据集进行softmax分类

发布时间 2023-07-24 14:09:13作者: Ann-

在之前,我们实现了使用torch自带的层对fashion_mnist数据集进行分类。这次,我们加入一个自己实现的block,实现一个四层的多层感知机进行softmax分类,作为对“自定义块”的代码实现的一个练习。

我们设计的多层感知机是这样的:输入维度为784,在展平层过后,第一层为全连接层,输入输出维度分别为784,256;第二层为全连接层,输入输出维度分别为256,128;第三层为全连接层,输入输出维度分别为128,64;第四层为全连接层(输出层),输入输出维度分别为64,10.代码如下:

import torch
from d2l import torch as d2l
from torch import nn
from torch.nn import functional as F

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
num_inputs = 784
num_outputs = 10

#输入层784; 隐藏层一784,256;隐藏层二256,128; 隐藏层三128,64; 输出层64,10
#我们用自定义Module实现隐藏层二、隐藏层三。
class practice_Module(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin1 = nn.Linear(256,128)
        self.lin2 = nn.Linear(128,64)
        nn.init.normal_(self.lin1.weight,std=0.01)
        nn.init.normal_(self.lin2.weight,std=0.01)
    def forward(self,X):
        X = self.lin1(X)
        X = F.relu(X)
        X = self.lin2(X)
        X = F.relu(X)
        return X
    
manual_block = practice_Module()
net = nn.Sequential(nn.Flatten(),
                   nn.Linear(784,256),
                   nn.ReLU(),
                   nn.Dropout(0.2),
                    manual_block,
                    nn.Dropout(0.3),
                    nn.Linear(64,10)
                   )

def init_weight(m):
    if m == nn.Linear:
        nn.init.normal_(m.weight,std=0.01)
    return 
net.apply(init_weight)

loss = torch.nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(),lr=0.1)
num_epochs = 20
d2l.train_ch3(net,train_iter,test_iter,loss,num_epochs,trainer)

 首先在我们自定义的模块中,初始化函数__init__中定义我们需要的两个层lin1和lin2.上面的代码在抽象的类practice_Module中的初始化函数__init__中进行了参数初始化,也就是说默认情况下用这个类创建的所有对象都会进行这样的默认初始化。

当然,也可以按我们的需要对具体的模块对象进行参数初始化。

然后在forward函数中定义这个模块进行的操作,即先让数据经过线性层lin1,激活,再经过线性层lin2,激活,然后输出。return X语句,return的X值作为输出,就会作为nn.Sequential中的下一层输入。

 注意:这里面的前向传播函数名必须是forward,而不能是其他的,改成其他的就会报错:

Module [practice_Module] is missing the required "forward" function

这也是为什么practice_Module类的实例在nn.Sequential中可以自动计算的原因,是因为系统会自动找到该实例中的方法forward并执行。

下面的语句初始化了一个practice_Module类的实例。可以这样理解:practice_Module是一个抽象的网络结构,而manual_block这个实例才是一个具体的我们需要的模型。

 可以用如下代码对模块实例进行初始化:

 在nn.Sequential中加入我们自定义的模块是非常简单的:

 init_weight()函数对torch中定义好了的层进行参数初始化: