<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def model_fn(hparams, seed):
 """Create a Keras model with the given hyperparameters. Args: hparams: A dict mapping hyperparameters in `HPARAMS` to values. seed: A hashable object to be used as a random seed (e.g., to construct dropout layers in the model). Returns: A compiled Keras model. """

  rng = random.Random(seed)

  model = tf.keras.models.Sequential()
  model.add(tf.keras.layers.Input(INPUT_SHAPE))
  model.add(tf.keras.layers.Reshape(INPUT_SHAPE + (1,)))  # grayscale channel

  # Add convolutional layers.
  conv_filters = 8
  for _ in xrange(hparams[HP_CONV_LAYERS]):
    model.add(tf.keras.layers.Conv2D(
        filters=conv_filters,
        kernel_size=hparams[HP_CONV_KERNEL_SIZE],
        padding="same",
        activation="relu",
    ))
    model.add(tf.keras.layers.MaxPool2D(pool_size=2, padding="same"))
    conv_filters *= 2

  model.add(tf.keras.layers.Flatten())
  model.add(tf.keras.layers.Dropout(hparams[HP_DROPOUT], seed=rng.random()))

  # Add fully connected layers.
  dense_neurons = 32
  for _ in xrange(hparams[HP_DENSE_LAYERS]):
    model.add(tf.keras.layers.Dense(dense_neurons, activation="relu"))
    dense_neurons *= 2

  # Add the final output layer.
  model.add(tf.keras.layers.Dense(OUTPUT_CLASSES, activation="softmax"))

  model.compile(
      loss="sparse_categorical_crossentropy",
      optimizer=hparams[HP_OPTIMIZER],
      metrics=["accuracy"],
  )
  return model