def build_cell(self, in_shapes:TensorShapesList, conf_cell:Config, cell_index:int) ->CellDesc: stem_shapes, stems = self.build_cell_stems(in_shapes, conf_cell, cell_index) cell_type = self.get_cell_type(cell_index) if self.template is None: node_count = self.get_node_count(cell_index) in_shape = stem_shapes[0] # input shape to noded is same as cell stem out_shape = stem_shapes[0] # we ask nodes to keep the output shape same node_shapes, nodes = self.build_nodes(stem_shapes, conf_cell, cell_index, cell_type, node_count, in_shape, out_shape) else: node_shapes, nodes = self.build_nodes_from_template(stem_shapes, conf_cell, cell_index) post_op_shape, post_op_desc = self.build_cell_post_op(stem_shapes, node_shapes, conf_cell, cell_index) cell_desc = CellDesc( id=cell_index, cell_type=self.get_cell_type(cell_index), conf_cell=conf_cell, stems=stems, stem_shapes=stem_shapes, nodes=nodes, node_shapes=node_shapes, post_op=post_op_desc, out_shape=post_op_shape, trainables_from=self.get_trainables_from(cell_index) ) # output same shape twice to indicate s0 and s1 inputs for next cell in_shapes.append([post_op_shape]) return cell_desc
def build_model_stems(self, in_shapes:TensorShapesList, conf_model_desc:Config)->List[OpDesc]: # TODO: why do we need stem_multiplier? # TODO: in original paper stems are always affine conf_model_stems = self.get_conf_model_stems() init_node_ch:int = conf_model_stems['init_node_ch'] stem_multiplier:int = conf_model_stems['stem_multiplier'] ops:List[str] = conf_model_stems['ops'] out_channels = init_node_ch*stem_multiplier conv_params = ConvMacroParams(self.get_ch(in_shapes[-1][0]), # channels of first input tensor init_node_ch*stem_multiplier) stems = [OpDesc(name=op_name, params={'conv': conv_params}, in_len=1, trainables=None) \ for op_name in ops] # get reduction factors done by each stem, typically they should be same but for # imagenet they can differ stem_reductions = ModelDescBuilder._stem_reductions(stems) # Each cell takes input from previous and 2nd previous cells. # To be consistence we create two outputs for model stems: [[s1, s0], [s0, s1] # This way when we access first element of each output we get s1, s0. # Normailly s0==s1 but for networks like imagenet, s0 will have twice the channels # of s1. for stem_reduction in stem_reductions: in_shapes.append([[out_channels, -1, -1.0/stem_reduction, -1.0/stem_reduction]]) return stems
def build_model_pool(self, in_shapes:TensorShapesList, conf_model_desc:Config)\ ->OpDesc: model_post_op = conf_model_desc['model_post_op'] last_shape = in_shapes[-1][0] in_shapes.append([copy.deepcopy(last_shape)]) return OpDesc(model_post_op, params={'conv': ConvMacroParams(last_shape[0], last_shape[0])}, in_len=1, trainables=None)