//  [python]
def create_seq_graph(input_shape, batch_size=None, 
                     # input_vocab_size=None,
                     attn_inputs=None,
                     attn_size=128, attn_vec_size=128,
                     # output_size=128,
                     input_size=None, 
                     hidden_size=128, n_layers=2,
                     cell_type='lstm', bidirectional=False,
                     initial_state=None,
                     #use_embeddings=True,
                     #embedding_size=64,
                     embeddings=None,
                     output_proj_size=None,
                     input_features_shape=None,
                     attn_masks=None):
  # Create inputs.
  seq_inputs = create_seq_inputs(
    shape=input_shape, dtype=tf.int32 if embeddings is not None else tf.float32)

  rnn_dropout = tf.placeholder_with_default(
    0.0, shape=None, name='rnn_dropout')

  # Create embedding layer.
  if embeddings is not None:
    embedded_inputs = embed_inputs(
      seq_inputs.tensor, embeddings=embeddings)
  else:
    embedded_inputs = seq_inputs.tensor
    
  input_dropout = tf.placeholder_with_default(
    0.0, shape=None, name='input_dropout')
    
  embedded_inputs = tf.nn.dropout(
    embedded_inputs, 1 - input_dropout)

  # If we include features in inputs, then add them here.
  if input_features_shape is not None:
    seq_input_features = create_seq_inputs(
      shape=input_features_shape, dtype=tf.int32)
    embedded_inputs = tf.concat(
      [embedded_inputs, tf.to_float(seq_input_features.tensor)],
      axis=-1)
    seq_inputs = SeqTensor(
      (seq_inputs.tensor, seq_input_features.tensor), seq_inputs.sequence_length)
  else:
    seq_input_features = None
  
  embedded_seq_inputs = SeqTensor(embedded_inputs, seq_inputs.sequence_length)
    
  # Create RNN cell
  cell = multilayer_dropout_cell(
    RNN_CELL_DICT[cell_type],
    hidden_size, n_layers, rnn_dropout)

  if bidirectional:
    cell_bw = multilayer_dropout_cell(
      RNN_CELL_DICT[cell_type],
      hidden_size, n_layers, rnn_dropout)
  else:
    cell_bw = None

  # Add attention.
  if attn_inputs is not None:
    cell = tf_utils.SeqAttentionCellWrapper(
      cell, attn_inputs=attn_inputs,
      attn_size=attn_size, attn_vec_size=attn_vec_size,
      output_size=hidden_size, attn_masks=attn_masks)
    if bidirectional:
      cell_bw = tf_utils.SeqAttentionCellWrapper(
        cell_bw, attn_inputs=attn_inputs,
        attn_size=attn_size, attn_vec_size=attn_vec_size,
        output_size=hidden_size, attn_masks=attn_masks)
    
  if initial_state is None:
    # Create zero state.
    zero_state = cell.zero_state(batch_size, tf.float32)
    
    if bidirectional:
      zero_state_bw = cell_bw.zero_state(batch_size, tf.float32)
      zero_state = (zero_state, zero_state_bw)

    initial_state = zero_state
      
  # Create RNN.
  outputs, final_state = create_rnn(
    cell, initial_state, embedded_seq_inputs.tensor,
    embedded_seq_inputs.sequence_length,
    hidden_size=hidden_size,
    bidirectional=bidirectional, cell_bw=cell_bw)
  rnn_outputs = outputs

  if bidirectional:
    outputs = tf.concat(outputs, axis=2)
    hidden_size *= 2
    
  # Whether to add linear transformation to outputs. 
  if output_proj_size is not None:
    outputs = tf.layers.dense(
      inputs=outputs, units=output_proj_size, use_bias=True)

  seq_outputs = SeqTensor(
    outputs,
    tf.placeholder_with_default(
      seq_inputs.sequence_length, shape=[None]))
  
  return (seq_inputs, initial_state, seq_outputs,
          final_state, input_dropout, rnn_dropout,
          rnn_outputs)