import numpy as np
import tensorflow as tf

from .sac import SAC, td_target
from .sac_classifier_multigoal import SACClassifierMultiGoal
from softlearning.misc.utils import mixup
from softlearning.models.utils import flatten_input_structure

class VICEGANMultiGoal(SACClassifierMultiGoal):
    def _epoch_after_hook(self, *args, **kwargs):
        for i in range(self._n_classifier_train_steps):
            feed_dicts = self._get_classifier_feed_dicts()
            self._train_classifier_step(feed_dicts)

class VICEMultiGoal(SACClassifierMultiGoal):
    # TODO: Implement VICE multi-goal
    pass

class VICEGANTwoGoal(SAC):
    def __init__(
            self,
            classifier_0,
            classifier_1,
            goal_examples_0,
            goal_examples_1,
            goal_examples_validation_0,
            goal_examples_validation_1,
            classifier_lr=1e-4,
            classifier_batch_size=128,
            reward_type = 'logits',
            n_classifier_train_steps=5,
            classifier_optim_name='adam',
            mixup_alpha=0.2,
            **kwargs,
    ):
        # TODO: Pass in a list of classifiers, a list of goal examples/validations instead.
        self._classifier_0 = classifier_0
        self._goal_examples_0 = goal_examples_0
        self._goal_examples_validation_0 = goal_examples_validation_0
        self._classifier_1 = classifier_1
        self._goal_examples_1 = goal_examples_1
        self._goal_examples_validation_1 = goal_examples_validation_1

        self._classifier_lr = classifier_lr
        self._reward_type = reward_type
        self._n_classifier_train_steps = n_classifier_train_steps
        self._classifier_optim_name = classifier_optim_name
        self._classifier_batch_size = classifier_batch_size
        self._mixup_alpha = mixup_alpha

        super(VICEGANTwoGoal, self).__init__(**kwargs)

    def _build(self):
        super(VICEGANTwoGoal, self)._build()
        self._init_classifier_update()

    def _init_placeholders(self):
        super(VICEGANTwoGoal, self)._init_placeholders()
        self._placeholders['labels'] = tf.placeholder(
            tf.float32,
            shape=(None, 1),
            name='labels',
        )

    def _get_classifier_training_ops(self):
        if self._classifier_optim_name == 'adam':
            opt_func = tf.train.AdamOptimizer
        elif self._classifier_optim_name == 'sgd':
            opt_func = tf.train.GradientDescentOptimizer
        else:
            raise NotImplementedError

        self._classifier_optimizer_0 = opt_func(
            learning_rate=self._classifier_lr,
            name='classifier_optimizer_0')
        self._classifier_optimizer_1 = opt_func(
            learning_rate=self._classifier_lr,
            name='classifier_optimizer_1')

        classifier_training_ops = [
            tf.contrib.layers.optimize_loss(
                self._classifier_loss_t_0,
                self.global_step,
                learning_rate=self._classifier_lr,
                optimizer=self._classifier_optimizer_0,
                variables=self._classifier_0.trainable_variables,
                increment_global_step=False,
            ),
            tf.contrib.layers.optimize_loss(
                self._classifier_loss_t_1,
                self.global_step,
                learning_rate=self._classifier_lr,
                optimizer=self._classifier_optimizer_1,
                variables=self._classifier_1.trainable_variables,
                increment_global_step=False,
            ),
       ]

        return classifier_training_ops

    def _init_classifier_update(self):
        classifier_inputs = flatten_input_structure({
            name: self._placeholders['observations'][name]
            for name in self._classifier_0.observation_keys
        })
        logits_0 = self._classifier_0(classifier_inputs)
        logits_1 = self._classifier_1(classifier_inputs)
        self._classifier_loss_t_0 = tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(
                logits=logits_0, labels=self._placeholders['labels']))
        self._classifier_loss_t_1 = tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(
                logits=logits_1, labels=self._placeholders['labels']))
        self._classifier_training_ops = self._get_classifier_training_ops()

    def _get_classifier_feed_dicts(self):
        # Get 2x the number of negatives, filter out by goal index
        negatives = self.sampler.random_batch(
            2 * self._classifier_batch_size)['observations']

        negative_ind_0 = (negatives['goal_index'] == 0).flatten()
        negative_ind_1 = (negatives['goal_index'] == 1).flatten()
        n_negatives_0, n_negatives_1 = (
            np.sum(negative_ind_0.astype(int)), np.sum(negative_ind_1.astype(int)))
        negatives_0 = {
            key: values[negative_ind_0]
            for key, values in negatives.items()
        }
        negatives_1 = {
            key: values[negative_ind_1]
            for key, values in negatives.items()
        }

        # Get positives from different goal pools
        rand_positive_ind_0 = np.random.randint(
            self._goal_examples_0[next(iter(self._goal_examples_0))].shape[0],
            size=self._classifier_batch_size)
        positives_0 = {
            key: values[rand_positive_ind_0]
            for key, values in self._goal_examples_0.items()
        }

        rand_positive_ind_1 = np.random.randint(
            self._goal_examples_1[next(iter(self._goal_examples_1))].shape[0],
            size=self._classifier_batch_size)
        positives_1 = {
            key: values[rand_positive_ind_1]
            for key, values in self._goal_examples_1.items()
        }

        # labels_batch_0 = np.zeros((2 * self._classifier_batch_size, 1))
        # labels_batch[self._classifier_batch_size:] = 1.0
        # labels_batch_0 = labels_batch.copy()
        # labels_batch_1 = labels_batch.copy()

        labels_batch_0 = np.zeros((n_negatives_0 + self._classifier_batch_size, 1))
        labels_batch_0[n_negatives_0:] = 1.0
        labels_batch_1 = np.zeros((n_negatives_1 + self._classifier_batch_size, 1))
        labels_batch_1[n_negatives_1:] = 1.0

        observations_batch_0 = {
            key: np.concatenate((negatives_0[key], positives_0[key]), axis=0)
            for key in self._classifier_0.observation_keys
        }
        observations_batch_1 = {
            key: np.concatenate((negatives_1[key], positives_1[key]), axis=0)
            for key in self._classifier_1.observation_keys
        }

        if self._mixup_alpha > 0:
            observation_batch_0, labels_batch_0 = mixup(
                observations_batch_0, labels_batch_0, alpha=self._mixup_alpha)
            observation_batch_1, labels_batch_1 = mixup(
                observations_batch_1, labels_batch_1, alpha=self._mixup_alpha)

        feed_dict_0 = {
            **{
                self._placeholders['observations'][key]:
                observations_batch_0[key]
                for key in self._classifier_0.observation_keys
            },
            self._placeholders['labels']: labels_batch_0
        }

        feed_dict_1 = {
            **{
                self._placeholders['observations'][key]:
                observations_batch_1[key]
                for key in self._classifier_1.observation_keys
            },
            self._placeholders['labels']: labels_batch_1
        }

        return feed_dict_0, feed_dict_1

    def _get_Q_target(self):
        policy_inputs = flatten_input_structure({
            name: self._placeholders['next_observations'][name]
            for name in self._policy.observation_keys
        })
        next_actions = self._policy.actions(policy_inputs)
        next_log_pis = self._policy.log_pis(policy_inputs, next_actions)

        next_Q_observations = {
            name: self._placeholders['next_observations'][name]
            for name in self._Qs[0].observation_keys
        }
        next_Q_inputs = flatten_input_structure(
            {**next_Q_observations, 'actions': next_actions})
        next_Qs_values = tuple(Q(next_Q_inputs) for Q in self._Q_targets)

        min_next_Q = tf.reduce_min(next_Qs_values, axis=0)
        next_values = min_next_Q - self._alpha * next_log_pis

        # TODO: pass through both, and filter by goal_index
        classifier_0_inputs = flatten_input_structure({
            name: self._placeholders['observations'][name]
            for name in self._classifier_0.observation_keys
        })
        classifier_1_inputs = flatten_input_structure({
            name: self._placeholders['observations'][name]
            for name in self._classifier_1.observation_keys
        })

        observation_logits_0 = self._classifier_0(classifier_0_inputs)
        observation_logits_1 = self._classifier_1(classifier_1_inputs)

        # TODO: Merge the two outputs, based on the info/obs/current_goal
        goal_index_mask = self._placeholders['observations']['goal_index']
        # Use above to merge the two.

        # Use observation_logits_1 where goal is 1, observation_logits_0 where goal is 0
        observation_logits = tf.where(
            tf.cast(goal_index_mask, dtype=tf.bool),
            x=observation_logits_1,
            y=observation_logits_0)

        self._reward_t = observation_logits

        terminals = tf.cast(self._placeholders['terminals'], next_values.dtype)

        Q_target = td_target(
            reward=self._reward_scale * self._reward_t,
            discount=self._discount,
            next_value=(1 - terminals) * next_values)

        return Q_target

    def _epoch_after_hook(self, *args, **kwargs):
        for i in range(self._n_classifier_train_steps):
            feed_dicts = self._get_classifier_feed_dicts()
            self._train_classifier_step(feed_dicts)

    def _train_classifier_step(self, feed_dicts):
        feed_dict_0, feed_dict_1 = feed_dicts
        classifier_training_op_0, classifier_training_op_1 = self._classifier_training_ops
        _, loss_0 = self._session.run((
                classifier_training_op_0, self._classifier_loss_t_0
            ), feed_dict_0)
        _, loss_1 = self._session.run((
                classifier_training_op_1, self._classifier_loss_t_1
            ), feed_dict_1)
        return (loss_0, loss_1)

    def get_diagnostics(self,
                        iteration,
                        batch,
                        training_paths,
                        evaluation_paths):
        diagnostics = super(VICEGANTwoGoal, self).get_diagnostics(
            iteration, batch, training_paths, evaluation_paths)

        sample_observations = batch['observations']
        goal_index_0 = np.random.randint(
            self._goal_examples_0[next(iter(self._goal_examples_0))].shape[0],
            size=sample_observations[next(iter(sample_observations))].shape[0])
        goal_observations_0 = {
            key: self._goal_examples_0[key][goal_index_0]
            for key in self._goal_examples_0.keys()
        }
        goal_index_1 = np.random.randint(
            self._goal_examples_1[next(iter(self._goal_examples_1))].shape[0],
            size=sample_observations[next(iter(sample_observations))].shape[0])
        goal_observations_1 = {
            key: self._goal_examples_1[key][goal_index_1]
            for key in self._goal_examples_1.keys()
        }

        goal_index_validation_0 = np.random.randint(
            self._goal_examples_validation_0[
                next(iter(self._goal_examples_0))].shape[0],
            size=sample_observations[next(iter(sample_observations))].shape[0])
        #goal_observations_validation_0 = (
        #    self._goal_examples_validation_0[goal_index_validation_0])
        goal_observations_validation_0 = {
            key: self._goal_examples_validation_0[key][goal_index_validation_0]
            for key in self._goal_examples_validation_0.keys()
        }

        goal_index_validation_1 = np.random.randint(
            self._goal_examples_validation_1[
                next(iter(self._goal_examples_1))].shape[0],
            size=sample_observations[next(iter(sample_observations))].shape[0])
        # goal_observations_validation_1 = (
        #     self._goal_examples_validation_1[goal_index_validation_1])
        goal_observations_validation_1 = {
            key: self._goal_examples_validation_1[key][goal_index_validation_1]
            for key in self._goal_examples_validation_1.keys()
        }

        reward_sample_goal_observations_0, classifier_loss_0 = self._session.run(
            (self._reward_t, self._classifier_loss_t_0),
            feed_dict={
                **{
                    self._placeholders['observations'][key]: np.concatenate((
                        sample_observations[key],
                        goal_observations_0[key],
                        goal_observations_validation_0[key]
                    ), axis=0)
                    for key in self._classifier_0.observation_keys
                },
                self._placeholders['labels']: np.concatenate([
                    np.zeros((sample_observations[next(iter(sample_observations))].shape[0], 1)),
                    np.ones((goal_observations_0[next(iter(goal_observations_0))].shape[0], 1)),
                    np.ones((goal_observations_validation_0[next(iter(goal_observations_validation_0))].shape[0], 1)),
                ])
            }
        )

        reward_sample_goal_observations_1, classifier_loss_1 = self._session.run(
            (self._reward_t, self._classifier_loss_t_1),
            feed_dict={
                **{
                    self._placeholders['observations'][key]: np.concatenate((
                        sample_observations[key],
                        goal_observations_1[key],
                        goal_observations_validation_1[key]
                    ), axis=0)
                    for key in self._classifier_0.observation_keys
                },
                self._placeholders['labels']: np.concatenate([
                    np.zeros((sample_observations[next(iter(sample_observations))].shape[0], 1)),
                    np.ones((goal_observations_1[next(iter(goal_observations_1))].shape[0], 1)),
                    np.ones((goal_observations_validation_1[next(iter(goal_observations_validation_1))].shape[0], 1)),
                ])
            }
        )

        # TODO: Make this clearer. Maybe just make all the vectors
        # the same size and specify number of splits
        (reward_sample_observations_0,
         reward_goal_observations_0,
         reward_goal_observations_validation_0) = np.split(
             reward_sample_goal_observations_0,
             (
                 sample_observations[next(iter(sample_observations))].shape[0],
                 sample_observations[next(iter(sample_observations))].shape[0] + goal_observations_0[next(iter(goal_observations_0))].shape[0]
             ),
             axis=0)

        (reward_sample_observations_1,
         reward_goal_observations_1,
         reward_goal_observations_validation_1) = np.split(
             reward_sample_goal_observations_1,
             (
                 sample_observations[next(iter(sample_observations))].shape[0],
                 sample_observations[next(iter(sample_observations))].shape[0] + goal_observations_1[next(iter(goal_observations_1))].shape[0]
             ),
             axis=0)

        # TODO: fix this so that classifier loss is split into train and val
        # currently the classifier loss printed is the mean
        # classifier_loss_train, classifier_loss_validation = np.split(
        #     classifier_loss,
        #     (sample_observations.shape[0]+goal_observations.shape[0],),
        #     axis=0)

        diagnostics.update({
            # 'reward_learning/classifier_loss_train':
            # np.mean(classifier_loss_train),
            # 'reward_learning/classifier_loss_validation':
            # np.mean(classifier_loss_validation),
            'reward_learning/classifier_loss_0': classifier_loss_0,
            'reward_learning/classifier_loss_1': classifier_loss_1,

            'reward_learning/reward_sample_obs_mean_0': np.mean(
                reward_sample_observations_0),
            'reward_learning/reward_goal_obs_mean_0': np.mean(
                reward_goal_observations_0),
            'reward_learning/reward_goal_obs_validation_mean_0': np.mean(
                reward_goal_observations_validation_0),

            'reward_learning/reward_sample_obs_mean_1': np.mean(
                reward_sample_observations_1),
            'reward_learning/reward_goal_obs_mean_1': np.mean(
                reward_goal_observations_1),
            'reward_learning/reward_goal_obs_validation_mean_1': np.mean(
                reward_goal_observations_validation_1),
        })

        return diagnostics

    def _evaluate_rollouts(self, episodes, env):
        """Compute evaluation metrics for the given rollouts."""
        diagnostics = super(VICEGANTwoGoal, self)._evaluate_rollouts(
            episodes, env)

        learned_reward = self._session.run(
            self._reward_t,
            feed_dict={
                self._placeholders['observations'][name]: np.concatenate([
                    episode['observations'][name]
                    for episode in episodes
                ])
                for name in self._classifier_0.observation_keys
            })

        diagnostics[f'reward_learning/reward-mean'] = np.mean(learned_reward)
        diagnostics[f'reward_learning/reward-min'] = np.min(learned_reward)
        diagnostics[f'reward_learning/reward-max'] = np.max(learned_reward)
        diagnostics[f'reward_learning/reward-std'] = np.std(learned_reward)

        return diagnostics

    @property
    def tf_saveables(self):
        saveables = super(VICEGANTwoGoal, self).tf_saveables
        saveables.update({
            '_classifier_optimizer_0': self._classifier_optimizer_0,
            '_classifier_optimizer_1': self._classifier_optimizer_1,
        })

        return saveables


# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

joint_colors = np.array([[0.4, 0.4, 0.4],
                    [0.4, 0.0, 0.0],
                    [0.6, 0.0, 0.0],
                    [0.8, 0.0, 0.0],
                    [1.0, 0.0, 0.0],
                    [0.4, 0.4, 0.0],
                    [0.6, 0.6, 0.0],
                    [0.8, 0.8, 0.0],
                    [1.0, 1.0, 0.0],
                    [0.0, 0.4, 0.2],
                    [0.0, 0.6, 0.3],
                    [0.0, 0.8, 0.4],
                    [0.0, 1.0, 0.5],
                    [0.0, 0.2, 0.4],
                    [0.0, 0.3, 0.6],
                    [0.0, 0.4, 0.8],
                    [0.0, 0.5, 1.0],
                    [0.4, 0.0, 0.4],
                    [0.6, 0.0, 0.6],
                    [0.7, 0.0, 0.8],
                    [1.0, 0.0, 1.0]])*255

joint_colors = joint_colors[:, ::-1]

bones_colors = [((0, 1), joint_colors[1, :]),
            ((1, 2), joint_colors[2, :]),
            ((2, 3), joint_colors[3, :]),
            ((3, 4), joint_colors[4, :]),

            ((0, 5), joint_colors[5, :]),
            ((5, 6), joint_colors[6, :]),
            ((6, 7), joint_colors[7, :]),
            ((7, 8), joint_colors[8, :]),

            ((0, 9), joint_colors[9, :]),
            ((9, 10), joint_colors[10, :]),
            ((10, 11), joint_colors[11, :]),
            ((11, 12), joint_colors[12, :]),

            ((0, 13), joint_colors[13, :]),
            ((13, 14), joint_colors[14, :]),
            ((14, 15), joint_colors[15, :]),
            ((15, 16), joint_colors[16, :]),

            ((0, 17), joint_colors[17, :]),
            ((17, 18), joint_colors[18, :]),
            ((18, 19), joint_colors[19, :]),
            ((19, 20), joint_colors[20, :])]


import string
import argparse

import sys
import torch
import torch.backends.cudnn as cudnn
import torch.utils.data
from torch.utils.data import Dataset, DataLoader
from PIL import Image
import numpy as np
import cv2
import math

from .utils import CTCLabelConverter, AttnLabelConverter
from .dataset import FileAlignCollate, AlignCollate
from .model import Model

class Recognition():

    def __init__(self, recog_config, device_ids = None ):

        """
            device_ids : int
        """

        self.opt = recog_config
        c_dict=open(self.opt.character , encoding='utf-8')
        c_dict=c_dict.read().split()
        self.opt.character=''.join(c_dict)
        self.device_ids = device_ids

        self.model= self.buildModel()

        self.AlignCollate_demo = FileAlignCollate(imgH=self.opt.imgH, imgW=self.opt.imgW, keep_ratio_with_pad=self.opt.PAD, c=self.opt.input_channel)

    def _cutRects(self, np_image, np_bboxes):
        """
            np_image: 整张图片 numpy格式, 需要RGB顺序
            np_bboxes: 这张图片的文字区域的bbox, numpy array (n,4,2), 点可以乱序,需要(x,y)格式
        """
        def order_points_old(pts):
            #TODO: parallel code

            rect = np.zeros_like(pts)

            s = pts.sum(axis=1)
            rect[0] = pts[np.argmin(s)]
            rect[2] = pts[np.argmax(s)]

            diff = np.diff(pts, axis=1)
            rect[1] = pts[np.argmin(diff)]
            rect[3] = pts[np.argmax(diff)]

            return rect

        rects = np.zeros_like(np_bboxes)
        for i in range(rects.shape[0]):
            rects[i] = order_points_old(np_bboxes[i])

        pil_results=[]
        for i, rect in enumerate(rects):

            w = int(np.linalg.norm(rect[0]-rect[1]))
            h = int(np.linalg.norm(rect[0]-rect[-1]))

            four_points=np.array(((0,0),(w-1,0),(w-1,h-1),(0,h-1)),dtype=np.float32)
            target_points = rect.astype(np.float32)

            try:
                M = cv2.getPerspectiveTransform(target_points, four_points)
                Rotated= cv2.warpPerspective(np_image, M, (w, h))
                pil_pic = Image.fromarray(Rotated)

                if self.opt.input_channel == 1 :
                    pil_pic = pil_pic.convert('L')
                else :
                    pil_pic = pil_pic.convert('RGB')
                pil_results.append(pil_pic)

            except:
                print('cut failed ')
                pass

        return pil_results

    def bboxPicRecognition(self ,np_image, np_bboxes):
        """
            np_image: 整张图片 numpy格式, 需要RGB顺序
            np_bboxes: 这张图片的文字区域的bbox, numpy array (n,4,2), 点可以乱序,需要(x,y)格式
        """
        if len(np_bboxes) == 0 :
            # print('empty !')
            image_list = []
        else :
            image_list = self._cutRects(np_image, np_bboxes)

        # print('preds str len{}-{}'.format(len(np_bboxes),len(image_list)))
        result, probs = self.imageBatchRecognition(image_list)

        return result, probs

    def buildModel(self):
        opt=self.opt

        """ model configuration """

        if len(opt.character) < opt.minC:
            opt.character += ' '*(opt.minC-len(opt.character))

        if 'CTC' in opt.Prediction:
            converter = CTCLabelConverter(opt.character)
        else:
            converter = AttnLabelConverter(opt.character)

        self.converter = converter

        opt.num_class = len(converter.character)

        model = Model(opt)

        if isinstance(self.device_ids, int) :
            self.device_ids = [self.device_ids]

        model = torch.nn.DataParallel(model, device_ids = self.device_ids)
        if torch.cuda.is_available():
            model = model.cuda()

        # load model
        if opt.saved_model:
            print('start load model')
            print('loading  model from {}'.format(opt.saved_model))
            model.load_state_dict(torch.load(opt.saved_model))
            print('success load model ')
        return model

    @torch.no_grad()
    def _recognition(self,images):
        model=self.model
        opt=self.opt
        model.eval()
        str_probs = None

        with torch.no_grad():
            images = images.cuda()
            length_for_pred = torch.cuda.IntTensor([opt.batch_max_length] * len(images))
            text_for_pred = torch.cuda.LongTensor(len(images), opt.batch_max_length + 1).fill_(0)

        if 'CTC' in opt.Prediction:
            preds=model(images,text_for_pred).softmax(-1)
            preds_size=torch.IntTensor([preds.size(1)]*len(images))
            preds_prob, preds_index = preds.permute(1,0,2).max(2)

            preds_index = preds_index.transpose(1,0).contiguous().view(-1)
            preds_prob = preds_prob.transpose(1,0).contiguous().view(-1)
            preds_str, str_probs= self.converter.decode(preds_index.data,preds_size.data, preds_prob)

        elif opt.Prediction == 'Transformer':
            preds_index = model(images, None, is_train= False)
            preds_str = self.converter.decode(preds_index)

        else :
            preds = model(images, text_for_pred, is_train=False)
            _, preds_index = preds.max(2)
            preds_str = self.converter.decode(preds_index, length_for_pred)

        result=[]

        for pred in preds_str:
            if 'Attn' in opt.Prediction:
                pred = pred[:pred.find('[s]')]  # prune after "end of sentence" token ([s])
            result.append(pred)

        return result, str_probs

    def fileRecognition(self,file_name):

        opt=self.opt
        model=self.model
        model.eval()
        if opt.input_channel == 1 :
            pil_image = Image.open(file_name).convert('L')
        else :
            pil_image = Image.open(file_name).convert('RGB')

        image_tensors=self.AlignCollate_demo([pil_image])

        result, *_=self._recognition(image_tensors)

        return result[0]

    def imageBatchRecognition(self, image_list, batch_size=64):
        """
            image_batch : list of PIL Image
            return : list of labels
        """

        index=0
        result=[]
        probs = []

        while index < len(image_list):
            # print(index,end='\r')

            images=self.AlignCollate_demo(image_list[index:index+batch_size])
            part_result, part_probs=self._recognition(images)
            result+=part_result
            probs+= part_probs
            index+=batch_size

        return result, probs


import torch
import torchvision
import torch.nn.functional as F
import torchvision.transforms as transforms
import os.path as osp
from torch.autograd import Variable
import time
from PIL import Image
import model
import cv2
import numpy as np

assert torch.__version__.split('.')[1] == '4' # pytorch 0.4.* only
My_CLASSES = (  # always index 0
    'a', 'b'
    )
img_size = 512
MyClassNum = len(My_CLASSES)
#print('Loading model..')

retinanet = torch.load('retinanet_9_2.pt')
retinanet.training = False

normalize = transforms.Normalize(
    mean=[0.485, 0.456, 0.406],
    std=[0.229, 0.224, 0.225]
)

preprocess = transforms.Compose([
    transforms.ToTensor(),
    normalize
])

idx=[]

for line in open(osp.join('/home/wynmew/workspace/Data', 'Data')):
    idx.append(('/home/wynmew/workspace/Data', line.strip()))

counter=0
for i in range(len(idx)):
    line = idx[i]
    #print(line)
    img=osp.join(line[0],line[1])
    imgfile=img.split()[0]
    label = img.split()[5]
    #label = img.split()[1]
    if int(label) < 9:
        print(counter)
        print('G:', imgfile, label)
        imgCV2 = cv2.imread(imgfile)
        imgPre = cv2.cvtColor(imgCV2, cv2.COLOR_BGR2RGB)
        img_pil = Image.fromarray(imgPre)
        img_pil_r = img_pil.resize((img_size, img_size))
        inputs = preprocess(img_pil_r)
        inputs.unsqueeze_(0)
        #start = time.time()
        scores, classification, transformed_anchors = retinanet(Variable(inputs.cuda(), volatile=True))
        idxs = np.where(scores > 0.01)
        for j in range(idxs[0].shape[0]):
            bbox = transformed_anchors[idxs[0][j], :]
            pts = bbox.tolist()
            lbs = classification[idxs[0][j]].tolist()
            scs = scores[idxs[0][j]].tolist()
            print('p:', pts, lbs, scs)
            print('--')
        counter+=1
        #end = time.time()
        #print('\ntime:', end - start)


import torch
import pit
import numpy as np
import torch.nn as nn
import argparse
import torch.nn.functional as F
from reprod_log import ReprodLogger
# import argparse
from deit.losses import DistillationLoss
#from deit.regnet import build_regnet as build_teacher_model
reprod_logger = ReprodLogger()
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--mixup', type=float, default=0.8,
                    help='mixup alpha, mixup enabled if > 0. (default: 0.8)')
args = parser.parse_args()
# 定义加载模型
class SoftTargetCrossEntropy(nn.Module):
    def __init__(self):
        super(SoftTargetCrossEntropy, self).__init__()

    def forward(self, x: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
        loss = torch.sum(-target * F.log_softmax(x, dim=-1), dim=-1)
        return loss.mean()
model = pit.pit_ti(pretrained=False)
model.load_state_dict(torch.load('weights/pit_ti_730.pth',map_location='cpu'))
# 载入数据
fake_data = np.load("fake_data_4.npy")
fake_label = np.load("fake_label_4.npy")
images = torch.tensor(fake_data)
target = torch.tensor(fake_label)
# 定义优化器
model_without_ddp = model
optimizer = torch.optim.AdamW(
            params=model.parameters(),
            lr=0.0005,
            betas=(0.9, 0.999),
            weight_decay=0.05,
            eps=0.1,
            amsgrad=False
            )

model.eval() # 手动处理dropout层
loss_list = []

if args.mixup > 0.:
    # smoothing is handled with mixup label transform
    criterion = SoftTargetCrossEntropy()
else:
    criterion = torch.nn.CrossEntropyLoss()
teacher_model = None
for i in range(5):
    output = model(images)
    dis = DistillationLoss(criterion ,teacher_model ,"none" ,0.5 ,1.0)
    loss = dis(images, output, target)
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    loss_list.append(loss)
    print("loss= ",loss)

for idx, loss in enumerate(loss_list):
    reprod_logger.add(f"loss_{idx}", loss.cpu().detach().numpy())
reprod_logger.save('bp_align_torch.npy')


import paddle
import paddle.nn as nn
import paddle.nn.functional as F
import math
import numpy as np
import cv2
import time
from ..loss import iou, build_loss, ohem_batch
from ..post_processing import pse
import sys
import os

class PSENet_Head(nn.Layer):
    def __init__(self,
                 in_channels,
                 hidden_dim,
                 num_classes,
                 loss_text,
                 loss_kernel):
        super(PSENet_Head, self).__init__()
        self.conv1 = nn.Conv2D(in_channels, hidden_dim, kernel_size=3, stride=1, padding=1)
        self.bn1 = nn.BatchNorm2D(hidden_dim)
        self.relu1 = nn.ReLU()

        self.conv2 = nn.Conv2D(hidden_dim, num_classes, kernel_size=1, stride=1, padding=0)

        self.text_loss = build_loss(loss_text)
        self.kernel_loss = build_loss(loss_kernel)

        for m in self.sublayers():
            if isinstance(m, nn.Conv2D):
                n = m.weight.shape[0] * m.weight.shape[1] * m.weight.shape[2]
                v = np.random.normal(loc=0., scale=np.sqrt(2. / n), size=m.weight.shape).astype('float32')
                m.weight.set_value(v)
            elif isinstance(m, nn.BatchNorm):
                m.weight.set_value(np.ones(m.weight.shape).astype('float32'))
                m.bias.set_value(np.zeros(m.bias.shape).astype('float32'))

    def forward(self, f):
        out = self.conv1(f)
        out = self.relu1(self.bn1(out))
        out = self.conv2(out)

        return out

    def loss(self, out, gt_texts, gt_kernels, training_masks):
        # output
        texts = out[:, 0, :, :]
        kernels = out[:, 1:, :, :]
        # text loss
        # logging.info('text', texts)
        # logging.info('kernels', kernels)
        selected_masks = ohem_batch(texts, gt_texts, training_masks)
        # logging.info('selected_masks', selected_masks)
        loss_text = self.text_loss(texts, gt_texts, selected_masks, reduce=False)
        # logging.info('loss_text', loss_text)
        iou_text = iou((texts > 0).cast('int32'), gt_texts, training_masks, reduce=False)
        # logging.info('iou_text', iou_text)
        losses = dict(
            loss_text=loss_text,
            iou_text=iou_text
        )

        # kernel loss
        loss_kernels = []
        selected_masks = gt_texts * training_masks
        for i in range(kernels.shape[1]):
            kernel_i = kernels[:, i, :, :]
            gt_kernel_i = gt_kernels[:, i, :, :]
            loss_kernel_i = self.kernel_loss(kernel_i, gt_kernel_i, selected_masks, reduce=False)
            loss_kernels.append(loss_kernel_i)
        loss_kernels = paddle.mean(paddle.stack(loss_kernels, axis=1), axis=1)
        # logging.info('loss_kernels', loss_kernels)
        iou_kernel = iou(
            (kernels[:, -1, :, :] > 0).cast('int32'), gt_kernels[:, -1, :, :], selected_masks, reduce=False)
        # logging.info('iou_kernel', iou_kernel)
        losses.update(dict(
            loss_kernels=loss_kernels,
            iou_kernel=iou_kernel
        ))

        return losses

    def get_results(self, out, img_meta, cfg):
        outputs = dict()
        # print(out[0,0,:,:])

        score = F.sigmoid(out[:, 0, :, :]).numpy()[0]
        # print(score)

        kernels = (out.numpy() > 0).astype(np.uint8)

        # print(kernels.shape)
        # print(np.sum(kernels[0,0,:,:]))
        # print(np.sum(kernels[0,1,:,:]))
        # print(np.sum(kernels[0,2,:,:]))
        # print(np.sum(kernels[0,3,:,:]))
        # print(np.sum(kernels[0,4,:,:]))
        # print(np.sum(kernels[0,5,:,:]))
        # print(np.sum(kernels[0,6,:,:]))

        # def to_rgb(img):
        #     img = img.reshape(img.shape[0], img.shape[1], 1)
        #     img = np.concatenate((img, img, img), axis=2) * 255
        #     return img
        #
        # def save(img_path, imgs):
        #     if not os.path.exists('vis/'):
        #         os.makedirs('vis/')
        #
        #     for i in range(len(imgs)):
        #         imgs[i] = cv2.copyMakeBorder(imgs[i], 3, 3, 3, 3, cv2.BORDER_CONSTANT, value=[255, 0, 0])
        #     res = np.concatenate(imgs, axis=1)
        #     if type(img_path) != str:
        #         img_name = img_path[0].split('/')[-1]
        #     else:
        #         img_name = img_path.split('/')[-1]
        #     print('saved %s.' % img_name)
        #     cv2.imwrite('vis/' + img_name, res)

        text_mask = kernels[:, :1, :, :]
        # print(np.sum(text_mask))
        # sys.exit()
        kernels[:, 1:, :, :] = kernels[:, 1:, :, :] * text_mask
        # print(np.sum(kernels))
        # kernel_0 = to_rgb(kernels[0, 0])
        # kernel_1 = to_rgb(kernels[0, 1])
        # kernel_2 = to_rgb(kernels[0, 2])
        # kernel_3 = to_rgb(kernels[0, 3])
        # kernel_4 = to_rgb(kernels[0, 4])
        # kernel_5 = to_rgb(kernels[0, 5])
        # kernel_6 = to_rgb(kernels[0, 6])
        #
        # save('kernel.png', [kernel_0, kernel_1, kernel_2, kernel_3, kernel_4, kernel_5, kernel_6])
        #
        # sys.exit()

        label = pse(kernels[0], cfg.test_cfg.min_area)

        # image size
        # print('org_img_size', img_meta['org_img_size'])
        # print('img_size', img_meta['img_size'])
        # sys.exit()
        org_img_size = img_meta['org_img_size']
        img_size = img_meta['img_size']

        label_num = np.max(label) + 1
        label = cv2.resize(label, (img_size[1], img_size[0]), interpolation=cv2.INTER_NEAREST)
        score = cv2.resize(score, (img_size[1], img_size[0]), interpolation=cv2.INTER_NEAREST)

        scale = (float(org_img_size[1]) / float(img_size[1]),
                 float(org_img_size[0]) / float(img_size[0]))

        bboxes = []
        scores = []
        # print('label_num: {}'.format(label_num))
        for i in range(1, label_num):
            # print(i)
            ind = label == i
            points = np.array(np.where(ind)).transpose((1, 0))

            if points.shape[0] < cfg.test_cfg.min_area:
                label[ind] = 0
                continue

            score_i = np.mean(score[ind])
            if score_i < cfg.test_cfg.min_score:
                label[ind] = 0
                continue

            if cfg.test_cfg.bbox_type == 'rect':
                rect = cv2.minAreaRect(points[:, ::-1])
                bbox = cv2.boxPoints(rect) * scale
            elif cfg.test_cfg.bbox_type == 'poly':
                binary = np.zeros(label.shape, dtype='uint8')
                binary[ind] = 1
                _, contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
                bbox = contours[0] * scale

            bbox = bbox.astype('int32')
            bboxes.append(bbox.reshape(-1))
            scores.append(score_i)

        outputs.update(dict(
            bboxes=bboxes,
            scores=scores
        ))

        return outputs


#! /usr/bin/python
import os
import pickle
import datetime

import numpy as np

from keras.models import Sequential, Model
from keras.layers import Input, Activation, Add
from keras.layers import BatchNormalization, LeakyReLU, Conv2D, Dense
from keras.layers import UpSampling2D
from keras.optimizers import Adam
from keras.applications import VGG19

from keras.callbacks import TensorBoard, ReduceLROnPlateau

from util import DataLoader, plot_test_images

class SRGAN():
    """
    Implementation of SRGAN as described in the paper:
    Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network
    https://arxiv.org/abs/1609.04802
    """

    def __init__(self, height_lr=64, width_lr=64, channels=3, upscaling_factor=4, gen_lr=1e-4, dis_lr=1e-4, gan_lr=1e-4):
        """
        :param int height_lr: Height of low-resolution images
        :param int width_lr: Width of low-resolution images
        :param int channels: Image channels
        :param int upscaling_factor: Up-scaling factor
        :param int gen_lr: Learning rate of generator
        :param int dis_lr: Learning rate of discriminator
        :param int gan_lr: Learning rate of GAN
        """

        # Low-resolution image dimensions
        self.height_lr = height_lr
        self.width_lr = width_lr

        # High-resolution image dimensions
        if upscaling_factor % 2 != 0:
            raise ValueError('Upscaling factor must be a multiple of 2; i.e. 2, 4, 8, etc.')
        self.upscaling_factor = upscaling_factor
        self.height_hr = int(self.height_lr * self.upscaling_factor)
        self.width_hr = int(self.width_lr * self.upscaling_factor)

        # Low-resolution and high-resolution shapes
        self.channels = channels
        self.shape_lr = (self.height_lr, self.width_lr, self.channels)
        self.shape_hr = (self.height_hr, self.width_hr, self.channels)

        # Optimizers used by networks
        optimizer_vgg = Adam(0.0001, 0.9)
        optimizer_generator = Adam(gen_lr, 0.9)
        optimizer_discriminator = Adam(dis_lr, 0.9)
        optimizer_gan = Adam(gan_lr, 0.9)

        # Build the basic networks
        self.vgg = self.build_vgg(optimizer_vgg) # model1
        self.generator = self.build_generator(optimizer_generator) # model2
        self.discriminator = self.build_discriminator(optimizer_discriminator) # model3

        # Build the combined network
        self.srgan = self.build_srgan(optimizer_gan)

    def save_weights(self, filepath):
        """Save the generator and discriminator networks"""
        self.generator.save_weights(filepath + "_generator.h5")
        self.discriminator.save_weights(filepath + "_discriminator.h5")

    def load_weights(self, generator_weights=None, discriminator_weights=None):
        if generator_weights:
            self.generator.load_weights(generator_weights)
        if discriminator_weights:
            self.discriminator.load_weights(discriminator_weights)

    def build_vgg(self, optimizer):
        """
        Load pre-trained VGG19 from keras applications
        Extract features to be used in loss function from last conv layer, see architecture at:
        https://github.com/keras-team/keras/blob/master/keras/applications/vgg19.py
        """

        # Input image to extract features from
        img = Input(shape=self.shape_hr)

        # Get the vgg network. Extract features from last conv layer
        vgg = VGG19(weights="imagenet")
        vgg.outputs = [vgg.layers[9].output]

        # Create model and compile
        model = Model(inputs=img, outputs=vgg(img))
        model.trainable = False
        model.compile(
            loss='mse',
            optimizer=optimizer,
            metrics=['accuracy']
        )
        return model

    def build_generator(self, optimizer, residual_blocks=16):
        """
        Build the generator network according to description in the paper.

        :param optimizer: Keras optimizer to use for network
        :param int residual_blocks: How many residual blocks to use
        :return: the compiled model
        """

        def residual_block(input):
            x = Conv2D(64, kernel_size=3, strides=1, padding='same')(input)
            x = Activation('relu')(x)
            x = BatchNormalization(momentum=0.8)(x)
            x = Conv2D(64, kernel_size=3, strides=1, padding='same')(x)
            x = BatchNormalization(momentum=0.8)(x)
            x = Add()([x, input])
            return x

        def deconv2d_block(input):
            x = UpSampling2D(size=2)(input)
            x = Conv2D(256, kernel_size=3, strides=1, padding='same')(x)
            x = Activation('relu')(x)
            return x

        # Input low resolution image
        lr_input = Input(shape=(None, None, 3))

        # Pre-residual
        x_start = Conv2D(64, kernel_size=9, strides=1, padding='same')(lr_input)
        x_start = Activation('relu')(x_start)

        # Residual blocks
        r = residual_block(x_start)
        for _ in range(residual_blocks - 1):
            r = residual_block(r)

        # Post-residual block
        x = Conv2D(64, kernel_size=3, strides=1, padding='same')(r)
        x = BatchNormalization(momentum=0.8)(x)
        x = Add()([x, x_start])

        # Upsampling (if 4; run twice, if 8; run thrice, etc.)
        for _ in range(int(np.log(self.upscaling_factor) / np.log(2))):
            x = deconv2d_block(x)

        # Generate high resolution output
        hr_output = Conv2D(self.channels, kernel_size=9, strides=1, padding='same', activation='tanh')(x)

        # Create model and compile
        model = Model(inputs=lr_input, outputs=hr_output)
        model.compile(
            loss='binary_crossentropy',
            optimizer=optimizer
        )
        return model

    def build_discriminator(self, optimizer, filters=64):
        """
        Build the discriminator network according to description in the paper.

        :param optimizer: Keras optimizer to use for network
        :param int filters: How many filters to use in first conv layer
        :return: the compiled model
        """

        def conv2d_block(input, filters, strides=1, bn=True):
            d = Conv2D(filters, kernel_size=3, strides=strides, padding='same')(input)
            d = LeakyReLU(alpha=0.2)(d)
            if bn:
                d = BatchNormalization(momentum=0.8)(d)
            return d

        # Input high resolution image
        img = Input(shape=self.shape_hr)
        x = conv2d_block(img, filters, bn=False)
        x = conv2d_block(x, filters, strides=2)
        x = conv2d_block(x, filters*2)
        x = conv2d_block(x, filters*2, strides=2)
        x = conv2d_block(x, filters*4)
        x = conv2d_block(x, filters*4, strides=2)
        x = conv2d_block(x, filters*8)
        x = conv2d_block(x, filters*8, strides=2)
        x = Dense(filters*16)(x)
        x = LeakyReLU(alpha=0.2)(x)
        x = Dense(1, activation='sigmoid')(x)

        # Create model and compile
        model = Model(inputs=img, outputs=x)
        model.compile(
            loss='mse',
            optimizer=optimizer,
            metrics=['accuracy']
        )
        return model

    def build_srgan(self, optimizer):
        """Create the combined SRGAN network"""

        # Input HR and corresponding LR images
        img_hr = Input(self.shape_hr)
        img_lr = Input(self.shape_lr)

        # Create a high resolution image from the low resolution one
        generated_hr = self.generator(img_lr)
        generated_features = self.vgg(generated_hr)

        # In the combined model we only train the generator
        self.discriminator.trainable = False

        # Determine whether the generator HR images are OK
        generated_check = self.discriminator(generated_hr)

        # Create model and compile
        model = Model(inputs=[img_lr, img_hr], outputs=[generated_check, generated_features])
        model.compile(
            loss=['binary_crossentropy', 'mse'],
            loss_weights=[1e-3, 1],
            optimizer=optimizer
        )
        return model

    def train(self, epochs,
        dataname, datapath,
        batch_size=1,
        test_images=None, test_frequency=50, test_path="./images/samples/",
        weight_frequency=None, weight_path='./data/weights/',
        print_frequency=1
    ):
        """Train the SRGAN network

        :param int epochs: how many epochs to train the network for
        :param str dataname: name to use for storing model weights etc.
        :param str datapath: path for the image files to use for training
        :param int batch_size: how large mini-batches to use
        :param list test_images: list of image paths to perform testing on
        :param int test_frequency: how often (in epochs) should testing be performed
        :param str test_path: where should test results be saved
        :param int weight_frequency: how often (in epochs) should network weights be saved. None for never
        :param int weight_path: where should network weights be saved
        :param int print_frequency: how often (in epochs) to print progress to terminal
        """

        # Create data loader
        loader = DataLoader(
            datapath,
            self.height_hr, self.width_hr,
            self.height_lr, self.width_lr,
            self.upscaling_factor
        )

        # Shape of output from discriminator
        disciminator_output_shape = list(self.discriminator.output_shape)
        disciminator_output_shape[0] = batch_size
        disciminator_output_shape = tuple(disciminator_output_shape)

        # VALID / FAKE targets for discriminator
        real = np.ones(disciminator_output_shape)
        fake = np.zeros(disciminator_output_shape)

        # Each epoch == "update iteration" as defined in the paper
        losses = []
        for epoch in range(epochs):

            # Start epoch time
            if epoch % (print_frequency + 1) == 0:
                start_epoch = datetime.datetime.now()

            # Train discriminator
            imgs_hr, imgs_lr = loader.load_batch(batch_size)
            generated_hr = self.generator.predict(imgs_lr)
            real_loss = self.discriminator.train_on_batch(imgs_hr, real)
            fake_loss = self.discriminator.train_on_batch(generated_hr, fake)
            discriminator_loss = 0.5 * np.add(real_loss, fake_loss)

            # Train generator
            imgs_hr, imgs_lr = loader.load_batch(batch_size)
            features_hr = self.vgg.predict(imgs_hr)
            generator_loss = self.srgan.train_on_batch([imgs_lr, imgs_hr], [real, features_hr])

            # Save losses
            losses.append({'generator': generator_loss, 'discriminator': discriminator_loss})

            # Plot the progress
            if epoch % print_frequency == 0:
                print("Epoch {}/{} | Time: {}s\n>> Generator: {}\n>> Discriminator: {}\n".format(
                    epoch, epochs,
                    (datetime.datetime.now() - start_epoch).seconds,
                    ", ".join(["{}={:.3e}".format(k, v) for k, v in zip(self.srgan.metrics_names, generator_loss)]),
                    ", ".join(["{}={:.3e}".format(k, v) for k, v in zip(self.discriminator.metrics_names, discriminator_loss)])
                ))

            # If test images are supplied, show them to the user
            if test_images and epoch % test_frequency == 0:
                plot_test_images(self, loader, test_images, test_path, epoch)

            # Check if we should save the network weights
            if weight_frequency and epoch % weight_frequency == 0:

                # Save the network weights
                self.save_weights(os.path.join(weight_path, dataname))

                # Save the recorded losses
                pickle.dump(losses, open(os.path.join(weight_path, dataname+'_losses.p'), 'wb'))

# Run the SRGAN network
if __name__ == '__main__':

    # Instantiate the SRGAN object
    print(">> Creating the SRGAN network")
    gan = SRGAN(gen_lr=1e-5)

    # Load previous imagenet weights
    print(">> Loading old weights")
    gan.load_weights('../data/weights/imagenet_generator.h5', '../data/weights/imagenet_discriminator.h5')

    # Train the SRGAN
    gan.train(
        epochs=200,
        dataname='pics',
        datapath='../pics/',
        batch_size=16,
        test_images=[
            '../pics/dcgan-0.jpg',
            '../pics/dcgan-8.jpg',
            '../pics/dcgan-59.jpg',
            '../pics/dcgan-154.jpg',
            '../pics/dcgan-258.jpg',
        ],
        test_frequency=10,
        test_path='../images/',
        weight_path='../data/',
        weight_frequency=10,
        print_frequency=10,
    )


import numpy as np
import pandas as pd

from sklearn.feature_extraction.text import CountVectorizer
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM
from keras.models import load_model
from keras.utils.np_utils import to_categorical
import re

turkish_characters = "a|b|c|ç|d|e|f|g|ğ|h|ı|i|j|k|l|m|n|o|ö|p|r|s|ş|t|u|ü|v|y|z|0-9"
data = pd.read_csv("data/data.tsv", header=0, \
                    delimiter="\t", quoting=3)

data = data[['Review','Sentiment']]

# Veri Setinin temizlenmesi.
data['Review'] = data['Review'].apply(lambda x: x.lower())
data['Review'] = data['Review'].apply((lambda x: re.sub('[^'+turkish_characters+'\s]','',x)))

# Veri setimizin işlenebilmesi için text verileri numaralara çevirmemiz gerekir.
# Keras bu işlem için hazır bir mekanizma sunmaktadır.
# Tokenizer sınıfı data içerisinde verilen cümleleri analiz ederek. Kelimelerin sıklıklarını hesaplar.
# Parameter: num_words = En sık geçen 25000 kelimeye odaklan. Diğerleri önemli değil
tokenizer = Tokenizer(split=' ',num_words=25000)
# Her bir kelimenin sıklığını(frekansını) hesaplar.
tokenizer.fit_on_texts(data['Review'].values)
# Tüm cümleler tam sayı dizisine dönüştürülür.
X = tokenizer.texts_to_sequences(data['Review'].values)
# Bütün metinlerimiz 400 sütundan oluşan bir dizi ile temsil edilecek.
# Çok kısa metinler 0'lar ile doldurulacak. Çok uzun metinler ise kesilecek.
X = pad_sequences(X,maxlen=400)

embed_dim = 128
lstm_out = 128
def build_model():
    model = Sequential()
    # Her bir kelimenin temsil edileceği vektör boyutu. Bu örnek için her bir kelime 128 boyutunda
    # bir vektör ile temsil edilir.
    model.add(Embedding(25000, embed_dim,input_length = X.shape[1], dropout=0.2))
    model.add(LSTM(lstm_out, dropout_U=0.2, dropout_W=0.2))
    model.add(Dense(2,activation='softmax'))
    model.compile(loss = 'categorical_crossentropy', optimizer='adam',metrics = ['accuracy'])
    return model

# Çıktılarımızı kategorik hale getirdik. (Opsiyonel)
Y = pd.get_dummies(data['Sentiment']).values

# Verinin %80'i train, %20'si test verisi olacak şekilde ayrılır.
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X,Y, test_size = 0.2, random_state = 2)

model = build_model()
# Oluşturulan model train verileri ile eğitilir. Yapay Sinir Ağı eğitilmeye başlar.
# nb_epoch: İterasyon sayısı
model.fit(X_train, Y_train, nb_epoch = 3, batch_size=32, verbose = 2)
# Train verileri ile model eğitildikten sonra test dataları ile doğruluk oranlarına bakılır.
score = model.evaluate(X_test, Y_test, verbose = 2)
print("score: %.2f" % (score[1]))

# Save Model
#model.save("models/sentiment_3440_model.h5")

# Load Model. Daha önce eğitilmiş olan model. Veriseti yada model parametreleri değişirse
# bu model geçersiz olur. Eğitim işlemi uzun sürdüğü için ağı bir defa eğitip oluşan modeli kaydettim.
model = load_model("models/sentiment_3440_model.h5")

my_text = ["güzel bir film tavsiye ederim",
           "hayat zor","bu filmi hiç beğenmedim",
           "daha iyi olabilir",
           "Dünyanın en aşağılık filmi.Bu filmde oynayanlardan filme çekene kadar hepsine yazıklar olsun diyorum.Kötü film demek bu filme iltifat kalır 1/10",
           "Babam bizimle hiç konuşmaz",
           "Senaryo harika değil, ama oyunculuk iyi ve sinematografi mükemmel",
           "roger Dodger bu temanın en etkileyici varyasyonlarından biridir",
           "vader akıllı, yakışıklı ve komik",
           "Gerçekten kötü, korkunç bir kitap"]

# Verilen örnekler Tokenizer yapısı ile tam sayı dizisine dönüştürülür
# Daha sonra eğitilen modele sırayla verilerek anlam analizi sonuçları elde edilir.
# Her Cümlenin yüzde kaç olumlu ve olumsuz olduğuna dair bilgiler çıktı olarak verilir.
sequences = tokenizer.texts_to_sequences(my_text)
data = pad_sequences(sequences, maxlen=400)
predictions = model.predict(data)
print(predictions)


# -*- coding: utf-8 -*-

"""
Description
-----------
Set of functions to calibrate the excess chemical potential and standard state volume of water

Marley Samways
"""

import numpy as np
import pymbar
import openmmtools
from simtk.openmm.app import *
from simtk.openmm import *
from simtk.unit import *

import grand

def get_lambda_values(lambda_in):
    """
    Calculate the lambda_sterics and lambda_electrostatics values for a given lambda.
    Electrostatics are decoupled from lambda=1 to 0.5, and sterics are decoupled from
    lambda=0.5 to 0.

    Parameters
    ----------
    lambda_in : float
        Input lambda value

    Returns
    -------
    lambda_vdw : float
        Lambda value for steric interactions
    lambda_ele : float
        Lambda value for electrostatic interactions
    """
    if lambda_in > 1.0:
        # Set both values to 1.0 if lambda > 1
        lambda_vdw = 1.0
        lambda_ele = 1.0
    elif lambda_in < 0.0:
        # Set both values to 0.0 if lambda < 0
        lambda_vdw = 0.0
        lambda_ele = 0.0
    else:
        # Scale values between 0 and 1
        lambda_vdw = min([1.0, 2.0*lambda_in])
        lambda_ele = max([0.0, 2.0*(lambda_in-0.5)])
    return lambda_vdw, lambda_ele

def calc_mu_ex(system, topology, positions, box_vectors, temperature, n_lambdas, n_samples, n_equil, log_file):
    """
    Calculate the excess chemical potential of a water molecule in a given system,
    as the hydration free energy, using MBAR

    Parameters
    ----------
    system : simtk.openmm.System
        System of interest
    topology : simtk.openmm.app.Topology
        Topology of the system
    positions : simtk.unit.Quantity
        Initial positions for the simulation
    box_vectors : simtk.unit.Quantity
        Periodic box vectors for the system
    temperature : simtk.unit.Quantity
        Temperature of the simulation
    n_lambdas : int
        Number of lambda values
    n_samples : int
        Number of energy samples to collect at each lambda value
    n_equil : int
        Number of MD steps to run between each sample
    log_file : str
        Name of the log file to write out

    Returns
    -------
    dG : simtk.unit.Quantity
        Calculated free energy value
    """
    # Use the BAOAB integrator to sample the equilibrium distribution
    integrator = openmmtools.integrators.BAOABIntegrator(temperature, 1.0/picosecond, 0.002*picoseconds)

    # Name the log file, if not already done
    if log_file is None:
        'dG-{}l-{}sa-{}st.log'.format(n_lambdas, n_samples, n_equil)

    # Define a GCMC sampler object, just to allow easy switching of a water - won't use this to sample
    gcmc_mover = grand.samplers.BaseGrandCanonicalMonteCarloSampler(system=system, topology=topology,
                                                                    temperature=temperature,
                                                                    log=log_file,
                                                                    ghostFile='calc_mu-ghosts.txt',
                                                                    overwrite=True)
    # Remove unneeded ghost file
    os.remove('calc_mu-ghosts.txt')

    # Testing with barostat
    pressure = 1 * bar
    system.addForce(MonteCarloBarostat(pressure, temperature, 25))

    # IDs of the atoms to switch on/off
    wat_ids = []
    for residue in topology.residues():
        for atom in residue.atoms():
            wat_ids.append(atom.index)
        break  # Make sure to stop after the first water

    # Define the platform, first try CUDA, then OpenCL, then CPU
    try:
        platform = Platform.getPlatformByName('CUDA')
        platform.setPropertyDefaultValue('Precision', 'mixed')
    except:
        try:
            platform = Platform.getPlatformByName('OpenCL')
            #platform.setPropertyDefaultValue('Precision', 'mixed')
        except:
            platform = Platform.getPlatformByName('CPU')

    # Create a simulation object
    simulation = Simulation(topology, system, integrator, platform)
    simulation.context.setPositions(positions)
    simulation.context.setVelocitiesToTemperature(temperature)
    simulation.context.setPeriodicBoxVectors(*box_vectors)

    # Make sure the GCMC sampler has access to the Context
    gcmc_mover.context = simulation.context

    lambdas = np.linspace(1.0, 0.0, n_lambdas)  # Lambda values to use
    U = np.zeros((n_lambdas, n_lambdas, n_samples))  # Energy values calculated

    # Simulate the system at each lambda window
    for i in range(n_lambdas):
        # Set lambda values
        gcmc_mover.logger.info('Simulating at lambda = {:.4f}'.format(np.round(lambdas[i], 4)))
        gcmc_mover.adjustSpecificWater(wat_ids, lambdas[i])
        for k in range(n_samples):
            # Run production MD
            simulation.step(n_equil)
            box_vectors = simulation.context.getState(getPositions=True).getPeriodicBoxVectors()
            volume = box_vectors[0][0] * box_vectors[1][1] * box_vectors[2][2]
            # Calculate energy at each lambda value
            for j in range(n_lambdas):
                # Set lambda value
                gcmc_mover.adjustSpecificWater(wat_ids, lambdas[j])
                # Calculate energy
                #U[i, j, k] = simulation.context.getState(getEnergy=True).getPotentialEnergy() / gcmc_mover.kT
                # Calculate energy (with volume correction)
                U[i, j, k] = (simulation.context.getState(getEnergy=True).getPotentialEnergy() + (pressure * volume * AVOGADRO_CONSTANT_NA) ) / gcmc_mover.kT
            # Reset lambda value
            gcmc_mover.adjustSpecificWater(wat_ids, lambdas[i])

    # Calculate equilibration & number of uncorrelated samples
    N_k = np.zeros(n_lambdas, np.int32)
    for i in range(n_lambdas):
        n_equil, g, neff_max = pymbar.timeseries.detectEquilibration(U[i, i, :])
        indices = pymbar.timeseries.subsampleCorrelatedData(U[i, i, :], g=g)
        N_k[i] = len(indices)
        U[i, :, 0:N_k[i]] = U[i, :, indices].T

    # Calculate free energy differences
    mbar = pymbar.MBAR(U, N_k)
    results = mbar.getFreeEnergyDifferences()
    deltaG_ij = results[0]
    ddeltaG_ij = results[1]

    # Extract overall free energy change
    dG = -deltaG_ij[0, -1]

    # Write out intermediate free energies
    for i in range(n_lambdas):
        dG_i = (-deltaG_ij[0, i] * gcmc_mover.kT).in_units_of(kilocalorie_per_mole)
        gcmc_mover.logger.info('Free energy ({:.3f} -> {:.3f}) = {}'.format(lambdas[0], lambdas[i], dG_i))

    # Convert free energy to kcal/mol
    dG = (dG * gcmc_mover.kT).in_units_of(kilocalorie_per_mole)
    dG_err = (ddeltaG_ij[0, -1] * gcmc_mover.kT).in_units_of(kilocalorie_per_mole)

    gcmc_mover.logger.info('Excess chemical potential = {}'.format(dG))
    gcmc_mover.logger.info('Estimated error = {}'.format(dG_err))

    return dG

def calc_std_volume(system, topology, positions, box_vectors, temperature, n_samples, n_equil):
    """
    Calculate the standard volume of a given system and parameters, this is the effective volume
    of a single molecule

    Parameters
    ----------
    system : simtk.openmm.System
        System of interest
    topology : simtk.openmm.app.Topology
        Topology of the system
    positions : simtk.unit.Quantity
        Initial positions for the simulation
    box_vectors : simtk.unit.Quantity
        Periodic box vectors for the system
    temperature : simtk.unit.Quantity
        Temperature of the simulation
    n_samples : int
        Number of volume samples to collect
    n_equil : int
        Number of MD steps to run between each sample

    Returns
    -------
    std_volume : simtk.unit.Quantity
        Calculated free energy value
    """
    # Use the BAOAB integrator to sample the equilibrium distribution
    integrator = openmmtools.integrators.BAOABIntegrator(temperature, 1.0 / picosecond, 0.002 * picoseconds)

    # Define the platform, first try CUDA, then OpenCL, then CPU
    try:
        platform = Platform.getPlatformByName('CUDA')
        platform.setPropertyDefaultValue('Precision', 'mixed')
    except:
        try:
            platform = Platform.getPlatformByName('OpenCL')
            #platform.setPropertyDefaultValue('Precision', 'mixed')
        except:
            platform = Platform.getPlatformByName('CPU')

    # Create a simulation object
    simulation = Simulation(topology, system, integrator, platform)
    simulation.context.setPositions(positions)
    simulation.context.setVelocitiesToTemperature(temperature)
    simulation.context.setPeriodicBoxVectors(*box_vectors)

    # Count number of residues
    n_molecules = 0
    for residue in topology.residues():
        n_molecules += 1

    # Collect volume samples
    volume_list = []
    for i in range(n_samples):
        # Run a short amount of MD
        simulation.step(n_equil)
        # Calculate volume & then volume per molecule
        state = simulation.context.getState(getPositions=True)
        box_vectors = state.getPeriodicBoxVectors(asNumpy=True)
        volume = box_vectors[0, 0] * box_vectors[1, 1] * box_vectors[2, 2]
        volume_list.append(volume / n_molecules)

    # Calculate mean volume per molecule
    std_volume = sum(volume_list) / len(volume_list)

    return std_volume