def generate_negatives(pccs): generators = None unfinished = True generators = {} while unfinished: finished = set() if unfinished is True: combos = ut.random_combinations(pccs, 2) else: combos = unfinished for pcc1, pcc2 in combos: key = (pcc1, pcc2) if key not in generators: generators[key] = ut.random_product([pcc1, pcc2]) gen = generators[key] try: edge = e_(next(gen)) yield edge except StopIteration: finished.add(key) if unfinished is True: unfinished = set(generators.keys()) unfinished.difference_update(finished)
def negative_sample(pccs, per_pair=None): import utool as ut rng = ut.ensure_rng(2039141610, 'python') neg_pcc_pairs = ut.random_combinations(pccs, 2, rng=rng) yield from util.roundrobin( ut.random_product((cc1, cc2), num=per_pair, rng=rng) for cc1, cc2 in neg_pcc_pairs)
def generate_positives(pccs): generators = { i: ut.random_combinations(pcc, 2) for i, pcc in enumerate(pccs) } while generators: to_remove = set() for i, gen in generators.items(): try: yield e_(next(gen)) except StopIteration: to_remove.add(i) for i in to_remove: generators.pop(i)
def positive_sample(pccs, per_cc=None): import utool as ut rng = ut.ensure_rng(2039141610, 'python') yield from util.roundrobin( ut.random_combinations(cc, size=2, num=per_cc, rng=rng) for cc in pccs)
def main_gen(infr, max_loops=None, use_refresh=True): """ The main outer loop. This function is designed as an iterator that will execute the graph algorithm main loop as automatically as possible, but if user input is needed, it will pause and yield the decision it needs help with. Once feedback is given for this item, you can continue the main loop by calling next. StopIteration is raised once the algorithm is complete. Args: max_loops(int): maximum number of times to run the outer loop, i.e. ranking is run at most this many times. use_refresh(bool): allow the refresh criterion to stop the algo Notes: Different phases of the main loop are implemented as subiterators CommandLine: python -m wbia.algo.graph.mixin_loops main_gen Doctest: >>> # xdoctest: +REQUIRES(--slow) >>> from wbia.algo.graph.mixin_loops import * >>> from wbia.algo.graph.mixin_simulation import UserOracle >>> import wbia >>> infr = wbia.AnnotInference('testdb1', aids='all', >>> autoinit='staging', verbose=4) >>> infr.params['manual.n_peek'] = 10 >>> infr.params['ranking.ntop'] = 1 >>> infr.oracle = UserOracle(.99, rng=0) >>> infr.simulation_mode = False >>> infr.reset() >>> #infr.load_published() >>> gen = infr.main_gen() >>> while True: >>> try: >>> reviews = next(gen) >>> edge, priority, data = reviews[0] >>> feedback = infr.request_oracle_review(edge) >>> infr.add_feedback(edge, **feedback) >>> except StopIteration: >>> break """ infr.print('Starting main loop', 1) infr.print('infr.params = {}'.format(ut.repr3(infr.params))) if max_loops is None: max_loops = infr.params['algo.max_outer_loops'] if max_loops is None: max_loops = np.inf if infr.test_mode: logger.info('------------------ {} -------------------'.format(infr.name)) # Initialize a refresh criteria infr.init_refresh() infr.phase = 0 # Phase 0.1: Ensure the user sees something immediately if infr.params['algo.quickstart']: infr.loop_phase = 'quickstart_init' # quick startup. Yield a bunch of random edges num = infr.params['manual.n_peek'] user_request = [] for edge in ut.random_combinations(infr.aids, 2, num=num): user_request += [infr._make_review_tuple(edge, None)] yield user_request if infr.params['algo.hardcase']: infr.loop_phase = 'hardcase_init' # Check previously labeled edges that where the groundtruth and the # verifier disagree. for _ in infr.hardcase_review_gen(): yield _ if infr.params['inference.enabled']: infr.loop_phase = 'incon_recover_init' # First, fix any inconsistencies for _ in infr.incon_recovery_gen(): yield _ # Phase 0.2: Ensure positive redundancy (this is generally quick) # so the user starts seeing real work after one random review is made # unless the graph is already positive redundant. if infr.params['redun.enabled'] and infr.params['redun.enforce_pos']: infr.loop_phase = 'pos_redun_init' # Fix positive redundancy of anything within the loop try: for _ in infr.pos_redun_gen(): yield _ except StopIteration: pass infr.phase = 1 if infr.params['ranking.enabled']: for count in it.count(0): infr.print('Outer loop iter %d ' % (count,)) # Phase 1: Try to merge PCCs by searching for LNBNN candidates infr.loop_phase = 'ranking_{}'.format(count) for _ in infr.ranked_list_gen(use_refresh): yield _ terminate = infr.refresh.num_meaningful == 0 if terminate: infr.print('Triggered break criteria', 1, color='red') # Phase 2: Ensure positive redundancy. infr.phase = 2 infr.loop_phase = 'posredun_{}'.format(count) if all(ut.take(infr.params, ['redun.enabled', 'redun.enforce_pos'])): # Fix positive redundancy of anything within the loop for _ in infr.pos_redun_gen(): yield _ logger.info('prob_any_remain = %r' % (infr.refresh.prob_any_remain(),)) logger.info( 'infr.refresh.num_meaningful = {!r}'.format( infr.refresh.num_meaningful ) ) if (count + 1) >= max_loops: infr.print('early stop', 1, color='red') break if terminate: infr.print('break triggered') break infr.phase = 3 # Phase 0.3: Ensure positive redundancy (this is generally quick) if all(ut.take(infr.params, ['redun.enabled', 'redun.enforce_neg'])): # Phase 3: Try to automatically acheive negative redundancy without # asking the user to do anything but resolve inconsistency. infr.print('Entering phase 3', 1, color='red') infr.loop_phase = 'negredun' for _ in infr.neg_redun_gen(): yield _ infr.phase = 4 infr.print('Terminate', 1, color='red') infr.print('Exiting main loop') if infr.params['inference.enabled']: infr.assert_consistency_invariant() return 'finished'