def find_latest_local(self): """ >>> self = Deployer() >>> self.find_pretrained() >>> self.find_latest_local() """ from os.path import getctime task_clf_candidates = self.find_pretrained() task_clf_fpaths = {} for task_key, fpaths in task_clf_candidates.items(): # Find the classifier most recently created fpath = fpaths[ut.argmax(map(getctime, fpaths))] task_clf_fpaths[task_key] = fpath return task_clf_fpaths
def find_latest_remote(self): """ Used to update the published dict CommandLine: python -m wbia.algo.verif.vsone find_latest_remote Example: >>> # DISABLE_DOCTEST >>> from wbia.algo.verif.vsone import * # NOQA >>> self = Deployer() >>> task_clf_names = self.find_latest_remote() """ base_url = 'https://{remote}/public/models/pairclf'.format( **self.publish_info) import requests import bs4 resp = requests.get(base_url) soup = bs4.BeautifulSoup(resp.text, 'html.parser') table = soup.findAll('table')[0] def parse_bs_table(table): n_columns = 0 n_rows = 0 column_names = [] # Find number of rows and columns # we also find the column titles if we can for row in table.find_all('tr'): td_tags = row.find_all('td') if len(td_tags) > 0: n_rows += 1 if n_columns == 0: n_columns = len(td_tags) # Handle column names if we find them th_tags = row.find_all('th') if len(th_tags) > 0 and len(column_names) == 0: for th in th_tags: column_names.append(th.get_text()) # Safeguard on Column Titles if len(column_names) > 0 and len(column_names) != n_columns: raise Exception( 'Column titles do not match the number of columns') columns = column_names if len(column_names) > 0 else range( 0, n_columns) import pandas as pd df = pd.DataFrame(columns=columns, index=list(range(0, n_rows))) row_marker = 0 for row in table.find_all('tr'): column_marker = 0 columns = row.find_all('td') for column in columns: df.iat[row_marker, column_marker] = column.get_text().strip() column_marker += 1 if len(columns) > 0: row_marker += 1 return df df = parse_bs_table(table) # Find all available models df = df[df['Name'].map(lambda x: x.endswith('.cPkl'))] # df = df[df['Last modified'].map(len) > 0] fname_fmt = self.fname_fmtstr + '.cPkl' task_clf_candidates = ut.ddict(list) import parse for idx, row in df.iterrows(): fname = basename(row['Name']) result = parse.parse(fname_fmt, fname) if result: task_key = result.named['task_key'] species = result.named['species'] task_clf_candidates[(species, task_key)].append(idx) task_clf_fnames = ut.ddict(dict) for key, idxs in task_clf_candidates.items(): species, task_key = key # Find the classifier most recently created max_idx = ut.argmax(df.loc[idxs]['Last modified'].tolist()) fname = df.loc[idxs[max_idx]]['Name'] task_clf_fnames[species][task_key] = fname logger.info('published = ' + ut.repr2(task_clf_fnames, nl=2)) return task_clf_fnames
def update_visual_attrs(infr, graph=None, show_reviewed_edges=True, show_unreviewed_edges=False, show_inferred_diff=True, show_inferred_same=True, show_recent_review=False, highlight_reviews=True, show_inconsistency=True, wavy=False, simple_labels=False, show_labels=True, reposition=True, use_image=False, edge_overrides=None, node_overrides=None, colorby='name_label', **kwargs # hide_unreviewed_inferred=True ): import wbia.plottool as pt infr.print('update_visual_attrs', 3) if graph is None: graph = infr.graph # if hide_cuts is not None: # # show_unreviewed_cuts = not hide_cuts # show_reviewed_cuts = not hide_cuts if not getattr(infr, '_viz_init_nodes', False): infr._viz_init_nodes = True nx.set_node_attributes(graph, name='shape', values='circle') # infr.set_node_attrs('shape', 'circle') if getattr(infr, '_viz_image_config_dirty', True): infr.update_node_image_attribute(graph=graph, use_image=use_image) def get_any(dict_, keys, default=None): for key in keys: if key in dict_: return dict_[key] return default show_cand = get_any( kwargs, ['show_candidate_edges', 'show_candidates', 'show_cand']) if show_cand is not None: show_cand = True show_reviewed_edges = True show_unreviewed_edges = True show_inferred_diff = True show_inferred_same = True if kwargs.get('show_all'): show_cand = True # alpha_low = .5 alpha_med = 0.9 alpha_high = 1.0 dark_background = graph.graph.get('dark_background', None) # Ensure we are starting from a clean slate # if reposition: ut.nx_delete_edge_attr(graph, infr.visual_edge_attrs_appearance) # Set annotation node labels node_to_nid = None if not show_labels: nx.set_node_attributes(graph, name='label', values=ut.dzip(graph.nodes(), [''])) else: if simple_labels: nx.set_node_attributes( graph, name='label', values={n: str(n) for n in graph.nodes()}) else: if node_to_nid is None: node_to_nid = nx.get_node_attributes(graph, 'name_label') node_to_view = nx.get_node_attributes(graph, 'viewpoint') if node_to_view: annotnode_to_label = { aid: 'aid=%r%s\nnid=%r' % (aid, node_to_view[aid], node_to_nid[aid]) for aid in graph.nodes() } else: annotnode_to_label = { aid: 'aid=%r\nnid=%r' % (aid, node_to_nid[aid]) for aid in graph.nodes() } nx.set_node_attributes(graph, name='label', values=annotnode_to_label) # NODE_COLOR: based on name_label ut.color_nodes(graph, labelattr=colorby, outof=kwargs.get('outof', None), sat_adjust=-0.4) # EDGES: # Grab different types of edges edges, edge_colors = infr.get_colored_edge_weights( graph, highlight_reviews) # reviewed_states = nx.get_edge_attributes(graph, 'evidence_decision') reviewed_states = { e: infr.edge_decision(e) for e in infr.graph.edges() } edge_to_inferred_state = nx.get_edge_attributes( graph, 'inferred_state') # dummy_edges = [edge for edge, flag in # nx.get_edge_attributes(graph, '_dummy_edge').items() # if flag] edge_to_reviewid = nx.get_edge_attributes(graph, 'review_id') recheck_edges = [ edge for edge, split in nx.get_edge_attributes( graph, 'maybe_error').items() if split ] decision_to_edge = ut.group_pairs(reviewed_states.items()) neg_edges = decision_to_edge[NEGTV] pos_edges = decision_to_edge[POSTV] incomp_edges = decision_to_edge[INCMP] unreviewed_edges = decision_to_edge[UNREV] inferred_same = [ edge for edge, state in edge_to_inferred_state.items() if state == 'same' ] inferred_diff = [ edge for edge, state in edge_to_inferred_state.items() if state == 'diff' ] inconsistent_external = [ edge for edge, state in edge_to_inferred_state.items() if state == 'inconsistent_external' ] inferred_notcomp = [ edge for edge, state in edge_to_inferred_state.items() if state == 'notcomp' ] reviewed_edges = incomp_edges + pos_edges + neg_edges compared_edges = pos_edges + neg_edges uncompared_edges = ut.setdiff(edges, compared_edges) nontrivial_inferred_same = ut.setdiff( inferred_same, pos_edges + neg_edges + incomp_edges) nontrivial_inferred_diff = ut.setdiff( inferred_diff, pos_edges + neg_edges + incomp_edges) nontrivial_inferred_edges = nontrivial_inferred_same + nontrivial_inferred_diff # EDGE_COLOR: based on edge_weight nx.set_edge_attributes(graph, name='color', values=ut.dzip(edges, edge_colors)) # LINE_WIDTH: based on review_state # unreviewed_width = 2.0 # reviewed_width = 5.0 unreviewed_width = 1.0 reviewed_width = 2.0 if highlight_reviews: nx.set_edge_attributes( graph, name='linewidth', values=ut.dzip(reviewed_edges, [reviewed_width]), ) nx.set_edge_attributes( graph, name='linewidth', values=ut.dzip(unreviewed_edges, [unreviewed_width]), ) else: nx.set_edge_attributes(graph, name='linewidth', values=ut.dzip(edges, [unreviewed_width])) # EDGE_STROKE: based on decision and maybe_error # fg = pt.WHITE if dark_background else pt.BLACK # nx.set_edge_attributes(graph, name='stroke', values=ut.dzip(reviewed_edges, [{'linewidth': 3, 'foreground': fg}])) if show_inconsistency: nx.set_edge_attributes( graph, name='stroke', values=ut.dzip(recheck_edges, [{ 'linewidth': 5, 'foreground': infr._error_color }]), ) # Set linestyles to emphasize PCCs # Dash lines between PCCs inferred to be different nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(inferred_diff, ['dashed'])) # Treat incomparable/incon-external inference as different nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(inferred_notcomp, ['dashed'])) nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(inconsistent_external, ['dashed'])) # Dot lines that we are unsure of nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(unreviewed_edges, ['dotted'])) # Cut edges are implicit and dashed # nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(cut_edges, [True])) # nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(cut_edges, ['dashed'])) # nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(cut_edges, [alpha_med])) nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(uncompared_edges, [True])) # Only matching edges should impose constraints on the graph layout nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(neg_edges, [True])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(neg_edges, [alpha_med])) nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(incomp_edges, [True])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(incomp_edges, [alpha_med])) # Ensure reviewed edges are visible nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(reviewed_edges, [False])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(reviewed_edges, [alpha_high])) if True: # Infered same edges can be allowed to constrain in order # to make things look nice sometimes nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(inferred_same, [False])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(inferred_same, [alpha_high])) if not kwargs.get('show_same', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(inferred_same, [0])) if not kwargs.get('show_diff', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(inferred_diff, [0])) if not kwargs.get('show_positive_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(pos_edges, [0])) if not kwargs.get('show_negative_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(neg_edges, [0])) if not kwargs.get('show_incomparable_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(incomp_edges, [0])) if not kwargs.get('show_between', True): if node_to_nid is None: node_to_nid = nx.get_node_attributes(graph, 'name_label') between_edges = [(u, v) for u, v in edges if node_to_nid[u] != node_to_nid[v]] nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(between_edges, [0])) # SKETCH: based on inferred_edges # Make inferred edges wavy if wavy: # dict(scale=3.0, length=18.0, randomness=None)] nx.set_edge_attributes( graph, name='sketch', values=ut.dzip( nontrivial_inferred_edges, [dict(scale=10.0, length=64.0, randomness=None)], ), ) # Make dummy edges more transparent # nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(dummy_edges, [alpha_low])) selected_edges = kwargs.pop('selected_edges', None) # SHADOW: based on most recent # Increase visibility of nodes with the most recently changed timestamp if show_recent_review and edge_to_reviewid and selected_edges is None: review_ids = list(edge_to_reviewid.values()) recent_idxs = ut.argmax(review_ids, multi=True) recent_edges = ut.take(list(edge_to_reviewid.keys()), recent_idxs) selected_edges = recent_edges if selected_edges is not None: # TODO: add photoshop-like parameters like # spread and size. offset is the same as angle and distance. nx.set_edge_attributes( graph, name='shadow', values=ut.dzip( selected_edges, [{ 'rho': 0.3, 'alpha': 0.6, 'shadow_color': 'w' if dark_background else 'k', 'offset': (0, 0), 'scale': 3.0, }], ), ) # Z_ORDER: make sure nodes are on top nodes = list(graph.nodes()) nx.set_node_attributes(graph, name='zorder', values=ut.dzip(nodes, [10])) nx.set_edge_attributes(graph, name='zorder', values=ut.dzip(edges, [0])) nx.set_edge_attributes(graph, name='picker', values=ut.dzip(edges, [10])) # VISIBILITY: Set visibility of edges based on arguments if not show_reviewed_edges: infr.print('Making reviewed edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(reviewed_edges, ['invis'])) if not show_unreviewed_edges: infr.print('Making un-reviewed edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(unreviewed_edges, ['invis'])) if not show_inferred_same: infr.print('Making nontrivial_same edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(nontrivial_inferred_same, ['invis'])) if not show_inferred_diff: infr.print('Making nontrivial_diff edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(nontrivial_inferred_diff, ['invis'])) if selected_edges is not None: # Always show the most recent review (remove setting of invis) # infr.print('recent_edges = %r' % (recent_edges,)) nx.set_edge_attributes(graph, name='style', values=ut.dzip(selected_edges, [''])) if reposition: # LAYOUT: update the positioning layout def get_layoutkw(key, default): return kwargs.get(key, graph.graph.get(key, default)) layoutkw = dict( prog='neato', splines=get_layoutkw('splines', 'line'), fontsize=get_layoutkw('fontsize', None), fontname=get_layoutkw('fontname', None), sep=10 / 72, esep=1 / 72, nodesep=0.1, ) layoutkw.update(kwargs) # logger.info(ut.repr3(graph.edges)) pt.nx_agraph_layout(graph, inplace=True, **layoutkw) if edge_overrides: for key, edge_to_attr in edge_overrides.items(): nx.set_edge_attributes(graph, name=key, values=edge_to_attr) if node_overrides: for key, node_to_attr in node_overrides.items(): nx.set_node_attributes(graph, name=key, values=node_to_attr)
def try_auto_review(infr, edge): review = { 'user_id': 'algo:auto_clf', 'confidence': const.CONFIDENCE.CODE.PRETTY_SURE, 'evidence_decision': None, 'meta_decision': NULL, 'timestamp_s1': None, 'timestamp_c1': None, 'timestamp_c2': None, 'tags': [], } if infr.is_recovering(): # Do not autoreview if we are in an inconsistent state infr.print('Must manually review inconsistent edge', 3) return None # Determine if anything passes the match threshold primary_task = 'match_state' try: decision_probs = infr.task_probs[primary_task][edge] except KeyError: if infr.verifiers is None: return None if infr.verifiers.get(primary_task, None) is None: return None # Compute probs if they haven't been done yet infr.ensure_priority_scores([edge]) try: decision_probs = infr.task_probs[primary_task][edge] except KeyError: return None primary_thresh = infr.task_thresh[primary_task] decision_flags = { k: decision_probs[k] > thresh for k, thresh in primary_thresh.items() } hasone = sum(decision_flags.values()) == 1 auto_flag = False if hasone: try: # Check to see if it might be confounded by a photobomb pb_probs = infr.task_probs['photobomb_state'][edge] # pb_probs = infr.task_probs['photobomb_state'].loc[edge] # pb_probs = data['task_probs']['photobomb_state'] pb_thresh = infr.task_thresh['photobomb_state']['pb'] confounded = pb_probs['pb'] > pb_thresh except KeyError: logger.info('Warning: confounding task probs not set (i.e. photobombs)') confounded = False if not confounded: # decision = decision_flags.argmax() evidence_decision = ut.argmax(decision_probs) review['evidence_decision'] = evidence_decision truth = infr.match_state_gt(edge) if review['evidence_decision'] != truth: infr.print( 'AUTOMATIC ERROR edge={}, truth={}, decision={}, probs={}'.format( edge, truth, review['evidence_decision'], decision_probs ), 2, color='red', ) auto_flag = True if auto_flag and infr.verbose > 1: infr.print('Automatic review success') if auto_flag: return review else: return None