### Load Word Vectors....

and define functions to convert words to vectors and vice-versa.

```python
import numpy as np
from __future__ import division

filename = 'glove.6B.100d.txt'

def loadEmbeddings(filename):
    vocab = []
    embd = []
    file = open(filename,'r')
    for line in file.readlines():
        row = line.strip().split(' ')
        vocab.append(row[0])
        embd.append(row[1:])
    print('Loaded!')
    file.close()
    return vocab,embd
vocab,embd = loadEmbeddings(filename)

word_vec_dim = len(embd[0])

vocab.append('<UNK>')
embd.append(np.asarray(embd[vocab.index('unk')],np.float32)+0.01)

vocab.append('<EOS>')
embd.append(np.asarray(embd[vocab.index('eos')],np.float32)+0.01)

vocab.append('<PAD>')
embd.append(np.zeros((word_vec_dim),np.float32))

embedding = np.asarray(embd)
embedding = embedding.astype(np.float32)

def word2vec(word):  # converts a given word into its vector representation
    if word in vocab:
        return embedding[vocab.index(word)]
    else:
        return embedding[vocab.index('<UNK>')]

def most_similar_eucli(x):
    xminusy = np.subtract(embedding,x)
    sq_xminusy = np.square(xminusy)
    sum_sq_xminusy = np.sum(sq_xminusy,1)
    eucli_dists = np.sqrt(sum_sq_xminusy)
    return np.argsort(eucli_dists)

def vec2word(vec):   # converts a given vector representation into the represented word
    most_similars = most_similar_eucli(np.asarray(vec,np.float32))
    return vocab[most_similars[0]]
```

    Loaded!

### Load Pre-processed Data

(Minimally processed data - only used pre-trained GloVe and padding to a fixed length)

```python
import pickle
with open ('NERPICKLE_10000', 'rb') as fp:
    processed_data = pickle.load(fp)

NER_tags = processed_data[0]
sentences = processed_data[1]
tags = processed_data[2]
```

### Splitting into training, validating and testing data.

```python
p = 0.8

train_len = int(.8*len(sentences))
val_len = int(.1*len(sentences))
test_len = len(sentences) - train_len - val_len

train_sentences = sentences[0:train_len]
train_tags = tags[0:train_len]

val_sentences = sentences[train_len:train_len+val_len]
val_tags = tags[train_len:train_len+val_len]

test_sentences = sentences[train_len+val_len:]
test_tags = tags[train_len+val_len:]
```

### Function to create 'meta-batches' of sentences and the target NER tags

```python
def create_batches(sentences,tags,batch_size):

    shuffle = np.arange(len(sentences))
    np.random.shuffle(shuffle)

    batches_sentence = []
    batches_tag = []

    i=0

    while i+batch_size<=len(sentences):

        batch_sentence = []
        batch_tag = []

        for j in xrange(i,i+batch_size):

            batch_sentence.append(sentences[shuffle[j]])
            batch_tag.append(tags[shuffle[j]])

        batch_sentence = np.asarray(batch_sentence,np.float32)
        batch_tag = np.asarray(batch_tag,np.int32)

        batches_sentence.append(batch_sentence)
        batches_tag.append(batch_tag)

        i+=batch_size

    batches_sentence = np.asarray(batches_sentence,np.float32)
    batches_tag = np.asarray(batches_tag,np.int32)

    return batches_sentence,batches_tag

```

### Hyperparamters

```python
import tensorflow as tf

# Hyperparameters

tf_sentences = tf.placeholder(tf.float32,[None,None,word_vec_dim])
tf_tags = tf.placeholder(tf.int32,[None,None])
traintestval = tf.placeholder(tf.bool)
scale_down = 1

hidden_size = 100
learning_rate = 0.01
beta = 0.0001
regularizer = tf.contrib.layers.l2_regularizer(scale=beta)

```

### Parameters

```python
# Parameters
init = tf.zeros_initializer()

with tf.variable_scope("Bi_GRU"):

    # FORWARD GRU PARAMETERS

    wzf = tf.get_variable("wzf", shape=[word_vec_dim, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer= regularizer)
    uzf = tf.get_variable("uzf", shape=[hidden_size, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    bzf = tf.get_variable("bzf", shape=[hidden_size],initializer=init)

    wrf = tf.get_variable("wrf", shape=[word_vec_dim, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    urf = tf.get_variable("urf", shape=[hidden_size, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    brf = tf.get_variable("brf", shape=[hidden_size],initializer=init)

    wf = tf.get_variable("wf", shape=[word_vec_dim, hidden_size],
                     initializer=tf.contrib.layers.xavier_initializer(),
                     regularizer=regularizer)
    uf = tf.get_variable("uf", shape=[hidden_size, hidden_size],
                     initializer=tf.contrib.layers.xavier_initializer(),
                     regularizer=regularizer)
    bf = tf.get_variable("bf", shape=[hidden_size],initializer=init)

    # BACKWARD GRU PARAMETERS

    wzb = tf.get_variable("wzb", shape=[word_vec_dim, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    uzb = tf.get_variable("uzb", shape=[hidden_size, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    bzb = tf.get_variable("bzb", shape=[hidden_size],initializer=init)

    wrb = tf.get_variable("wrb", shape=[word_vec_dim, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    urb = tf.get_variable("urb", shape=[hidden_size, hidden_size],
                      initializer=tf.contrib.layers.xavier_initializer(),
                      regularizer=regularizer)
    brb = tf.get_variable("brb", shape=[hidden_size],initializer=init)

    wb = tf.get_variable("wb", shape=[word_vec_dim, hidden_size],
                     initializer=tf.contrib.layers.xavier_initializer(),
                     regularizer=regularizer)
    ub = tf.get_variable("ub", shape=[hidden_size, hidden_size],
                     initializer=tf.contrib.layers.xavier_initializer(),
                     regularizer=regularizer)
    bb = tf.get_variable("bb", shape=[hidden_size],initializer=init)

W_score = tf.get_variable("W_score", shape=[2*hidden_size,len(NER_tags)],
                     initializer=tf.contrib.layers.xavier_initializer(),
                     regularizer=regularizer)

B_score = tf.get_variable("B_score", shape=[len(NER_tags)],initializer=init)

Transition_matrix = tf.get_variable("T",shape=[len(NER_tags),len(NER_tags)],
                                    initializer=tf.random_normal_initializer(),
                                    regularizer=regularizer)

l1 = tf.get_variable("l1", shape=[1],
                     initializer=tf.constant_initializer(0.5),
                     regularizer=regularizer)

l2 = tf.get_variable("l2", shape=[1],
                     initializer=tf.constant_initializer(0.5),
                     regularizer=regularizer)

```

### Function for layer normalization

Without scale and shift.

```python
def layer_norm(inputs,scope,epsilon = 1e-5):

    mean, var = tf.nn.moments(inputs, [1,2], keep_dims=True)

    LN = tf.multiply((1/ tf.sqrt(var + epsilon)),(inputs - mean))

    return LN
```

### Barebones implementation of Bi-directional GRU

```python
def bi_GRU(inp,hidden,seq_len,scope):

    #inp shape = batch_size x seq_len x vector_dimension

    inp = tf.transpose(inp,[1,0,2])

    #now inp shape = seq_len x batch_size x vector_dimension

    hidden_forward = tf.TensorArray(size=seq_len,dtype=tf.float32)
    hidden_backward = tf.TensorArray(size=seq_len,dtype=tf.float32)

    hiddenf = hidden
    hiddenb = hidden

    with tf.variable_scope(scope, reuse=True):

        wzf = tf.get_variable("wzf")
        uzf = tf.get_variable("uzf")
        bzf = tf.get_variable("bzf")

        wrf = tf.get_variable("wrf")
        urf = tf.get_variable("urf")
        brf = tf.get_variable("brf")

        wf = tf.get_variable("wf")
        uf = tf.get_variable("uf")
        bf = tf.get_variable("bf")

        wzb = tf.get_variable("wzb")
        uzb = tf.get_variable("uzb")
        bzb = tf.get_variable("bzb")

        wrb = tf.get_variable("wrb")
        urb = tf.get_variable("urb")
        brb = tf.get_variable("brb")

        wb = tf.get_variable("wb")
        ub = tf.get_variable("ub")
        bb = tf.get_variable("bb")

    i = 0
    j = seq_len - 1

    def cond(i,j,hiddenf,hiddenb,hidden_forward,hidden_backward):
        return i < seq_len

    def body(i,j,hiddenf,hiddenb,hidden_forward,hidden_backward):

        xf = inp[i]
        xb = inp[j]

        # FORWARD GRU EQUATIONS:
        z = tf.sigmoid( tf.matmul(xf,wzf) + tf.matmul(hiddenf,uzf) + bzf )
        r = tf.sigmoid( tf.matmul(xf,wrf) + tf.matmul(hiddenf,urf) + brf )
        h_ = tf.tanh( tf.matmul(xf,wf) + tf.multiply(r,tf.matmul(hiddenf,uf)) + bf )
        hiddenf = tf.multiply(z,h_) + tf.multiply((1-z),hiddenf)

        hidden_forward = hidden_forward.write(i,hiddenf)

        # BACKWARD GRU EQUATIONS:
        z = tf.sigmoid( tf.matmul(xb,wzb) + tf.matmul(hiddenb,uzb) + bzb )
        r = tf.sigmoid( tf.matmul(xb,wrb) + tf.matmul(hiddenb,urb) + brb )
        h_ = tf.tanh( tf.matmul(xb,wb) + tf.multiply(r,tf.matmul(hiddenb,ub)) + bb )
        hiddenb = tf.multiply(z,h_) + tf.multiply((1-z),hiddenb)

        hidden_backward = hidden_backward.write(j,hiddenb)

        return i+1,j-1,hiddenf,hiddenb,hidden_forward,hidden_backward

    _,_,_,_,hidden_forward,hidden_backward = tf.while_loop(cond,body,[i,j,
                                                                        hiddenf,
                                                                        hiddenb,
                                                                        hidden_forward,
                                                                        hidden_backward])

    forward = hidden_forward.stack()
    backward = hidden_backward.stack()

    hidden_list = tf.concat([forward,backward],2)

    #forward\backward\hidden_list shape = seq_len x  batch_size x 2*hidden_size

    hidden_list = tf.transpose(hidden_list,[1,0,2])

    #now hidden_list shape = batch_size x seq_len x 2*hidden_size

    return hidden_list

```

### The model

The fist part (The GRU layer) is straight forward. The input sentences are passed through a bi-directional GRU and then each words are transformed to a unnormalized probability distribution over the NER tags through a linear layer.

The second part is a CRF layer. The following is the core equation of CRF.

\begin{equation}
P(y_{1:N}\mid x_{1:N})  =\frac1Zexp( \Sigma^N_{n=1} \Sigma^F_{i=1} \lambda_i f(y_{n-1},y_n,x_n)
\end{equation}

Here P(y1:n | x1: n) is the probability of the sequence y1,y2....yn given the inputs x1,x2,...xn.
Z is the normalizing factor.

To train the CRF negative log likelihood of the P(y|x) can be used as the cost function, where y is the target sequence, and x is the input sequence. The equation of the cost function can be thus expressed as:-

\begin{align}
-log(P(y_{1:N}\mid x_{1:N})) &= -log(\frac1Zexp( \Sigma^N_{n=1} \Sigma^F_{i=1} \lambda_i f(y_{n-1},y_n,x_n))\\
                             &= -(\Sigma^N_{n=1} \Sigma^F_{i=1} \lambda_i f(y_{n-1},y_n,x_n) - log(Z))
\end{align}

Z is the sum of

\begin{equation}
exp( \Sigma^N_{n=1} \Sigma^F_{i=1} \lambda_i f(y_{n-1},y_n,x_n)
\end{equation}

for all possible sequence values: y1,y2,...yn. That is,

\begin{equation}
Z = \Sigma^S_{s=1}exp( \Sigma^N_{n=1} \Sigma^F_{i=1} \lambda_i f(y_{s,n-1},y_{s,n},x_n)
\end{equation}

Where s is the sequence no. ysn indicates the nth position of the sth sequence.

For

\begin{equation}
\Sigma^F_{i=1} \lambda_i f(y_{n-1},y_n,x_n)
\end{equation}

I am using:

\begin{equation}
l_1 GRUscores(x_n) + l_2 Transition_{y_{n-1},y_n}
\end{equation}

l1, and l2 are learnable parameters. Transition_yn-1,yn represents Transition_matrix[y_n-1][y_n] which constitutes a score for y_n (a given tag at position n) given that the previous tag (at n-1 position) is y_n-1.
Transition_matrix is a matrix of learnable parameters.

The first part of the CRF layer, computes log(Z) and the second part computes the unormalized probability score of the target sequence (if we are testing, validation or training).
The second part is a straight forward summation:

\begin{equation}
score = \Sigma^N_{n=1} l_1 GRUscores(x_n) + l_2 Transition_{y_{n-1},y_n}
\end{equation}

This score is then used in the cost function as defined before. The cost function is basically:
-(score - log(Z))

The first part, that is, computing the Z of log(Z) is a bit troublesome. I used Dynamic programming is for this. To describe it briefly:

To calculate a the **sum of all sequences of size i,and ending with tag K** (S), I can use this:

```
for all j:
e = exp(l1*GRU_score(position_i,tag_k) + Transition[j][K])
Sk += e*sum_of_all_sequences_of_size_(i-1)_ending_with_j
```
where sum_of_all_sequences_of_size_(i-1)_ending_with_j =
```
exp(unexponentiated score of i-1 sized seq 1 ending with j) + exp(unexponentiated score of i-1 sized seq 2 ending with j).....

```
As a result of multiplying e with sum_of_all_sequences_of_size_(i-1)_ending_with_j we get:
```
exp(l1*GRU_score(position_i,tag_k)+ Transition[j][K])*exp(unexponentiated score of i-1 sized seq 1 ending with j) + exp(l1*GRU_score(position_i,tag_k)+ Transition[j][K])*exp(unexponentiated score of i-1 sized seq 2 ending with j).....
```
Which is:

```
exp(l1*GRU_score(position_i,tag_k)+ Transition[j][K] + unexp score of i-1 sized seq 1 ending with j) +
exp(l1*GRU_score(position_i,tag_k)+ Transition[j][K] + unexp score of i-1 sized seq 2 ending with j).....
```
Which is:
```
exp(unexp score of i sized seq 1 ending with j) +
exp(unexp score of i sized seq 2 ending with j).....
```

Now, we can do the same thing by adding logs:

```
for all j:
unexp_e = l1*GRU_score(position_i,tag_k) + Transition[j][K]
Sk += exp(unexp_e+log(sum_of_all_sequences_of_size_(i-1)_ending_with_j))
```
Because:
```
exp(unexp_e+log(sum_of_all_sequences_of_size_(i-1)_ending_with_j))
= exp(unexp_e)*exp(log(sum_of_all_sequences_of_size_(i-1)_ending_with_j))
= exp(unexp_e)*(sum_of_all_sequences_of_size_(i-1)_ending_with_j)
Which is equal to e*(sum_of_all_sequences_of_size_(i-1)_ending_with_j)
```
Doing this can bring more stability. For more stability I did something more:
```
let mj = unexp_e+log(sum_of_all_sequences_of_size_(i-1)_ending_with_j)
So we get Sk = exp(m1) + exp(m2)....
```

exponentials of big no.s can can bring numerical instability, so I did this:

```
m_max = maximum(m1,m2....)
```
Sk = exp(m1-m_max) + exp(m2-m_max).....
While taking the log(Sk) to add it to other components while computing Sk values for next sequence,
I use:

```
m_max + log(Sk)

```

m_max + log(exp(m1-m_max) + exp(m2-m_max).....) is equivalent to log(exp(m1) + exp(m2).....) since:

```
m_max + log(exp(m1-m_max) + exp(m2-m_max).....)
= log(exp(m_max)) + log(exp(m1-m_max) + exp(m2-m_max).....)
= log ( exp(m_max) * (exp(m1-m_max) + exp(m2-m_max).....))
= log ( exp(m_max + m1 - m_max) + exp(m_max+m2-m_max)......)
= log ( exp(m1) + exp(m2)....)
```

```python

def fn1(tf_batch_size,seq_len,y_score,scores):

    batch_indices = tf.range(tf_batch_size)

    batch_indices = tf.reshape(batch_indices,[-1,1])
    tags_to_concat = tf.reshape(tf_tags[:,0],[-1,1])

    indices_batch_tag_i = tf.concat([batch_indices,tags_to_concat],1)

    y_score = (tf.gather_nd(scores[0],indices_batch_tag_i))
    y_score = l1*y_score

    i=tf.constant(1)

    def cond(i,y_score):

        return i<seq_len

    def body(i,y_score):

        batch_indices = tf.range(tf_batch_size)
        batch_indices = tf.reshape(batch_indices,[-1,1])
        tags_to_concat = tf.reshape(tf_tags[:,i],[-1,1])

        indices_batch_tag_i = tf.concat([batch_indices,tags_to_concat],1)

        tags_i_1 = tf.reshape(tf_tags[:,i-1],[-1,1])
        tags_i = tf.reshape(tf_tags[:,i],[-1,1])

        indices_i_1_to_i = tf.concat([tags_i_1,tags_i],1)

        GRU_scores = tf.gather_nd(scores[i],indices_batch_tag_i)
        T_scores = tf.gather_nd(Transition_matrix,indices_i_1_to_i)

        y_score +=  l1*GRU_scores + l2*T_scores

        return i+1, y_score

    _,y_score = tf.while_loop(cond,body,[i,y_score])

    return y_score

def fn2(y_score):
    return y_score

def model(traintestval):

    # GRU LAYER

    tf_batch_size = tf.shape(tf_sentences)[0]
    seq_len = tf.shape(tf_sentences)[1]

    hidden = tf.zeros([tf_batch_size,hidden_size],tf.float32)

    hidden_list = bi_GRU(tf_sentences,hidden,seq_len,'Bi_GRU')

    hidden_list = tf.reshape(hidden_list,[-1,2*hidden_size])

    scores = tf.nn.relu(tf.matmul(hidden_list,W_score) + B_score)

    GRU_scores = tf.reshape(scores,[tf_batch_size,seq_len,len(NER_tags)])

    GRU_scores = layer_norm(GRU_scores,"GRU_out")

    # CRF LAYER

    scores =tf.transpose(GRU_scores,[1,0,2])

    # now scores shape = seq_len x batch_size x ner_tags

    scores = scores*scale_down

    i_1_scores = l1*scores[0]

    # now i_1_scores = batch_size x ner_tags

    i = tf.constant(1)

    def cond(i,i_1_scores):
        return i < seq_len

    def body(i,i_1_scores):

        # j -> k

        i_scores = []

        for k in xrange(len(NER_tags)):

            score_k = []

            for j in xrange(len(NER_tags)):

                score_k.append(l1*scores[i,:,k] + l2*Transition_matrix[j,k] + i_1_scores[:,j])

            score_k = tf.convert_to_tensor(score_k)

            score_k = tf.transpose(score_k)

            max_k = tf.reduce_max(score_k,1)

            score_k = score_k-tf.reshape(max_k,[-1,1])
            score_k = tf.exp(score_k)

            score_k = tf.reduce_sum(score_k,1)

            score_k = max_k + tf.log(score_k)

            i_scores.append(score_k)

        i_1_scores = tf.convert_to_tensor(i_scores)

        # now i_1_scores = NER_tags_len x batch_size

        i_1_scores = tf.transpose(i_1_scores)

        return i+1,i_1_scores

    _,seq_len_scores = tf.while_loop(cond,body,[i,i_1_scores])

    # now seq_lens = batch_size x NER_tags_len
    max_scores = tf.reduce_max(seq_len_scores,1)
    seq_len_scores = seq_len_scores - tf.reshape(max_scores,[-1,1])
    seq_len_scores = tf.exp(seq_len_scores)
    Z = tf.reduce_sum(seq_len_scores,1)
    logZ = max_scores + tf.log(Z)

    y_score = tf.zeros([tf_batch_size])

    y_score = tf.cond(tf.equal(traintestval,True),
                      lambda:fn1(tf_batch_size,seq_len,y_score,scores),
                      lambda:fn2(y_score))

    return GRU_scores,logZ,y_score

```

```python
GRU_scores,logZ,y_score = model(traintestval)

log_PyX = y_score - logZ

# l2 regularization
reg_variables = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
regularization = tf.contrib.layers.apply_regularization(regularizer, reg_variables)

# Define loss and optimizer

#GRU_cost = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=GRU_scores, labels=tf_tags))+regularization
cost = -tf.reduce_mean(log_PyX) + regularization

#optimizer_GRU = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(GRU_cost)
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

# Initializing the variables
init = tf.global_variables_initializer()
```

### Prediction function:

This function computes the most probable sequence given the GRU scores and the transition matrix values.
While iterating through each position the code, keeps the maximum scoring sequence ending with tag k at i_scores[k].
At the end, we will have the maximum scoring sequences ending with tag K (where k=0:no.of_classes-1).
We can then take the maximum out of it.
The paths of the sequence ending at k, are stored in Paths[:,k] which is updated at every step.

```python
def predict(T,GRU_scores):

    batch_size = GRU_scores.shape[0]
    seq_len = GRU_scores.shape[1]

    GRU_scores = np.transpose(GRU_scores,[1,0,2])

    GRU_scores = GRU_scores*scale_down

    i_1_scores = GRU_scores[0]

    paths = np.zeros((batch_size,len(NER_tags),seq_len),np.int32)

    for b in xrange(batch_size):

        for i in xrange(len(NER_tags)):

            paths[b,i,0] = i

    for i in xrange(len(GRU_scores)):

        new_paths = np.zeros((batch_size,len(NER_tags),seq_len),np.int32)
        i_1_scores_temp = np.copy(i_1_scores)

        for k in xrange(len(NER_tags)):

            score_k = []

            for j in xrange(len(NER_tags)):

                score_ijk = GRU_scores[i,:,k]+T[j,k]+i_1_scores[:,j]
                score_k.append(score_ijk)

            score_k = np.asarray(score_k,np.float32)
            # score_k size = NER_tags x batch_size

            score_k = np.transpose(score_k)

            best_j = np.argmax(score_k,1)

            k_max_scores = np.amax(score_k,1)

            for b in xrange(batch_size):

                new_paths[b,k] = paths[b,best_j[b]]
                new_paths[b,k,i] = k
                i_1_scores_temp[b,k] = k_max_scores[b]

        paths = np.copy(new_paths)
        i_1_scores = np.copy(i_1_scores_temp)

    optimal_seq = np.zeros((batch_size,seq_len),np.int32)

    # scores_i_1 = NER_tags x batch_size

    for b in xrange(batch_size):

        best_seq_end_tag = np.argmax(i_1_scores[b,:])
        optimal_seq[b] = paths[b,best_seq_end_tag]

    return optimal_seq
```

```python
def measure_plain_acc(predicted_seq,tags):

    acc_tensor = np.equal(predicted_seq,tags)
    acc_tensor.astype(np.float32)
    acc = np.mean(acc_tensor)
    return acc
```

### Training......

```python
with tf.Session() as sess: # Start Tensorflow Session

    saver = tf.train.Saver()

    sess.run(init) #initialize all variables
    step = 1
    loss_list=[]
    acc_list=[]
    val_loss_list=[]
    val_acc_list=[]
    best_val_loss=2**30
    prev_val_loss=2**30
    patience = 20
    impatience = 0
    display_step = 20
    epochs = 200

    batch_size = 100

    while step <= epochs:

        total_loss=0
        total_acc=0
        total_val_loss = 0
        total_val_acc = 0

        batches_sentences,batches_tags = create_batches(train_sentences,train_tags,batch_size)

        for i in xrange(len(batches_sentences)):

            # Run optimization operation (backpropagation)
            _,loss,GRU_scores_out,T,npZ,npy_score = sess.run([optimizer,cost,GRU_scores,
                                                          Transition_matrix,logZ,log_PyX],
                                      feed_dict={tf_sentences: batches_sentences[i],
                                                  tf_tags: batches_tags[i],
                                                  traintestval: True})

            total_loss += loss

            predicted_seq = predict(T,GRU_scores_out)
            acc = measure_plain_acc(predicted_seq,batches_tags[i])

            total_acc += acc

            if i%display_step == 0:
                print "Iter "+str(i)+", Loss= "+\
                      "{:.3f}".format(loss)+", Accuracy= "+\
                      "{:.3f}".format(acc*100)

        avg_loss = total_loss/len(batches_sentences)
        avg_acc = total_acc/len(batches_sentences)

        loss_list.append(avg_loss)
        acc_list.append(avg_acc)

        val_batch_size = 100
        batches_sentences,batches_tags = create_batches(val_sentences,val_tags,batch_size)

        for i in xrange(len(batches_sentences)):

            # Run optimization operation (backpropagation)
            val_loss,val_GRU_scores,val_T = sess.run([cost,GRU_scores,Transition_matrix],
                                       feed_dict={tf_sentences: batches_sentences[i],
                                                  tf_tags: batches_tags[i],
                                                  traintestval: True})
            total_val_loss += val_loss

            predicted_seq = predict(val_T,val_GRU_scores)
            val_acc = measure_plain_acc(predicted_seq,batches_tags[i])

            total_val_acc += val_acc

        avg_val_loss = total_val_loss/len(batches_sentences)
        avg_val_acc = total_val_acc/len(batches_sentences)

        val_loss_list.append(avg_val_loss)
        val_acc_list.append(avg_val_acc)

        print "\nEpoch " + str(step) + ", Validation Loss= " + \
                "{:.3f}".format(avg_val_loss) + ", validation Accuracy= " + \
                "{:.3f}%".format(avg_val_acc*100)+""
        print "Epoch " + str(step) + ", Average Training Loss= " + \
              "{:.3f}".format(avg_loss) + ", Average Training Accuracy= " + \
              "{:.3f}%".format(avg_acc*100)+""

        impatience += 1

        if avg_val_loss <= best_val_loss:
            impatience = 0
            best_val_loss = avg_val_loss
            saver.save(sess, 'CRF_Model_Backup/model.ckpt')
            print "Checkpoint created!"

        if impatience > patience:
            print "\nEarly Stopping since best validation loss not decreasing for "+str(patience)+" epochs."
            break

        print ""
        step += 1

    print "\nOptimization Finished!\n"

    print "Best Validation Loss: %.3f"%((best_val_loss))

```

    Iter 0, Loss= 100.976, Accuracy= 0.467
    Iter 20, Loss= 25.402, Accuracy= 91.300
    Iter 40, Loss= 13.638, Accuracy= 95.100
    Iter 60, Loss= 9.456, Accuracy= 95.067

    Epoch 1, Validation Loss= 6.851, validation Accuracy= 95.453%
    Epoch 1, Average Training Loss= 19.559, Average Training Accuracy= 91.532%
    Checkpoint created!

    Iter 0, Loss= 6.885, Accuracy= 95.567
    Iter 20, Loss= 5.857, Accuracy= 95.567
    Iter 40, Loss= 4.720, Accuracy= 96.300
    Iter 60, Loss= 4.283, Accuracy= 96.067

    Epoch 2, Validation Loss= 3.736, validation Accuracy= 96.440%
    Epoch 2, Average Training Loss= 4.955, Average Training Accuracy= 96.043%
    Checkpoint created!

    Iter 0, Loss= 4.001, Accuracy= 95.800
    Iter 20, Loss= 3.207, Accuracy= 96.367
    Iter 40, Loss= 2.763, Accuracy= 97.000
    Iter 60, Loss= 2.623, Accuracy= 96.767

    Epoch 3, Validation Loss= 2.777, validation Accuracy= 96.953%
    Epoch 3, Average Training Loss= 2.967, Average Training Accuracy= 96.918%
    Checkpoint created!

    Iter 0, Loss= 2.281, Accuracy= 97.333
    Iter 20, Loss= 2.133, Accuracy= 97.367
    Iter 40, Loss= 2.358, Accuracy= 97.200
    Iter 60, Loss= 2.209, Accuracy= 97.300

    Epoch 4, Validation Loss= 2.455, validation Accuracy= 96.983%
    Epoch 4, Average Training Loss= 2.222, Average Training Accuracy= 97.352%
    Checkpoint created!

    Iter 0, Loss= 2.204, Accuracy= 97.133
    Iter 20, Loss= 1.731, Accuracy= 97.900
    Iter 40, Loss= 1.544, Accuracy= 97.700
    Iter 60, Loss= 1.542, Accuracy= 97.967

    Epoch 5, Validation Loss= 2.458, validation Accuracy= 96.890%
    Epoch 5, Average Training Loss= 1.827, Average Training Accuracy= 97.704%

    Iter 0, Loss= 1.806, Accuracy= 98.333
    Iter 20, Loss= 1.446, Accuracy= 98.033
    Iter 40, Loss= 1.365, Accuracy= 98.200
    Iter 60, Loss= 1.732, Accuracy= 97.600

    Epoch 6, Validation Loss= 2.434, validation Accuracy= 96.907%
    Epoch 6, Average Training Loss= 1.581, Average Training Accuracy= 97.930%
    Checkpoint created!

    Iter 0, Loss= 1.211, Accuracy= 98.200
    Iter 20, Loss= 1.935, Accuracy= 97.433
    Iter 40, Loss= 1.550, Accuracy= 98.100
    Iter 60, Loss= 1.006, Accuracy= 98.133

    Epoch 7, Validation Loss= 2.571, validation Accuracy= 96.667%
    Epoch 7, Average Training Loss= 1.362, Average Training Accuracy= 98.166%

    Iter 0, Loss= 1.163, Accuracy= 98.567
    Iter 20, Loss= 1.033, Accuracy= 98.433
    Iter 40, Loss= 1.142, Accuracy= 98.067
    Iter 60, Loss= 1.414, Accuracy= 97.900

    Epoch 8, Validation Loss= 2.526, validation Accuracy= 96.827%
    Epoch 8, Average Training Loss= 1.203, Average Training Accuracy= 98.373%

    Iter 0, Loss= 0.858, Accuracy= 98.733
    Iter 20, Loss= 0.930, Accuracy= 98.467
    Iter 40, Loss= 1.033, Accuracy= 98.500
    Iter 60, Loss= 1.000, Accuracy= 98.000

    Epoch 9, Validation Loss= 2.613, validation Accuracy= 96.883%
    Epoch 9, Average Training Loss= 1.042, Average Training Accuracy= 98.503%

    Iter 0, Loss= 1.180, Accuracy= 98.733
    Iter 20, Loss= 0.876, Accuracy= 98.833
    Iter 40, Loss= 0.955, Accuracy= 98.567
    Iter 60, Loss= 0.924, Accuracy= 98.567

    Epoch 10, Validation Loss= 2.695, validation Accuracy= 96.943%
    Epoch 10, Average Training Loss= 0.921, Average Training Accuracy= 98.662%

    Iter 0, Loss= 0.652, Accuracy= 99.200
    Iter 20, Loss= 0.918, Accuracy= 98.500
    Iter 40, Loss= 0.815, Accuracy= 98.467
    Iter 60, Loss= 0.722, Accuracy= 98.933

    Epoch 11, Validation Loss= 2.772, validation Accuracy= 96.647%
    Epoch 11, Average Training Loss= 0.811, Average Training Accuracy= 98.769%

    Iter 0, Loss= 0.684, Accuracy= 98.867
    Iter 20, Loss= 0.616, Accuracy= 99.167
    Iter 40, Loss= 0.796, Accuracy= 98.900
    Iter 60, Loss= 1.050, Accuracy= 98.300

    Epoch 12, Validation Loss= 2.865, validation Accuracy= 96.767%
    Epoch 12, Average Training Loss= 0.738, Average Training Accuracy= 98.875%

    Iter 0, Loss= 0.542, Accuracy= 99.133
    Iter 20, Loss= 0.648, Accuracy= 98.933
    Iter 40, Loss= 0.589, Accuracy= 99.100
    Iter 60, Loss= 0.470, Accuracy= 99.000

    Epoch 13, Validation Loss= 2.988, validation Accuracy= 96.503%
    Epoch 13, Average Training Loss= 0.692, Average Training Accuracy= 98.867%

    Iter 0, Loss= 0.629, Accuracy= 98.767
    Iter 20, Loss= 0.613, Accuracy= 99.033
    Iter 40, Loss= 0.643, Accuracy= 98.767
    Iter 60, Loss= 1.052, Accuracy= 98.533

    Epoch 14, Validation Loss= 2.998, validation Accuracy= 96.477%
    Epoch 14, Average Training Loss= 0.643, Average Training Accuracy= 98.930%

    Iter 0, Loss= 0.682, Accuracy= 99.033
    Iter 20, Loss= 0.802, Accuracy= 98.867
    Iter 40, Loss= 0.566, Accuracy= 99.200
    Iter 60, Loss= 0.556, Accuracy= 98.900

    Epoch 15, Validation Loss= 3.026, validation Accuracy= 96.713%
    Epoch 15, Average Training Loss= 0.593, Average Training Accuracy= 98.947%

    Iter 0, Loss= 0.422, Accuracy= 99.267
    Iter 20, Loss= 0.573, Accuracy= 98.767
    Iter 40, Loss= 0.593, Accuracy= 99.000
    Iter 60, Loss= 0.555, Accuracy= 98.700

    Epoch 16, Validation Loss= 3.152, validation Accuracy= 96.647%
    Epoch 16, Average Training Loss= 0.580, Average Training Accuracy= 98.900%

    Iter 0, Loss= 0.355, Accuracy= 99.400
    Iter 20, Loss= 0.557, Accuracy= 98.967
    Iter 40, Loss= 0.464, Accuracy= 98.700
    Iter 60, Loss= 0.625, Accuracy= 98.667

    Epoch 17, Validation Loss= 3.187, validation Accuracy= 96.567%
    Epoch 17, Average Training Loss= 0.527, Average Training Accuracy= 98.987%

    Iter 0, Loss= 0.379, Accuracy= 98.933
    Iter 20, Loss= 0.456, Accuracy= 98.900
    Iter 40, Loss= 0.456, Accuracy= 99.067
    Iter 60, Loss= 0.398, Accuracy= 99.233

    Epoch 18, Validation Loss= 3.244, validation Accuracy= 96.437%
    Epoch 18, Average Training Loss= 0.502, Average Training Accuracy= 99.005%

    Iter 0, Loss= 0.535, Accuracy= 98.867
    Iter 20, Loss= 0.409, Accuracy= 99.433
    Iter 40, Loss= 0.633, Accuracy= 98.667
    Iter 60, Loss= 0.551, Accuracy= 98.933

    Epoch 19, Validation Loss= 3.338, validation Accuracy= 96.370%
    Epoch 19, Average Training Loss= 0.518, Average Training Accuracy= 98.955%

    Iter 0, Loss= 0.463, Accuracy= 98.867
    Iter 20, Loss= 0.323, Accuracy= 99.467
    Iter 40, Loss= 0.370, Accuracy= 99.133
    Iter 60, Loss= 0.497, Accuracy= 98.933

    Epoch 20, Validation Loss= 3.347, validation Accuracy= 96.513%
    Epoch 20, Average Training Loss= 0.499, Average Training Accuracy= 98.924%

    Iter 0, Loss= 0.312, Accuracy= 99.267
    Iter 20, Loss= 0.342, Accuracy= 99.333
    Iter 40, Loss= 0.308, Accuracy= 99.200
    Iter 60, Loss= 0.376, Accuracy= 98.867

    Epoch 21, Validation Loss= 3.414, validation Accuracy= 96.500%
    Epoch 21, Average Training Loss= 0.443, Average Training Accuracy= 99.000%

    Iter 0, Loss= 0.295, Accuracy= 99.000
    Iter 20, Loss= 0.343, Accuracy= 99.300
    Iter 40, Loss= 0.364, Accuracy= 99.200
    Iter 60, Loss= 0.541, Accuracy= 98.700

    Epoch 22, Validation Loss= 3.475, validation Accuracy= 96.557%
    Epoch 22, Average Training Loss= 0.437, Average Training Accuracy= 99.010%

    Iter 0, Loss= 0.477, Accuracy= 99.100
    Iter 20, Loss= 0.509, Accuracy= 98.733
    Iter 40, Loss= 0.311, Accuracy= 99.233
    Iter 60, Loss= 0.460, Accuracy= 99.167

    Epoch 23, Validation Loss= 3.390, validation Accuracy= 96.403%
    Epoch 23, Average Training Loss= 0.432, Average Training Accuracy= 99.002%

    Iter 0, Loss= 0.295, Accuracy= 99.167
    Iter 20, Loss= 0.573, Accuracy= 98.567
    Iter 40, Loss= 0.372, Accuracy= 98.867
    Iter 60, Loss= 0.447, Accuracy= 99.333

    Epoch 24, Validation Loss= 3.422, validation Accuracy= 96.333%
    Epoch 24, Average Training Loss= 0.438, Average Training Accuracy= 98.968%

    Iter 0, Loss= 0.357, Accuracy= 99.167
    Iter 20, Loss= 0.330, Accuracy= 99.200
    Iter 40, Loss= 0.322, Accuracy= 99.033
    Iter 60, Loss= 0.454, Accuracy= 99.100

    Epoch 25, Validation Loss= 3.452, validation Accuracy= 96.360%
    Epoch 25, Average Training Loss= 0.441, Average Training Accuracy= 98.934%

    Iter 0, Loss= 0.300, Accuracy= 98.767
    Iter 20, Loss= 0.312, Accuracy= 99.133
    Iter 40, Loss= 0.475, Accuracy= 98.633
    Iter 60, Loss= 0.432, Accuracy= 98.933

    Epoch 26, Validation Loss= 3.425, validation Accuracy= 96.280%
    Epoch 26, Average Training Loss= 0.465, Average Training Accuracy= 98.833%

    Iter 0, Loss= 0.286, Accuracy= 99.200
    Iter 20, Loss= 0.460, Accuracy= 99.100
    Iter 40, Loss= 0.424, Accuracy= 99.100
    Iter 60, Loss= 0.574, Accuracy= 98.867

    Epoch 27, Validation Loss= 3.443, validation Accuracy= 96.493%
    Epoch 27, Average Training Loss= 0.466, Average Training Accuracy= 98.819%

    Early Stopping since best validation loss not decreasing for 20 epochs.

    Optimization Finished!

    Best Validation Loss: 2.434

### Testing.....

Note: This is just the normal accuracy. I haven't calculated the F1 score which will probably be much lower.
The dataset is pretty skewed. First most words are not named entities and have the tag 'O' - that's natural, but also makes the data biased.
ON TOP OF THAT, I used PADDING WITHOUT BUCKETING.
One can achieve a fairly high accuracy just by predicting all words as 'O'. F1 accuracy is needed to make a fair estimate.

I will implement it later.

```python
with tf.Session() as sess: # Begin session

    print 'Loading pre-trained weights for the model...'
    saver = tf.train.Saver()
    saver.restore(sess, 'CRF_Model_Backup/model.ckpt')
    sess.run(tf.global_variables())
    print '\nRESTORATION COMPLETE\n'

    print 'Testing Model Performance...'

    total_test_loss = 0
    total_test_acc = 0

    test_batch_size = 100 #(should be able to divide total no. of test samples without remainder)
    batches_sentences,batches_tags = create_batches(test_sentences,test_tags,test_batch_size)

    for i in xrange(len(batches_sentences)):

            # Run optimization operation (backpropagation)
            test_loss,T,GRU_out = sess.run([cost,Transition_matrix,GRU_scores],
                                       feed_dict={tf_sentences: batches_sentences[i],
                                                  tf_tags: batches_tags[i],
                                                  traintestval: True})
            total_test_loss += test_loss
            predicted_seq = predict(T,GRU_out)
            test_acc = measure_plain_acc(predicted_seq,batches_tags[i])
            total_test_acc += test_acc

    avg_test_loss = total_test_loss/len(batches_sentences)
    avg_test_acc = total_test_acc/len(batches_sentences)

    print "\nTest Loss= " + \
          "{:.3f}".format(avg_test_loss) + ", Test Accuracy= " + \
          "{:.3f}%".format(avg_test_acc*100)+""

```

    Loading pre-trained weights for the model...
    INFO:tensorflow:Restoring parameters from CRF_Model_Backup/model.ckpt

    RESTORATION COMPLETE

    Testing Model Performance...

    Test Loss= 2.470, Test Accuracy= 96.777%

### Prediction on a random test sample

The model seems to be working at least.
This cell can be run more than one times, and the prediction of different test sequences can be compared with the actual tags.

```python
import random

rand = random.randint(0,len(test_sentences))

print "SENTENCE ABOUT TO BE FED:\n"
print map(vec2word,test_sentences[rand])

print "\n"

with tf.Session() as sess: # Begin session

    saver = tf.train.Saver()
    saver.restore(sess, 'CRF_Model_Backup/model.ckpt')
    sess.run(tf.global_variables())
    scores,T = sess.run([GRU_scores,Transition_matrix],
                          feed_dict={tf_sentences: [test_sentences[rand]],
                          tf_tags: [test_tags[rand]],
                          traintestval: True})
    prediction = predict(T,scores)
    acc = measure_plain_acc(prediction,[test_tags[rand]])

print "\nRESULT:\n"

for i in xrange(len(prediction[0])):
    ##removing Prediction of pads
    if vocab.index(vec2word(test_sentences[rand,i])) == vocab.index('<PAD>'):
        break
    print vec2word(test_sentences[rand,i]),
    print "- Tag: "+NER_tags[test_tags[rand,i]],
    print "Prediction: "+NER_tags[prediction[0,i]]

print "\n\nACCURACY: "+str(acc*100)+"%"
```

    SENTENCE ABOUT TO BE FED:

    ['pakistani', 'military', 'authorities', 'say', 'they', 'have', 'arrested', 'a', 'key', 'taliban', 'commander', 'who', 'is', 'accused', 'of', 'slaughtering', 'military', 'personnel', '.', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>', '<PAD>']

    INFO:tensorflow:Restoring parameters from CRF_Model_Backup/model.ckpt

    RESULT:

    pakistani - Tag: B-gpe Prediction: B-gpe
    military - Tag: O Prediction: O
    authorities - Tag: O Prediction: O
    say - Tag: O Prediction: O
    they - Tag: O Prediction: O
    have - Tag: O Prediction: O
    arrested - Tag: O Prediction: O
    a - Tag: O Prediction: O
    key - Tag: O Prediction: O
    taliban - Tag: B-org Prediction: B-org
    commander - Tag: O Prediction: O
    who - Tag: O Prediction: O
    is - Tag: O Prediction: O
    accused - Tag: O Prediction: O
    of - Tag: O Prediction: O
    slaughtering - Tag: O Prediction: O
    military - Tag: O Prediction: O
    personnel - Tag: O Prediction: O
    . - Tag: O Prediction: O

    ACCURACY: 100.0%

### Prediction

A very lame implementation of a cell that predicts user given sentences.
One has to enter a sentence in the code in a tokenized lower case format.
I may polish this part later, and make it more user friendly, or not.

```python
import random

rand = random.randint(0,len(sentences))

sentence = ['the','british','is','planning','to','attack','india','at','eleven']
# ENTER YOUR OWN SENTENCE HERE IN THIS FORMAT; LOWER CASE PLEASE.

print "SENTENCE ABOUT TO BE FED: "
print sentence

print "\n"

sentence_vec = map(word2vec,sentence)

with tf.Session() as sess: # Begin session

    saver = tf.train.Saver()
    saver.restore(sess, 'CRF_Model_Backup/model.ckpt')
    sess.run(tf.global_variables())
    T,scores = sess.run([Transition_matrix,GRU_scores],
                          feed_dict={tf_sentences: [sentence_vec],
                                     traintestval: False})
    prediction = predict(T,scores)

print "\nRESULT:\n"
for i in xrange(len(prediction[0])):
    print sentence[i],
    print "- "+NER_tags[prediction[0,i]]

```

    SENTENCE ABOUT TO BE FED:
    ['the', 'british', 'is', 'planning', 'to', 'attack', 'india', 'at', 'eleven']

    INFO:tensorflow:Restoring parameters from CRF_Model_Backup/model.ckpt

    RESULT:

    the - O
    british - B-gpe
    is - O
    planning - O
    to - O
    attack - O
    india - B-geo
    at - O
    eleven - O

```python

```


# Load and Process models

This script will load the M models in the collection using cobrapy, and convert them to a normalized format. They will also be exported to the "mat" format used by the COBRA toolbox.

This requires [cobrapy](https://opencobra.github.io/cobrapy) version 0.4.0b1 or later.

```python
import os
import warnings
import re
from itertools import chain

import sympy
import scipy
import scipy.io

import cobra

from read_excel import read_excel
```

## Read in Models

```python
def open_exchanges(model, amount=10):
    for reaction in model.reactions:
        if len(reaction.metabolites) == 1:
            # Ensure we are not creating any new sinks
            if reaction.metabolites.values()[0] > 0:
                reaction.upper_bound = max(reaction.upper_bound, amount)
            else:
                reaction.lower_bound = min(reaction.lower_bound, -amount)

def add_exchanges(model, extracellular_suffix="[e]", uptake_amount=10):
    for metabolite in model.metabolites:
        if str(metabolite).endswith(extracellular_suffix):
            if len(metabolite.reactions) == 0:
                print "no reactions for " + metabolite.id
                continue
            if min(len(i.metabolites) for i in metabolite.reactions) > 1:
                EX_reaction = cobra.Reaction("EX_" + metabolite.id)
                EX_reaction.add_metabolites({metabolite: 1})
                m.add_reaction(EX_reaction)
                EX_reaction.upper_bound = uptake_amount
                EX_reaction.lower_bound = -uptake_amount
```

### SBML models

These models will be read in using [libSBML](http://sbml.org/Software/libSBML) through cobrapy. Some models will need their exchanges opened.

```python
legacy_SBML = {"T_Maritima", "iNJ661m", "iSR432", "iTH366"}
open_boundaries = {"iRsp1095", "iWV1314", "iFF708", "iZM363"}

models = cobra.DictList()
for i in sorted(os.listdir("sbml")):
    if not i.endswith(".xml"):
        continue
    model_id = i[:-4]
    filepath = os.path.join("sbml", i)
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        m = cobra.io.read_legacy_sbml(filepath) if model_id in legacy_SBML \
            else cobra.io.read_sbml_model(filepath)
    m.id = m.description = model_id.replace(".", "_")

    if m.id in open_boundaries:
        open_exchanges(m)

    models.append(m)
```

### Models available in COBRA Toolbox "mat" format

```python
for i in sorted(os.listdir("mat")):
    if not i.endswith(".mat"):
        continue
    m = cobra.io.load_matlab_model(os.path.join("mat", i))
    m.id = i[:-4]

    if m.id in open_boundaries:
        open_exchanges(m)

    models.append(m)
```

### Some models are only available as Microsoft Excel files

```python
m = read_excel("xls/iJS747.xls",
               verbose=False, rxn_sheet_header=7)
models.append(m)
```

```python
m = read_excel("xls/iRM588.xls",
               verbose=False, rxn_sheet_header=5)
models.append(m)
```

```python
m = read_excel("xls/iSO783.xls", verbose=False, rxn_sheet_header=2)
models.append(m)
```

```python
m = read_excel("xls/iCR744.xls", rxn_sheet_header=4, verbose=False)
models.append(m)
```

```python
m = read_excel("xls/iNV213.xls", rxn_str_key="Reaction Formula", verbose=False)
# remove boundary metabolites
for met in list(m.metabolites):
    if met.id.endswith("[b]"):
        met.remove_from_model()
models.append(m)
```

```python
m = read_excel("xls/iTL885.xls", verbose=False,
               rxn_id_key="Rxn name", rxn_gpr_key="Gene-reaction association", met_sheet_name="ignore")
models.append(m)
```

    cobra/core/Reaction.py:98 UserWarning: malformed gene_reaction_rule '(PICST_57189 or PICST_52197or PICST_32180 or PICST_68755 or PICST_11039 or PICST_78721 or PICST_37009 or PICST_41966 or PICST_67826 or PICST_52358 or PICST_28502)' for <Reaction SS1034 at 0x7f6d192ddc50>

```python
m = read_excel("xls/iWZ663.xls", verbose=False,
               rxn_id_key="auto", rxn_name_key="Reaction name", rxn_gpr_key="Local gene")
models.append(m)
```

```python
m = read_excel("xls/iOR363.xls", verbose=False)
models.append(m)
```

```python
m = read_excel("xls/iMA945.xls", verbose=False)
models.append(m)
```

```python
m = read_excel("xls/iPP668.xls", verbose=False)
add_exchanges(m)
models.append(m)
```

```python
m = read_excel("xls/iVM679.xls", verbose=False, met_sheet_name="ignore",
               rxn_id_key="Name", rxn_name_key="Description", rxn_str_key="Reaction")
open_exchanges(m)
models.append(m)
```

```python
m = read_excel("xls/iTY425.xls", rxn_sheet_header=1,
               rxn_sheet_name="S8", rxn_id_key="Number", rxn_str_key="Reaction", verbose=False)
add_exchanges(m, "xt")
# Protein production reaction does not prdoue "PROTEIN" metabolite
m.reactions.R511.add_metabolites({m.metabolites.PROTEIN: 1})
m.id = m.id + "_fixed"
models.append(m)
```

```python
m = read_excel("xls/iSS724.xls", rxn_str_key="Reactions",
               rxn_sheet_header=1, met_sheet_header=1, rxn_id_key="Name",
               verbose=False)
add_exchanges(m, "xt")
models.append(m)
```

```python
m = read_excel("xls/iCS400.xls", rxn_sheet_name="Complete Rxn List",
               rxn_sheet_header=2, rxn_str_key="Reaction",
               rxn_id_key="Name", verbose=False)
add_exchanges(m, "xt")
models.append(m)
```

```python
m = read_excel("xls/iLL672.xls",
               rxn_id_key="auto", met_sheet_name="Appendix 3 iLL672 metabolites",\
               rxn_str_key="REACTION", rxn_gpr_key="skip", verbose=False,
               rxn_sheet_name='Appendix 3 iLL672 reactions')
m.reactions[-1].objective_coefficient = 1
m.metabolites.BM.remove_from_model()
add_exchanges(m, "xt")
models.append(m)
```

```python
plus_re = re.compile("(?<=\S)\+")  # substitute H+ with H, etc.
m = read_excel("xls/iMH551.xls", rxn_sheet_name="GPR Annotation", rxn_sheet_header=4,
               rxn_id_key="auto", rxn_str_key="REACTION", rxn_gpr_key="skip",
               rxn_name_key="ENZYME", rxn_skip_rows=[625, 782, 787], verbose=False,
               rxn_sheet_converters={"REACTION": lambda x: plus_re.sub("", x)})
for met in m.metabolites:
    if met.id.endswith("(extracellular)"):
        met.id = met.id[:-15] + "_e"
m.repair()
add_exchanges(m, "_e")
models.append(m)
```

```python
m = read_excel("xls/iCS291.xls", rxn_sheet_name="Sheet1",
               rxn_str_key="Reaction",
               rxn_sheet_header=5, rxn_id_key="Name",
               verbose=False)
add_exchanges(m, "xt")
# BIOMASS is just all model metabolites in the Demands list
m.add_reaction(cobra.Reaction("BIOMASS"))
# taken from Table 1 in publication
biomass_mets = {}
for i in {"ALA", "ARG", "ASN", "ASP", "CYS", "GLU", "GLN", "GLY",
          "HIS", "ILE", "LEU", "LYS", "MET", "PHE", "PRO", "SER",
          "THR", "TRP", "TYR", "VAL", "PTRC", "SPMD", "ATP", "GTP",
          "CTP", "UTP", "DATP", "DGTP", "DCTP", "DTTP", "PS", "PE",
          "PG", "PEPTIDO", "LPS", "OPP", "UDPP", "NAD", "NADP", "FAD",
          "COA", "ACP", "PTH", "THIAMIN", "MTHF", "MK", "DMK"
         }:
    biomass_mets[m.metabolites.get_by_id(i)] = -1
    dm = cobra.Reaction("DM_" + i)
    m.add_reaction(dm)
    dm.add_metabolites({m.metabolites.get_by_id(i): -1})
m.reactions.BIOMASS.add_metabolites(biomass_mets)
m.change_objective("BIOMASS")
add_exchanges(m, "xt")
models.append(m)
```

```python
m = read_excel("xls/iYO844.xls", rxn_sheet_name="Reaction and locus", verbose=False, rxn_gpr_key="Locus name",
           rxn_str_key=u'Equation (note [c] and [e] at the beginning refer to the compartment \n'
                       'the reaction takes place in, cytosolic and extracellular respectively)')
add_exchanges(m)

# create the biomass reaction from supplementary data table
# http://www.jbc.org/content/suppl/2007/06/29/M703759200.DC1/Biomass_composition.doc
r = cobra.Reaction("biomass")
r.objective_coefficient = 1.
m.add_reaction(r)
r.reaction = ("408.3 gly[c] + 266.9 ala-L[c] + 306.7 val-L[c] + 346.4 leu-L[c] + 269.9 ile-L[c] + "
              "216.2 ser-L[c] + 186.3 thr-L[c] + 175.9 phe-L[c] + 110.8 tyr-L[c] + 54.3 trp-L[c] + "
              "56.7 cys-L[c] + 113.3 met-L[c] + 323.1 lys-L[c] + 193.0 arg-L[c] + 81.7 his-L[c] + "
              "148.0 asp-L[c] +  260.4 glu-L[c] + 148.0 asp-L[c] + 260.3 gln-L[c] + 160.6 pro-L[c] + "
              "62.7 gtp[c] + 38.9 ctp[c] + 41.5 utp[c] + 23.0 datp[c] + 17.4 dgtp[c] + 17.4 dctp[c] + "
              "22.9 dttp[c] + 0.085750 m12dg_BS[c] + 0.110292 d12dg_BS[c] + 0.065833 t12dg_BS[c] + "
              "0.004642 cdlp_BS[c] + 0.175859 pgly_BS[c] + 0.022057 lysylpgly_BS[c] + 0.559509 psetha_BS[c] + "
              "0.006837 lipo1-24_BS[c] + 0.006123 lipo2-24_BS[c] + 0.018162 lipo3-24_BS[c] + "
              "0.014676 lipo4-24_BS[c] + 101.82 peptido_BS[c] + 3.62 gtca1-45_BS[c] + 2.35 gtca2-45_BS[c] + "
              "1.82 gtca3-45_BS[c] + 3.11 tcam_BS[c] + 706.3 k[c] + 101.7 mg2[c] + 3.4 fe3[c] + 3.2 ca2[c] + "
              "0.9 ppi[c] + 0.3 mql7[c] + 0.4 10fthf[c] + 16.2 nad[c] + 4.7 amp[c]  + 2.6 adp[c] + 1.0 cmp[c]  + "
              "0.9 nadp[c] + 0.5 ctp[c]  + 0.5 gmp[c] + 0.4 gtp[c] + 0.3 cdp[c] + 0.2 nadph[c] + 0.2 gdp[c] + "
              "105053.5 atp[c] + 105000 h2o[c] --> 104985.6 pi[c] + 104997.4 adp[c] + 105000 h[c]")
# units are in mg for this reaction, so scale to grams
r *= 0.001
models.append(m)
```

```python
models.sort()
```

## Determine Objective Reactions

Some of these models do not specify an objective (or biomass) reaction. These will be automatically detected if possible, or set from a manually curated list.

```python
# regular expression to detect "biomass"
biomass_re = re.compile("biomass", re.IGNORECASE)

# manually identified objective reactions
curated_objectives = {"VvuMBEL943": "R806",
                      "iAI549": "BIO_CBDB1_DM_855",
                      "mus_musculus": "BIO028",
                      "iRsp1095": "RXN1391",
                      "iLC915": "r1133",
                      "PpaMBEL1254": "R01288",
                      "AbyMBEL891": "R761",
                      "iAbaylyiV4": "GROWTH_DASH_RXN",
                      "iOG654": "RM00001",
                      "iOR363": "OF14e_Retli",
                      "iRM588": "agg_GS13m",
                      "iJS747": "agg_GS13m_2",
                      "iTL885": "SS1240",
                      "iMH551": "R0227"}
```

```python
for m in models:
    if len(m.reactions.query(lambda x: x > 0, "objective_coefficient")):
        continue
    if m.id in curated_objectives:
        m.change_objective(curated_objectives[m.id])
        continue

    # look for reactions with "biomass" in the id or name
    possible_objectives = m.reactions.query(biomass_re)
    if len(possible_objectives) == 0:
        possible_objectives = m.reactions.query(biomass_re, "name")

    # In some cases, a biomass "metabolite" is produced, whose production
    # should be the objective function.
    possible_biomass_metabolites = m.metabolites.query(biomass_re)
    if len(possible_biomass_metabolites) == 0:
        possible_biomass_metabolites = m.metabolites.query(biomass_re, "name")

    if len(possible_biomass_metabolites) > 0:
        biomass_met = possible_biomass_metabolites[0]
        r = cobra.Reaction("added_biomass_sink")
        r.objective_coefficient = 1
        r.add_metabolites({biomass_met: -1})
        m.add_reaction(r)
        print ("autodetected biomass metabolite '%s' for model '%s'" %
              (biomass_met.id, m.id))

    elif len(possible_objectives) > 0:
        print("autodetected objective reaction '%s' for model '%s'" %
              (possible_objectives[0].id, m.id))
        m.change_objective(possible_objectives[0])

    else:
        print("no objective found for " + m.id)

# Ensure the biomass objective flux is unconstrained
for m in models:
    for reaction in m.reactions.query(lambda x: x > 0, "objective_coefficient"):
        reaction.lower_bound = min(reaction.lower_bound, 0)
        reaction.upper_bound = max(reaction.upper_bound, 1000)
```

    autodetected biomass metabolite 'BIOMASS_c' for model 'GSMN_TB'
    autodetected objective reaction 'Biomass' for model 'PpuMBEL1071'
    autodetected objective reaction 'RXNBiomass' for model 'SpoMBEL1693'
    autodetected objective reaction 'BIOMASS_LM3' for model 'iAC560'
    autodetected biomass metabolite '140' for model 'iAO358'
    autodetected biomass metabolite 'PROT_LPL_v60[c]' for model 'iBT721_fixed'
    autodetected objective reaction 'BIO_Rfer3' for model 'iCR744'
    autodetected objective reaction 'BIOMASS' for model 'iCS400'
    autodetected biomass metabolite 'BIOMASS' for model 'iMA871'
    autodetected objective reaction 'ST_biomass_core' for model 'iMA945'
    autodetected objective reaction 'biomass_mm_1_no_glygln' for model 'iMM1415'
    autodetected objective reaction 'biomass_STR' for model 'iMP429_fixed'
    autodetected objective reaction 'R_biomass_target' for model 'iNV213'
    autodetected objective reaction 'BIOMASS' for model 'iPP668'
    autodetected objective reaction 'Biomass_Chlamy_auto' for model 'iRC1080'
    autodetected objective reaction 'ST_Biomass_Final' for model 'iRR1083'
    autodetected objective reaction 'Biomass' for model 'iSO783'
    autodetected objective reaction 'biomass_target' for model 'iSR432'
    autodetected biomass metabolite 'BIOMASS' for model 'iSS724'
    autodetected biomass metabolite 'm828' for model 'iSS884'
    autodetected biomass metabolite 'BIOMASS' for model 'iTY425_fixed'
    autodetected objective reaction 'Biomass' for model 'iVM679'
    autodetected biomass metabolite 'Biomass' for model 'iWV1314'
    autodetected objective reaction 'R0822' for model 'iWZ663'

## Fixes of various encoding bugs

### General

GSMN_TB does not use the convention of extracellular metabolites with exchanges. Although the model still solves with this formulation, this is still normalized here. This process does not change the mathematical structure of the model.

```python
h_c = models.GSMN_TB.metabolites.H_c
for r in models.GSMN_TB.reactions:
    if len(r.metabolites) == 2 and h_c in r.metabolites:
        met = [i for i in r.metabolites if i is not h_c][0]
        EX_met = cobra.Metabolite(met.id[:-1] + "e")
        r.add_metabolites({EX_met: -r.metabolites[met]})
        if "EX_" + EX_met.id not in models.GSMN_TB.reactions:
            exchange = cobra.Reaction("EX_" + EX_met.id)
            exchange.add_metabolites({EX_met: -1})
            exchange.lower_bound = -1000000.0
            exchange.upper_bound = 1000000.0
            models.GSMN_TB.add_reaction(exchange)
```

### Reaction and Metabolites

### id's

```python
# reaction id's with spaces in them
models.iJS747.reactions.get_by_id("HDH [deleted 01/16/2007  12:02:30 PM]").id = "HDH_del"
models.iJS747.reactions.get_by_id("HIBD [deleted 03/21/2007  01:06:12 PM]").id = "HIBD_del"
models.iAC560.reactions.get_by_id("GLUDx [m]").id = "GLUDx[m]"
for r in models.iOR363.reactions:
    if " " in r.id:
        r.id = r.id.split()[0]

models.textbook.reactions.query("Biomass")[0].id = "Biomass_Ecoli_core"
```

Use the convention underscore + compartment i.e. _c instead of [c] (c) etc.

```python
SQBKT_re = re.compile("\[([a-z])\]$")

def fix_brackets(id_str, compiled_re):
    result = compiled_re.findall(id_str)
    if len(result) > 0:
        return compiled_re.sub("_" + result[0], id_str)
    else:
        return id_str

for r in models.iRS1597.reactions:
    r.id = fix_brackets(r.id, re.compile("_LSQBKT_([a-z])_RSQBKT_$"))

for m_id in ["iJS747", "iRM588", "iSO783", "iCR744", "iNV213", "iWZ663", "iOR363", "iMA945", "iPP668",
             "iTL885", "iVM679", "iYO844", "iZM363"]:
    for met in models.get_by_id(m_id).metabolites:
        met.id = fix_brackets(met.id, SQBKT_re)

for met in models.S_coilicolor_fixed.metabolites:
    if met.id.endswith("_None_"):
        met.id = met.id[:-6]

# Some models only have intra and extracellular metabolites, but don't use _c and _e.
for m_id in ["iCS291", "iCS400", "iTY425_fixed", "iSS724"]:
    for metabolite in models.get_by_id(m_id).metabolites:
        if metabolite.id.endswith("xt"):
            metabolite.id = metabolite.id[:-2] + "_e"
        elif len(metabolite.id) < 2 or metabolite.id[-2] != "_":
            metabolite.id = metabolite.id + "_c"

# Exchange reactions should have the id of the metabolite after with the same convention
for m_id in ["iAF1260", "iJO1366", "iAF692", "iJN746", "iRC1080", "textbook", "iNV213",
             "iIT341", "iJN678", "iJR904", "iND750", "iNJ661", "iPS189_fixed", "iSB619",
             "iZM363", "iMH551"]:
    for r in models.get_by_id(m_id).reactions:
        if len(r.metabolites) != 1:
            continue
        if r.id.startswith("EX_"):
            r.id = "EX_" + list(r.metabolites.keys())[0].id
        if r.id.startswith("DM_"):
            r.id = "DM_" + list(r.metabolites.keys())[0].id

for m in models:
    m.repair()
```

### Metabolite Formulas

```python
for model in models:
    for metabolite in model.metabolites:
        if metabolite.formula is None:
            metabolite.formula = ""
            continue
        if str(metabolite.formula).lower() == "none":
            metabolite.formula = ""
            continue
        # some characters should not be in a formula
        if "(" in metabolite.formula or \
                ")" in metabolite.formula or \
                "." in metabolite.formula:
            metabolite.formula = ""
```

### Metabolite Compartments

```python
compartments = {
    'c': 'Cytoplasm',
    'e': 'Extracellular',
    'p': 'Periplasm',
    'm': 'Mitochondria',
    'g': 'Golgi',
    'n': "Nucleus",
    'r': "Endoplasmic reticulum",
    'x': "Peroxisome",
    'v': "Vacuole",
    "h": "Chloroplast",
    "x": "Glyoxysome",
    "s": "Eyespot",
    "default": "No Compartment"}

for model in models:
    for metabolite in model.metabolites:
        if metabolite.compartment is None or len(metabolite.compartment.strip()) == 0 or metabolite.compartment == "[":
            if len(metabolite.id) > 2 and metabolite.id[-2] == "_" and metabolite.id[-1].isalpha():
                metabolite.compartment = metabolite.id[-1]
            else:
                metabolite.compartment = "default"
        if metabolite.compartment not in model.compartments:
            model.compartments[metabolite.compartment] = compartments.get(metabolite.compartment, metabolite.compartment)
```

### Metabolite and Reaction Names
Names which start with numbers don't need to be escaped with underscores.

```python
for model in models:
    for x in chain(model.metabolites, model.reactions):
        if x.name is not None and x.name.startswith("_"):
            x.name = x.name.lstrip("_")
        if x.name is not None:
            x.name = x.name.strip()
        if x.name is None:
            x.name = x.id
```

### MISC fixes

```python
models.iMM1415.reactions.EX_lnlc_dup_e.remove_from_model()
models.iMM1415.reactions.EX_retpalm_e.remove_from_model(remove_orphans=True)

# these reaction names are reaction strings
for r in models.iCac802.reactions:
    r.name = ""
```

## Fix Genes and GPR's

A lot of genes have characters which won't work in their names

```python
# nonbreaking spaces
models.iCB925.reactions.FDXNRy.gene_reaction_rule = '( Cbei_0661 or Cbei_2182 )'
for r in models.iCB925.reactions:
    if "\xa0" in r.gene_reaction_rule:
        r.gene_reaction_rule = r.gene_reaction_rule.replace("\xc2", " ").replace("\xa0", " ")
for g in list(models.iCB925.genes):
    if len(g.reactions) == 0:
        models.iCB925.genes.remove(g)
```

Some GPR's are not valid boolean expressions.

```python
multiple_ors = re.compile("(\s*or\s+){2,}")
multiple_ands = re.compile("(\s*and\s+){2,}")

for model_id in ["iRS1563", "iRS1597", "iMM1415"]:
    model = models.get_by_id(model_id)
    for reaction in model.reactions:
        gpr = reaction.gene_reaction_rule
        gpr = multiple_ors.sub(" or ", gpr)
        gpr = multiple_ands.sub(" and ", gpr)
        if "[" in gpr:
            gpr = gpr.replace("[", "(").replace("]", ")")
        if gpr.endswith(" or"):
            gpr = gpr[:-3]
        if gpr.count("(") != gpr.count(")"):
            gpr = ""  # mismatched parenthesis somewhere
        reaction.gene_reaction_rule = gpr
    for gene in list(model.genes):
        if gene.id.startswith("[") or gene.id.endswith("]"):
            if len(gene.reactions) == 0:
                model.genes.remove(gene.id)

# Some models are missing spaces between the ands/ors in some of their GPR's
for m_id in ["iJN678", "iTL885"]:
    for r in models.get_by_id(m_id).reactions:
        r.gene_reaction_rule = r.gene_reaction_rule.replace("and", " and ").replace("or", " or ")

models.iCac802.reactions.R0095.gene_reaction_rule = \
    models.iCac802.reactions.R0095.gene_reaction_rule.replace(" AND ", " and ")

# make sbml3 output deterministic by sorting genes
for m in models:
    m.genes.sort()
```

## Ensure all ID's are SBML compliant

```python
for m in models:
    cobra.manipulation.escape_ID(m)
```

## Export Models

### SBML 3
Export the models to the use the fbc version 2 (draft RC6) extension to SBML level 3 version 1.

```python
for model in models:
    cobra.io.write_sbml_model(model, "sbml3/%s.xml" % model.id)
```

### mat
Save all the models into a single mat file. In addition to the usual fields in the "mat" struct, we will also include S_num and S_denom, which are the numerator and denominator of the stoichiometric coefficients encoded as rational numbers.

```python
def convert_to_rational(value):
    return sympy.Rational("%.15g" % value)

def construct_S_num_denom(model):
    """convert model to two S matrices

    they encode the numerator and denominator of stoichiometric
    coefficients encoded as rational numbers

    """
    # intialize to 0
    dimensions = (len(model.metabolites), len(model.reactions))
    S_num = scipy.sparse.lil_matrix(dimensions)
    S_denom = scipy.sparse.lil_matrix(dimensions)
    # populate with stoichiometry
    for i, r in enumerate(model.reactions):
        for met, value in r._metabolites.iteritems():
            rational_value = convert_to_rational(value)
            num, denom = (rational_value.p, rational_value.q)
            S_num[model.metabolites.index(met), i] = num
            S_denom[model.metabolites.index(met), i] = denom
    return S_num, S_denom
```

```python
all_model_dict = {}
for model in models:
    model_dict = cobra.io.mat.create_mat_dict(model)
    model_dict["S_num"], model_dict["S_denom"] = construct_S_num_denom(model)
    all_model_dict[model.id] = model_dict
scipy.io.savemat("all_models.mat", all_model_dict, oned_as="column")
```