神经网络架构搜索-Nasnet

model_network

这是一个PyTorch实现的神经网络代码,下面是每一行的作用:

import torch
import torch.nn as nn
from operations import *
from genotypes import Genotype

导入PyTorch和必要的库。

class Cell(nn.Module):
    def __init__(self, genotype, C_prev_prev, C_prev, C, reduction, reduction_prev, steps=4):
        super(Cell, self).__init__()
        self.steps = steps
        self.C = C

定义一个Cell类,继承自nn.Module。这个类表示一个组成神经网络的单元。genotype是一个基因型,它决定了这个单元中的操作集合。C_prev_prev、C_prev和C分别是前两个输入通道数和当前输入通道数。reduction和reduction_prev表示当前单元和前一个单元是否进行下采样。steps表示单元中操作的数量。

if reduction_prev:
    self.preprocess0 = FactorizedReduce(C_prev_prev, C)
else:
    self.preprocess0 = ReLUConvBN(C_prev_prev, C, 1, 1, 0)
self.preprocess1 = ReLUConvBN(C_prev, C, 1, 1, 0)

根据前一个单元是否进行下采样,选择不同的预处理方式。

if reduction:
    self.geno = genotype.reduce
    self.concat = genotype.reduce_concat
else:
    self.geno = genotype.normal
    self.concat = genotype.normal_concat
self.compiler(C,reduction)
self.multiplier = len(self.concat)

根据当前单元是否进行下采样,选择不同的基因型。调用compiler方法编译单元中的操作集合,并计算连接操作的数量。

def compiler(self, C, reduction):
    self.nodes = []
    self.ops = nn.ModuleList()
    self.combs = nn.ModuleList()
    for (n1, n2, op1_name, op2_name, comb_name) in self.geno:
        node1 = Node(self.steps, n1, C, reduction)
        node2 = Node(self.steps, n2, C, reduction)
        op1 = OPS[op1_name](C, C)
        op2 = OPS[op2_name](C, C)
        comb = combinatorial_func[comb_name]
        self.nodes += [node1, node2]
        self.ops += [op1, op2]
        self.combs += [comb]

编译单元中的操作集合。对于每一个操作对,创建两个节点、两个操作以及一个连接操作。

class Node(nn.Module):
    def __init__(self, steps, node_id, C, reduction):
        super(Node, self).__init__()
        self.steps = steps
        self.node_id = node_id
        self.C = C
        self.reduction = reduction
        self.op_names = nn.ParameterList()
        for i in range(self.steps):
            op_name = 'op_{}_{}'.format(self.node_id, i)
            if reduction:
                choices = [k for k in OPS_REDUCE.keys() if k != 'none']
            else:
                choices = [k for k in OPS.keys() if k != 'none']
            op = nn.Parameter(torch.Tensor(len(choices)))
            op.data.uniform_(0, 1)
            self.op_names.append(op)

定义一个Node类,继承自nn.Module。这个类表示一个单元中的节点。steps表示节点中操作的数量,node_id表示节点的编号,C表示节点的通道数,reduction表示当前单元是否进行下采样。对于每一个操作,创建一个可学习的参数。

def forward(self, s0, s1, weights):
    states = [s0, s1]
    offset = 0
    for i in range(self.steps):
        new_states = []
        for j in range(len(states)):
            h = states[j]
            for k in range(len(self.op_names)):
                op_weights = weights[offset + k]
                op_name = OPS_REDUCE if self.reduction else OPS
                op_func = op_name[self.op_names[k].argmax().item()]
                op = op_func(self.C, self.C)
                h_prime = op(h) * op_weights
                new_states.append(h_prime)
            offset += len(self.op_names)
        s = sum(new_states)
        states.append(s)
    return torch.cat([states[-self.multiplier:]], dim=1)

节点前向传播函数。对于每一个操作,计算其权重和输出,并将输出加权求和。最后将最后几个输出连接起来返回。

这是一个神经网络的类定义,包含了网络的结构和前向传播的方法。下面是每一行代码的作用:

class Network(nn.Module):
    def __init__(self, genotype, num_classes=10, C=4, stem_multiplier=2, layers=4):
        super(Network, self).__init__()

定义一个Network类,继承自nn.Module。这个类表示神经网络的结构和前向传播方法。

        C_curr = stem_multiplier * C
        self.stem = nn.Sequential(
            nn.Conv2d(1, C_curr, 3, padding=1, bias=False),
            nn.BatchNorm2d(C_curr)
        )

定义网络的第一层,包含一个卷积层和一个批量归一化层。

        C_prev_prev, C_prev, C_curr = C_curr, C_curr, C
        self.cells = nn.ModuleList()
        reduction_prev = False
        for i in range(layers):
            if i in [0,2]:
                C_curr *= 2
                reduction = True
            else:
                reduction = False
            cell = Cell(genotype, C_prev_prev, C_prev, C_curr, reduction, reduction_prev)
            reduction_prev = reduction
            self.cells += [cell]
            C_prev_prev, C_prev = C_prev, cell.multiplier * C_curr

定义网络的中间层,包含若干个Cell。根据layers参数指定的层数,循环创建Cell。根据当前层数i的值,判断是否需要进行下采样。然后创建一个Cell,并将其添加到cells列表中。最后更新输入通道数。

        self.global_pooling = nn.AdaptiveAvgPool2d(1)
        self.classifier = nn.Linear(C_prev, num_classes)

定义网络的最后两层,分别是全局平均池化层和线性分类器。

    def forward(self, input):
        s0 = s1 = self.stem(input)
        for i, cell in enumerate(self.cells):
            s0, s1 = s1, cell(s0, s1)
        out = self.global_pooling(s1)
        logits = self.classifier(out.view(out.size(0), -1))
        return logits

定义前向传播方法。首先对输入进行预处理,然后循环遍历每个Cell,并将当前Cell的输出作为下一个Cell的输入。最后对输出进行全局平均池化,然后通过线性分类器得到最终结果。

posted @ 2023-06-14 15:04  祁德龙冬强  阅读(91)  评论(0)    收藏  举报