<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def transformer_encoder_attention_unit(x, hparams, encoder_self_attention_bias, attention_dropout_broadcast_dims, save_weights_to=None, make_image_summary=True):
 """Applies multihead attention function which is parametrised for encoding. Args: x: input hparams: model hyper-parameters encoder_self_attention_bias: a bias tensor for use in encoder self-attention attention_dropout_broadcast_dims: Fpr noise broadcasting in the dropout layers to save memory during training save_weights_to: an optional dictionary to capture attention weights for visualization; the weights tensor will be appended there under a string key created from the variable scope (including name). make_image_summary: Whether to make an attention image summary. Returns: the output tensor """


  with tf.variable_scope("self_attention"):
    y = common_attention.multihead_attention(
        common_layers.layer_preprocess(x, hparams),
        None,
        encoder_self_attention_bias,
        hparams.attention_key_channels or hparams.hidden_size,
        hparams.attention_value_channels or hparams.hidden_size,
        hparams.hidden_size,
        hparams.num_heads,
        hparams.attention_dropout,
        attention_type=hparams.self_attention_type,
        save_weights_to=save_weights_to,
        max_relative_position=hparams.max_relative_position,
        make_image_summary=make_image_summary,
        dropout_broadcast_dims=attention_dropout_broadcast_dims,
        hard_attention_k=hparams.hard_attention_k)
    x = common_layers.layer_postprocess(x, y, hparams)
  return x