欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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两个变量如下图所示。
cell结构代码阅读记录
cell结构代码阅读记录

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)
相关标签: 代码阅读记录

上一篇:

下一篇: