Keras modelΒΆ

Example of using a keras RNN model along with Vectorize to fit a set of string expressions.

from itertools import product
import numpy as np
from keras.layers import LSTM, Input, TimeDistributed, Activation, Embedding, Dense
import keras.backend as K
from keras.models import Model
from keras.optimizers import Adam
from grammaropt.grammar import build_grammar
from grammaropt.grammar import Vectorizer


def precision(y_true, y_pred):
    return (y_true.argmax(axis=-1) == y_pred.argmax(axis=-1)).mean()


def categorical_crossentropy(y_true, y_pred):
    yt = y_true.flatten()
    ypr = y_pred.reshape((y_pred.shape[0]*y_pred.shape[1], y_pred.shape[2]))
    return K.categorical_crossentropy(yt, ypr)


def onehot(X, D=10):
    X = X.astype('int32')
    nb = np.prod(X.shape)
    x = X.flatten()
    m = np.zeros((nb, D))
    m[np.arange(nb), x] = 1.
    m = m.reshape(X.shape + (D,))
    return m.astype('float32')

def generate(model, length, nb=1):
    x = np.zeros((nb, length + 1,)).astype('int32')
    for i in range(length):
        y = model.predict(x[:, 0:length])
        for e in range(nb):
            symbol = np.random.choice(np.arange(y.shape[2]), p=y[e, i])
            x[e, i + 1] = symbol
    return x


# Grammar and corpus
rules = r"""
    S = (T "+" S) / (T "*" S) / (T "/" S) / T
    T = (po S pc) / ("sin" po S pc) / ("cos" po S pc) / ("exp" po S pc) / "x" / int
    po = "("
    pc = ")"
    int = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
"""
grammar = build_grammar(rules)
corpus = [
    'x*{}+{}'.format(i, j)
    for i, j in product(range(10), range(10))
]

vect = Vectorizer(grammar, pad=True)
X = vect.transform(corpus)
X = [[0] + x for x in X]
X = np.array(X).astype('int32')

# Model
max_length = max(map(len, X))
vocab_size = len(vect.tok_to_id)
emb_size = 32
batch_size = 32
epochs = 800
inp = Input(shape=(max_length - 1,))
x = Embedding(vocab_size, emb_size)(inp)
x = LSTM(32, return_sequences=True)(x)
x = TimeDistributed(Dense(vocab_size))(x)
out = Activation('softmax')(x)
model = Model(inputs=inp, outputs=out)
model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=1e-3))
I = X[:, 0:-1]
O = X[:, 1:]

# Training
avg_precision = 0.0
avg_loss = 0.0
for i in range(epochs):
    for j in range(0, len(I), batch_size):
        inp = I[j:j+batch_size]
        out = O[j:j+batch_size]
        out = onehot(out, D=vocab_size)
        loss = model.train_on_batch(inp, out)
        p = np.mean(precision(out, model.predict(inp)))
        avg_precision = avg_precision * 0.9 + p * 0.1
        avg_loss = avg_loss * 0.9 + loss * 0.1
        if i % 10 == 0:
            print('Epoch : {:05d} Avg loss : {:.6f} Avg Precision : {:.6f}'.format(i, avg_loss, avg_precision))
    y = generate(model, max_length - 1, nb=1)
    y = [expr[1:] for expr in y]
    try:
        y = vect.inverse_transform(y)
    except Exception:
        # happens because the `generate` function does not take into
        # account the forbidden rules by the grammar. So the exception
        # occurs because of a syntax error.
        continue
    print('Generated:')
    for expr in y:
        print(expr)

Total running time of the script: ( 0 minutes 0.000 seconds)

Gallery generated by Sphinx-Gallery