Ejemplo n.º 1
0
def 字典_取最小值(indexable, key=None):
    """
    # assert argmin({'a': 3, 'b': 2, 'c': 100}) == 'b'
    # assert argmin(['a', 'c', 'b', 'z', 'f']) == 0
    # assert argmin([[0, 1], [2, 3, 4], [5]], key=len) == 2
    # assert argmin({'a': 3, 'b': 2, 3: 100, 4: 4}) == 'b'
    # assert argmin(iter(['a', 'c', 'A', 'z', 'f'])) == 2
    """
    return ub.argmin(indexable, key)
Ejemplo n.º 2
0
        def add_pokemon(mon):
            add_poke1_button = driver.find_elements_by_class_name(
                'add-poke-btn')[0]
            add_poke1_button.click()

            select_drop = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/select')

            if 1:
                import xdev
                all_names = select_drop.text.split('\n')
                distances = xdev.edit_distance(mon.display_name(), all_names)
                chosen_name = all_names[ub.argmin(distances)]
            else:
                chosen_name = mon.name

            search_box = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/input')
            search_box.send_keys(chosen_name)

            advanced_ivs_arrow = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/a/span[1]')
            advanced_ivs_arrow.click()

            level40_cap = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[2]/div[2]/div[2]'
            )
            level41_cap = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[2]/div[2]/div[3]'
            )
            level50_cap = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[2]/div[2]/div[4]'
            )
            level51_cap = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[2]/div[2]/div[5]'
            )

            if mon.level >= 51:
                level51_cap.click()
            elif mon.level >= 50:
                level50_cap.click()
            elif mon.level >= 41:
                level41_cap.click()
            elif mon.level >= 40:
                level40_cap.click()

            level_box = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[1]/input'
            )
            level_box.click()
            level_box.clear()
            level_box.clear()
            level_box.send_keys(str(mon.level))

            iv_a = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[1]/div/input[1]'
            )
            iv_d = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[1]/div/input[2]'
            )
            iv_s = driver.find_element_by_xpath(
                '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[9]/div/div[1]/div/input[3]'
            )

            # TODO
            # driver.find_elements_by_class_name('move-select')

            iv_a.clear()
            iv_a.send_keys(str(mon.ivs[0]))

            iv_d.clear()
            iv_d.send_keys(str(mon.ivs[1]))

            iv_s.clear()
            iv_s.send_keys(str(mon.ivs[2]))

            # USE_MOVES = 1
            if mon.moves is not None:
                # mon.populate_all()

                fast_select = driver.find_element_by_xpath(
                    '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[10]/select[1]'
                )
                fast_select.click()
                fast_select.send_keys(mon.pvp_fast_move['name'])
                fast_select.send_keys(Keys.ENTER)

                charge1_select = driver.find_element_by_xpath(
                    '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[10]/select[2]'
                )
                charge1_select.click()
                charge1_select.send_keys(mon.pvp_charge_moves[0]['name'])
                charge1_select.send_keys(Keys.ENTER)

                charge2_select = driver.find_element_by_xpath(
                    '/html/body/div[5]/div/div[3]/div[1]/div[2]/div[10]/select[3]'
                )
                charge2_select.click()
                charge2_select.send_keys(mon.pvp_charge_moves[1]['name'])
                charge2_select.send_keys(Keys.ENTER)

            save_button = driver.find_elements_by_class_name('save-poke')[0]
            save_button.click()
Ejemplo n.º 3
0
def lr_range_test(harn, init_value=1e-8, final_value=10., beta=0.98,
                  explode_factor=10, num_iters=100):
    """
    Implementation of Leslie Smith's LR-range described in [2] test based on
    code found in [1].

    Args:
        init_value : initial learning rate
        beta (float): smoothing param

    Notes:
        It is critical that `init_value` starts off much lower than the actual
        valid LR-range. This is because this test actually modifies a copy of
        the model parameters as it runs, so the metrics (i.e. loss) of each LR
        actually benefits from all steps taken in previous iterations with
        previous lr values.

    References:
        .. _[1]: https://sgugger.github.io/how-do-you-find-a-good-learning-rate.html
        .. _[2]: https://arxiv.org/abs/1803.09820
        .. _[3]: https://github.com/fastai/fastai/blob/e6b56de53f80d2b2d39037c82d3a23ce72507cd7/old/fastai/sgdr.py

    Example:
        >>> from netharn.prefit.lr_tests import *
        >>> import netharn as nh
        >>> harn = nh.FitHarn.demo().initialize()
        >>> result = lr_range_test(harn)
        >>> print('result = {!r}'.format(result))
        >>> # xdoctest: +REQUIRES(--show)
        >>> import kwplot
        >>> result.draw()
        >>> kwplot.show_if_requested()

    Ignore:
        >>> import sys
        >>> sys.path.append('/home/joncrall/code/netharn/examples')
        >>> from mnist import setup_harn
        >>> harn = setup_harn().initialize()
        >>> harn.preferences['prog_backend'] = 'progiter'
        >>> result = lr_range_test(harn)
        >>> print('result = {!r}'.format(result))
        >>> result.draw()

    Ignore:
        >>> import sys
        >>> sys.path.append('/home/joncrall/code/netharn/examples')
        >>> from cifar import setup_harn
        >>> from mnist import setup_harn
        >>> harn = setup_harn().initialize()

        from netharn.mixins import *
        import xdev
        globals().update(xdev.get_func_kwargs(lr_range_test))

        init_value = 1e-5
        final_value = 0.1
    """
    import netharn as nh

    # Save the original state
    orig_model_state = copy.deepcopy(harn.model.state_dict())
    orig_optim_state = copy.deepcopy(harn.optimizer.state_dict())
    _orig_on_batch = harn.on_batch
    _orig_on_epoch = harn.on_epoch

    try:
        # TODO: find a way to disable callabacks nicely
        harn.on_batch = lambda *args, **kw: None
        harn.on_epoch = lambda *args, **kw: None

        def set_optimizer_property(optimizer, attr, value):
            for group in optimizer.param_groups:
                group[attr] = value

        def get_optimizer_property(optimizer, attr):
            return [group[attr] for group in optimizer.param_groups]

        optimizer = harn.optimizer
        ub.inject_method(optimizer, set_optimizer_property, 'set_property')
        ub.inject_method(optimizer, get_optimizer_property, 'get_property')

        orig_state = harn.model.state_dict()

        # This line seems like a safe way to reset model weights
        harn.model.load_state_dict(orig_state)

        tag = 'train'
        loader = harn.loaders[tag]

        num_epochs = min(num_iters, len(loader))

        # These are the learning rates we will scan through
        learning_rates = np.logspace(
            np.log10(init_value), np.log10(final_value),
            num=num_epochs, base=10, endpoint=False)

        # Bookkeeping
        metrics = nh.util.ExpMovingAve(alpha=1 - beta, correct_bias=True)
        best_loss = float('inf')
        best_lr = init_value
        records = ub.ddict(list)

        # Note: ignore the loss for thie first iteration. The loss computed here
        # corresponds to the original model without any SGD steps, so it doesn't
        # belong to any of the learning rates in our scan range.
        optimizer.set_property('lr', init_value)

        batch_iter = iter(loader)
        prog = ub.ProgIter(range(num_epochs), desc='running lr test')
        for bx in prog:
            # The LR that corresponds to the loss in the iteration belongs
            # to the LR that was set in the previous iteration.
            curr_lr = 0 if bx == 0 else optimizer.get_property('lr')[0]

            # Update the lr for the next step, but the loss computed was for
            # the previous iteration's LR value.
            next_lr = learning_rates[bx]
            optimizer.set_property('lr', next_lr)
            optimizer.zero_grad()

            # Get the loss for this mini-batch of inputs/outputs
            raw_batch = next(batch_iter)
            batch = harn.prepare_batch(raw_batch)
            outputs, loss = harn.run_batch(batch)
            if isinstance(loss, dict):
                loss = sum(loss.values())
            raw_loss = float(loss.data.cpu().item())

            # Compute the smoothed loss
            metrics.update({'loss': raw_loss})
            curr_loss = metrics.mean()['loss']

            # Record the best loss
            if curr_loss < best_loss:
                best_loss = curr_loss
                best_lr = curr_lr

            prog.set_extra(' best_lr={:.2g}, curr_lr={:.2g}, best_loss={:.2f}, curr_loss={:.2f}'.format(best_lr, curr_lr, best_loss, curr_loss))

            if bx > 0:
                # This loss was achived by a step with the previous lr, so
                # ensure we are associating the correct lr with the loss that
                # corresponds to it.
                records['loss_std'].append(metrics.std()['loss'])
                records['loss'].append(curr_loss)
                records['raw_loss'].append(raw_loss)
                records['lr'].append(curr_lr)

                # Stop if the loss is exploding
                if curr_loss > explode_factor * best_loss:
                    prog.update()
                    prog.ensure_newline()
                    print('\nstopping because loss is exploding')
                    break

            # Do SGD step, so now the nest loss computation correspond to
            # the first learning rate in our scan range.
            loss.backward()
            optimizer.step()

        # TODO: ensure that the loader is cleaned up properly
        prog.end()
        prog = None
        if hasattr(batch_iter, 'shutdown'):
            batch_iter._shutdown_workers()
        batch_iter = None
        loader = None

        best_x = ub.argmin(records['loss'])
        best_lr = records['lr'][best_x]
        print('best_lr = {!r}'.format(best_lr))

        recommended_lr = best_lr / 10
        # recommended_lr = best_lr
        print('recommended_lr = {!r}'.format(recommended_lr))
    except Exception:
        raise
    finally:
        # Reset model back to its original state
        harn.optimizer.load_state_dict(orig_optim_state)
        harn.model.load_state_dict(orig_model_state)
        harn.on_batch = _orig_on_batch
        harn.on_epoch = _orig_on_epoch

    def draw():
        import kwplot
        kwplot.autompl()
        ylimits = records['loss'] + (6 * records['loss_std'])
        ymax = np.percentile(ylimits, 96.9) / .9
        kwplot.multi_plot(
            xdata=records['lr'],
            ydata=records['loss'],
            spread=records['loss_std'],
            xlabel='learning-rate',
            ylabel='smoothed-loss',
            xscale='log',
            ymin=0,
            ymax=ymax,
            xmin='data',
            xmax='data',
            # xmin=min(records['lr']),
            # xmax=max(records['lr']),
            doclf=True,
            fnum=1,
        )

    result = TestResult(records, recommended_lr)
    result.draw = draw
    return result
Ejemplo n.º 4
0
def lr_range_scan(harn, low=1e-6, high=10.0, num=8, niter_train=1,
                  niter_vali=0, scale='log'):
    """
    This takes longer than lr_range_test, but is theoretically more robust.

    Args:
        low (float, default=1e-6): minimum lr to scan
        high (float, default=1.0): maximum lr to scan
        num (int, default=32): number of lrs to scan
        niter_train (int, default=10): number of training batches to test for each lr
        niter_vali (int, default=0): number of validation batches to test for each lr

    Notes:
        New better lr test:
            * For each lr in your scan range
            * reset model to original state
            * run a few batches and backprop after each
            * iterate over those batches again and compute their
              loss, but dont backprop this time.
            * associate the average of those losses with the learning rate.

    Example:
        >>> from netharn.prefit.lr_tests import *
        >>> import netharn as nh
        >>> harn = nh.FitHarn.demo().initialize()
        >>> result = lr_range_scan(harn)
        >>> print('result = {!r}'.format(result))
        >>> # xdoctest: +REQUIRES(--show)
        >>> import kwplot
        >>> result.draw()
        >>> kwplot.show_if_requested()

    Ignore:
        >>> import sys
        >>> sys.path.append('/home/joncrall/code/netharn/examples')
        >>> from mnist import setup_harn
        >>> harn = setup_harn().initialize()
        >>> harn.preferences['prog_backend'] = 'progiter'
        >>> result = lr_range_scan(harn, niter_train=100, niter_vali=10, num=32)
        >>> print('result = {!r}'.format(result))
        >>> result.draw()

    Ignore:
        >>> from netharn.mixins import *
        >>> import sys
        >>> sys.path.append('/home/joncrall/code/netharn/examples')
        >>> from ggr_matching import setup_harn
        >>> harn = setup_harn(workers=6, xpu=0).initialize()
        >>> result = lr_range_scan(harn, niter_train=6 * 2)
        >>> print('recommended_lr = {!r}'.format(recommended_lr))
        >>> draw()

    TODO:
        - [ ] ensure that this is a randomized sample of the validation
        dataset.
        - [ ] cache the dataset if it fits into memory after we run the first
        epoch.
    """
    import netharn as nh
    use_vali = bool(niter_vali)

    # These are the learning rates we will scan through
    if scale == 'linear':
        learning_rates = np.linspace(low, high, num=num,
                                     endpoint=True)
    elif scale == 'log':
        log_b, base = np.log10, 10
        learning_rates = np.logspace(log_b(low), log_b(high),
                                     num=num, base=base, endpoint=True)
    else:
        raise KeyError(scale)

    orig_model_state = copy.deepcopy(harn.model.state_dict())
    orig_optim_state = copy.deepcopy(harn.optimizer.state_dict())
    _orig_on_batch = harn.on_batch
    _orig_on_epoch = harn.on_epoch

    try:
        failed_lr = None
        best_lr = 0
        best_loss = float('inf')

        records = {}
        records['train'] = ub.ddict(list)
        if use_vali:
            records['vali'] = ub.ddict(list)

        # TODO: find a way to disable callabacks nicely
        harn.on_batch = lambda *args, **kw: None
        harn.on_epoch = lambda *args, **kw: None

        prog = harn._make_prog(learning_rates, desc='scan learning rates',
                               disable=not harn.preferences['show_prog'],
                               total=len(learning_rates), leave=True,
                               dynamic_ncols=True, position=0)

        harn.info('Running lr-scan')
        for lr in prog:
            # prog.set_description(ub.color_text('scan lr = {:.2g}'.format(lr), 'darkgreen'))
            if hasattr(prog, 'ensure_newline'):
                prog.ensure_newline()
            # Reset model back to its original state
            harn.optimizer.load_state_dict(orig_optim_state)
            harn.model.load_state_dict(orig_model_state)

            # Set the optimizer to the current lr we are scanning
            harn.optimizer.param_groups[0]['lr'] = lr

            # Run a partial training and validation epoch
            try:
                epoch_metrics = {}
                epoch_metrics['train'] = harn._demo_epoch('train', learn=True, max_iter=niter_train)
                curr_loss = epoch_metrics['train']['loss']

                if curr_loss > 1000:

                    raise nh.fit_harn.TrainingDiverged

                if use_vali:
                    epoch_metrics['vali'] = harn._demo_epoch('vali', learn=False, max_iter=niter_vali)
                    curr_loss = epoch_metrics['vali']['loss']

                if curr_loss < best_loss:
                    best_lr = lr
                    best_loss = curr_loss
                    curr_text = ub.color_text('curr_lr={:.2g}, best_loss={:.2f}'.format(lr, curr_loss), 'green')
                else:
                    curr_text = ub.color_text('curr_lr={:.2g}, best_loss={:.2f}'.format(lr, curr_loss), 'red')

                if hasattr(prog, 'ensure_newline'):
                    prog.set_extra(
                        curr_text + ', ' +
                        ub.color_text('best_lr={:.2g}, best_loss={:.2f}'.format(best_lr, best_loss), 'white')
                    )
                    prog.update()
                    prog.ensure_newline()
            except nh.fit_harn.TrainingDiverged:
                harn.info('Learning is causing divergence, stopping lr-scan')
                for tag in records.keys():
                    records[tag]['lr'].append(lr)
                    records[tag]['loss'].append(1000)
                raise

            for tag, epoch_metrics in epoch_metrics.items():
                records[tag]['lr'].append(lr)
                for key, value in epoch_metrics.items():
                    records[tag][key].append(value)

        harn.info('Finished lr-scan')

    except nh.fit_harn.TrainingDiverged:
        failed_lr = lr
        print('failed_lr = {!r}'.format(failed_lr))
    except Exception:
        failed_lr = lr
        print('failed_lr = {!r}'.format(failed_lr))
        raise
    finally:
        # Reset model back to its original state
        harn.optimizer.load_state_dict(orig_optim_state)
        harn.model.load_state_dict(orig_model_state)
        harn.on_batch = _orig_on_batch
        harn.on_epoch = _orig_on_epoch

    # Choose an lr to recommend
    tag = 'vali' if 'vali' in records else 'train'
    if records.get(tag, []):
        best_idx = ub.argmin(records[tag]['loss'])
        best_lr = records[tag]['lr'][best_idx]
        # Because we aren't doing crazy EWMAs and because we reset weights, we
        # should be able to simply recommend the lr that minimized the loss.
        # We may be able to do parabolic extrema finding to get an even better
        # estimate in most cases.
        recommended_lr = best_lr
    else:
        recommended_lr = None

    # Give the user a way of visualizing what we did
    def draw():
        import kwplot
        plt = kwplot.autoplt()
        plotkw = dict(
            xlabel='learning-rate', ylabel='loss', xscale=scale,
            ymin=0, xmin='data', xmax=high, fnum=1,
        )
        R = 2 if 'vali' in records else 1
        for i, tag in enumerate(['train', 'vali']):
            if tag in records:
                kwplot.multi_plot(
                    xdata=records[tag]['lr'], ydata=records[tag]['loss'],
                    ymax=1.2 * np.percentile(records[tag]['loss'], 60) / .6,
                    pnum=(1, R, i), title=tag + ' lr-scan', **plotkw)
                plt.plot(best_lr, best_loss, '*')

    result = TestResult(records, recommended_lr)
    result.draw = draw
    return result
Ejemplo n.º 5
0
def _check():
    # Find the sigma closest to the pyrDown op [1, 4, 6, 4, 1] / 16
    import cv2
    import numpy as np
    import scipy
    import ubelt as ub
    def sigma_error(sigma):
        sigma = np.asarray(sigma).ravel()[0]
        got = (cv2.getGaussianKernel(5, sigma) * 16).ravel()
        want = np.array([1, 4, 6, 4, 1])
        loss = ((got - want) ** 2).sum()
        return loss
    result = scipy.optimize.minimize(sigma_error, x0=1.0, method='Nelder-Mead')
    print('result = {}'.format(ub.repr2(result, nl=1)))

    best_loss = float('inf')
    best = None
    methods = ['Nelder-Mead', 'Powell', 'CG', 'BFGS',
               # 'Newton-CG',
               'L-BFGS-B', 'TNC', 'COBYLA', 'SLSQP',
               # 'trust-constr',
               # 'dogleg',
               # 'trust-ncg', 'trust-exact',
               # 'trust-krylov'
              ]
    # results = {}
    x0 = 1.06
    for i in range(100):
        for method in methods:
            best_method_loss, best_method_sigma, best_method_x0 = results.get(method, (float('inf'), 1.06, x0))
            result = scipy.optimize.minimize(sigma_error, x0=x0, method=method)
            sigma = np.asarray(result.x).ravel()[0]
            loss = sigma_error(sigma)
            if loss <= best_method_loss:
                results[method] = (loss, sigma, x0)

        best_method = ub.argmin(results)
        best_loss, best_sigma = results[best_method][0:2]
        rng = np.random
        if rng.rand() > 0.5:
            x0 = best_sigma
        else:
            x0 = best_sigma + rng.rand() * 0.0001
        print('best_method = {!r}'.format(best_method))
        print('best_loss = {!r}'.format(best_loss))
        print('best_sigma = {!r}'.format(best_sigma))

    print('results = {}'.format(ub.repr2(results, nl=1, align=':')))
    print('best_method = {}'.format(ub.repr2(best_method, nl=1)))
    print('best_method = {!r}'.format(best_method))

    sigma_error(1.0565139268118493)
    sigma_error(1.0565137190917149)
    # scipy.optimize.minimize_scalar(sigma_error, bounds=(1, 1.1))

    import kwarray
    import numpy as np
    a = (kwarray.ensure_rng(0).rand(32, 32) * 256).astype(np.uint8)
    a = kwimage.ensure_float01(a)
    b = cv2.GaussianBlur(a.copy(), (1, 1), 3, 3)
    assert np.all(a == b)

    import timerit
    ti = timerit.Timerit(100, bestof=10, verbose=2)
    for timer in ti.reset('time'):
        with timer:
            b = cv2.GaussianBlur(a.copy(), (9, 9), 3, 3)

    import timerit
    ti = timerit.Timerit(100, bestof=10, verbose=2)
    for timer in ti.reset('time'):
        with timer:
            c = cv2.GaussianBlur(a.copy(), (1, 9), 3, 3)
            zR= cv2.GaussianBlur(c.copy(), (9, 1), 3, 3)