def _parse(weights): """ :param weights: [14, 8] :return: """ gene = [] n = 2 start = 0 for i in range(self.steps): # for each node end = start + n W = weights[start:end].copy() # [2, 8], [3, 8], ... edges = sorted(range(i + 2), # i+2 is the number of connection for node i key=lambda x: -max(W[x][k] # by descending order for k in range(len(W[x])) # get strongest ops if k != PRIMITIVES.index('none')) )[:2] # only has two inputs for j in edges: # for every input nodes j of current node i k_best = None for k in range(len(W[j])): # get strongest ops for current input j->i if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) # save ops and input node start = end n += 1 return gene
def _parse(weights): #操作范围还是在一个cell中 gene = [] n = 2 #两个输入Node start = 0 for i in range( self._steps): #self._steps=4,从这个参数可以看出这是对一个cell进行的操作 end = start + n W = weights[start:end].copy() #一个cell中所有path组成一个矩阵,取出对应path的权重 # 每个Node的输入是前面所有Node输出(包括两个输入Node),下面的作用是从所有输入path中找到两条包含最大概率op的path,具体分析如下 # 可以看到排序的主体是range(i + 2) # 注意lambda表达式,出入的参数x in range(i + 2) # W[x][k] for k in range(len(W[x])) 遍历矩阵W第x行,实际上是在遍历第x条path上的op权重,找出权重最大的op,max()前之所以加“-” # ;因为sorted函数默认升序排序,这样可以使拥有最大权重op的path排在前面 # 注意最后的[:2]选择了两个最大的path edges = sorted( range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] for j in edges: #遍历我们选择的两个拥有最大权重op的path k_best = None for k in range(len(W[j])): #遍历每条path上的op的权重 if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k #记录最佳op gene.append((PRIMITIVES[k_best], j)) #第j条path,最佳op为PRIMITIVES[k_best] start = end # 进行下一个Node,在W中所有Node的输入path按顺序排好了 n += 1 # 对于下一个Node,输入Node增加一个 return gene #注意返回的格式,可参考genotypes.py中的格式
def _parse(weights, weights2): gene = [] n = 2 start = 0 for i in range(self._steps): end = start + n W = weights[start:end].copy() W2 = weights2[start:end].copy() for j in range(n): W[j, :] = W[j, :] * W2[j] edges = sorted( range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] #edges = sorted(range(i + 2), key=lambda x: -W2[x])[:2] for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def __init__(self, C, stride, PRIMITIVES): super(MixedOp, self).__init__() self._ops = nn.ModuleList() if 'none' not in PRIMITIVES: PRIMITIVES.insert(0, 'none') for primitive in PRIMITIVES: op = OPS[primitive](C, stride, False) if 'pool' in primitive: op = nn.Sequential( op, nn.BatchNorm2d(C, affine=False, track_running_stats=False)) self._ops.append(op)
def _parse(weights): """ Parse the weights that describe the architecture of the model. :param weights: torch.Tensor, rows are probability distributions (not actually necessary). :return: list, list of tuples with the following structure: [ (<operation_string>, <index_of_input>), ... ] The ordering follows the numbering of nodes in the cell. In other words, the first 2 are for node 0, the next 3 are for node 1, etc... """ gene = [] n = 2 start = 0 # For connection in the cell described by the alpha matrix... for i in range(self._steps): end = start + n # Get the rows that correspond to the alpha vectors that govern the current node in the cell. W = weights[start:end].copy() # Determine the two connections that are going to be used. # This weird sort lambda gets the indices of the two rows that have the largest values. # This determines the states that will be inputs to this node. edges = sorted( range(i + 2), key=lambda x: \ # This if statement disallows ever picking a "none" connection. # This functions as not connecting the nodes. -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')) )[:2] # For each of the edges we just determined, append their corresponding operation and index to the gene. for j in edges: k_best = None # Get the index of the maximum value in the aplpha vector. for k in range(len(W[j])): # None check allows for explicitly not having a connection between two nodes. if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k # Create the primitive and append it to the genome. gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def _parse(stride, sess): offset = 0 genotype = [] arch_var_name, arch_var = utils.get_var(tf.trainable_variables(), 'arch_params') for i in range(cells_num): edges = [] edges_confident = [] for j in range(i + 2): with tf.variable_scope("", reuse=tf.AUTO_REUSE): weight = arch_var[arch_var_name.index( "arch_params/weight{}_{}:0".format(stride, offset + j))] value = sess.run(weight) if np.argmax(value) == PRIMITIVES.index('none'): value = np.delete(value, np.argmax(value)) edges.append((PRIMITIVES[np.argmax(value)], j)) edges_confident.append(np.max(value)) edges_confident = np.array(edges_confident) max_edges = [ edges[np.argsort(edges_confident)[-1]], edges[np.argsort(edges_confident)[-2]] ] genotype.extend(max_edges) offset += i + 2 return genotype
def forward(self, s0, s1, weights, selected_idxs=None, att=None): edge_index = self.dilated_knn_graph(s0) s0 = self.preprocess0(s0) s1 = self.preprocess1(s1) states = [s0, s1] offset = 0 for i in range(self._steps): o_list = [] for j, h in enumerate(states): if selected_idxs[offset + j] == -1: # undecided mix edges o = self._ops[offset + j](h, edge_index, weights[offset + j], att=att) # call the gcn module, elif selected_idxs[offset + j] == PRIMITIVES.index( 'none'): # pruned edges pass else: # decided discrete edges o = self._ops[offset + j](h, edge_index, None, selected_idxs[offset + j], att=att) o_list.append(o) s = sum(o_list) offset += len(states) states.append(s) # import pdb;pdb.set_trace() return torch.cat(states[-self._multiplier:], dim=1)
def _parse(stride, sess): offset = 0 genotype = [] arch_var_name, arch_var = utils.get_var(tf.trainable_variables(), 'arch_var') for i in range(cells_num): edges = [] edges_confident = [] for j in range(i + 2): with tf.variable_scope("", reuse=tf.AUTO_REUSE): weight = arch_var[arch_var_name.index( "arch_var/weight{}_{}:0".format(stride, offset + j))] value = sess.run(weight) value_sorted = value.argsort() max_index = value_sorted[-2] if value_sorted[ -1] == PRIMITIVES.index('none') else value_sorted[-1] edges.append((PRIMITIVES[max_index], j)) edges_confident.append(value[max_index]) edges_confident = np.array(edges_confident) max_edges = [ edges[np.argsort(edges_confident)[-1]], edges[np.argsort(edges_confident)[-2]] ] genotype.extend(max_edges) offset += i + 2 return genotype
def _parse(weights): """ We have 4 steps, each step can have edge with previous steps + 2 inputs. So total edges = 2 + 3 + 4 + 5 = 14 We will have total 8 primitives for each of the 14 edges within each cell. So weight shape is [14, 8]. These are the alpha parameters and shared across cells. For each of the edges for a node, we want to find out top 2 strongest prmitives and make them as "final" for that node. As we don't consider none edge, this guerentees that each node will exactly end up with 2 edges, one final non-none primitive attached to each. :param weights: [14, 8] :return: string array, each member describes edge in the cell """ gene = [] n = 2 start = 0 for i in range(self.steps): # for each node end = start + n W = weights[start:end].copy() # [2, 8], [3, 8], ... # so far each edge has 8 primitives attached, we will chose top two so that # we get two best edges on which best primitives resides edges = sorted( range(i + 2), # i+2 is the number of connection for node i key=lambda x: -max(W[x][k] # by descending order for k in range(len(W[x]) ) # get strongest ops if k != PRIMITIVES.index('none')) )[:2] # only has two inputs # Each node i now we have 2 edges that still has 8 primitives each and # we want to select best primitive for each edge for j in edges: # for every input nodes j of current node i k_best = None for k in range(len( W[j])): # get strongest ops for current input j->i if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append( (PRIMITIVES[k_best], j)) # save ops and input node start = end n += 1 # at this point we should have each node, with exactly two edges and associated best primitive return gene
def _parse(probs): gene = [] start = 0 for i in range(STEPS): end = start + i + 1 W = probs[start:end].copy() j = sorted( range(i + 1), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[0] k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end return gene
def _parse(weights): gene = [] n = 2 start = 0 #self._steps:我认为是用来控制cell中的节点个数,此处=4 #i代表的是生成中间节点的第几个,i=0,表示第2个节点,...,i=3,表示第5个节点, # 因此最后将[2,3,4,5],即range(2,6)个节点进行torch.cat()操作 for i in range(self._steps): end = start + n W = weights[start:end].copy() #在这一部分就已经相应位置的alpha取了出来 '''weights.size()=[14,8],14个连线,每个线有8个操作 i=0,[start:end]=[0:2],n=3 i=1,[start:end]=[2:5],n=4 i=2,[start:end]=[5:9],n=5 i=3,[start:end]=[9:14],n=6 ''' #选出权重最大的两条边,即:第i个节点与哪两条边相连 '''range(i+2) i=0,range(2)=[0,1] i=1,range(3)=[0,1,2] i=2,range(4)=[0,1,2,3] i=3,range(5)=[0,1,2,3,4] ''' edges = sorted( range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] #为上面选出的两条边分别确定一个权重最大的操作:j代表边的位置:即起始点的连接节点,相应的i代表对应的终点连接的节点。 for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) #PRIMITIVES[k_best]:挑选出具有最大权重的操作 #j in [0,1,2,3,4],代表的是当前节点与几号节点相连,生成的中间节点[2,3,4,5]只保留权重最大的两个操作 start = end n += 1 return gene
def multi_parsev1(self, weights): weights = torch.round(torch.clamp(weights, 0, 1)) weights = weights.data.cpu().numpy() gene = [] start = 0 n = 2 for i in range(self._steps): end = start + n W = weights[start:end].copy() # 每个节点保留两个对应非零边的个数最大的连接 edges = sorted(range(i + 2), key=lambda x: sum(1 for k in range(len(W[x])) if k != PRIMITIVES.index('none') and W[x][k] == 0))[:2] # 该节点应该保留的两条边中 边j的情况 for j in edges: for k in range(len(W[j])): if k != PRIMITIVES.index("none") and W[j][k] != 0: gene.append((PRIMITIVES[k], j, 2 + i)) start = end n += 1 return gene
def _parse(weights): gene = [] n = 1 start = 0 for i in range(self._steps): end = start + n W = weights[start:end].copy() edges = sorted( range(i + 1), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:i + 1] for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def _parse(weights): gene = [] n = 2 start = 0 for i in range( self._steps ): # 当前规则是这样的,两个输入作为节点0和1,外加四个node构成全部cell,gene每两个pair对应一个node,每个pair的第二项就是该node连接的上一个node或者input的序号(0-该node-1中选择两个),所以每个node可能的连接依次加1,每个连接都在几种primitive中选择。 end = start + n W = weights[start:end].copy() edges = sorted( range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def _parse(weights): gene = [] n = 2 start = 0 for i in range(self._steps): end = start + n W = weights[start:end].copy() edges = sorted(range(i + 2), key=lambda x: -max( W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none') ) )[:2] # 找到前两个对应index for j in edges: # 访问对应边 k_best = None for k in range(len(W[j])): # shape (8,) if k != PRIMITIVES.index('none'): # 如果是第一个none,跳过 if k_best is None or W[j][k] > W[j][k_best]: k_best = k # 迭代更新,找到大对应的alpha gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def _parse(weights): gene = [] n = 2 start = 0 #self._steps:我认为是用来控制cell中的节点个数,此处=4 for i in range(self._steps): end = start + n W = weights[start:end].copy() edges = sorted( range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) #PRIMITIVES[k_best]:挑选出具有最大权重的操作 #j in [0,1,2,3,4],代表的是当前节点与几号节点相连,中间节点只取权重最大的两个操作 start = end n += 1 return gene
def _parse_global(probs): gene = [] start = 0 for i in range(STEPS): end = start + i + 1 W = F.softmax(probs[start:end].view(-1), dim=-1).view(i + 1, len(PRIMITIVES)).data.cpu().numpy() # W = probs[start:end].copy() listj = sorted( range(i + 1), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none'))) j = listj[0] if j == 0 and i > 0: j = listj[1] k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end return gene
def multi_parsev3(self,weights): weights = weights.data.cpu().numpy() gene = [] start = 0 n = 2 for i in range(self._steps): end = start + n W = weights[start:end].copy() # 保留所有mixop的非零连接 for j in range(len(W)): for k in range(len(W[j])): if k != PRIMITIVES.index("none") and W[j][k] != 0: gene.append((PRIMITIVES[k],j,2+i)) start = end n += 1 return gene
def check_edges(self, flags, selected_idxs): n = 2 max_num_edges = 2 start = 0 for i in range(self._steps): end = start + n num_selected_edges = torch.sum(1 - flags[start:end].int()) if num_selected_edges >= max_num_edges: for j in range(start, end): if flags[j]: flags[j] = False selected_idxs[j] = PRIMITIVES.index('none') # pruned edges self.alphas_normal[j].requires_grad = False else: pass start = end n += 1 return flags, selected_idxs
def multi_parsev1(self,weights): sweights = F.softmax(weights, dim=-1).data.cpu().numpy() gene = [] start = 0 n = 2 for i in range(self._steps): end = start + n OW = weights[start:end].copy() W = sweights[start:end].copy() # 每个节点保留两个对应softmax最大值最大的连接 edges = sorted(range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] # 每个节点保留两个对应非零边的个数最大的连接 # edges = sorted(range(i + 2), key=lambda x: sum( 1 for k in range(len(W[x])) if k !=PRIMITIVES.index('none') and W[x][k] == 0))[:2] # 该节点应该保留的两条边中 边j的情况 for j in edges: for k in range(len(W[j])): if k != PRIMITIVES.index("none") and OW[j][k] != 0: gene.append((PRIMITIVES[k],j,2+i)) start = end n += 1 return gene
def forward(self, s0, s1, weights, selected_idxs=None): s0 = self.preprocess0(s0) s1 = self.preprocess1(s1) states = [s0, s1] offset = 0 for i in range(self._steps): o_list = [] for j, h in enumerate(states): if selected_idxs[offset + j] == -1: # undecided mix edges o = self._ops[offset + j](h, weights[offset + j]) elif selected_idxs[offset + j] == PRIMITIVES.index('none'): # pruned edges pass else: # decided discrete edges o = self._ops[offset + j](h, None, selected_idxs[offset + j]) o_list.append(o) s = sum(o_list) offset += len(states) states.append(s) return torch.cat(states[-self._multiplier:], dim=1)
def _parse(weights: chainer.Parameter) -> List[Tuple[str, int]]: gene = [] n = 2 start = 0 none_index = PRIMITIVES.index('none') for i in range(self._steps): end = start + n w = weights[start:end] # 最も確率の高いedgeへのリンクを2つ取得する (何もしない操作の確率は無視) edges = sorted(range(i + 2), key=lambda x: max(w[x][op] for op in range(len(w[x])) if op != none_index), reverse=True)[:2] # 2つのリンクの中で最も確率の高いoperationを取得する (何もしない操作の確率は無視) for j in edges: k_best = None for k in range(len(w[j])): if k != none_index and (k_best is None or w[j][k] > w[j][k_best]): k_best = k gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def parse(weights, steps): gene = [] n = 2 start = 0 for i in range(steps): end = start + n W = weights[start:end].copy() edges = sorted(range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end n += 1 multiplier = 4 concat = range(2 + steps - multiplier, steps + 2) Genotype = namedtuple('Genotype', 'normal normal_concat') genotype_normal = Genotype(normal=gene, normal_concat=concat) return genotype_normal
def _parse(probs): """ build the discrete representation of the cell :param probs: tensor of dim (|max_edges| x |operations| representing the prob distribution of the ops """ gene = [] start = 0 # 'i' is the index regarding the edge to the ith intermediate node for i in range(STEPS): end = start + i + 1 # selecting the alpha vectors dedicated to the incoming edges of intermediate node i # for i = 2, get the vectors regarding edges: e(0,2), e(1,2) # for i = 3, get the vectors regarding edges: e(0,3), e(1,3), e(2,3) W = probs[start:end].copy() # among the vectors of the valid edges, select the vector of # the edge with the highest probable operation, this is for # the constraint that each node has only 1 incoming edge (see paper) j = sorted(range(i + 1), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[0] k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k # appending tuple describing the edge towards the ith node, # describing the activation function and the previous node (j) gene.append((PRIMITIVES[k_best], j)) start = end return gene
def _parse_tp(weights, weights2): gene = [] n = 2 start_op = 0 start_tp = 0 for i in range(self._steps): end_op = start_op + n end_tp = start_tp + Cal_Combination_Numbers(2 + i, 2) W = weights[start_op:end_op].copy() W2 = weights2[start_tp:end_tp].copy() edges = list(combinations(list(range(2 + i)), 2))[W2.argmax()] for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start_tp = end_tp start_op = end_op n += 1 return gene
def _parse_node(probs, node_probs): gene = [] start = 0 for i in range(STEPS): end = start + i + 1 W_node = F.softmax(node_probs[i, 0:i + 1], dim=-1).data.cpu().numpy() W = probs[start:end].copy() j_best = None k_best = None for j in range(len(W_node)): if j_best is None or W_node[j] > W_node[j_best]: j_best = j for k in range(len(W[j_best])): if k != PRIMITIVES.index('none'): if k_best is None or W[j_best][k] > W[j_best][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j_best)) start = end return gene
def _parse(stride): genotype = [] offset = 0 for i in range(steps): edges = [] edges_confident = [] for j in range(i + 2): value = arch_values[arch_names.index("arch/weight{}_{}".format( stride, offset + j))] value_sorted = value.argsort() max_index = value_sorted[-2] if value_sorted[ -1] == PRIMITIVES.index('none') else value_sorted[-1] edges.append((PRIMITIVES[max_index], j)) edges_confident.append(value[max_index]) edges_confident = np.array(edges_confident) max_edges = [ edges[np.argsort(edges_confident)[-1]], edges[np.argsort(edges_confident)[-2]] ] genotype.extend(max_edges) offset += i + 2 return genotype
def _parse(weights): gene = [] n = 2 start = 0 for i in range(self._steps): end = start + n #节点与其他节点存在连接的权重 W = weights[start:end].copy() #根据节点间的连接的权重,选择最优两个连接,未确定连接的op edges = sorted(range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != PRIMITIVES.index('none')))[:2] #对于每条边选择最优OP #对于每个节点。选择两条边及op。 for j in edges: k_best = None for k in range(len(W[j])): if k != PRIMITIVES.index('none'): if k_best is None or W[j][k] > W[j][k_best]: k_best = k gene.append((PRIMITIVES[k_best], j)) start = end n += 1 return gene
def forward(self, x, dag_node): output = self._ops[PRIMITIVES.index(dag_node.name_op)](x) if output.shape[1] != self._max_width: pd = (0, self._max_width - output.shape[1]) output = F.pad(output, pd, 'constant') return output