cell结构代码阅读记录
程序员文章站
2024-01-01 12:38:34
...
首先是Cell类的初始化过程——
注意:在__init__()函数中,比较难理解的是最后的step循环。需要结合论文3.1和4.1.1部分综合理解。每一步step都对应一个Block的建立过程,其中每一个Op都对应当前Block的一个输入张量。
Cell(nn.Module)
class Cell(nn.Module):
def __init__(self, steps, block_multiplier, prev_prev_fmultiplier,
prev_fmultiplier_down, prev_fmultiplier_same, prev_fmultiplier_up,
filter_multiplier):
''' 输入变量简释:
steps: 步骤数;
block_multiplier: 块乘数;
prev_prev_fmultiplier: 前前层的卷积核乘数;
prev_fmultiplier_down: 前下层的卷积核乘数;
prev_fmultiplier_same: 前同层的卷积核乘数;
prev_fmultiplier_up: 前上层的卷积核乘数;
filter_multiplier: 当前层的卷积核乘数。
'''
super(Cell, self).__init__()
self.C_in = block_multiplier * filter_multiplier
# 当前Cell的输出维度为:当前层的卷积核乘数。
self.C_out = filter_multiplier
self.C_prev_prev = int(prev_prev_fmultiplier * block_multiplier)
self._prev_fmultiplier_same = prev_fmultiplier_same
# 如果当前Cell的前一层里,有比当前级别低一级的Cell(即有前下层的Cell)。
if prev_fmultiplier_down is not None:
# 获取 中间块数???
self.C_prev_down = int(prev_fmultiplier_down * block_multiplier)
# 建立前下层到当前层的预处理中间卷积层。
self.preprocess_down = ReLUConvBN(
self.C_prev_down, self.C_out, 1, 1, 0, affine=False)
# 如果当前Cell的前一层里,有与当前Cell同级别的Cell(即有前同层的Cell)。
if prev_fmultiplier_same is not None:
self.C_prev_same = int(prev_fmultiplier_same * block_multiplier)
# 建立前同层到当前Cell的预处理Relu卷积层。
self.preprocess_same = ReLUConvBN(
self.C_prev_same, self.C_out, 1, 1, 0, affine=False)
# 如果当前Cell的前一层里,有比当前Cell高一级别的Cell(即有前同层的Cell)。
if prev_fmultiplier_up is not None:
self.C_prev_up = int(prev_fmultiplier_up * block_multiplier)
# 建立前高层到当前Cell的预处理ReLu卷积层。
self.preprocess_up = ReLUConvBN(
self.C_prev_up, self.C_out, 1, 1, 0, affine=False)
# 如果当前Cell有对应的前前层Cell。
if prev_prev_fmultiplier != -1:
# 建立前前层Cell的中间处理卷积层。
self.pre_preprocess = ReLUConvBN(
self.C_prev_prev, self.C_out, 1, 1, 0, affine=False)
self._steps = steps
self.block_multiplier = block_multiplier
self._ops = nn.ModuleList()
# 这里的step应该理解为打算构建的block数。
for i in range(self._steps):
# 2代表初始就有的两个输入张量,H(l-1)和H(l-2)。
# 每建完一个i,就多一个可选的张量,也就多一次此处的Op操作。
for j in range(2 + i):
stride = 1
# 当没有前前Cell时,则少一个对H(l-2)的Op操作。
if prev_prev_fmultiplier == -1 and j == 0:
op = None
else:
# 调用MixedOp()函数。
op = MixedOp(self.C_out, stride)
self._ops.append(op)
# 初始化权重
self._initialize_weights()
接下来解释两个上面提到的函数和类,MixedOp()和ReLUConvBN()。
ReLUConvBN(nn.Module)
class ReLUConvBN(nn.Module):
# 这里的输入跟nn.Conv2d的输入很像。
def __init__(self, C_in, C_out, kernel_size, stride, padding, affine=True, use_ABN=False):
super(ReLUConvBN, self).__init__()
# 当使用ABN时。
if use_ABN:
self.op = nn.Sequential(
nn.Conv2d(C_in, C_out, kernel_size, stride=stride, padding=padding, bias=False),
ABN(C_out)
)
else: # 在Cell结构初始化的时候,都没有采用ABN。因此进入以下分支。
# 建立一个次序模块,包含三个子模块:ReLU,Conv2d二维卷积,二维BN。
self.op = nn.Sequential(
nn.ReLU(inplace=False),
nn.Conv2d(C_in, C_out, kernel_size, stride=stride, padding=padding, bias=False),
nn.BatchNorm2d(C_out, affine=affine)
)
# 初始化权重。
self._initialize_weights()
MixedOp(nn.Module)
__init__()函数中,PRIMITIVES和OPS两个变量如下图所示。
class MixedOp(nn.Module):
def __init__(self, C, stride):
super(MixedOp, self).__init__()
# 创建一个空的ModuleList。
self._ops = nn.ModuleList()
# PRIMITIVES里存放了8种可以采用的layer type名称。
for primitive in PRIMITIVES:
# OPS是一个词典。存放每种layer type对应的类函数。
# 创建一个当前primitive定义的类的实例。
op = OPS[primitive](C, stride, False, False)
# 如果当前layer type是池化层的话,则需要进行BN操作。
if 'pool' in primitive:
op = nn.Sequential(op, nn.BatchNorm2d(C, affine=False))
# 将当前层次操作加入整体的模块List中。
self._ops.append(op)