Exemple #1
0
    def unbuffer_data(self):
        # flatten
        buf = ''.join(self.rxd)

        while True:
            buf_len = len(buf)
            if buf_len < self.header.size:
                break

            payload_len = self.header.unpack_from(buf[:self.header.size])[0]
            if buf_len < payload_len + self.header.size:
                break

            # good, we have a message
            offset = self.header.size
            compressed_data = buf[offset:offset + payload_len]
            offset += payload_len

            data = zlib.decompress(compressed_data)
            msg = attrutil.json_to_attr(data)
            yield msg

            buf = buf[offset:]

        # compact
        self.rxd = []
        if len(buf):
            self.rxd.append(buf)
Exemple #2
0
    def __init__(self, conf_filename):
        super().__init__()

        self.conf_filename = conf_filename
        if os.path.exists(conf_filename):
            conf = attrutil.json_to_attr(open(conf_filename).read())
            assert isinstance(conf, confs.WorkerConfig)
        else:
            conf = default_conf()

        self.conf = conf
        print "CONF", attrutil.pprint(conf)
        self.save_our_config()

        self.register(msgs.Ping, self.on_ping)
        self.register(msgs.RequestConfig, self.on_request_config)

        self.register(msgs.ConfigureSelfPlay, self.on_configure)
        self.register(msgs.RequestSamples, self.on_request_samples)
        self.register(msgs.RequestNetworkTrain, self.on_train_request)

        self.nn = None
        self.sm = None
        self.game_info = None
        self.supervisor = None
        self.self_play_conf = None

        # will be created on demand
        self.trainer = None

        self.cmds_running = []

        # connect to server
        reactor.callLater(0, self.connect)
Exemple #3
0
 def render_GET(self, request):
     summary_path = matches_path("summary.json")
     self.obj = attrutil.json_to_attr(open(summary_path).read())
     x = self.obj
     x.queryMatches = x.queryMatches[:20]
     augment_header(request.responseHeaders)
     return json.dumps(attr.asdict(self.obj))
Exemple #4
0
    def render_GET(self, request):
        try:
            obj = attrutil.json_to_attr(open(self.match_path).read())
            augment_header(request.responseHeaders)
            return json.dumps(attr.asdict(obj))

        except Exception as exc:
            log.debug("ERROR %s" % exc)
            return ""
Exemple #5
0
    def get_summary(self, create=False):
        if create or not os.path.exists(self.summary_path):
            summary = datadesc.GenDataSummary(game=self.transformer.game,
                                              gen_prefix=self.gen_prefix,
                                              last_updated=timestamp(),
                                              total_samples=0)
        else:
            summary = attrutil.json_to_attr(open(self.summary_path).read())

        return summary
Exemple #6
0
    def load_network(self, game, generation_name):
        json_str = open(self.generation_path(game, generation_name)).read()
        generation_descr = attrutil.json_to_attr(json_str)

        json_str = open(self.model_path(game, generation_name)).read()
        keras_model = keras_models.model_from_json(json_str)

        keras_model.load_weights(self.weights_path(game, generation_name))
        transformer = self.get_transformer(game, generation_descr)
        return NeuralNetwork(transformer, keras_model, generation_descr)
Exemple #7
0
    def load_and_check_data(self):
        log.info("checking if generation data available")
        try:
            gen_samples = attrutil.json_to_attr(
                gzip.open(self.sample_data_filename).read())
            log.info("data exists, with generation: %s, adding %s samples" %
                     (gen_samples.with_generation, gen_samples.num_samples))

            self.add_new_samples(gen_samples.samples, dedupe=False)

        except IOError as exc:
            log.info("Not such file for generation: %s" % exc)
Exemple #8
0
    def __init__(self, conf_filename, conf=None):
        Broker.__init__(self)

        self.conf_filename = conf_filename
        if conf is None:
            assert os.path.exists(conf_filename)
            conf = attrutil.json_to_attr(open(conf_filename).read())

        assert isinstance(conf, confs.ServerConfig)
        attrutil.pprint(conf)

        self.conf = conf

        self.game_info = lookup.by_name(self.conf.game)

        self.workers = {}
        self.free_players = []
        self.the_nn_trainer = None

        self.accumulated_samples = []
        self.unique_states_set = set()
        self.unique_states = []

        # when a generation object is around, we are in the processing of training
        self.pending_gen_samples = None
        self.training_in_progress = False

        # register messages:
        self.register(msgs.Pong, self.on_pong)

        self.register(msgs.Ok, self.on_ok)
        self.register(msgs.WorkerConfigMsg, self.on_worker_config)

        self.register(msgs.RequestSampleResponse, self.on_sample_response)

        self.check_files_exist()
        self.load_and_check_data()

        self.create_self_play_config()
        self.save_our_config()

        # finally start listening on port
        reactor.listenTCP(conf.port, ServerFactory(self))

        # save the samples periodically
        self.checkpoint_cb = reactor.callLater(self.conf.checkpoint_interval,
                                               self.checkpoint)
Exemple #9
0
    def __init__(self, conf_filename, cb_fn=None):
        super().__init__()

        self.conf_filename = conf_filename
        self.cb_fn = cb_fn

        if os.path.exists(conf_filename):
            conf = attrutil.json_to_attr(open(conf_filename).read())
            assert isinstance(conf, confs.WorkerConfig)
        else:
            conf = default_conf()

        self.conf = conf
        print "CONF", attrutil.pprint(conf)
        self.save_our_config()

        self.register(msgs.Ping, self.on_ping)
        self.register(msgs.RequestConfig, self.on_request_config)

        self.register(msgs.ConfigureSelfPlay, self.on_configure)
        self.register(msgs.RequestSamples, self.on_request_samples)
        self.register(msgs.RequestNetworkTrain, self.on_train_request)

        self.nn = None
        self.sm = None
        self.game_info = None
        self.supervisor = None
        self.self_play_conf = None

        # will be created on demand
        self.trainer = None

        self.cmds_running = []

        if False and self.conf.callback:
            fn_py_path = self.conf.callback
            mod_name, func_name = fn_py_path.rsplit('.', 1)
            mod = importlib.import_module(mod_name)
            func = getattr(mod, func_name)
            func()

        # connect to server
        reactor.callLater(0, self.connect)
Exemple #10
0
    def files_to_sample_data(self, conf):
        man = get_manager()

        assert isinstance(conf, confs.TrainNNConfig)

        step = conf.next_step - 1

        starting_step = conf.starting_step
        if starting_step < 0:
            starting_step = max(step + starting_step, 0)

        while step >= starting_step:
            store_path = man.samples_path(conf.game, conf.generation_prefix)
            fn = os.path.join(store_path,
                              "gendata_%s_%s.json.gz" % (conf.game, step))
            if fn not in self.sample_data_cache:
                raw_data = attrutil.json_to_attr(gzip.open(fn).read())
                data = SamplesData(raw_data.game, raw_data.with_generation,
                                   raw_data.num_samples)

                total_draws = 0
                for s in raw_data.samples:
                    if abs(s.final_score[0] - 0.5) < 0.01:
                        total_draws += 1

                draws_ratio = total_draws / float(len(raw_data.samples))
                log.info("Draws ratio %.2f" % draws_ratio)

                for s in raw_data.samples:
                    data.add_sample(s)

                if len(data.samples) != data.num_samples:
                    # pretty inconsequential, but we should at least notify
                    msg = "num_samples (%d) versus actual samples (%s) differ... trimming"
                    log.warning(msg % (data.num_samples, len(data.samples)))

                    data.num_samples = min(len(data.samples), data.num_samples)
                    data.samples = data.samples[:data.num_samples]

                self.sample_data_cache[fn] = data

            yield fn, self.sample_data_cache[fn]
            step -= 1
Exemple #11
0
def test_attrs_recursive():
    print 'test_attrs_recursive.1'

    c = Container(DummyMsg('a'), DummyMsg('b'), DummyMsg('c'))

    m = Container(DummyMsg('o'), DummyMsg('p'), DummyMsg(c))

    d = attrutil.asdict_plus(m)
    pprint(d)

    r = attrutil.fromdict_plus(d)
    assert isinstance(r, Container)

    assert r.x.what == 'o'
    assert r.z.what.x.what == 'a'

    json_str = attrutil.attr_to_json(m, indent=4)
    print json_str

    k = attrutil.json_to_attr(json_str)
    assert k.x.what == 'o'
    assert k.z.what.x.what == 'a'
def update_summaries(game, match_info):
    # generate a TiltyardMatchSummary
    summary = TiltyardMatchSummary()
    for k in ("randomToken playerNamesFromHost scrambled startTime "
              "playClock tournamentNameFromHost startClock matchId gameMetaURL "
              "isAborted isCompleted goalValues".split()):
        setattr(summary, k, getattr(match_info, k))
    summary.matchURL = "http://simulated.tech:8800/%s/%s" % (game, match_info.randomToken)

    try:
        the_summaries = attrutil.json_to_attr(open(summary_path()).read())
    except:
        the_summaries = MatchSummaries()

    # find the summary:
    for idx, s in enumerate(the_summaries.queryMatches):
        if s.randomToken == summary.randomToken:
            the_summaries.queryMatches[idx] = summary
            return the_summaries

    # add to front
    the_summaries.queryMatches = [summary] + the_summaries.queryMatches
    return the_summaries
Exemple #13
0
    def sync(self):
        # check summary matches current set of files
        if not self.check_summary() or not self.verify_db():
            self.get_summary(create=True)
            self.create_db()

        for step, file_path, md5sum in self.files_to_process():
            # lets delete any spurious memory
            gc.collect()

            log.debug("Processing %s" % file_path)
            data = attrutil.json_to_attr(gzip.open(file_path).read())

            if len(data.samples) != data.num_samples:
                # pretty inconsequential, but we should at least notify
                msg = "num_samples (%d) versus actual samples (%s) differ... trimming"
                log.warning(msg % (data.num_samples, len(data.samples)))

                data.num_samples = min(len(data.samples), data.num_samples)
                data.samples = data.samples[:data.num_samples]

            log.debug("Game %s, with gen: %s and sample count %s" %
                      (data.game, data.with_generation, data.num_samples))

            indx = self.db.size
            stats = StatsAccumulator()
            t = self.transformer

            # ZZZ really slow
            # ZZZ profile/gather times in loop... (guessing the time is in decoding state)
            time_check = 0
            time_stats = 0
            time_decode = 0
            time_decode_prevs = 0
            time_channels = 0
            time_outputs = 0
            time_db_resize = 0
            time_db_insert = 0

            cur_size = indx

            for sample in self.augment_data(data.samples):
                et = ElaspedTime()
                #t.check_sample(sample)
                time_check += et.update()

                stats.add(sample)
                time_stats += et.update()

                # add channels

                # only decode if not already decoded (as in the case of augmentation)
                state = fast_decode_state(sample.state)

                time_decode += et.update()

                prev_states = [
                    fast_decode_state(s) for s in sample.prev_states
                ]

                time_decode_prevs += et.update()

                cols = [t.state_to_channels(state, prev_states)]
                time_channels += et.update()

                for ri, policy in enumerate(sample.policies):
                    cols.append(t.policy_to_array(policy, ri))
                time_outputs += et.update()

                cols.append(t.value_to_array(sample.final_score))

                # is this an efficient way to do things?
                if indx >= cur_size:
                    cur_size += 20
                    self.db.resize(cur_size)
                time_db_resize += et.update()
                for ii, name in enumerate(self.db.names):
                    self.db[name][indx] = cols[ii]
                indx += 1
                time_db_insert += et.update()

            print "time_check: %.2f" % time_check
            print "time_stats: %.2f" % time_stats
            print "time_decode: %.2f" % time_decode
            print "time_decode_prevs: %.2f" % time_decode_prevs
            print "time_channels: %.2f" % time_channels
            print "time_outputs: %.2f" % time_outputs
            print "time_db_resize: %.2f" % time_db_resize
            print "time_db_insert: %.2f" % time_db_insert

            if indx != cur_size:
                cur_size = indx
                self.db.resize(indx)

            self.db.flush()
            log.debug("Added %d samples to db" % stats.num_samples)

            # add to the summary and save it
            step_sum = datadesc.StepSummary(
                step=step,
                filename=file_path,
                with_generation=data.with_generation,
                num_samples=stats.num_samples,
                md5sum=md5sum,
                stats_unique_matches=stats.unique_matches,
                stats_draw_ratio=stats.draw_ratio,
                stats_bare_policies_ratio=stats.bare_policies_ratio,
                stats_av_starting_depth=stats.av_starting_depth,
                stats_av_ending_depth=stats.av_ending_depth,
                stats_av_resigns=stats.av_resigns,
                stats_av_resign_false_positive=stats.av_resign_false_positive,
                stats_av_puct_visits=stats.av_puct_visits,
                stats_ratio_of_roles=stats.ratio_of_roles,
                stats_av_final_scores=stats.av_final_scores,
                stats_av_puct_score_dist=stats.av_puct_score_dist)

            print attrutil.attr_to_json(step_sum, pretty=True)

            self.summary.last_updated = timestamp()
            self.summary.total_samples = self.db.size
            self.summary.step_summaries.append(step_sum)

            self.save_summary_file()
            log.debug("Saved summary file")

        # lets delete any spurious memory
        gc.collect()
        self.save_summary_file()
        log.info("Data cache synced, saved summary file.")
Exemple #14
0
def gen_elo(match_info, all_players, filename, move_generator=None, verbose=False):
    if os.path.exists(filename):
        ratings = at.json_to_attr(open(filename).read())
    else:
        ratings = AllRatings(match_info.name)

        # only add random if in all_players
        if "random" in all_players:
            ratings.players.append(PlayerRating("random", fixed=True, elo=500.0))

    # add in all the players

    # slow add one playeer
    slow_add_count = 0
    for p in all_players:
        if verbose:
            print "Adding", p.get_name()

        playerinfo = None
        for info in ratings.players:
            if info.name == p.get_name():
                playerinfo = info

        if playerinfo is None:
            if slow_add_count >= MAX_ADD_COUNT:
                if verbose:
                    print "SKIPPING for now", playerinfo
                continue
            else:
                playerinfo = PlayerRating(p.get_name(), 0, STARTING_ELO)
                ratings.players.append(playerinfo)

        p.rating = playerinfo
        if playerinfo.played < 20:
            slow_add_count += 1

    # check no leftover ratings for players
    for rated_player in ratings.players:
        found = False
        for p in all_players:
            if rated_player.name == p.get_name():
                assert not found, "bad config %s" % rated_player.name
                found = True

        if not found:
            log.warning("Dangling rating in elo file: %s" % rated_player.name)

    # update the ratings with players
    elo_dump_and_save(filename, ratings)

    for i in range(NUM_GAMES):
        players = choose_players(all_players)
        if players is None:
            break

        player0, player1 = players

        moves = None
        if move_generator:
            moves = move_generator()

        # play the game
        try:
            res = match_info.play(players,
                                  MOVE_TIME,
                                  moves=moves,
                                  resign_score=RESIGN_PCT,
                                  verbose=True)

            (_, score0), (_, score1) = res[1]
            res_str = ""
            k = INITIAL_K
            if score0 == 100:
                res_str = "1st player wins"
                player0_wins = True

            elif score1 == 100:
                res_str = "2nd player wins"
                player0_wins = False

            else:
                res_str = "Draws"
                k /= 2.0

                # fake a win for player with lower elo
                player0_wins = player0.rating.elo < player1.rating.elo

            res_str = "%s: %s (%.1f) / %s (%.1f) " % (res_str, player0.get_name(),
                                                      player0.rating.elo, player1.get_name(),
                                                      player1.rating.elo)
            print res_str
            ratings.log.append(res_str)

        except MatchTooLong as exc:
            err = 'MatchTooLong, %s v %s' % (player0, player1)
            ratings.log.append(err)
            print "match aborted", exc
            continue

        except Exception as exc:
            print "match aborted", str(exc)
            raise

        def getk(r, o):
            if r.fixed:
                return 0.0

            if r.played < 10:
                return k * 2

            if r.played < 20:
                scale = 1.0 + (20 - r.played) / 2.0
                return k * scale

            if r.played < 40:
                return k

            if r.played < 60:
                return k / 2.0

            if r.played > 60:
                kx = k / 2.5

            else:
                kx = k

            # extra penalty if o not established
            if o.played < 10:
                kx /= 10.0

            elif o.played < 20:
                kx /= 3.0

            elif o.played < 40:
                kx /= 2.0

            return kx

        player0.rating.played += 1
        player1.rating.played += 1

        (player0.rating.elo,
         player1.rating.elo) = next_elo_rating(player0.rating.elo,
                                               player1.rating.elo,
                                               getk(player0.rating, player1.rating),
                                               getk(player1.rating, player0.rating),
                                               player0_wins)

        elo_dump_and_save(filename, ratings)

        # check if there are any LG games waiting, and finish up if so
        if check_lg():
            break
Exemple #15
0
def main(genname_mapping,
         filename,
         gen_modifier=None,
         ignore_non_models=False,
         check_evals=800):
    ratings = at.json_to_attr(open(filename).read())
    genmodel_to_data = {}

    # side effect of setting the size of graph
    plt.figure(figsize=(18, 14))

    def get(name):
        if name not in genmodel_to_data:
            genmodel_to_data[name] = ([], [])
        return genmodel_to_data[name]

    for p in ratings.players:
        if "_" in p.name:
            if gen_modifier is not None:
                gen = gen_modifier(p.name)
            else:
                gen = int(p.name.split('_')[-1])

            was_evals = False
            for genname in genname_mapping:
                if genname in p.name:
                    datapoints = get(genname)
                    datapoints[0].append(gen)
                    datapoints[1].append(p.elo)

                    if check_evals is not None:
                        was_evals = str(check_evals) in p.name
                    else:
                        was_evals = True

                    break
            else:
                print "UNHANDLED", p.name
                continue

            txt = "* " if not was_evals else ""

            if p.played < Runner._elo_min:
                txt += "  %s" % p.played

            if txt:
                plt.text(gen, p.elo, txt)

        else:
            if not ignore_non_models:
                plt.plot(-10, [p.elo], "bx")
                txt = "  " + p.name
                if p.played < Runner._elo_min:
                    txt += "  %s" % p.played

                plt.text(-10, p.elo, txt)

    for name, color in genname_mapping.items():
        datapoints = get(name)
        if len(datapoints[0]):
            plt.plot(datapoints[0], datapoints[1], color, label=name)

    plt.ylabel("ELO")
    plt.xlabel("Generation")
    plt.legend(loc='lower right')
    plt.show()
Exemple #16
0
    def sync(self):
        # check summary matches current set of files
        if not self.check_summary() or not self.verify_db():
            self.get_summary(create=True)
            self.create_db()

        for step, file_path, md5sum in self.files_to_process():
            # lets delete any spurious memory
            gc.collect()

            log.debug("Processing %s" % file_path)
            data = attrutil.json_to_attr(gzip.open(file_path).read())

            if len(data.samples) != data.num_samples:
                # pretty inconsequential, but we should at least notify
                msg = "num_samples (%d) versus actual samples (%s) differ... trimming"
                log.warning(msg % (data.num_samples, len(data.samples)))

                data.num_samples = min(len(data.samples), data.num_samples)
                data.samples = data.samples[:data.num_samples]

            log.debug("Game %s, with gen: %s and sample count %s" % (data.game,
                                                                     data.with_generation,
                                                                     data.num_samples))

            indx = self.db.size
            stats = StatsAccumulator()
            t = self.transformer

            # ZZZ really slow
            # ZZZ profile/gather times in loop... (guessing the time is in decoding state)
            time_check = 0
            time_stats = 0
            time_decode = 0
            time_decode_prevs = 0
            time_channels = 0
            time_outputs = 0
            time_db_resize = 0
            time_db_insert = 0

            cur_size = indx

            for sample in self.augment_data(data.samples):
                # ensure that final scores are clamped before adding to db
                sample.final_score = [min(1.0, v) for v in sample.final_score]
                sample.final_score = [max(0.0, v) for v in sample.final_score]

                sample_is_draw = False
                if abs(sample.final_score[0] - 0.5) < 0.01:
                    assert abs(sample.final_score[1] - 0.5) < 0.01
                    sample_is_draw = True

                # XXX highly experimental
                if sample_is_draw and self.score_draw_as_random_hack:
                    # the idea is just to randomly asign a win or loss to train on.  Then the
                    # network can average out over a 'bazillion' draw samples and determine that
                    # the value should be 0.5.  In theory.  XXX Who knows?

                    if random.random() > 0.5:
                        sample.final_score = [1.0, 0]
                    else:
                        sample.final_score = [0, 1.0]

                et = ElaspedTime()

                # XXX too slow, and only useful for debugging serious bugs - disable
                # t.check_sample(sample)
                time_check += et.update()

                stats.add(sample, was_draw=sample_is_draw)
                time_stats += et.update()

                # add channels

                # only decode if not already decoded (as in the case of augmentation)
                state = fast_decode_state(sample.state)

                time_decode += et.update()

                prev_states = [fast_decode_state(s) for s in sample.prev_states]

                time_decode_prevs += et.update()

                cols = [t.state_to_channels(state, prev_states)]
                time_channels += et.update()

                for ri, policy in enumerate(sample.policies):
                    cols.append(t.policy_to_array(policy, ri))

                time_outputs += et.update()

                cols.append(t.value_to_array(sample.final_score))

                # is this an efficient way to do things?
                if indx >= cur_size:
                    cur_size += 20
                    self.db.resize(cur_size)

                time_db_resize += et.update()
                for ii, name in enumerate(self.db.names):
                    self.db[name][indx] = cols[ii]

                indx += 1
                time_db_insert += et.update()

            print "time_check: %.2f" % time_check
            print "time_stats: %.2f" % time_stats
            print "time_decode: %.2f" % time_decode
            print "time_decode_prevs: %.2f" % time_decode_prevs
            print "time_channels: %.2f" % time_channels
            print "time_outputs: %.2f" % time_outputs
            print "time_db_resize: %.2f" % time_db_resize
            print "time_db_insert: %.2f" % time_db_insert

            if indx != cur_size:
                cur_size = indx
                self.db.resize(indx)

            self.db.flush()
            log.debug("Added %d samples to db" % stats.num_samples)

            # add to the summary and save it
            step_sum = datadesc.StepSummary(step=step,
                                            filename=file_path,
                                            with_generation=data.with_generation,
                                            num_samples=stats.num_samples,
                                            md5sum=md5sum,
                                            stats_unique_matches=stats.unique_matches,
                                            stats_draw_ratio=stats.draw_ratio,
                                            stats_bare_policies_ratio=stats.bare_policies_ratio,
                                            stats_av_starting_depth=stats.av_starting_depth,
                                            stats_av_ending_depth=stats.av_ending_depth,
                                            stats_av_resigns=stats.av_resigns,
                                            stats_av_resign_false_positive=stats.av_resign_false_positive,
                                            stats_av_puct_visits=stats.av_puct_visits,
                                            stats_ratio_of_roles=stats.ratio_of_roles,
                                            stats_av_final_scores=stats.av_final_scores,
                                            stats_av_puct_score_dist=stats.av_puct_score_dist)

            print attrutil.attr_to_json(step_sum, pretty=True)

            self.summary.last_updated = timestamp()
            self.summary.total_samples = self.db.size
            self.summary.step_summaries.append(step_sum)

            self.save_summary_file()
            log.debug("Saved summary file")

        # lets delete any spurious memory
        gc.collect()
        self.save_summary_file()
        log.info("Data cache synced, saved summary file.")
Exemple #17
0
    setup_once()

    from ggpzero.util.keras import init
    init()

    import tensorflow as tf
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
    tf.logging.set_verbosity(tf.logging.ERROR)


if __name__ == "__main__":
    ''' to create a template config file, use -c config_filename.
        otherwise to run, provide the config_filename '''

    setup()

    conf_filename = sys.argv[1]
    if os.path.exists(conf_filename):
        config = at.json_to_attr(open(conf_filename).read())
    else:
        print "Creating config"
        config = template_config()

    # save it - pick up new features
    with open(conf_filename, "w") as f:
        contents = at.attr_to_json(config, pretty=True)
        f.write(contents)

    lg = LittleGolemConnection(config)
    lg.loop_forever()