# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['tf_al', 'tf_al.utils', 'tf_al.wrapper']

package_data = \
{'': ['*']}

install_requires = \
['numpy>=1,<2',
 'scikit-learn>=0.24.2,<0.25.0',
 'tensorflow>=2,<3',
 'tqdm>=4.62.2,<5.0.0']

setup_kwargs = {
    'name': 'tf-al',
    'version': '0.0.4',
    'description': 'Active learning with tensorflow. Create custom and generic active learning loops. Export and share your experiments.',
    'long_description': '\n\n[![PyPI version](https://badge.fury.io/py/tf-al.svg)](https://badge.fury.io/py/tf-al)\n[![PyPi license](https://badgen.net/pypi/license/tf-al/)](https://pypi.org/project/tf-al/)\n![Python Version: ^3.6](https://img.shields.io/badge/python-%5E3.6-blue)\n\n\n# Active learning with tensorflow\n\n<sup>*Currently only supports classification tasks.</sup>\n\nPerform active learning in tensorflow with extendable parts.  \n\n\n\n\n# Index\n\n1. [Installation](#Installation)\n2. [Documentation](https://exleonem.github.io/tf-al/)\n3. [Getting started](#Getting-started)\n    1. [Model wrapper](#Model-wrapper)\n    2. [Acquisition functions](#Acquisition-functions)\n    1. [Basic active learning loop](#Basic-active-learning-loop)\n4. [Development](#Development)\n    1. [Setup](#Setup)\n    2. [Scripts](#Scripts)\n5. [Contribution](#Contribution)\n6. [Issues](#Issues)\n\n\n\n# Dependencies\n\n```toml\npython="^3.6"\ntensorflow="^2.0.0"\nscikit-learn="^0.24.2"\nnumpy="^1.0.0"\ntqdm="^4.62.6"\n```\n\n# Installation\n\n\n```shell\n$ pip install tf-al\n```\n\n<sup>*To use a specific version of tensorflow or if you want gpu support you should manually install tensorflow. Else this package automatically will install the lastest version of tensorflow described in the [dependencies](#Dependencies).</sup>\n\n# Getting started\n\n\nFollowing the active learning paradigm the most essential parts are the model and the pool of labeled/unlabeled data.\n\n\nTo enable modularity tensorflow models are wrapped. The model wrapper acts as an interface between the active learning loop and the model.\nIn essence the model wrapper defines methods which are called at different steps in the active learning loop.\nTo manage the labeled and unlabeled datapoints the pool class can be used. Which offers methods to label and select datapoints, labels and indices.\n\n\nOther parts provided by the library easy the setup of active learning loops. The active learning loop class uses a dataset and model to creat an iterator, which then can be used to perform active learning over a single experiment.(model and query strategy combination)\n\nThe experiment suit can be used to perform a couple of experiments in a row, which is useful if for example you want to compare differnt acquisition functions.\n\n\n## Model wrapper\n\nModel wrappers are used to create an interface between the tensorflow model and the active learning loop.\nCurrently there are two wrappers defined. `Model` and `McDropout` for bayesian active learning. \nThe `Model` wrapper can be used to create custom model wrappers.\n\n\nHere is an example of how to create and wrap a basic McDropout model.\n\n```python\nfrom tensorflow.keras import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Dense, Input, Flatten\nfrom tf_al.wrapper import McDropout\n\n# Define and wrap model (here McDropout)\nbase_model = Sequential([\n    Conv2D(32, 3, activation=tf.nn.relu, padding="same", input_shape=input_shape),\n    Conv2D(64, 3, activation=tf.nn.relu, padding="same"),\n    MaxPooling2D(),\n    Dropout(.25),\n    Flatten(),\n    Dense(128, activation=tf.nn.relu),\n    Dropout(.5),\n    Dense(output, activation="softmax")        \n])\n\n# Wrap, configure and compile\nmodel_config = Config(\n    fit={"epochs": 200, "batch_size": 10},\n    query={"sample_size" 25},\n    eval={"batch_size": 900, "sample_size": 25}\n)\nmodel = McDropout(base_model, config=model_config)\nmodel.compile(\n    optimizer="adam", \n    loss="sparse_categorical_crossentropy", \n    metrics=[keras.metrics.SparseCategoricalAccuracy()]\n)\n```\n\n\n### Basic methods\n\n\nThe model wrapper in essence can be used like a regular tensorflow model.\n\n```python\nmodel = McDropout(base_model)\nmodel.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=[keras.metrics.SparseCategoricalAccuracy()])\n\n\n# Fitting the model\nmodel.fit(inputs, targets, batch_size=25, epochs=100)\n\n# Evaluating\nmodel.evaluate(some_inputs, some_targets)\n\n# Predicting\nmodel(inputs, **additional_params)\n```\n\nTo define a custom  custom model wrapper, simply extend your own class using the `Model` class and \noverwrite functions as needed. The regular tensorflow model can be accessed via `self._model`.\n\nTo provide your model wrappers as a package you can simply use the [template on github](https://github.com/ExLeonem/tf-al-ext), which already offers a poetry package setup.\n\n\n\n```python\nfrom tf_al import Model\n\n\nclass CustomModel(Model):\n\n    def __init__(self, model, **kwargs):\n        super().__init__(model, **kwargs)\n\n\n    def __call__(self, *args, **kwargs):\n        # Custom __call__ or standard tensorflow __call__\n\n\n    def predict(self, inputs, **kwargs):\n        # Custom prediction method or the standard tensorflow call model(inputs)\n        \n\n    def evaluate(self, inputs, targets, **kwargs):\n        # Defining custom evaluate method\n        # else standard evaluate method of tensorflow used.\n        return {"metric_1": some_value, "metrics_2": some_other_value}\n\n\n    def fit(self, *args, **kwargs):\n        # Custom fitting procedure, else tensorflow .fit() method is used. \n        \n\n    def compile(self, *args, **kwargs):\n        # Custom compile method else using tensorflow .compile(**kwargs)\n        \n\n    def reset(self, pool, dataset):\n        # In Which way to reset the network after each active learning round\n        # standard is re-loading weights when enabled\n```\n\n\n## Acquisition functions\n\n\n\n## Basic active learning loop\n\n\n```python\n\nimport tensorflow.keras as keras\nfrom tensorflow.keras import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Dense, Input, Flatten\n\nfrom tf_al import ActiveLearningLoop, Dataset\nfrom tf_al.wrapper import McDropout\n\n# Load dataset and pack into dataset\n(x_train, y_train), test_set = keras.datasets.mnist.load()\ninital_pool_size = 20\ndataset = Dataset(x_train, y_train, test=test_set, init_size=initial_pool_size)\n\n# Create and wrap model\nbase_model = Sequential([\n    Conv2D(32, 3, activation=tf.nn.relu, padding="same", input_shape=input_shape),\n    Conv2D(64, 3, activation=tf.nn.relu, padding="same"),\n    MaxPooling2D(),\n    Dropout(.25),\n    Flatten(),\n    Dense(128, activation=tf.nn.relu),\n    Dropout(.5),\n    Dense(output, activation="softmax")        \n])\n\nmc_model = McDropout(base_model)\nmc_model.compile(\n    optimizer="adam", \n    loss="sparse_categorical_crossentropy", \n    metrics=[keras.metrics.SparseCategoricalAccuracy()]\n)\n\n# Create and start experiment suit (Collection of different experiments model + query_strategy)\nquery_strategy = "random"\nactive_learning_loop = ActiveLearningLoop(\n    mc_model,\n    dataset,\n    query_strategy,\n    step_size=10, # Number of new datapoints to select after each round\n    max_rounds=100 # How many active learning rounds per experiment?\n)\n\n# To completely run through the active learning loop\nactive_learning_loop.run()\n\n# Manually iterate over active learning loop\nfor step in active_learning_loop:\n\n    # Dict with accumulated metrics \n    # ["train", "train_time", "query_time", "optim", "optim_time", "eval", "eval_time", "indices_selected"]\n    step["train"]\n\n\n# Alternativly iterate step inside the loop\nnum_rounds = 10\nfor i in range(num_rounds):\n\n    metrics = active_learning_loop.step()\n    # ... do something with the metrics\n```\n\n## Basic experiment suit setup\n\n```python\nimport tensorflow as tf\nfrom tensorflow.keras import Model, Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Dense, Input, Flatten\n\nfrom tf_al import ActiveLearningLoop, Dataset, Config, ExperimentSuit, AcquisitionFunction\nfrom tf_al.wrapper import McModel\n\n# Split data and put into a dataset\nx_train, x_test, y_train, y_test = train_test_split(some_inputs, some_targets, test_size=test_set_size)\n\n# Number of initial datapoints in pool of labeled data\ninitial_pool_size = 20 \ndataset = Dataset(\n    x_train, y_train,\n    test=(x_test, y_test),\n    init_size=initial_pool_size\n)\n\n# Define and wrap model (here McDropout)\nbase_model = Sequential([\n    Conv2D(32, 3, activation=tf.nn.relu, padding="same", input_shape=input_shape),\n    Conv2D(64, 3, activation=tf.nn.relu, padding="same"),\n    MaxPooling2D(),\n    Dropout(.25),\n    Flatten(),\n    Dense(128, activation=tf.nn.relu),\n    Dropout(.5),\n    Dense(output, activation="softmax")        \n])\n\nmodel_config = Config(\n    fit={"epochs": 200, "batch_size": 10}, # Passed to fit() of the wrapper\n    query={"sample_size" 25}, # Configuration passed to acquisition function during query step\n    eval={"batch_size": 900, "sample_size": 25} # Parameters passed to evaluation method of the wrapper\n)\nmodel = McDropout(base_model, config=model_config)\nmodel.compile(\n    optimizer="adam", \n    loss="sparse_categorical_crossentropy", \n    metrics=[keras.metrics.SparseCategoricalAccuracy()]\n)\n\n# Over which model to perform experiments single or list [model_1, ..., model_n]\nmodels = model\n\n# Define which acquisition functions to apply in separate runs either single one or a list [acquisition_1, ...] \nacquisition_functions = ["random", AcqusitionFunction("max_entropy", batch_size=900)]\nexperiments = ExperimentSuit(\n    models,\n    acquisition_functions,\n    step_size=10, # Number of new datapoints to select after each round\n    max_rounds=100 # How many active learning rounds per experiment?\n)\n\n```\n\n# Development\n\n\n## Setup\n\n1. Fork and clone the forked repository\n2. Create a virtual env (optional)\n3. [Install and Setup Poetry](https://python-poetry.org/docs/#installation)\n4. Install package dependencies [using poetry](https://python-poetry.org/docs/cli/#install) or set them up manually\n5. Start development\n\n\n## Scripts\n\n### Create documentation\n\nTo create documentation for the `./tf_al` directory. Execute following command\nin `./docs`\n\n```shell\n$ make html\n```\n\nTo clear the generated documentation use following command.\n\n```shell\n$ make clean\n```\n\n\n### Run tests\n\nTo perform automated unittests run following command in the root package directory.\n\n```shell\n$ pytest\n```\n\nTo generate additional coverage reports run.\n\n```shell\n$ pytest --cov\n```\n\n\n# Contribution\n\n\n# Issues',
    'author': 'Maksim Sandybekov',
    'author_email': 'maksim.sandybekov@live.de',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/ExLeonem/tf-al',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.6,<4.0',
}


setup(**setup_kwargs)
