import matchzoo as mz
print(mz.__version__)

"""
Explanation: <img src="../artworks/matchzoo-logo.png" alt="logo" style="width:600px;float: center"/>
MatchZoo Quick Start
End of explanation
"""


task = mz.tasks.Ranking()
print(task)

"""
Explanation: Define Task
There are two types of tasks available in MatchZoo. mz.tasks.Ranking and mz.tasks.Classification. We will use a ranking task for this demo.
End of explanation
"""


train_raw = mz.datasets.toy.load_data(stage='train', task=task)
test_raw = mz.datasets.toy.load_data(stage='test', task=task)

type(train_raw)

"""
Explanation: Prepare Data
End of explanation
"""


train_raw.left.head()

train_raw.right.head()

train_raw.relation.head()

"""
Explanation: DataPack is a MatchZoo native data structure that most MatchZoo data handling processes build upon. A DataPack is consists of three pandas.DataFrame:
End of explanation
"""


train_raw.frame().head()

"""
Explanation: It is also possible to convert a DataPack into a single pandas.DataFrame that holds all information.
End of explanation
"""


preprocessor = mz.preprocessors.BasicPreprocessor()

"""
Explanation: However, using such pandas.DataFrame consumes much more memory if there are many duplicates in the texts, and that is the exact reason why we use DataPack. For more details about data handling, consult matchzoo/tutorials/data_handling.ipynb.
Preprocessing
MatchZoo preprocessors are used to convert a raw DataPack into a DataPack that ready to be fed into a model.
End of explanation
"""


preprocessor.fit(train_raw)

"""
Explanation: There are two steps to use a preprocessor. First, fit. Then, transform. fit will only changes the preprocessor's inner state but not the input DataPack.
End of explanation
"""


preprocessor.context

"""
Explanation: fit will gather useful information into its context, which will be used later in a transform or used to set hyper-parameters of a model.
End of explanation
"""


train_processed = preprocessor.transform(train_raw)
test_processed = preprocessor.transform(test_raw)

train_processed.left.head()

"""
Explanation: Once fit, the preprocessor has enough information to transform.  transform will not change the preprocessor's inner state and the input DataPack, but return a transformed DataPack.
End of explanation
"""


vocab_unit = preprocessor.context['vocab_unit']
print('Orig Text:', train_processed.left.loc['Q1']['text_left'])
sequence = train_processed.left.loc['Q1']['text_left']
print('Transformed Indices:', sequence)
print('Transformed Indices Meaning:',
      '_'.join([vocab_unit.state['index_term'][i] for i in sequence]))

"""
Explanation: As we can see, text_left is already in sequence form that nerual networks love.
Just to make sure we have the correct sequence:
End of explanation
"""


mz.models.list_available()

"""
Explanation: For more details about preprocessing, consult matchzoo/tutorials/data_handling.ipynb.
Build Model
MatchZoo provides many built-in text matching models.
End of explanation
"""


model = mz.models.DenseBaseline()

"""
Explanation: Let's use mz.models.DenseBaseline for our demo.
End of explanation
"""


print(model.params)

"""
Explanation: The model is initialized with a hyper parameter table, in which values are partially filled. To view parameters and their values, use print.
End of explanation
"""


model.params.to_frame()[['Name', 'Description', 'Value']]

"""
Explanation: to_frame gives you more informartion in addition to just names and values.
End of explanation
"""


model.params['task'] = task
model.params['mlp_num_units'] = 3
print(model.params)

"""
Explanation: To set a hyper-parameter:
End of explanation
"""


print(preprocessor.context['input_shapes'])

"""
Explanation: Notice that we are still missing input_shapes, and that information is store in the preprocessor.
End of explanation
"""


model.params.update(preprocessor.context)

"""
Explanation: We may use update to load a preprocessor's context into a model's hyper-parameter table.
End of explanation
"""


model.params.completed()

"""
Explanation: Now we have a completed hyper-parameter table.
End of explanation
"""


model.build()
model.compile()

"""
Explanation: With all parameters filled in, we can now build and compile the model.
End of explanation
"""


model.backend.summary()

"""
Explanation: MatchZoo models are wrapped over keras models, and the backend property of a model gives you the actual keras model built.
End of explanation
"""


x, y = train_processed.unpack()
test_x, test_y = test_processed.unpack()

model.fit(x, y, batch_size=32, epochs=5)

"""
Explanation: For more details about models, consult matchzoo/tutorials/models.ipynb.
Train, Evaluate, Predict
A DataPack can unpack itself into data that can be directly used to train a MatchZoo model.
End of explanation
"""


data_generator = mz.DataGenerator(train_processed, batch_size=32)

model.fit_generator(data_generator, epochs=5, use_multiprocessing=True, workers=4)

model.evaluate(test_x, test_y)

model.predict(test_x)

"""
Explanation: An alternative to train a model is to use a DataGenerator. This is useful for delaying expensive preprocessing steps or doing real-time data augmentation. For some models that needs dynamic batch-wise information, using a DataGenerator is required. For more details about DataGenerator, consult matchzoo/tutorials/data_handling.ipynb.
End of explanation
"""


for model_class in mz.models.list_available():
    print(model_class)
    model, preprocessor, data_generator_builder, embedding_matrix = mz.auto.prepare(
        task=task,
        model_class=model_class,
        data_pack=train_raw,
    )
    train_processed = preprocessor.transform(train_raw, verbose=0)
    test_processed = preprocessor.transform(test_raw, verbose=0)
    train_gen = data_generator_builder.build(train_processed)
    test_gen = data_generator_builder.build(test_processed)
    model.fit_generator(train_gen, epochs=1)
    model.evaluate_generator(test_gen)
    print()

"""
Explanation: A Shortcut to Preprocessing and Model Building
Since data preprocessing and model building are laborious and special setups of some models makes this even worse, MatchZoo provides prepare, a unified interface that handles interaction among data, model, and preprocessor automatically.
More specifically, prepare does these following things:
 - create a default preprocessor of the model class (if not given one)
 - fit the preprocessor using the raw data
 - create an embedding matrix
 - instantiate a model and fill in hype-parameters
 - build the model
 - instantiate a DataGeneratorBuilder that will build a correctly formed DataGenerator given a DataPack
It also does many special handling for specific models, but we will not go into the details of that here.
End of explanation
"""


model.save('my-model')
loaded_model = mz.load_model('my-model')

"""
Explanation: Save and Load the Model
End of explanation
"""


