# Path: keras_image_captioning/config.py
# def active_config(new_active_config=None):
#     if new_active_config:
#         global _active_config
#         _active_config = new_active_config
#     return _active_config
# 
# Path: keras_image_captioning/losses.py
# def categorical_crossentropy_from_logits(y_true, y_pred):
#     # Discarding is still needed although CaptionPreprocessor.preprocess_batch
#     # has added dummy words as all-zeros arrays because the sum of losses is
#     # the same but the mean of losses is different.
#     y_true = y_true[:, :-1, :]  # Discard the last timestep/word (dummy)
#     y_pred = y_pred[:, :-1, :]  # Discard the last timestep/word (dummy)
# 
#     loss = tf.nn.softmax_cross_entropy_with_logits(labels=y_true,
#                                                    logits=y_pred)
#     return loss
# 
# Path: keras_image_captioning/metrics.py
# def categorical_accuracy_with_variable_timestep(y_true, y_pred):
#     # Actually discarding is not needed if the dummy is an all-zeros array
#     # (It is indeed encoded in an all-zeros array by
#     # CaptionPreprocessing.preprocess_batch)
#     y_true = y_true[:, :-1, :]  # Discard the last timestep/word (dummy)
#     y_pred = y_pred[:, :-1, :]  # Discard the last timestep/word (dummy)
# 
#     # Flatten the timestep dimension
#     shape = tf.shape(y_true)
#     y_true = tf.reshape(y_true, [-1, shape[-1]])
#     y_pred = tf.reshape(y_pred, [-1, shape[-1]])
# 
#     # Discard rows that are all zeros as they represent dummy or padding words.
#     is_zero_y_true = tf.equal(y_true, 0)
#     is_zero_row_y_true = tf.reduce_all(is_zero_y_true, axis=-1)
#     y_true = tf.boolean_mask(y_true, ~is_zero_row_y_true)
#     y_pred = tf.boolean_mask(y_pred, ~is_zero_row_y_true)
# 
#     accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(y_true, axis=1),
#                                                tf.argmax(y_pred, axis=1)),
#                                       dtype=tf.float32))
#     return accuracy
# 
# Path: keras_image_captioning/word_vectors.py
# def get_word_vector_class(name):
#     if name == 'glove':
#         return Glove
#     elif name == 'fasttext':
#         return Fasttext
#     else:
#         raise ValueError('Word vector = {} is not found!'.format(name))


from keras.applications.inception_v3 import InceptionV3
from keras.initializers import RandomUniform
from keras.models import Model
from keras.layers import (Dense, Embedding, GRU, Input, LSTM, RepeatVector,
                          TimeDistributed)
from keras.layers.merge import Concatenate
from keras.layers.normalization import BatchNormalization
from keras.layers.wrappers import Bidirectional
from keras.optimizers import Adam
from keras.regularizers import l1_l2
from .config import active_config
from .losses import categorical_crossentropy_from_logits
from .metrics import categorical_accuracy_with_variable_timestep
from .word_vectors import get_word_vector_class



class ImageCaptioningModel(object):
    """A very configurable model to produce captions from images."""

    def __init__(self,
                 learning_rate=None,
                 vocab_size=None,
                 embedding_size=None,
                 rnn_output_size=None,
                 dropout_rate=None,
                 bidirectional_rnn=None,
                 rnn_type=None,
                 rnn_layers=None,
                 l1_reg=None,
                 l2_reg=None,
                 initializer=None,
                 word_vector_init=None):
        """
        If an arg is None, it will get its value from config.active_config.
        """
        self._learning_rate = learning_rate or active_config().learning_rate
        self._vocab_size = vocab_size or active_config().vocab_size
        self._embedding_size = embedding_size or active_config().embedding_size
        self._rnn_output_size = (rnn_output_size or
                                 active_config().rnn_output_size)
        self._dropout_rate = dropout_rate or active_config().dropout_rate
        self._rnn_type = rnn_type or active_config().rnn_type

# Path: keras_image_captioning/config.py
# def active_config(new_active_config=None):
#     if new_active_config:
#         global _active_config
#         _active_config = new_active_config
#     return _active_config
# 
# Path: keras_image_captioning/losses.py
# def categorical_crossentropy_from_logits(y_true, y_pred):
#     # Discarding is still needed although CaptionPreprocessor.preprocess_batch
#     # has added dummy words as all-zeros arrays because the sum of losses is
#     # the same but the mean of losses is different.
#     y_true = y_true[:, :-1, :]  # Discard the last timestep/word (dummy)
#     y_pred = y_pred[:, :-1, :]  # Discard the last timestep/word (dummy)
# 
#     loss = tf.nn.softmax_cross_entropy_with_logits(labels=y_true,
#                                                    logits=y_pred)
#     return loss
# 
# Path: keras_image_captioning/metrics.py
# def categorical_accuracy_with_variable_timestep(y_true, y_pred):
#     # Actually discarding is not needed if the dummy is an all-zeros array
#     # (It is indeed encoded in an all-zeros array by
#     # CaptionPreprocessing.preprocess_batch)
#     y_true = y_true[:, :-1, :]  # Discard the last timestep/word (dummy)
#     y_pred = y_pred[:, :-1, :]  # Discard the last timestep/word (dummy)
# 
#     # Flatten the timestep dimension
#     shape = tf.shape(y_true)
#     y_true = tf.reshape(y_true, [-1, shape[-1]])
#     y_pred = tf.reshape(y_pred, [-1, shape[-1]])
# 
#     # Discard rows that are all zeros as they represent dummy or padding words.
#     is_zero_y_true = tf.equal(y_true, 0)
#     is_zero_row_y_true = tf.reduce_all(is_zero_y_true, axis=-1)
#     y_true = tf.boolean_mask(y_true, ~is_zero_row_y_true)
#     y_pred = tf.boolean_mask(y_pred, ~is_zero_row_y_true)
# 
#     accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(y_true, axis=1),
#                                                tf.argmax(y_pred, axis=1)),
#                                       dtype=tf.float32))
#     return accuracy
# 
# Path: keras_image_captioning/word_vectors.py
# def get_word_vector_class(name):
#     if name == 'glove':
#         return Glove
#     elif name == 'fasttext':
#         return Fasttext
#     else:
#         raise ValueError('Word vector = {} is not found!'.format(name))


# Path: keras_image_captioning/models.py
from keras.applications.inception_v3 import InceptionV3
from keras.initializers import RandomUniform
from keras.models import Model
from keras.layers import (Dense, Embedding, GRU, Input, LSTM, RepeatVector,
                          TimeDistributed)
from keras.layers.merge import Concatenate
from keras.layers.normalization import BatchNormalization
from keras.layers.wrappers import Bidirectional
from keras.optimizers import Adam
from keras.regularizers import l1_l2
from .config import active_config
from .losses import categorical_crossentropy_from_logits
from .metrics import categorical_accuracy_with_variable_timestep
from .word_vectors import get_word_vector_class




class ImageCaptioningModel(object):
    """A very configurable model to produce captions from images."""

    def __init__(self,
                 learning_rate=None,
                 vocab_size=None,
                 embedding_size=None,
                 rnn_output_size=None,
                 dropout_rate=None,
                 bidirectional_rnn=None,
                 rnn_type=None,
                 rnn_layers=None,
                 l1_reg=None,
                 l2_reg=None,
                 initializer=None,
                 word_vector_init=None):
        """
        If an arg is None, it will get its value from config.active_config.
        """
        self._learning_rate = learning_rate or active_config().learning_rate
        self._vocab_size = vocab_size or active_config().vocab_size
        self._embedding_size = embedding_size or active_config().embedding_size
        self._rnn_output_size = (rnn_output_size or
                                 active_config().rnn_output_size)
        self._dropout_rate = dropout_rate or active_config().dropout_rate
        self._rnn_type = rnn_type or active_config().rnn_type

        self._rnn_layers = rnn_layers or active_config().rnn_layers