예제 #1
0
def main(argv):
    """
    Parses command line options and starts the batch processing.

    :param argv: Command line arguments
    :type argv: list
    :return: None
    """
    # Parse command line arguments
    parser = argparse.ArgumentParser(description='SPtP Batch Processing')
    parser.add_argument('-i', '--input-folder-path', dest='input_folder_path',
                        help='Path to the folder containing input data (i. e. images, SURs file, and *.truth.kml files).')
    parser.add_argument('-o', '--output-folder-path', dest='output_folder_path',
                        help='Path to the folder that will contain the resulting KML files. It will be deleted if it exists.')
    parser.add_argument('-s', '--surs-file-path', dest='surs_file_path', default='./input/surs.txt',
                        help='Path to the text file containing the SURs. (Default: ./input/surs.txt)')
    parser.add_argument('-f', '--factors-file-path', dest='factors_file_path', default='./data/factors.txt',
                        help='Path to the text file containing the SURs. (Default: ./data/factors.txt).')
    parser.add_argument('-c', '--cache-folder-path', dest='cache_folder_path',
                        help='Path to the folder containing cache data (i. e. data from OpenStreetMap)')
    parser.add_argument('-u', '--force-cache-update', dest='force_cache_update', help='Force cache update.',
                        action='store_true')
    parser.add_argument('--skip-cache-update', dest='skip_cache_update',
                        help='Skip automatic cache update. Useful e.g. if no internet connection is available.',
                        action='store_true')
    parser.add_argument('-q', '--quiet-mode', dest='quiet_mode', help='Do not write to stdout.', action='store_true')
    parser.add_argument('--exclude-slow-classifiers', dest='exclude_slow_classifiers',
                        help='Exclude classifiers with suboptimal running times.', action='store_true')
    parser.add_argument('--overpass-radius', dest='overpass_radius', help='Overpass API query radius.', type=int)
    parser.add_argument('--compare-results', dest='compare_results',
                        help='Compare computed polygons to polygons in *.truth.kml files.', action='store_true')
    parser.add_argument('--log-prefix', dest='log_file_prefix', default='icup_',
                        help='Sets a prefix for log file names. (Default: icup_)')
    parser.add_argument('--debug-output', dest='debug_output', help='Saves CSV files for debug purposes.',
                        action='store_true')
    parser.add_argument('--two-circle-intersection', dest='use_two_circle_intersection_ratio',
                        help='Use two circle intersection ratio method. Default: False', action='store_true')

    args = parser.parse_args()

    # Compile settings
    settings = batch.default_settings()
    if args.input_folder_path:
        settings['input_folder_path'] = args.input_folder_path + os.path.sep
    if args.output_folder_path:
        settings['output_folder_path'] = args.output_folder_path + os.path.sep
    if args.cache_folder_path:
        settings['cache_folder_path'] = args.cache_folder_path + os.path.sep
    if args.overpass_radius:
        settings['overpass_radius'] = args.overpass_radius
    settings['surs_file_path'] = args.surs_file_path
    settings['factors_file_path'] = args.factors_file_path
    settings['force_cache_update'] = args.force_cache_update
    settings['skip_cache_update'] = args.skip_cache_update
    settings['quiet_mode'] = args.quiet_mode
    settings['exclude_slow_classifiers'] = args.exclude_slow_classifiers
    settings['compare_results'] = args.compare_results
    settings['log_file_prefix'] = args.log_file_prefix
    settings['debug_output'] = args.debug_output
    settings['use_two_circle_intersection_ratio'] = args.use_two_circle_intersection_ratio

    # Run batch processing
    exit_code = batch.main(settings)
    if not args.quiet_mode:
        if exit_code == 0:
            print('Batch processing finished successfully.')
        else:
            print('Batch processing failed. Check log files for details.')
    return exit_code
예제 #2
0
def main(settings):
    """
    Runs the learning process.

    :param settings: Settings dict like default_learning_settings. Defaults to default_learning_settings
    :type settings: dict
    :return: 0 if success, 1 otherwise
    :rtype: int
    """

    def get_random_number():
        """
        Returns a random number.

        The chance of getting a number between 0-1 is equal to 1-settings['max_factor_value']
        The numbers are uniformly distributed in both ranges.

        :return: Random number between 0 and settings['max_factor_value']
        :rtype: float
        """
        random_num = random.random()
        if random_num < 0.5:
            return random_num * 2
        else:
            return random.uniform(1, settings['max_factor_value'])

    def test_result(batch_settings, learning_settings, winner):
        """
        Tests the accuracy after learning.

        :param batch_settings: The settings used for batch processing. Path will be corrected in the method
        :type batch_settings: Dict from batch.default_settings()
        :param learning_settings: The settings used for learning. Path will be corrected in the method
        :type learning_settings: Dict from batch.default_settings()
        :param batch_settings: The winner of the learning
        :type batch_settings: factors.Factors
        :return: None
        """
        nonlocal main_log_file
        settings = batch_settings.copy()
        settings['surs_file_path'] = learning_settings['test_surs_file_path']
        settings['input_folder_path'] = learning_settings['test_folder_path']
        settings['factors'] = winner
        batch.main(settings)
        try:
            comparator = Comparator(settings['input_folder_path'], settings['output_folder_path'], settings['minimum_intersection_ratio'], raise_on_critical_error=True)
            comparator.run()
        except Exception as exception:
            print('Comparison failed! See log file for more information.')
            main_log_file.write('COMPARISON FAILURE\n')
            main_log_file.write('%s\n' % str(exception))
            main_log_file.write('Can not complete comparison, aborting.\n')
            return 1

        comparator.print(sys.stdout, False)
        comparator.print(main_log_file, False)


    def clear_learning_tmp():
        """
        Deletes temporary files created by processing.

        :return: None
        """
        nonlocal main_log_file
        main_log_file.write('Deleting temporary files...')
        try:
            shutil.rmtree(settings['temp_folder_path'])
            main_log_file.write('OK\n')
        except Exception as error:
            main_log_file.write('FAILURE\n')
            main_log_file.write('%s\n' % str(error))
            main_log_file.write('Can not delete temporary folder "%s", aborting.\n' % settings['temp_folder_path'])
            sys.exit(1)

    #Create header
    header = format_header(settings)
    print(header + '\n')

    # Initialize
    if not os.path.exists(settings['log_folder_path']):
        try:
            os.makedirs(settings['log_folder_path'])
        except OSError as error:
            print('FAILURE')
            print('%s' % str(error))
            print('Can not create log folder "%s", aborting.' % settings['print_folder_path'])
            sys.exit(1)

    # Settings for batch processing
    batch_settings = batch.default_settings()
    batch_settings['surs_file_path'] = settings['surs_file_path']
    batch_settings['input_folder_path'] = settings['db_folder_path']
    batch_settings['output_folder_path'] = settings['temp_folder_path']
    batch_settings['log_folder_path'] = settings['log_folder_path']
    batch_settings['cache_folder_path'] = settings['cache_folder_path']
    batch_settings['force_cache_update'] = True  # Force cache update
    batch_settings['maximum_cache_file_age'] = settings['maximum_cache_file_age']
    batch_settings['overpass_radius'] = settings['overpass_radius']
    batch_settings['minimum_intersection_ratio'] = settings['minimum_intersection_ratio']
    batch_settings['use_two_circle_intersection_ratio'] = settings['use_two_circle_intersection_ratio']
    batch_settings['compare_results'] = False
    batch_settings['quiet_mode'] = True
    batch_settings['log_file_prefix'] = 'learning_'

    main_log_file_path = settings['log_folder_path'] + 'learning.log'
    try:
        with open(main_log_file_path, 'w', 1) as main_log_file:
            main_log_file.write(header + '\n')
            main_log_file.write('Initializing...')
            if not os.path.exists(settings['cache_folder_path']):
                try:
                    os.makedirs(settings['cache_folder_path'])
                except OSError as error:
                    main_log_file.write('FAILURE\n')
                    main_log_file.write('%s\n' % str(error))
                    main_log_file.write('Can not create folder "%s", aborting.\n' % settings['cache_folder_path'])
                    return 1
            if not os.path.exists(settings['temp_folder_path']):
                try:
                    os.makedirs(settings['temp_folder_path'])
                except OSError as error:
                    main_log_file.write('FAILURE\n')
                    main_log_file.write('%s\n' % str(error))
                    main_log_file.write('Can not create folder "%s", aborting.\n' % settings['temp_folder_path'])
                    return 1
            if not os.path.exists(settings['log_folder_path']):
                try:
                    os.makedirs(settings['log_folder_path'])
                except OSError as error:
                    main_log_file.write('FAILURE\n')
                    main_log_file.write('%s\n' % str(error))
                    main_log_file.write('Can not create folder "%s", aborting.\n' % settings['log_folder_path'])
                    return 1
            main_log_file.write('OK\n')

            main_log_file.write('Initializing factors...')
            factor_list = []
            for i in range(0, settings['population']):
                temp_factor = Factors()
                for classifier in classifiers_list:
                    temp_factor.factors[classifier.name()] = get_random_number()
                factor_list.append((temp_factor, None))
            main_log_file.write('OK\n')

            winner = None
            for round in range(settings['rounds']):
                print('Round %i' % (round + 1), end='', flush=True)
                main_log_file.write('Round %i' % (round + 1))

                # New population
                current_population = factor_list.copy()
                result_population = []
                for i in range(0, settings['new_population_per_turn']):
                    parent1 = current_population[random.randint(0, len(current_population) - 1)][0]
                    parent2 = current_population[random.randint(0, len(current_population) - 1)][0]
                    child = Factors()
                    for classifier in classifiers_list:
                        if random.randint(0, 1) == 0:
                            child.factors[classifier.name()] = parent1.factors[classifier.name()]
                        else:
                            child.factors[classifier.name()] = parent2.factors[classifier.name()]
                    # Mutation of children
                    if random.random() < settings['mutations_rate']:
                        child.factors[classifiers_list[random.randint(0, len(classifiers_list) - 1)].name()] = get_random_number()
                    current_population.append((child, None))

                # Processing
                for current_factor in current_population:
                    if current_factor[1] is None:
                        batch_settings['factors'] = current_factor[0]
                        if batch.main(batch_settings) == 1:
                            main_log_file.write(' ERROR - Can not complete batch processing!')
                            print('!', end='', flush=True)
                            result_population.append((current_factor[0], -1.0))
                            continue
                        batch_settings['force_cache_update'] = False

                        try:
                            comparator = Comparator(settings['db_folder_path'], settings['temp_folder_path'], settings['minimum_intersection_ratio'], raise_on_critical_error=True, use_two_circle_intersection_ratio=settings['use_two_circle_intersection_ratio'])
                            comparator.run()
                        except Exception as exception:
                            main_log_file.write(' ERROR - %s!' % str(exception))
                            result_population.append((current_factor[0], -1.0))
                            print('!', end='', flush=True)
                            continue
                        if settings['use_two_circle_intersection_ratio']:
                            passed = len(comparator.passed)
                            points = (passed / (passed + len(comparator.failed) + len(comparator.erroneous))) - (comparator.average_intersection_ratio/100)
                        else:
                            points = comparator.average_intersection_ratio
                        result_population.append((current_factor[0], points))
                        print('.', end='', flush=True)
                        main_log_file.write('.')
                    else:
                        print(':', end='', flush=True)
                        main_log_file.write(':')
                        result_population.append(current_factor)
                result_population.sort(key=lambda x: x[1], reverse=True)
                print('[ ', end='', flush=True)
                main_log_file.write('[ ')
                for tuple in result_population:
                    print('%5.4f ' % tuple[1], end='', flush=True)
                    main_log_file.write('%5.4f ' % tuple[1])
                print(']', end='', flush=True)
                main_log_file.write(']')

                winner = result_population[0][0]
                factor_list = []
                for _ in range(0, settings['population']):
                    factor_list.append(result_population.pop(0))
                print(' OK')
                main_log_file.write(' OK\n')
            print('All rounds complete!')
            main_log_file.write('All rounds complete!\n')
            winner.write_file(settings['factors_file_path'])
            test_result(batch_settings, settings, winner)
            clear_learning_tmp()
    except OSError as error:
        print('FAILURE\n')
        print('%s\n' % str(error))
        print('Can not write log file "%s", aborting.\n' % main_log_file_path)
        return 1

    return 0