Example #1
0
def layer_test(layer_cls,
               kwargs={},
               input_shape=None,
               input_dtype=None,
               input_data=None,
               expected_output=None,
               expected_output_dtype=None,
               fixed_batch_size=False):
    """Test routine for a layer with a single input tensor
    and single output tensor.

    Copy of the function in keras-team/keras because it's not in the public API.
    If we use the one from keras-team/keras it won't work with tf.keras.
    """
    # generate input data
    if input_data is None:
        assert input_shape
        if not input_dtype:
            input_dtype = K.floatx()
        input_data_shape = list(input_shape)
        for i, e in enumerate(input_data_shape):
            if e is None:
                input_data_shape[i] = np.random.randint(1, 4)
        input_data = (10 * np.random.random(input_data_shape))
        input_data = input_data.astype(input_dtype)
    else:
        if input_shape is None:
            input_shape = input_data.shape
        if input_dtype is None:
            input_dtype = input_data.dtype
    if expected_output_dtype is None:
        expected_output_dtype = input_dtype

    # instantiation
    layer = layer_cls(**kwargs)

    # test get_weights , set_weights at layer level
    weights = layer.get_weights()
    layer.set_weights(weights)

    expected_output_shape = layer.compute_output_shape(input_shape)

    # test in functional API
    if fixed_batch_size:
        x = Input(batch_shape=input_shape, dtype=input_dtype)
    else:
        x = Input(shape=input_shape[1:], dtype=input_dtype)
    y = layer(x)
    assert K.dtype(y) == expected_output_dtype

    # check with the functional API
    model = Model(x, y)

    actual_output = model.predict(input_data)
    actual_output_shape = actual_output.shape
    for expected_dim, actual_dim in zip(expected_output_shape,
                                        actual_output_shape):
        if expected_dim is not None:
            assert expected_dim == actual_dim

    if expected_output is not None:
        assert_allclose(actual_output, expected_output, rtol=1e-3)

    # test serialization, weight setting at model level
    model_config = model.get_config()
    custom_objects = {layer.__class__.__name__: layer.__class__}
    recovered_model = model.__class__.from_config(model_config, custom_objects)
    if model.weights:
        weights = model.get_weights()
        recovered_model.set_weights(weights)
        _output = recovered_model.predict(input_data)
        assert_allclose(_output, actual_output, rtol=1e-3)

    # test training mode (e.g. useful when the layer has a
    # different behavior at training and testing time).
    if has_arg(layer.call, 'training'):
        model.compile('rmsprop', 'mse')
        model.train_on_batch(input_data, actual_output)

    # test instantiation from layer config
    layer_config = layer.get_config()
    layer_config['batch_input_shape'] = input_shape
    layer = layer.__class__.from_config(layer_config)

    # for further checks in the caller function
    return actual_output
Example #2
0
class ChessModel:
    def __init__(self, config: Config):
        self.config = config
        self.channels_first = True
        self.data_format = "channels_first"
        self.Input_Layer_Dim = Input((18,8,8))
        self.api = None

    def get_pipes(self, num = 1):
        """
        Creates a list of pipes on which observations of the game state will be listened for. Whenever
        an observation comes in, returns policy and value network predictions on that pipe.

        :param int num: number of pipes to create
        :return str(Connection): a list of all connections to the pipes that were created
        """
        if self.api is None:
            self.api = ChessAPI(self)
            self.api.start()
        return [self.api.create_pipe() for _ in range(num)]


    def build_model(self):

        mc = self.config.model
        in_x = x = self.Input_Layer_Dim # used as the input first layer of the model
        x = Conv2D(filters=mc.cnn_filter_num, kernel_size=mc.cnn_first_filter_size, padding='same',
                                    data_format=self.data_format, use_bias=False, kernel_regularizer=l2(mc.l2_reg),
                                    name='input_convolutional-{}-{}'.format(str(mc.cnn_first_filter_size), str(mc.cnn_filter_num)))(x)
        x = BatchNormalization(axis=1, name='input_batchnorm')(x) # used for forward training instead of gradient descent
        x = Activation("relu", name="input_relu")(x)

        for i in range(mc.res_layer_num):
            x = self._build_remaining_block(x, i+1)

        res_out = x

        # chain the res_out through the policy and value neural nets
        x = Conv2D(filters=mc.p_filter_size, kernel_size=mc.p_kernel_size, data_format=self.data_format,
                    use_bias=False, kernel_regularizer=l2(mc.l2_reg),
                    name="policy_conv-{}-{}".format(mc.p_kernel_size, mc.p_filter_size))(res_out)
        x = BatchNormalization(axis=1, name='policy_batchnorm')(x)
        x = Activation("relu", name="policy_relu")(x)
        x = Flatten(name='policy_flatten')(x)


        policy_out = Dense(self.config.num_labels, kernel_regularizer=l2(mc.l2_reg), activation="softmax", name="policy_out")(x)

        x = Conv2D(filters=mc.v_filter_size, kernel_size=mc.v_kernel_size, data_format=self.data_format,
                   use_bias=False, kernel_regularizer=l2(mc.l2_reg),
                   name="value_conv-{}-{}".format(mc.v_kernel_size, mc.v_filter_size))(res_out)
        x = BatchNormalization(axis=1, name="value_bactchnorm")(x)
        x = Activation("relu", name="value_relu")(x)
        x = Flatten(name="value_flatten")(x)
        x = Dense(mc.value_fc_size, kernel_regularizer=l2(mc.l2_reg), activation="relu", name="value_dense")(x)

        value_out = Dense(1,kernel_regularizer=l2(mc.l2_reg), activation="tanh", name="value_out")(x)

        self.model = Model(in_x, [policy_out, value_out], name="Chesster")


    def _build_remaining_block(self, x, index):
        mc = self.config.model
        in_x = x
        indexed_name="res{}".format(str(index))
        x = Conv2D(filters=mc.cnn_filter_num, kernel_size=mc.cnn_filter_size, padding="same",
           data_format=self.data_format, use_bias=False, kernel_regularizer=l2(mc.l2_reg),
           name=indexed_name+"_conv1-{}-{}".format(str(mc.cnn_filter_size),str(mc.cnn_filter_num)))(x)
        x = BatchNormalization(axis=1, name=indexed_name+"_batchnorm1")(x)
        x = Activation("relu",name=indexed_name+"_relu1")(x)
        x = Conv2D(filters=mc.cnn_filter_num, kernel_size=mc.cnn_filter_size, padding="same",
                   data_format=self.data_format, use_bias=False, kernel_regularizer=l2(mc.l2_reg),
                   name=indexed_name+"_conv2-"+str(mc.cnn_filter_size)+"-"+str(mc.cnn_filter_num))(x)
        x = BatchNormalization(axis=1, name="res"+str(index)+"_batchnorm2")(x)
        x = Add(name=indexed_name+"_add")([in_x, x])
        x = Activation("relu", name=indexed_name+"_relu2")(x)
        return x

    @staticmethod
    def fetch_digest(weights_path):
        if os.path.exists(weights_path):
            m = hashlib.sha256()
            with open(weights_path, "rb") as f:
                m.update(f.read())
            return m.hexdigest()

    def save(self, config_path, weights_path):
        """
        Saves the model.
            arguments:
                config_path: path to configuration file
                weight_path: path to the weights
        """
        logger.debug("saved model to {}".format(config_path))
        with open(config_path, 'wt') as f:
            json.dump(self.model.get_config(), f)
            self.model.save_weights(weights_path)
        self.digest = self.fetch_digest(weights_path)
        logger.debug("Saved model digest {}".format(self.digest))

    def load(self, config_path, weights_path):
        if os.path.exists(config_path) and os.path.exists(weights_path):
            logger.debug("loading model from {}".format(config_path))
            with open(config_path, 'rt') as f:
                self.model = Model.from_config(json.load(f))
            self.model.load_weights(weights_path)
            self.model.make_predict_function()
            self.digest = self.fetch_digest(weights_path)
            logger.debug("loaded model digest = {}".format(self.digest))
            return True
        else:
            logger.debug("model no existy..")
            return False
Example #3
0
class Connect4Model:
    def __init__(self, config: Config):
        self.config = config
        self.model = None  # type: Model
        self.digest = None

    def build(self):
        mc = self.config.model
        in_x = x = Input((2, 6, 7))  # [own(8x8), enemy(8x8)]

        # (batch, channels, height, width)
        x = Conv2D(filters=mc.cnn_filter_num,
                   kernel_size=mc.cnn_filter_size,
                   padding="same",
                   data_format="channels_first",
                   kernel_regularizer=l2(mc.l2_reg))(x)
        x = BatchNormalization(axis=1)(x)
        x = Activation("relu")(x)

        for _ in range(mc.res_layer_num):
            x = self._build_residual_block(x)

        res_out = x
        # for policy output
        x = Conv2D(filters=2,
                   kernel_size=1,
                   data_format="channels_first",
                   kernel_regularizer=l2(mc.l2_reg))(res_out)
        x = BatchNormalization(axis=1)(x)
        x = Activation("relu")(x)
        x = Flatten()(x)
        # no output for 'pass'
        policy_out = Dense(self.config.n_labels,
                           kernel_regularizer=l2(mc.l2_reg),
                           activation="softmax",
                           name="policy_out")(x)

        # for value output
        x = Conv2D(filters=1,
                   kernel_size=1,
                   data_format="channels_first",
                   kernel_regularizer=l2(mc.l2_reg))(res_out)
        x = BatchNormalization(axis=1)(x)
        x = Activation("relu")(x)
        x = Flatten()(x)
        x = Dense(mc.value_fc_size,
                  kernel_regularizer=l2(mc.l2_reg),
                  activation="relu")(x)
        value_out = Dense(1,
                          kernel_regularizer=l2(mc.l2_reg),
                          activation="tanh",
                          name="value_out")(x)

        self.model = Model(in_x, [policy_out, value_out],
                           name="connect4_model")
        self.model.summary()

    def _build_residual_block(self, x):
        mc = self.config.model
        in_x = x
        x = Conv2D(filters=mc.cnn_filter_num,
                   kernel_size=mc.cnn_filter_size,
                   padding="same",
                   data_format="channels_first",
                   kernel_regularizer=l2(mc.l2_reg))(x)
        x = BatchNormalization(axis=1)(x)
        x = Activation("relu")(x)
        x = Conv2D(filters=mc.cnn_filter_num,
                   kernel_size=mc.cnn_filter_size,
                   padding="same",
                   data_format="channels_first",
                   kernel_regularizer=l2(mc.l2_reg))(x)
        x = BatchNormalization(axis=1)(x)
        x = Add()([in_x, x])
        x = Activation("relu")(x)
        return x

    @staticmethod
    def fetch_digest(weight_path):
        if os.path.exists(weight_path):
            m = hashlib.sha256()
            with open(weight_path, "rb") as f:
                m.update(f.read())
            return m.hexdigest()

    def load(self, config_path, weight_path):
        mc = self.config.model
        resources = self.config.resource
        if mc.distributed and config_path == resources.model_best_config_path:
            logger.debug(f"loading model from server")
            ftp_connection = ftplib.FTP(
                resources.model_best_distributed_ftp_server,
                resources.model_best_distributed_ftp_user,
                resources.model_best_distributed_ftp_password)
            ftp_connection.cwd(
                resources.model_best_distributed_ftp_remote_path)
            ftp_connection.retrbinary("RETR model_best_config.json",
                                      open(config_path, 'wb').write)
            ftp_connection.retrbinary("RETR model_best_weight.h5",
                                      open(weight_path, 'wb').write)
            ftp_connection.quit()

        if os.path.exists(config_path) and os.path.exists(weight_path):
            logger.debug(f"loading model from {config_path}")
            with open(config_path, "rt") as f:
                self.model = Model.from_config(json.load(f))
            self.model.load_weights(weight_path)
            self.digest = self.fetch_digest(weight_path)
            logger.debug(f"loaded model digest = {self.digest}")
            return True
        else:
            logger.debug(
                f"model files does not exist at {config_path} and {weight_path}"
            )
            return False

    def save(self, config_path, weight_path):
        logger.debug(f"save model to {config_path}")
        with open(config_path, "wt") as f:
            json.dump(self.model.get_config(), f)
            self.model.save_weights(weight_path)
        self.digest = self.fetch_digest(weight_path)
        logger.debug(f"saved model digest {self.digest}")

        mc = self.config.model
        resources = self.config.resource
        if mc.distributed and config_path == resources.model_best_config_path:
            logger.debug(f"saving model to server")
            ftp_connection = ftplib.FTP(
                resources.model_best_distributed_ftp_server,
                resources.model_best_distributed_ftp_user,
                resources.model_best_distributed_ftp_password)
            ftp_connection.cwd(
                resources.model_best_distributed_ftp_remote_path)
            fh = open(config_path, 'rb')
            ftp_connection.storbinary('STOR model_best_config.json', fh)
            fh.close()

            fh = open(weight_path, 'rb')
            ftp_connection.storbinary('STOR model_best_weight.h5', fh)
            fh.close()
            ftp_connection.quit()