神经网络架构搜索-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的输入。最后对输出进行全局平均池化,然后通过线性分类器得到最终结果。

浙公网安备 33010602011771号