# -*- coding: utf-8 -*-
"""
Created on Wed Aug 12 16:23:45 2020

@author: LWS

从cifar10以及cifar100的序列化文件中，提取图片以及标签、文件名等信息
"""

import os
import pickle
#import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

def load_labels_name(filename):
    """使用pickle反序列化labels文件，得到存储内容
        cifar10的label文件为“batches.meta”，cifar100则为“meta”
        反序列化之后得到字典对象，可根据key取出相应内容
    """
    with open(filename, 'rb') as f:
        obj = pickle.load(f)
    return obj

def load_data_cifar(filename, mode='cifar10'):
    """ load data and labels information from cifar10 and cifar100
    cifar10 keys(): dict_keys([b'batch_label', b'labels', b'data', b'filenames'])
    cifar100 keys(): dict_keys([b'filenames', b'batch_label', b'fine_labels', b'coarse_labels', b'data'])
    """
    with open(filename,'rb') as f:
        dataset = pickle.load(f, encoding='bytes')
        if mode == 'cifar10':
            data = dataset[b'data']
            labels = dataset[b'labels']
            img_names = dataset[b'filenames']
        elif mode == 'cifar100':
            data = dataset[b'data']
            labels = dataset[b'fine_labels']
            img_names = dataset[b'filenames']
        else:
            print("mode should be in ['cifar10', 'cifar100']")
            return None, None, None

    return data, labels, img_names

def load_cifar10(cifar10_path, mode = 'train'):

    if mode == "train":
        data_all = np.empty(shape=[0, 3072],dtype=np.uint8)
        labels_all = []
        img_names_all = []
        for i in range(1,6):
            filename = os.path.join(cifar10_path, 'data_batch_'+str(i)).replace('\\','/')
            print("Loading {}".format(filename))
            data, labels, img_names = load_data_cifar(filename, mode='cifar10')
            data_all = np.vstack((data_all, data))
            labels_all += labels
            img_names_all += img_names
        return data_all,labels_all,img_names_all
    elif mode == "test":
        filename = os.path.join(cifar10_path, 'test_batch').replace('\\','/')
        print("Loading {}".format(filename))
        return load_data_cifar(filename, mode='cifar10')

def load_cifar100(cifar100_path, mode = 'train'):
    if mode == "train":
        filename = os.path.join(cifar100_path, 'train')
        print("Loading {}".format(filename))
        data, labels, img_names = load_data_cifar(filename, mode='cifar100')
    elif mode == "test":
        filename = os.path.join(cifar100_path, 'test')
        print("Loading {}".format(filename))
        data, labels, img_names = load_data_cifar(filename, mode='cifar100')
    else:
        print("mode should be in ['train', 'test']")
        return None, None, None

    return data, labels, img_names

def to_pil(data):
    r = Image.fromarray(data[0])
    g = Image.fromarray(data[1])
    b = Image.fromarray(data[2])
    pil_img = Image.merge('RGB', (r,g,b))
    return pil_img

def random_visualize(imgs, labels, label_names):
    figure = plt.figure(figsize=(len(label_names),10))
    idxs = list(range(len(imgs)))
    np.random.shuffle(idxs)
    count = [0]*len(label_names)
    for idx in idxs:
        label = labels[idx]
        if count[label]>=10:
            continue
        if sum(count)>10 * len(label_names):
            break

        img = to_pil(imgs[idx])
        label_name = label_names[label]

        subplot_idx = count[label] * len(label_names) + label + 1
        print(label, subplot_idx)
        plt.subplot(10,len(label_names), subplot_idx)
        plt.imshow(img)
        plt.xticks([])
        plt.yticks([])
        if count[label] == 0:
            plt.title(label_name)

        count[label] += 1

    plt.show

if __name__ == "__main__":
    cifar10_path = "D:/dataset/cifar10/cifar-10-batches-py"
    cifar100_path = "D:/dataset/cifar100/cifar-100-python"

    obj_cifar10 = load_labels_name(os.path.join(cifar10_path, 'batches.meta')) # label_names、num_cases_per_batch、num_vis
    obj_cifar100 = load_labels_name(os.path.join(cifar100_path, 'meta')) # coarse_label_names、fine_label_names

    # 提取cifar10、cifar100的图片数据、标签、文件名
    data_cifar10_train,labels_cifar10_train,img_names_cifar10_train = \
                                load_cifar10(cifar10_path, mode='train')
    data_cifar10_test,labels_cifar10_test,img_names_cifar10_test = \
                                load_cifar10(cifar10_path, mode='test')
    imgs_cifar10_train = data_cifar10_train.reshape(data_cifar10_train.shape[0],3,32,32)
    imgs_cifar10_test = data_cifar10_test.reshape(data_cifar10_test.shape[0],3,32,32)

    data_cifar100_train,labels_cifar100_train,img_names_cifar100_train = \
                                load_cifar100(cifar100_path, mode = 'train')
    data_cifar100_test,labels_cifar100_test,img_names_cifar100_test = \
                                load_cifar100(cifar100_path, mode = 'test')
    imgs_cifar100_train = data_cifar100_train.reshape(data_cifar100_train.shape[0],3,32,32)
    imgs_cifar100_test = data_cifar100_test.reshape(data_cifar100_test.shape[0],3,32,32)

    # visualize fro cifar10
    label_names_cifar10 = obj_cifar10['label_names']
    random_visualize(imgs=imgs_cifar10_train,
                     labels=labels_cifar10_train,
                     label_names=label_names_cifar10)

    # visualize fro cifar100
    label_names_cifar100 = obj_cifar100['fine_label_names']
    random_visualize(imgs=imgs_cifar100_train,
                     labels=labels_cifar100_train,
                     label_names=label_names_cifar100)


import datetime
import logging
import azure.functions as func
from JERA_main import JERA_main

app = func.FunctionApp()

@app.schedule(schedule="0 0 13 * * 5", arg_name="myTimer", run_on_startup=False,
              use_monitor=False)
def TimerTrigger(myTimer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()

    if myTimer.past_due:
        logging.info('The timer is past due!')

    logging.info('Python timer trigger function ran at %s', utc_timestamp)

    JERA_main()


import func
from time import sleep
op=[1,2,3]
blok=0
while True:
    func.cab('GERENCIADOR DE SENHAS')
    print('\033[1;33m1>\033[m \033[1;34mLOGIN\033[m')
    print('\033[1;33m2>\033[m \033[1;34mNOVO CADASTRO\033[m')
    print('\033[1;33m3>\033[m \033[1;34mSAIR\033[m')
    func.linha()
    opi=int(input('\033[1;33mOPÇÃO: \033[m'))
    if opi not in op:
        print('\033[1;31mOPÇÃO INVALIDA!\033[m')
    if opi == 2:
        while True:
            func.cab('CADASTRO')
            cu= str(input('\033[1;33m>\033[m \033[1;34mDIGITE O NOME DE USUARIO: \033[m'))
            cs= str(input('\033[1;33m>\033[m \033[1;34mDIGTE UMA SENHA: \033[m'))
            if not func.ex(f'{cu}.txt'):
                func.cri(f'{cu}.txt')
                func.cada(f'{cu}.txt',cs,'at')
                print('\033[1;32mUSUARIO CRIADO COM SUCESSO!\033[m')
                break
            if func.ex(f'{cu}.txt'):
                print("\033[1;31mNOME DE USUARIO INVALIDO!")
                print('DIGITE OUTRO:\033[m')
    if opi == 3:
        print('\033[1;31mSISTEMA FINALIZADO!\033[m')
        break
    if opi == 1:
        while True:
            func.cab('LOGIN')
            id= str(input('\033[1;33m> \033[m\033[1;34mDIGITE O NOME DE ÚSUARIO: \033[m'))
            pas= str(input('\033[1;33m> \033[m\033[1;34mDIGITE O A SENHA: \033[m'))
            try:
                a = open(f'{id}.txt', 'rt')
            except:
                func.linha()
                blok+=1
                print('\033[1;31mERRO: USUARIO NÃO ENCONTRADO!\033[m')
            else:
                rnh = a.readline().strip()
                if f'{rnh}' == f'{pas}':
                    func.lar(f'{id}.txt')
                    break
                else:
                    blok+=1
                    print('\033[1;31mERRO: SENHA INCORRETA\033[m')
            if blok == 3:
                print('\033[1;31mAÇÕES BLOQUEADAS POR 1min!\033[m')
                blok=0
                sleep(60)


from sklearn import datasets
from sklearn.semi_supervised import LabelPropagation
from sklearn.metrics import confusion_matrix
import numpy as np
import helpers
import functions
from sklearn.feature_extraction.text import TfidfVectorizer
from scikitTSVM import SKTSVM
import warnings
warnings.filterwarnings("ignore", category=PendingDeprecationWarning)
warnings.filterwarnings("ignore", category=DeprecationWarning)

tsvm = SKTSVM(probability=False,C=0.01,gamma=1.0,kernel= 'linear',lamU= 1.0)
percent_test = 0.15
positive_set = 'data/bc_samples.txt'
negative_set = 'data/bc_grounds.txt'
unlabeled_set = 'data/unlabeled-data.csv'
analogy_list = functions.get_list_re(positive_set)
non_analogy_list = functions.get_list_re(negative_set)
unlabeled_list = functions.get_list_re(unlabeled_set)
samples = [(text, 1) for text in analogy_list] + [(text, 0) for text in non_analogy_list]
train_data, train_labels, test_data, test_labels = functions.preprocess(samples, percent_test)
j = 0
for sample in unlabeled_list:
    if j <= 20000:
        train_data.append(sample)
        train_labels.append(-1)
    j += 1
train_labels = np.array(train_labels)
test_labels = np.array(test_labels)
train_data = np.array(train_data)
TfidfVect = TfidfVectorizer(tokenizer=lambda doc: doc, lowercase=False)
train_set = TfidfVect.fit_transform(train_data).toarray()
test_set = TfidfVect.transform(test_data).toarray()

# Label Propagation
"""
label_prop_model = helpers.get_function('LP')
label_prop_model.fit(train_set, train_labels)
test_predict = label_prop_model.predict(test_set)
print(label_prop_model.score(test_set, test_labels))
"""

print("Total size of training set: ",len(train_labels))
i = 0
for l in train_labels:
    if l==-1:
        i += 1
print("Size of unlabeled data: ", i)
print("Size of the testing set ",len(test_data))

# TSVM
#"""
tsvm.fit(train_set, train_labels)
test_predict = tsvm.predict(test_set)
print("Accuracy: ", tsvm.score(test_set, test_labels))
#"""
print("Confusion matrix:")
matrix = confusion_matrix(test_labels, test_predict, labels = [1, 0])
print(matrix)
precision, recall, f_measure = functions.fmeasure(matrix)
print("Precision: ", precision)
print("Recall: ", recall)
print("f_measure: ", f_measure)


class Node:
	def __init__(self, data):
		self.data = data
		self.next = None

class NodeOperation:

	def pushNode(self, head_ref, data_val):

		new_node = Node(data_val)

		new_node.next = head_ref

		head_ref = new_node
		return head_ref

	def printNode(self, head):
		while (head != None):
			print('%d->' % head.data, end="")
			head = head.next
		print("NULL")

	''' Utility Function to find length of linked list '''

	def getLen(self, head):
		temp = head
		len = 0

		while (temp != None):
			len += 1
			temp = temp.next

		return len

	def printMiddle(self, head):
		if head != None:
			# find length
			len = self.getLen(head)
			temp = head

			# traverse till we reached half of length
			midIdx = len // 2
			while midIdx != 0:
				temp = temp.next
				midIdx -= 1

			# temp will be storing middle element
			print('The middle element is [%d]' % temp.data)

# Driver Code
head = None
temp = NodeOperation()
for i in range(5, 0, -1):
	head = temp.pushNode(head, i)
	temp.printNode(head)
	temp.printMiddle(head)

Linked List/Mid point of linkedlist/MidPointOfLL.py


from numpy import block
from Blockchain import Blockchain
from Block import Block
from User import User
import json
import binascii
import Crypto
import Crypto.Random
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from queue import Queue
from threading import Thread, Event

blockchain = Blockchain()

#Users generation

users =[]
users.append(User('Sari'))
users.append(User('Hubert'))
users.append(User('Adam'))
users.append(User('Filip'))

flag = True
proposed_block = None
transaction_list = []
proof = 0

def display_blockchain():
    return json.dumps(blockchain.chain, default=Block.to_dict)

def create_block(data="", nonce=0):
    previous_block = blockchain.show_last_block()
    prev_hash = previous_block.hash_block()
    block = blockchain.create_block(prev_hash, data, nonce)
    hashed_block = block.hash_block()
    date = json.dumps(block.timestamp, default=str)
    response = {'message': 'Created block',
                'previous_hash': block.prev_hash,
                'nonce': block.nonce,
                'data': block.block_data,
                'timestamp': date,
                'hashblock': hashed_block,}

    return json.dumps(response)

def userThread(u :User, b):
    blockchain.updateTransactions(transaction_list)
    global flag
    global proposed_block
    global proof
    while flag:
        b = blockchain.proof_of_work()
        if b != -1:
            proof = b
            flag = False
    if b == -1:
            return print("bład uzytkownika "  + u.name)
    proposed_block = blockchain.create_block(blockchain.proof_of_work())

if __name__ == '__main__':
    blockchain.addUsers(users)
    blockchain.checkWallet(users[0].identity)
    blockchain.checkWallet(users[1].identity)
    blockchain.checkWallet(users[2].identity)
    blockchain.checkWallet(users[3].identity)

    blockchain.generateCoins()

    blockchain.checkWallet(blockchain.users[0].identity)
    blockchain.checkWallet(blockchain.users[1].identity)
    blockchain.checkWallet(blockchain.users[2].identity)
    blockchain.checkWallet(blockchain.users[3].identity)

    blockchain.new_transaction(blockchain.users[0], blockchain.users[1], 1)

    blockchain.checkWallet(blockchain.users[0].identity)
    blockchain.checkWallet(blockchain.users[1].identity)
    blockchain.checkWallet(blockchain.users[2].identity)
    blockchain.checkWallet(blockchain.users[3].identity)

    # thread1 = Thread(target=userThread, args=(users[0],-1,))
    # thread2 = Thread(target=userThread, args=(users[1],-1,))

    # thread1.start()
    # thread2.start()

    # thread1.join()
    # thread2.join()

    random = Crypto.Random.new().read
    rsa = RSA.generate(1024, random)
    pub = binascii.hexlify(rsa.publickey().exportKey(format='DER')).decode('ascii')

    print(blockchain.validateSignature(blockchain.users[0].identity, blockchain.pending_transactions[0]))

    blockchain.create_block(blockchain.proof_of_work())
    print(blockchain.checkBlock(blockchain.chain[0]))


# ##INCOMPLETE##

# from operator import itemgetter

# def person_lister(f):
#     def inner(people):
#         people.sort(key = itemgetter(2))
#     return inner

# @person_lister
# def name_format(*person):
#     print("In n_f: ", person)
#     print("Mr. " if person[3] == "M" else "Ms. ")
#     return ("Mr. " if person[3] == "M" else "Ms. ") + person[0] + " " + person[1]

# if __name__ == '__main__':
#     people = [input().split() for i in range(int(input()))]
#     print("Main after input: ",people)
#     # print(*name_format(people), sep='\n')
#     print(name_format(people))

# ms = "ABCDCDC"
# ss = "CDC"
# cnt = 0
# for i in range((len(ms)-len(ss))+1):
#     # print("For: ",ms[i:i+len(ss)])
#     cnt = cnt +(ms.count(ss,i,i+len(ss)))
# print(cnt)

def count_substring(string, sub_string):
    # count = 0
    string.count(sub_string)
    # for i in range((len(string)-len(sub_string))+1):
    #     print(string[i:i+len(sub_string)])
    #     print(sub_string)
    #     count = count + string.count(sub_string,i,len(sub_string))
    #     print(count)
    return string.count(sub_string)

if __name__ == '__main__':
    string = "ABCDCDC"
    sub_string = "CDC"

    count = count_substring(string, sub_string)
    print(count)


import pygame
import os
import random
import time

# set root window
WIDTH, HEIGHT = 800, 600
root = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Space Shooter')

# load and scale files
# background file
background_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'background.png')), (WIDTH, HEIGHT))

# ship files
player_ship_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'player_ship.png')), (120, 120))
enemy_ship_green_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'enemy_ship_green.png')), (65, 75))
enemy_ship_red_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'enemy_ship_red.png')), (62, 75))
enemy_ship_blue_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'enemy_ship_blue.png')), (62, 75))
charger_ship_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'charger.png')), (200, 100))

# laser files
laser_player_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'laser_smp.png')), (15, 30))
laser_green_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'laser_green.png')), (12, 22))
laser_red_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'laser_red.png')), (12, 22))
laser_blue_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'laser_blue.png')), (12, 22))
laser_charger_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'laser_1.png')), (17, 30))

# collision file
collision_file = pygame.transform.scale(
    pygame.image.load(os.path.join('images', 'collision.png')), (150, 150))

# global params
game_is_over = False
level = 1
lives = 5
score = 0
FPS = 100
LEVEL = 10

# other params
pygame.font.init()
main_font = pygame.font.SysFont('comicsans', 50)

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

tuple_files = {
    'player': (player_ship_file, laser_player_file),
    'red': (enemy_ship_red_file, laser_red_file),
    'blue': (enemy_ship_blue_file, laser_blue_file),
    'green': (enemy_ship_green_file, laser_green_file),
    'charger': (charger_ship_file, laser_charger_file)
}

player_init_x = int((WIDTH - player_ship_file.get_width()) / 2)
player_init_y = int(HEIGHT - player_ship_file.get_height())
charger_init_x = int((WIDTH - charger_ship_file.get_width()) / 2)
charger_init_y = -250
player_move_by = 5
enemy_move_by = 1
laser_move_by = 2
laser_gap_player = 200
laser_gap_charger = 1350
charger_move_left = True
incoming_message = 0

clock = pygame.time.Clock()

# laser class
class Laser:
    def __init__(self, x, y, image_file):
        self.x = x
        self.y = y
        self.image_file = image_file
        self.mask = pygame.mask.from_surface(self.image_file)

    def move(self, vel):
        self.y += vel

    def is_off_screen(self):
        return self.y < 0 or self.y > HEIGHT

    def draw(self, window):
        window.blit(self.image_file, (self.x, self.y))

class Ship:
    def __init__(self, x, y, files):
        self.x = x
        self.y = y
        self.image_file = files[0]
        self.laser_image_file = files[1]
        self.mask = pygame.mask.from_surface(self.image_file)
        self.lasers = []
        self.prev_tick = 0

    def move_lasers(self, vel):
        for laser in self.lasers:
            laser.move(vel)

    def draw(self, window):
        window.blit(self.image_file, (self.x, self.y))
        for laser in self.lasers:
            laser.draw(window)

    def remove_lasers(self):
        for laser in self.lasers:
            if laser.is_off_screen():
                self.lasers.remove(laser)

# player class
class PlayerShip(Ship):
    def move(self, keys):
        if keys[pygame.K_a] and self.x > 0:
            self.x -= player_move_by
        if keys[pygame.K_d] and self.x < WIDTH - self.image_file.get_width():
            self.x += player_move_by
        if keys[pygame.K_s] and self.y < HEIGHT - self.image_file.get_height():
            self.y += player_move_by
        if keys[pygame.K_w] and self.y > 0:
            self.y -= player_move_by

    def shoot(self, keys):
        if keys[pygame.K_SPACE] and pygame.time.get_ticks() - self.prev_tick >= laser_gap_player:
            x = int(self.x + (self.image_file.get_width() - self.laser_image_file.get_width()) / 2)
            y = self.y
            laser = Laser(x, y, self.laser_image_file)
            self.lasers.append(laser)
            self.prev_tick = pygame.time.get_ticks()

# enemy ship class
class EnemyShip(Ship):
    def move(self):
        self.y += enemy_move_by

    def is_off_screen(self):
        return self.y > HEIGHT - self.image_file.get_height()

    def shoot(self):
        if pygame.time.get_ticks() - self.prev_tick >= random.randrange(3500, 6000):
            x = self.x + int((self.image_file.get_width() - self.laser_image_file.get_width()) / 2)
            y = self.y + int(self.image_file.get_height())
            laser = Laser(x, y, self.laser_image_file)
            self.lasers.append(laser)
            self.prev_tick = pygame.time.get_ticks()

class Charger(Ship):
    def __init__(self, x, y, files):
        super().__init__(x, y, files)
        self.health = 100
        self.max_down = HEIGHT / 2 - 200
        self.max_left = 10
        self.max_right = WIDTH - self.image_file.get_width() - 10

    def move_down(self, vel):
        self.y += vel

    def move_left(self, vel):
        if self.x >= self.max_left:
            self.x -= vel

    def move_right(self, vel):
        if self.x <= self.max_right:
            self.x += vel

    def shoot(self):
        if pygame.time.get_ticks() - self.prev_tick >= laser_gap_charger:
            x = self.x + int((self.image_file.get_width() - self.laser_image_file.get_width()) / 2)
            y = self.y + int(self.image_file.get_height())
            laser_m = Laser(x, y, self.laser_image_file)
            laser_l = Laser(x-30, y, self.laser_image_file)
            laser_r = Laser(x+30, y, self.laser_image_file)
            self.lasers.append(laser_m)
            self.lasers.append(laser_l)
            self.lasers.append(laser_r)
            self.prev_tick = pygame.time.get_ticks()

# player ship and enemies
player = PlayerShip(player_init_x, player_init_y, tuple_files['player'])
enemies = []
charger = Charger(charger_init_x, charger_init_y, tuple_files['charger'])

# function to create enemies list
def create_enemies():
    enemy_list = []
    for i in range(level * 1):
        x = random.randrange(10, WIDTH - 50)
        y = random.randrange(-600, -100)
        enemy_object = EnemyShip(x, y, tuple_files[random.choice(['red', 'blue', 'green'])])
        enemy_list.append(enemy_object)
    return enemy_list

# function to check collision
def collides(obj1, obj2):
    offset_x = obj2.x - obj1.x
    offset_y = obj2.y - obj1.y
    return obj1.mask.overlap(obj2.mask, (offset_x, offset_y)) is not None

def boss_fight():
    global charger_move_left, lives, score

    if charger.x == charger.max_left:
        charger_move_left = False
    if charger.x == charger.max_right:
        charger_move_left = True

    if charger.y <= charger.max_down:
        charger.move_down(enemy_move_by)
    elif charger_move_left:
        charger.move_left(enemy_move_by)
    else:
        charger.move_right(enemy_move_by)

    charger.shoot()
    charger.move_lasers(laser_move_by)
    charger.remove_lasers()

    for laser in charger.lasers:
        if collides(player, laser):
            charger.lasers.remove(laser)
            if lives > 0:
                lives -= 1

    for laser in player.lasers:
        if collides(charger, laser):
            player.lasers.remove(laser)
            if charger.health > 0:
                charger.health -= 5

    if collides(charger, player):
        if lives > 0:
            lives -= 1
        if charger.health > 0:
            charger.health -= 5

# function to put items on root window
def put_items():
    global player, enemies, game_is_over, incoming_message
    # put the background
    root.blit(background_file, (0, 0))

    # put all enemy and lasers
    for enemy in enemies:
        enemy.draw(root)

    if level > LEVEL:
        if incoming_message == 0:
            incoming_message = pygame.time.get_ticks()
        elif pygame.time.get_ticks() - incoming_message <= 2000:
            incoming_message_label = main_font.render('Incoming Charger', 1, WHITE)
            x = int((WIDTH - incoming_message_label.get_width()) / 2)
            y = int((HEIGHT - incoming_message_label.get_height()) / 2)
            root.blit(incoming_message_label, (x, y))
        if charger.health > 0:
            charger.draw(root)

    # put the player and lasers
    player.draw(root)

    # put the scoreboard
    lives_label = main_font.render(f'Lives: {lives}', 1, WHITE)
    score_label = main_font.render(f'Score: {score}', 1, WHITE)
    if level <= LEVEL:
        level_label = main_font.render(f'Level: {level}', 1, WHITE)
    else:
        level_label = main_font.render(f'Charger: {charger.health}', 1, WHITE)

    root.blit(lives_label, (10, 10))
    root.blit(level_label, (WIDTH - level_label.get_width() - 10, 10))
    root.blit(score_label, (10, lives_label.get_height() + 20))

    # put game over label
    if lives == 0:
        collision_x = int(player.x - (collision_file.get_width() - player.image_file.get_width()) / 2)
        collision_y = int(player.y - (collision_file.get_height() - player.image_file.get_height()) / 2)
        root.blit(collision_file, (collision_x, collision_y))
        game_over_label = main_font.render('Game Over!', 1, WHITE)
        x = int((WIDTH - game_over_label.get_width()) / 2)
        y = int((HEIGHT - game_over_label.get_height()) / 2)
        root.blit(game_over_label, (x, y))
        game_is_over = True

    # put you win label
    if level > LEVEL and lives != 0 and charger.health == 0:
        collision_x = int(charger.x + (charger.image_file.get_width() - collision_file.get_width()) / 2)
        collision_y = int(charger.y - (collision_file.get_height() - charger.image_file.get_height()) / 2)
        root.blit(collision_file, (collision_x, collision_y))
        you_win_label = main_font.render('You Win!', 1, WHITE)
        x = int((WIDTH - you_win_label.get_width()) / 2)
        y = int((HEIGHT - you_win_label.get_height()) / 2)
        root.blit(you_win_label, (x, y))
        game_is_over = True

# driver function
def main():
    pygame.init()
    global lives, score, level, enemies, game_is_over

    while True:
        pygame.display.update()
        clock.tick(FPS)
        put_items()

        # check if quit is pressed
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                raise SystemExit

        if game_is_over:
            continue  # freeze the screen

        # move player based on key press
        player.move(pygame.key.get_pressed())  # if
        player.shoot(pygame.key.get_pressed())  # if
        player.move_lasers(-laser_move_by)

        # remove lasers from player
        player.remove_lasers()

        if level > LEVEL:
            boss_fight()
            continue

        # create enemies list
        if not enemies and level <= LEVEL:
            enemies = create_enemies()

        # move and remove all enemy
        for enemy in enemies:
            enemy.move()
            if enemy.is_off_screen():
                enemies.remove(enemy)
                if lives > 0:
                    lives -= 1

        # append lasers to enemy
        for enemy in enemies:
            enemy.shoot()  # if
            enemy.move_lasers(laser_move_by)
            enemy.remove_lasers()  # if

        # collision check player laser to enemy
        for laser in player.lasers:
            for enemy in enemies:
                if collides(enemy, laser):
                    player.lasers.remove(laser)
                    enemies.remove(enemy)
                    score += 5

        # collision check enemy, enemy laser to player
        for enemy in enemies:
            if collides(enemy, player):
                enemies.remove(enemy)
                if lives > 0:
                    lives -= 1
            for laser in enemy.lasers:
                if collides(player, laser):
                    enemy.lasers.remove(laser)
                    if lives > 0:
                        lives -= 1

        if not enemies and level <= LEVEL:
            level += 1

if __name__ == '__main__':
    main()


import tensorflow as tf
from module import Module

from math import ceil

from tensorflow.python.framework import ops
from tensorflow.python.framework import sparse_tensor
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import sparse_ops
from tensorflow.python.ops import nn_ops, gen_nn_ops

# 3D maxpooling 을 구현
# 기존의 코드에서 3Dmaxpooling을 추가로 구현
class MaxPool3D(Module):
    def __init__(self, pool_size=2, pool_stride=None, pad='SAME', name='maxpool3D'):
        self.name = name
        Module.__init__(self)
        self.pool_size = pool_size
        self.pool_kernel = [1, self.pool_size, self.pool_size, self.pool_size, 1]
        self.pool_stride = pool_stride
        if self.pool_stride is None:
            self.stride_size = self.pool_size
            self.pool_stride = [1, self.stride_size, self.stride_size, self.stride_size, 1]
        self.pad = pad

    def forward(self, input_tensor, batch_size=10, img_dim=28):
        self.input_tensor = input_tensor
        self.in_N, self.in_h, self.in_c, self.in_w, self.in_depth = self.input_tensor.get_shape().as_list()

        # with tf.variable_scope(self.name):
        with tf.name_scope(self.name):
            self.activations = tf.nn.max_pool3d(self.input_tensor, ksize=self.pool_kernel, strides=self.pool_stride,
                                              padding=self.pad, name=self.name)
            tf.summary.histogram('activations', self.activations)

        return self.activations

    def clean(self):
        self.activations = None
        self.R = None

    # LRP 상의 메모리 와 속도 문제를 해결하기 위해 기존의 코드를 수정 및 재구현
    # heatmapping.org의 tutorial에 나온 sudo코드 참조
    def _simple_lrp(self,R):
        '''
        LRP according to Eq(56) in DOI: 10.1371/journal.pone.0130140
        '''
        self.check_shape(R)

        in_N, in_h, in_w, in_c, in_depth = self.input_tensor.get_shape().as_list()
        Z = tf.nn.max_pool3d(self.input_tensor, ksize=self.pool_kernel, strides=self.pool_stride, padding='SAME') + 1e-9
        S = self.R / Z
        C = gen_nn_ops._max_pool3d_grad(self.input_tensor, Z, S, ksize=self.pool_kernel, strides=self.pool_stride, padding='SAME')
        result = self.input_tensor*C
        return result

    def _alphabeta_lrp(self, R, alpha):
        '''
        Since there is only one (or several equally strong) dominant activations, default to _simple_lrp
        '''
        return self._simple_lrp(R)

    def check_shape(self, R):
        self.R = R
        R_shape = self.R.get_shape().as_list()
        if len(R_shape) != 4:
            activations_shape = self.activations.get_shape().as_list()
            if R_shape[0] == 1:
                self.batchsize_to_one()
            else:
                self.R = tf.reshape(self.R, activations_shape)
        N, self.Hout, self.Wout, self.Cout, NF = self.R.get_shape().as_list()
        if R_shape[0] == 1:
            self.batchsize_to_one()

    def batchsize_to_one(self):
        self.input_tensor = self.input_tensor[0, :, :, :]
        self.input_tensor = tf.expand_dims(self.input_tensor, 0)
        self.activations = self.activations[0, :, :, :]
        self.activations = tf.expand_dims(self.activations, 0)

        activations_shape = self.activations.get_shape().as_list()
        self.R = tf.reshape(self.R,
                            [activations_shape[0], activations_shape[1], activations_shape[2], activations_shape[3], activations_shape[4]])
        self.in_N = 1;


#!/usr/bin/env python2
# vim:fileencoding=utf-8
from __future__ import (unicode_literals, division, absolute_import,
                        print_function)

__license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'

import httplib, zlib, json, binascii, time, os
from io import BytesIO

from calibre.ebooks.metadata.epub import get_metadata
from calibre.ebooks.metadata.opf2 import OPF
from calibre.srv.tests.base import LibraryBaseTest
from calibre.utils.imghdr import identify
from calibre.utils.shared_file import share_open

def setUpModule():
    # Needed for cover generation
    from calibre.gui2 import ensure_app, load_builtin_fonts
    ensure_app(), load_builtin_fonts()

class ContentTest(LibraryBaseTest):

    def test_static(self):  # {{{
        'Test serving of static content'
        with self.create_server() as server:
            conn = server.connect()

            def missing(url, body=b''):
                conn.request('GET', url)
                r = conn.getresponse()
                self.ae(r.status, httplib.NOT_FOUND)
                self.ae(r.read(), body)

            for prefix in ('static', 'icon'):
                missing('/%s/missing.xxx' % prefix)
                missing('/%s/../out.html' % prefix, b'Naughty, naughty!')
                missing('/%s/C:/out.html' % prefix, b'Naughty, naughty!')

            def test_response(r):
                self.assertIn(b'max-age=', r.getheader('Cache-Control'))
                self.assertIn(b'public', r.getheader('Cache-Control'))
                self.assertIsNotNone(r.getheader('Expires'))
                self.assertIsNotNone(r.getheader('ETag'))
                self.assertIsNotNone(r.getheader('Content-Type'))

            def test(src, url, sz=None):
                raw = P(src, data=True)
                conn.request('GET', url)
                r = conn.getresponse()
                self.ae(r.status, httplib.OK)
                data = r.read()
                if sz is None:
                    self.ae(data, raw)
                else:
                    self.ae(sz, identify(data)[1])
                test_response(r)
                conn.request('GET', url, headers={'If-None-Match':r.getheader('ETag')})
                r = conn.getresponse()
                self.ae(r.status, httplib.NOT_MODIFIED)
                self.ae(b'', r.read())

            test('content-server/empty.html', '/static/empty.html')
            test('images/lt.png', '/favicon.png')
            test('images/lt.png', '/icon/lt.png?sz=full')
            test('images/lt.png', '/icon/lt.png', sz=48)
            test('images/lt.png', '/icon/lt.png?sz=16', sz=16)
    # }}}

    def test_get(self):  # {{{
        'Test /get'
        with self.create_server() as server:
            db = server.handler.router.ctx.library_broker.get(None)
            conn = server.connect()

            def get(what, book_id, library_id=None, q=''):
                q = ('?' + q) if q else q
                conn.request('GET', '/get/%s/%s' % (what, book_id) + (('/' + library_id) if library_id else '') + q)
                r = conn.getresponse()
                return r, r.read()

            # Test various invalid parameters
            def bad(*args):
                r, data = get(*args)
                self.ae(r.status, httplib.NOT_FOUND)
            bad('xxx', 1)
            bad('fmt1', 10)
            bad('fmt1', 1, 'zzzz')
            bad('fmt1', 'xx')

            # Test simple fetching of format without metadata update
            r, data = get('fmt1', 1, db.server_library_id)
            self.ae(data, db.format(1, 'fmt1'))
            self.assertIsNotNone(r.getheader('Content-Disposition'))
            self.ae(r.getheader('Used-Cache'), 'no')
            r, data = get('fmt1', 1)
            self.ae(data, db.format(1, 'fmt1'))
            self.ae(r.getheader('Used-Cache'), 'yes')

            # Test fetching of format with metadata update
            raw = P('quick_start/eng.epub', data=True)
            r, data = get('epub', 1)
            self.ae(r.status, httplib.OK)
            etag = r.getheader('ETag')
            self.assertIsNotNone(etag)
            self.ae(r.getheader('Used-Cache'), 'no')
            self.assertTrue(data.startswith(b'PK'))
            self.assertGreaterEqual(len(data), len(raw))
            db.set_field('title', {1:'changed'})
            r, data = get('epub', 1)
            self.assertNotEqual(r.getheader('ETag'), etag)
            etag = r.getheader('ETag')
            self.ae(r.getheader('Used-Cache'), 'no')
            mi = get_metadata(BytesIO(data), extract_cover=False)
            self.ae(mi.title, 'changed')
            r, data = get('epub', 1)
            self.ae(r.getheader('Used-Cache'), 'yes')

            # Test plugboards
            import calibre.library.save_to_disk as c
            orig, c.DEBUG = c.DEBUG, False
            try:
                db.set_pref('plugboards', {u'epub': {u'content_server': [[u'changed, {title}', u'title']]}})
                # this is needed as the cache is not invalidated for plugboard changes
                db.set_field('title', {1:'again'})
                r, data = get('epub', 1)
                self.assertNotEqual(r.getheader('ETag'), etag)
                etag = r.getheader('ETag')
                self.ae(r.getheader('Used-Cache'), 'no')
                mi = get_metadata(BytesIO(data), extract_cover=False)
                self.ae(mi.title, 'changed, again')
            finally:
                c.DEBUG = orig

            # Test the serving of covers
            def change_cover(count, book_id=2):
                cpath = db.format_abspath(book_id, '__COVER_INTERNAL__')
                db.set_cover({2:I('lt.png', data=True)})
                t = time.time() + 1 + count
                # Ensure mtime changes, needed on OS X where HFS+ has a 1s
                # mtime resolution
                os.utime(cpath, (t, t))

            r, data = get('cover', 1)
            self.ae(r.status, httplib.OK)
            self.ae(data, db.cover(1))
            self.ae(r.getheader('Used-Cache'), 'no')
            self.ae(r.getheader('Content-Type'), 'image/jpeg')
            r, data = get('cover', 1)
            self.ae(r.status, httplib.OK)
            self.ae(data, db.cover(1))
            self.ae(r.getheader('Used-Cache'), 'yes')
            r, data = get('cover', 3)
            self.ae(r.status, httplib.OK)  # Auto generated cover
            r, data = get('thumb', 1)
            self.ae(r.status, httplib.OK)
            self.ae(identify(data), ('jpeg', 60, 60))
            self.ae(r.getheader('Used-Cache'), 'no')
            r, data = get('thumb', 1)
            self.ae(r.status, httplib.OK)
            self.ae(r.getheader('Used-Cache'), 'yes')
            r, data = get('thumb', 1, q='sz=100')
            self.ae(r.status, httplib.OK)
            self.ae(identify(data), ('jpeg', 100, 100))
            self.ae(r.getheader('Used-Cache'), 'no')
            r, data = get('thumb', 1, q='sz=100x100')
            self.ae(r.status, httplib.OK)
            self.ae(r.getheader('Used-Cache'), 'yes')
            change_cover(1, 1)
            r, data = get('thumb', 1, q='sz=100')
            self.ae(r.status, httplib.OK)
            self.ae(identify(data), ('jpeg', 100, 100))
            self.ae(r.getheader('Used-Cache'), 'no')

            # Test file sharing in cache
            r, data = get('cover', 2)
            self.ae(r.status, httplib.OK)
            self.ae(data, db.cover(2))
            self.ae(r.getheader('Used-Cache'), 'no')
            path = binascii.unhexlify(r.getheader('Tempfile')).decode('utf-8')
            f, fdata = share_open(path, 'rb'), data
            # Now force an update
            change_cover(1)
            r, data = get('cover', 2)
            self.ae(r.status, httplib.OK)
            self.ae(data, db.cover(2))
            self.ae(r.getheader('Used-Cache'), 'no')
            path = binascii.unhexlify(r.getheader('Tempfile')).decode('utf-8')
            f2, f2data = share_open(path, 'rb'), data
            # Do it again
            change_cover(2)
            r, data = get('cover', 2)
            self.ae(r.status, httplib.OK)
            self.ae(data, db.cover(2))
            self.ae(r.getheader('Used-Cache'), 'no')
            self.ae(f.read(), fdata)
            self.ae(f2.read(), f2data)

            # Test serving of metadata as opf
            r, data = get('opf', 1)
            self.ae(r.status, httplib.OK)
            self.ae(r.getheader('Content-Type'), 'application/oebps-package+xml; charset=UTF-8')
            self.assertIsNotNone(r.getheader('Last-Modified'))
            opf = OPF(BytesIO(data), populate_spine=False, try_to_guess_cover=False)
            self.ae(db.field_for('title', 1), opf.title)
            self.ae(db.field_for('authors', 1), tuple(opf.authors))
            conn.request('GET', '/get/opf/1', headers={'Accept-Encoding':'gzip'})
            r = conn.getresponse()
            self.ae(r.status, httplib.OK), self.ae(r.getheader('Content-Encoding'), 'gzip')
            raw = r.read()
            self.ae(zlib.decompress(raw, 16+zlib.MAX_WBITS), data)

            # Test serving metadata as json
            r, data = get('json', 1)
            self.ae(r.status, httplib.OK)
            self.ae(db.field_for('title', 1), json.loads(data)['title'])
            conn.request('GET', '/get/json/1', headers={'Accept-Encoding':'gzip'})
            r = conn.getresponse()
            self.ae(r.status, httplib.OK), self.ae(r.getheader('Content-Encoding'), 'gzip')
            raw = r.read()
            self.ae(zlib.decompress(raw, 16+zlib.MAX_WBITS), data)

    # }}}


import unittest

from project.shopping_cart import ShoppingCart

class ShoppingCartTest(unittest.TestCase):
    def setUp(self) -> None:
        self.shop = ShoppingCart("NewShop", 100)

    def test_initialization(self):
        self.assertEqual("NewShop", self.shop.shop_name)
        self.assertEqual(100, self.shop.budget)
        self.shop.products = {'Product1': 50}
        self.assertEqual({'Product1': 50}, self.shop.products)

    def test_new_shop_name_with_small_first_letter_raises_value_error(self):
        with self.assertRaises(ValueError) as ve:
            self.shop.shop_name = "newShop"
        expected = "Shop must contain only letters and must start with capital letter!"
        self.assertEqual(expected, str(ve.exception))
        self.assertEqual("NewShop", self.shop.shop_name)

    def test_new_shop_name_with_with_number_raises_value_error(self):
        with self.assertRaises(ValueError) as ve:
            self.shop.shop_name = "newShop1"
        expected = "Shop must contain only letters and must start with capital letter!"
        self.assertEqual(expected, str(ve.exception))
        self.assertEqual("NewShop", self.shop.shop_name)

    def test_add_to_cart_correct(self):
        expected = 'Product product was successfully added to the cart!'
        actual = self.shop.add_to_cart("Product", 50)
        self.assertEqual(expected, actual)
        self.assertEqual({'Product': 50}, self.shop.products)

    def test_add_to_cart_with_expensive_product_raises_value_error(self):
        with self.assertRaises(ValueError) as ve:
            self.shop.add_to_cart("Product", 100)
        expected = 'Product Product cost too much!'
        self.assertEqual(expected, str(ve.exception))
        self.assertEqual({}, self.shop.products)

    def test_remove_from_cart_correct(self):
        self.shop.add_to_cart("Product1", 50)
        self.shop.add_to_cart("Product2", 50)
        expected = 'Product Product1 was successfully removed from the cart!'
        actual = self.shop.remove_from_cart("Product1")
        self.assertEqual(expected, actual)
        self.assertEqual({"Product2": 50}, self.shop.products)

    def test_remove_from_cart_with_non_existing_product_raises_value_error(self):
        self.shop.add_to_cart("Product2", 50)
        with self.assertRaises(ValueError) as ve:
            self.shop.remove_from_cart("Product1")
        expected = 'No product with name Product1 in the cart!'
        self.assertEqual(expected, str(ve.exception))
        self.assertEqual({"Product2": 50}, self.shop.products)

    def test__add__correct(self):
        self.shop2 = ShoppingCart("OldShop", 100)
        self.shop.add_to_cart("Product1", 50)
        self.shop2.add_to_cart("Product2", 50)
        self.shop3 = self.shop.__add__(self.shop2)
        self.assertEqual('NewShopOldShop', self.shop3.shop_name)
        self.assertEqual(200, self.shop3.budget)
        self.assertEqual({"Product1":  50, "Product2": 50}, self.shop3.products)

    def test_buy_products_correct(self):
        self.shop.add_to_cart("Product1", 10)
        self.shop.add_to_cart("Product2", 20)
        expected = 'Products were successfully bought! Total cost: 30.00lv.'
        actual = self.shop.buy_products()
        self.assertEqual(expected, actual)

    def test_buy_products_with_smallest_budget_raises_value_error(self):
        self.shop.add_to_cart("Product1", 90)
        self.shop.add_to_cart("Product2", 20)
        with self.assertRaises(ValueError) as ve:
            self.shop.buy_products()
        expected = 'Not enough money to buy the products! Over budget with 10.00lv!'
        self.assertEqual(expected, str(ve.exception))


"""
Exercise No. 149

Implement a generator called enum() that works just like the enumerate() built-in function.

For simplicity, the function gets an iterable object and returns a tuple (index, element).

Example:

    [IN]: list(enum(['TEN', 'CDR', 'BBT']))
    [OUT]: [(0, 'TEN'), (1, 'CDR'), (2, 'BBT')]

Note! All you have to do is define a generator.
"""
# Solution I

def enum(iterable):
    for i, item in enumerate(iterable):
        yield i, item

print(list(enum(['TEN', 'CDR', 'BBT'])))

# Solution II
def enum(items):
    idx = 0
    for item in items:
        yield idx, item
        idx += 1

print(list(enum(['TEN', 'CDR', 'BBT'])))


from django.shortcuts import render
from django.shortcuts import HttpResponse
import multiprocessing
import pandas as pd
import numpy as np
import jieba
import yaml
# gensim:用于从原始的非结构化的文本中，无监督地学习到文本隐层的主题向量表达。
from gensim.corpora import Dictionary
from gensim.models import Word2Vec
from keras import Sequential
from keras.layers import Embedding, LSTM, Dropout, Dense, Activation, Bidirectional, Conv1D, GlobalMaxPooling1D
from keras.models import model_from_yaml
from keras.preprocessing import sequence
from sklearn.model_selection import train_test_split
from keras.utils import to_categorical
import matplotlib.pyplot as plt

vocab_dim = 100  # 是指特征向量的维度，默认为100。大的size需要更多的训练数据,但是效果会更好. 推荐值为几十到几百。
n_exposures = 10  # 可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5
window_size = 7  # 表示当前词与预测词在一个句子中的最大距离是多少
cpu_count = multiprocessing.cpu_count()  # 参数控制训练的并行数
n_iterations = 1  # 迭代次数，默认为5
max_len = 10
input_length = 100
batch_size = 32
n_epoch = 11  # 训练次数

# Create your views here.
evaluate = []

'''
* ━━━━━━神兽出没━━━━━━
* 　　　┏┓　　　┏┓
* 　　┏┛┻━━━┛┻┓
* 　　┃　　　　　　　┃
* 　　┃　　　━　　　┃
* 　　┃　┳┛　┗┳　┃
* 　　┃　　　　　　　┃
* 　　┃　　　┻　　　┃
* 　　┃　　　　　　　┃
* 　　┗━┓　　　┏━┛Code is far away from bug with the animal protecting
* 　　　　┃　　　┃ 神兽保佑,代码无bug
* 　　　　┃　　　┃
* 　　　　┃　　　┗━━━┓
* 　　　　┃　　　　　　　┣┓
* 　　　　┃　　　　　　　┏┛
* 　　　　┗┓┓┏━┳┓┏┛
* 　　　　　┃┫┫　┃┫┫
* 　　　　　┗┻┛　┗┻┛
*
* ━━━━━━感觉萌萌哒━━━━━━
'''

def index(request):
    category = ""
    classes = ""
    response = ""

    if request.method == "POST":
        sentence = request.POST.get("sentence", None)
        temp = {"value": sentence}
        evaluate.append(temp)
        s = lstm_predict(sentence)
        print(s)
        if s == 0:
            category = "积极"
            classes = "此评论是积极评论"
            response = "谢谢小主的支持"
        else:
            category = "消极"
            classes = "第"+str(s)+"类评论"
            if s == 1:
                classes = classes + "  吐槽内容"
                response = "内容不好，非常抱歉"
            elif s == 2:
                classes = classes + "  吐槽服务"
                response = "服务不好，非常抱歉"
            elif s == 3:
                classes = classes + "  吐槽质量"
                response = "质量不好，非常抱歉"
            elif s == 4:
                classes = classes + "  吐槽物流"
                response = "物流不好，非常抱歉"
            elif s == 5:
                classes = classes + "  吐槽价格"
                response = "价格不好，非常抱歉"
            elif s == 6:
                classes = classes + "  吐槽酒店服务"
                response = "酒店服务不好，非常抱歉"
            elif s == 7:
                classes = classes + "  吐槽酒店设施"
                response = "酒店设施不好，非常抱歉"
            elif s == 8:
                classes = classes + "  吐槽周边环境"
                response = "周边环境不好，非常抱歉"
            elif s == 9:
                classes = classes + "  吐槽酒店价格"
                response = "酒店价格不好，非常抱歉"
    return render(request, "index.html", {"classes": classes,
                                          "category": category,
                                          "response": response,
                                          "evaluate": evaluate})

# 加载文件
def loadfile():
    # 读取文件
    neg = pd.read_excel('../static/data/neg1.xlsx', sheet_name=0, header=None)
    pos = pd.read_excel('../static/data/pos1.xls', sheet_name=0, header=None, index=None)

    negative = np.delete(np.array(neg[0]), 0)
    # pos = pos[:600]
    # print(len(pos))
    label = np.concatenate((np.zeros(len(pos), dtype=int), negative))
    text = np.concatenate((np.array(pos[0]), np.delete(np.array(neg[1]), 0)))
    return label, text

# 对句子进行分词，并取掉换行
def tokenizer(text):
    """Simple Parser converting each document to lower-case, then
        removing the breaks for new lines and finally splitting on the
        whitespace
    """
    text = [jieba.lcut(document.replace('\n', '')) for document in text]
    return text

# 创建词语字典，并返回每个词语的索引，词向量，以及每个句子所对应的词语索引
def word2vec_train(text):
    # 建立一个空的模型对象
    model = Word2Vec(size=vocab_dim,
                     min_count=n_exposures,
                     window=window_size,
                     workers=cpu_count,
                     iter=n_iterations)
    # 遍历一次语料库建立词典
    model.build_vocab(text)
    # 第二次遍历语料库建立神经网络模型
    model.train(text, total_examples=model.corpus_count, epochs=model.epochs)
    # 查询结果训练可以通过model.save('fname')或model.save_word2vec_format(fname)来保存为文件
    model.save('../static/lstm_data/Word2vec_model.pkl')

    index_dict, word_vectors, text = create_dictionaries(model=model, text=text)
    return index_dict, word_vectors, text

# 创建词语字典，并返回每个词语的索引，词向量，以及每个句子所对应的词语索引
def create_dictionaries(model=None,
                        text=None):
    maxlen = 100  # 向量截断长度
    """Function does are number of Jobs:
            1- Creates a word to index mapping
            2- Creates a word to vector mapping
            3- Transforms the Training and Testing Dictionaries
    """
    if (text is not None) and model is not None:
        # 可以理解为python中的字典对象, 其Key是字典中的词，其Val是词对应的唯一数值型ID
        gensim_dict = Dictionary()

        # 函数doc2bow()只是计算每个唯一的词的出现频率，将词转化整型词id并且将结果作为稀疏向量返回
        gensim_dict.doc2bow(model.wv.vocab.keys(), allow_update=True)

        # 获取给定词的索引
        w2indx = {v: k + 1 for k, v in gensim_dict.items()}  # 所有词频数超过10的词语的索引  k->key v->value

        # 输出给定词的词向量
        w2vec = {word: model[word] for word in w2indx.keys()}  # 所有词频数超过10的词语的词向量

        # 文本变数字
        def parse_dataset(text):
            """
            Words become integers
            """
            data = []
            for sentence in text:
                # print(sentence) # 已经分词好的句子
                new_txt = []
                for word in sentence:
                    try:
                        # print(word)# 单个分词
                        new_txt.append(w2indx[word])
                        # print(w2indx[word]) # 索引
                    except:
                        new_txt.append(0)
                # print(new_txt) # 所有词向量
                data.append(new_txt)
            return data

        text = parse_dataset(text)

        # 将多个序列截断或补齐为相同长度
        text = sequence.pad_sequences(text, maxlen=maxlen)
        return w2indx, w2vec, text
    else:
        print('No data provide')

def get_data(index_dict, word_vectors, text, label):
    n_symbols = len(index_dict) + 1  # 所有单词的索引数，词频小于10的词语索引为0，所以加1
    # print(n_symbols) # 4683

    embedding_weights = np.zeros((n_symbols, vocab_dim))  # 索引为0的词语，词向量全为0
    # print(embedding_weights)

    for word, index in index_dict.items():  # 从索引为1的词语开始，对每个词语对应其词向量
        embedding_weights[index, :] = word_vectors[word]

    """
    随机划分训练集和测试集的函数
    参数：
    test_size：测试集大小。如果为浮点型，则在0.0-1.0之间，代表测试集的比例；如果为整数型，则为测试集样本的绝对数量；如果没有，则为训练集的补充。默认情况下，值为0.25 。此外，还与版本有关。
    train_size: 训练集大小。如果为浮点型，则在0.0-1.0之间，代表训练集的比例；如果为整数型，则为训练集样本的绝对数量；如果没有，则为测试集的补充。
    random_state：指定随机方式。一个整数或者RandomState实例，或者None 。如果为整数，则它指定了随机数生成器的种子；如果为RandomState实例，则指定了随机数生成器；如果为None，则使用默认的随机数生成器，随机选择一个种子
    shuffle：布尔值。是否在拆分前重组数据。如果shuffle=False，则stratify必须为None。
    stratify：array-like or None。如果不是None,则数据集以分层方式拆分，并使用此作为类标签。
    返回值：拆分得到的train和test数据集。
    """
    x_train, x_test, label_train, label_test = train_test_split(text, label, test_size=0.2, random_state=None)
    return n_symbols, embedding_weights, x_train, label_train, x_test, label_test

# 定义网络结构
def train_lstm(n_symbols, embedding_weights, text_train, label_train, text_test, label_test):
    print('Defining a simple Keras Model')
    kernel_size = 3
    filters = 250

    """
    顺序模型是多个网络层的线性堆叠。
    参数:
    input_dim：大或等于0的整数，字典长度，即输入数据最大下标+1
    output_dim：大于0的整数，代表全连接嵌入的维度
    embeddings_initializer: 嵌入矩阵的初始化方法，为预定义初始化方法名的字符串，或用于初始化权重的初始化器。参考initializers
    embeddings_regularizer: 嵌入矩阵的正则项，为Regularizer对象
    embeddings_constraint: 嵌入矩阵的约束项，为Constraints对象
    mask_zero：布尔值，确定是否将输入中的‘0’看作是应该被忽略的‘填充’（padding）值，该参数在使用递归层处理变长输入时有用。设置为True的话，模型中后续的层必须都支持masking，否则会抛出异常。如果该值为True，则下标0在字典中不可用，input_dim应设置为|vocabulary| + 1。
    input_length：当输入序列的长度固定时，该值为其长度。如果要在该层后接Flatten层，然后接Dense层，则必须指定该参数，否则Dense层的输出维度无法自动推断。
    """
    model = Sequential()  # or Graph or whatever
    model.add(Embedding(n_symbols, embedding_weights))        # 使用Embedding层将每个词编码转换为词向量
    model.add(Conv1D(filters,
                     kernel_size,
                     padding='valid',
                     activation='relu',
                     strides=1))
    # 池化
    model.add(GlobalMaxPooling1D())
    model.add(Dense(label_train.shape[1], activation='softmax'))  # 第一个参数units: 全连接层输出的维度，即下一层神经元的个数。
    model.add(Dropout(0.2))
    model.compile(loss='categorical_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])

    model.summary()

    # 本函数编译模型以供训练
    # binary_crossentropy二分类
    print('Compiling the Model...')
    model.compile(loss='categorical_crossentropy',  # 损失函数，为预定义损失函数名或一个目标函数
                  optimizer='rmsprop',              # 优化器，为预定义优化器名或优化器对象
                  metrics=['accuracy'])

    #  本函数用以训练模型
    #  参数：
    #  x_train输入数据
    #  y_train标签
    #  batch_size：整数，指定进行梯度下降时每个batch包含的样本数
    #  epochs：整数，训练终止时的epoch值，训练将在达到该epoch值时停止
    #  verbose：日志显示，0为不在标准输出流输出日志信息，1为输出进度条记录，2为每个epoch输出一行记录
    #  validation_data：形式为（X，y）或（X，y，sample_weights）的tuple，是指定的验证集。此参数将覆盖validation_spilt
    print("Train...")
    history = model.fit(text_train, label_train,
                        batch_size=batch_size,
                        epochs=n_epoch,
                        verbose=2,
                        validation_data=(text_test, label_test))

    """
    本函数按batch计算在某些输入数据上模型的误差
    参数
    x：输入数据，与fit一样，是numpy array或numpy array的list
    y：标签，numpy array
    batch_size：整数，含义同fit的同名参数
    verbose：含义同fit的同名参数，但只能取0或1
    sample_weight：numpy array，含义同fit的同名参数
    """
    print("Evaluate...")
    score = model.evaluate(text_test, label_test,
                           batch_size=batch_size)

    #  model.to_yaml() 以 YAML 字符串的形式返回模型的表示
    yaml_string = model.to_yaml()

    # python open() 函数用于打开一个文件，创建一个 file 对象，相关的方法才可以调用它进行读写
    with open('D:/javafile/Text_classify_test/static/lstm_data/lstm.yml', 'w') as outfile:
        outfile.write(yaml.dump(yaml_string, default_flow_style=True))

    #  model.save_weights(filepath) 将模型权重存储为 HDF5 文件
    model.save_weights('D:/javafile/Text_classify_test/static/lstm_data/lstm.h5')

    #  输出误差
    print(model.metrics_names)
    print('Test score:', score)

    # 绘制训练 & 验证的准确率值
    plt.plot(history.history['acc'])
    plt.plot(history.history['val_acc'])
    plt.title('Model accuracy')
    plt.ylabel('Accuracy')
    plt.xlabel('Epoch')
    plt.legend(['Train', 'Test'], loc='upper left')
    plt.show()

    # 绘制训练 & 验证的损失值
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model loss')
    plt.ylabel('Loss')
    plt.xlabel('Epoch')
    plt.legend(['Train', 'Test'], loc='upper left')
    plt.show()

# 训练模型，并保存
def train():
    print('Loading Data...')
    label, text = loadfile()

    """
    将类向量（整数）转换为二进制类矩阵
    参数：
    y: 需要转换成矩阵的类矢量 (从 0 到 num_classes 的整数)。
    num_classes: 总类别数。
    dtype: 字符串，输入所期望的数据类型 (float32, float64, int32...)
    """

    print('Tokenising...')
    text = tokenizer(text)

    print('Training a Word2vec model...')
    index_dict, word_vectors, text = word2vec_train(text)

    print('Setting up Arrays for Keras Embedding Layer...')
    n_symbols, embedding_weights, text_train, label_train, text_test, label_test \
        = get_data(index_dict, word_vectors, text, label)

    print(label_train)
    label_test = to_categorical(label_test)
    label_train = to_categorical(label_train)
    print(label_train.shape)
    print(label_train[0])

    train_lstm(n_symbols, embedding_weights, text_train, label_train, text_test, label_test)

def input_transform(string):
    words = jieba.lcut(string)
    words = np.array(words).reshape(1, -1)

    # 使用model.load(fname)或model.load_word2vec_format(fname,encoding='utf-8')读取查询结果
    model = Word2Vec.load('static/lstm_data/Word2vec_model.pkl')
    _, _, text = create_dictionaries(model, words)
    return text

# 执行结果
def lstm_predict(string):
    print('loading model......')
    with open('static/lstm_data/lstm.yml', 'r') as f:
        yaml_string = yaml.load(f, Loader=yaml.FullLoader)

    # 加载回来
    model = model_from_yaml(yaml_string)

    #  model.load_weights(filepath, by_name=False): 从 HDF5 文件（由 save_weights 创建）中加载权重
    print('loading weights......')
    model.load_weights('static/lstm_data/lstm.h5')
    model.compile(loss='categorical_crossentropy',
                  optimizer='adam', metrics=['accuracy'])
    data = input_transform(string)

    # 数组(2,2,-1)就是c的形状，一共有三阶，第三个数字是reshape后数组a中最小单元中元素个数，在这里是3，如果是-1则表示可以自动推测出
    data.reshape(1, -1)

    # print(data)
    # 本函数按batch产生输入数据的类别预测结果
    result = model.predict_classes(data)
    print(result)
    print(string, '：----》第', result[0], '类')
    return result[0]

if __name__ == '__main__':
    train()
    # loadfile()


from enum import Enum

class ChoiceEnum(Enum):
    @classmethod
    def choices(cls):
        return tuple((x.value, x.name) for x in cls)

class UserRole(ChoiceEnum):
    SUPER_ADMIN = 1
    INSTITUTION_MANAGER = 2
    STRENGTH_COACH = 3
    ATHLETE = 4

class TypeSubparameters(ChoiceEnum):
    NUM = 1
    NUMERIC_CATALOG = 2
    TIME = 3
    CHOICE = 4
    PERCENTAGE = 5
    CHARACTER_OF_EFFORT = 6
    PERCENTAGE_CATALOG = 7
    DECIMAL = 8

class TypeValueExersiceBlock(ChoiceEnum):
    WARMUP = 1
    FAILURE = 2
    DROPSET = 3
    DEFAULT = 4

class TypeQuestion(ChoiceEnum):
    TEXT = 1
    TIME = 2
    INTEGER = 3

class TypeSurvey(ChoiceEnum):
    PRE = 1
    POST = 2

class TypeSubcription(ChoiceEnum):
    TRIAL = 1
    PAYING = 2
    DEMOS = 3

class Currency(ChoiceEnum):
    EUR = 1
    USD = 2
    MXN = 3

class Gender(ChoiceEnum):
    FEMALE = 1
    MALE = 2
    OTHER = 3

class NivelsQuantityExercise(ChoiceEnum):
    Beginner = 0
    Intermediate = 9
    Advanced = 17
    Athlete = 25
    Elite  = 49


from distribution import *

class FilterModel:
    """ A general filter model """

    def __init__(self, X0: Distribution, V: NoiseDistribution, W: NoiseDistribution, f, F, h, H):
        self.xs = []
        self.ys = []
        self.k = 0

        self.X0 = X0
        self.f = f
        self.F = F
        self.h = h
        self.H = H

        # Generate x0
        self.x = X0.draw()
        self.y = None

        self.V = V
        self.W = W

        # Use the same truth
        self.sameTruth = False

    def generate(self):
        """
        Given self.x = x_k, generate x_{k+1} = x_k + v_k and y_k = x_k + w_k
        """

        # If the same truth is used, the same data is used...
        if self.sameTruth:
            random.seed(len(self.xs))
        self.x = self.f(self.x) + self.V.draw()

        # ... but different observations of the data are created
        if self.sameTruth:
            random.seed()
        self.y = self.h(self.x) + self.W.draw()

        # Save the data history
        self.xs.append(self.x)
        self.ys.append(self.y)

        self.k += 1

        return self.y

    @property
    def name(self):
        return 'Filter model'

class LinearFilterModel(FilterModel):
    """ A specific, linear filter model """

    def __init__(self, X0: Distribution, V: NoiseDistribution, W: NoiseDistribution, F, H):
        super().__init__(X0, V, W, lambda x: F * x, lambda _: F, lambda x: H * x, lambda _: H)

    @property
    def name(self):
        return 'Linear filter model'


# **Задачи на закрепление типов аргументов:
# 1.Написать функцию, которая принимает любое количество аргументов чисел.
# Среди них она находит максимальное и минимальное. И возвращает оба
def func_any_numb(*arg_s):
    """Возвращает минимальное и максимальное число"""
    x = min(arg_s)
    y = max(arg_s)
    return x, y

print(func_any_numb(1,2,3,4,5,123123,-123123,6,7,8))


import os
import copy
import logging

import numpy as np
import pandas as pd
from torchsummary.torchsummary import summary
from tqdm import tqdm
from matplotlib import pyplot as plt

import torch
import torch.utils.data
from torch.utils.tensorboard import SummaryWriter
from torch.optim.lr_scheduler import ReduceLROnPlateau as ReduceLROnPlateau

from config import ParseConfig
from utils import visualize_image
from utils import heatmap_loss
from activelearning import ActiveLearning
from dataloader import load_hp_dataset
from dataloader import Dataset_MPII_LSPET_LSP
from evaluation import PercentageCorrectKeypoint
from models.learning_loss.LearningLoss import LearnLossActive
from models.stacked_hourglass.StackedHourglass import PoseNet as Hourglass

# Global declarations
logging.getLogger().setLevel(logging.INFO)
os.chdir(os.path.dirname(os.path.realpath(__file__)))
logging.basicConfig(filename='test.log', level=logging.INFO, format='%(asctime)s::%(levelname)s::%(message)s')

class Train(object):
    def __init__(self, network, learnloss, hyperparameters, dataset_obj, conf, tb_writer):
        '''
        Class for training the model
        Training will train the Hourglass module

        :param network: (torch.nn) Hourglass model
        :param llal_ntwk: (torch.nn) Learning Loss model
        :param hyperparameters: (dict) Various hyperparameters used in training
        :param loc_object: (Object of LocalizationLoader) Controls the data fed into torch_dataloader
        :param model_save_path (string) The path directory where the training output will be logged.
        :param conf: (Object of ParseConfig) Contains the configurations for the model
        :param tb_writer: (Object of SummaryWriter) Tensorboard writer to log values
        :param wt_reg: (Bool) Whether to use weight regularization or not
        '''

        # Dataset Settings
        self.dataset_obj = dataset_obj
        self.tb_writer = tb_writer                                           # Tensorboard writer
        self.network = network                                               # Hourglass network
        self.batch_size = conf.batch_size
        self.epoch = hyperparameters['num_epochs']
        self.hyperparameters = hyperparameters
        self.model_save_path = conf.model_save_path
        self.optimizer = hyperparameters['optimizer']                        # Adam / SGD
        self.loss_fn = hyperparameters['loss_fn']                            # MSE
        self.learning_rate = hyperparameters['optimizer_config']['lr']
        self.start_epoch = hyperparameters['start_epoch']                    # Used in case of resume training
        self.num_hm = conf.num_hm                                            # Number of heatmaps
        self.joint_names = self.dataset_obj.ind_to_jnt
        self.hg_depth = 4                                                    # Depth of hourglass
        self.n_stack = conf.n_stack
        self.conf = conf

        self.train_learning_loss = conf.train_learning_loss
        self.learnloss_network = learnloss
        self.learnloss_margin = conf.learning_loss_margin
        self.learnloss_warmup = conf.learning_loss_warmup
        self.learnloss_original = conf.learning_loss_original
        self.learnloss_obj = conf.learning_loss_obj

        # Stacked Hourglass scheduling
        if self.train_learning_loss:
            min_lr = [0.000003, conf.lr]
        else:
            min_lr = 0.000003

        self.scheduler = ReduceLROnPlateau(self.optimizer, factor=0.5, patience=8, cooldown=2, min_lr=min_lr, verbose=True)

        self.torch_dataloader = torch.utils.data.DataLoader(self.dataset_obj, self.batch_size,
                                                            shuffle=True, num_workers=0, drop_last=True)

        if torch.cuda.device_count() > 1:
            cuda_devices = [torch.device('cuda:0'), torch.device('cuda:1')]
        else:
            cuda_devices = [torch.device('cuda:0'), torch.device('cuda:0')]

        self.cuda_devices = cuda_devices
        if conf.learnloss_only:
            self.train_hg_bool = torch.tensor(0.0).cuda(cuda_devices[-1])
        else:
            self.train_hg_bool = torch.tensor(1.0).cuda(cuda_devices[-1])

    def train_model(self):
        '''
        Training Loop: Hourglass and/or Learning Loss
        :return: None
        '''

        print("Initializing training: Epochs - {}\tBatch Size - {}".format(self.hyperparameters['num_epochs'],
                                                                           self.batch_size))

        best_val_hg = np.inf
        best_val_learnloss = np.inf
        best_epoch_hg = -1
        best_epoch_learnloss = -1
        global_step = 0

        # Variable to store all the loss values for logging
        loss_across_epochs = []
        validation_across_epochs = []

        for e in range(self.start_epoch, self.epoch):
            epoch_loss = []
            epoch_loss_learnloss = []

            # Network alternates between train() and validate()
            self.network.train()
            if self.train_learning_loss:
                self.learnloss_network.train()

            self.dataset_obj.input_dataset(train=True)

            # Training loop
            logging.info('Training for epoch: {}'.format(e+1))
            for (images, heatmaps, _, _, _, gt_per_image, split, _, _, _, joint_exist) in tqdm(self.torch_dataloader):

                assert split[0] == 0, "Training split should be 0."

                gt_per_image = gt_per_image.to(non_blocking=True, device=self.cuda_devices[-1])

                # Will clear the gradients of hourglass
                self.optimizer.zero_grad()
                outputs, hourglass_features = self.network(images)

                heatmaps = heatmaps.to(non_blocking=True, device=self.cuda_devices[-1])
                loss = heatmap_loss(outputs, heatmaps, self.n_stack)

                learning_loss_ = loss.clone().detach()
                learning_loss_ = torch.mean(learning_loss_, dim=[1])

                loss = (torch.mean(loss)) * self.train_hg_bool
                self.tb_writer.add_scalar('Train/Loss_batch', torch.mean(loss), global_step)

                loss.backward()

                # Train the learning loss network
                if self.train_learning_loss:
                    loss_learnloss = self.learning_loss(hourglass_features, learning_loss_, self.learnloss_margin, gt_per_image, e)
                    loss_learnloss.backward()
                    epoch_loss_learnloss.append(loss_learnloss.cpu().data.numpy())

                # Weight update
                self.optimizer.step()
                global_step += 1

                # Store the loss per batch
                epoch_loss.append(loss.cpu().data.numpy())

            epoch_loss = np.mean(epoch_loss)
            if self.train_learning_loss:
                epoch_loss_learnloss = np.mean(epoch_loss_learnloss)

            # Returns average validation loss per element
            if self.train_learning_loss:
                validation_loss_hg, validation_learning_loss = self.validation(e)
            else:
                validation_loss_hg = self.validation(e)
                validation_learning_loss = 0.0

            # Learning rate scheduler on the HourGlass validation loss
            self.scheduler.step(validation_loss_hg)

            # TensorBoard Summaries
            self.tb_writer.add_scalar('Train', torch.Tensor([epoch_loss]), global_step)
            self.tb_writer.add_scalar('Validation/HG_Loss', torch.Tensor([validation_loss_hg]), global_step)
            if self.train_learning_loss:
                self.tb_writer.add_scalar('Validation/Learning_Loss', torch.Tensor([validation_learning_loss]), global_step)

            # Save the model
            torch.save(self.network.state_dict(),
                       self.model_save_path.format("model_epoch_{}.pth".format(e + 1)))

            if self.train_learning_loss:
                torch.save(self.learnloss_network.state_dict(),
                           self.model_save_path.format("model_epoch_{}_learnloss.pth".format(e + 1)))

            # For resume training ONLY:
            # If learn_loss, then optimizer will have two param groups
            # Hence during load, ensure llal module is loaded/not loaded
            torch.save({'epoch': e + 1,
                        'optimizer_load_state_dict': self.optimizer.state_dict(),
                        'mean_loss': epoch_loss,
                        'mean_loss_validation': {'HG': validation_loss_hg, 'LearningLoss': validation_learning_loss},
                        'learn_loss': self.train_learning_loss},
                        self.model_save_path.format("optim_epoch_{}.tar".format(e + 1)))

            # Save if best model
            if best_val_hg > validation_loss_hg:
                torch.save(self.network.state_dict(),
                           self.model_save_path.format("best_model.pth"))

                torch.save(self.learnloss_network.state_dict(),
                           self.model_save_path.format("best_model_learnloss_hg.pth"))

                best_val_hg = validation_loss_hg
                best_epoch_hg = e + 1

                torch.save({'epoch': e + 1,
                            'optimizer_load_state_dict': self.optimizer.state_dict(),
                            'mean_loss_train': epoch_loss,
                            'mean_loss_validation': {'HG': validation_loss_hg, 'LearningLoss': validation_learning_loss},
                            'learn_loss': self.train_learning_loss},
                           self.model_save_path.format("optim_best_model.tar"))

            if self.train_learning_loss:
                if best_val_learnloss > validation_learning_loss and validation_learning_loss != 0.0:
                    torch.save(self.learnloss_network.state_dict(),
                               self.model_save_path.format("best_model_learnloss_{}.pth".format(self.learnloss_obj)))

                    best_val_learnloss = validation_learning_loss
                    best_epoch_learnloss = e + 1

            print("Loss at epoch {}/{}: (train) {}\t"
                  "Learning Loss: (train) {}\t"
                  "(validation: HG) {}\t"
                  "(Validation: Learning Loss) {}\t"
                  "(Best Model) {}".format(
                e+1,
                self.epoch,
                epoch_loss,
                epoch_loss_learnloss,
                validation_loss_hg,
                validation_learning_loss,
                best_epoch_hg))

            loss_across_epochs.append(epoch_loss)
            validation_across_epochs.append(validation_loss_hg)

            # Save the loss values
            f = open(self.model_save_path.format("loss_data.txt"), "w")
            f_ = open(self.model_save_path.format("validation_data.txt"), "w")
            f.write("\n".join([str(lsx) for lsx in loss_across_epochs]))
            f_.write("\n".join([str(lsx) for lsx in validation_across_epochs]))
            f.close()
            f_.close()

            # metric_obj = Metric(network=self.network, dataset_obj=self.dataset_obj, conf=self.conf)
            # print("I read the model!")
            # metric_obj.eval()

        self.tb_writer.close()
        logging.info("Model training completed\nBest validation loss (HG): {}\tBest Epoch: {}"
                     "\nBest validation loss (LLAL): {}\tBest Epoch: {}".format(
            best_val_hg, best_epoch_hg, best_val_learnloss, best_epoch_learnloss))

    def validation(self, e):
        '''
        Validation loss
        :param e: (int) Epoch
        :return: (Float): Mean validation loss per batch for Hourglass and Learning Loss (if LL activated in inc_config file.)
        '''
        with torch.no_grad():
            # Stores the loss for all batches
            epoch_val_hg = []

            if self.train_learning_loss:
                epoch_val_learnloss = []

            self.network.eval()
            if self.train_learning_loss:
                self.learnloss_network.eval()

            # Augmentation only needed in Training
            self.dataset_obj.input_dataset(validate=True)

            # Compute and store batch-wise validation loss in a list
            logging.info('Validation for epoch: {}'.format(e+1))
            for (images, heatmaps, _, _, _, gt_per_img, split, _, _, _, joint_exist) in tqdm(self.torch_dataloader):

                assert split[0] == 1, "Validation split should be 1."

                gt_per_img = gt_per_img.to(non_blocking=True, device=self.cuda_devices[-1])

                outputs, hourglass_features = self.network(images)

                heatmaps = heatmaps.to(non_blocking=True, device=self.cuda_devices[-1])

                loss_val_hg = heatmap_loss(outputs, heatmaps, self.n_stack)

                learning_loss_val = loss_val_hg.clone().detach()
                learning_loss_val = torch.mean(learning_loss_val, dim=[1])

                loss_val_hg = torch.mean(loss_val_hg)
                epoch_val_hg.append(loss_val_hg.cpu().data.numpy())

                if self.train_learning_loss:
                    loss_val_learnloss = self.learning_loss(hourglass_features, learning_loss_val, self.learnloss_margin, gt_per_img, e)
                    epoch_val_learnloss.append(loss_val_learnloss.cpu().data.numpy())

            print("Validation Loss HG at epoch {}/{}: {}".format(e+1, self.epoch, np.mean(epoch_val_hg)))

            if self.train_learning_loss:
                print("Validation Learning Loss at epoch {}/{}: {}".format(e+1, self.epoch, np.mean(epoch_val_learnloss)))
                return np.mean(epoch_val_hg), np.mean(epoch_val_learnloss)

            else:
                return np.mean(epoch_val_hg)

    def learning_loss(self, hg_encodings, true_loss, margin, gt_per_img, epoch):
        '''
        Learning Loss module
        Refer:
        1. "Learning Loss For Active Learning, CVPR 2019"
        2. "A Mathematical Analysis of Learning Loss for Active Learning in Regression, CVPRW 2021"

        :param hg_encodings: (Dict of tensors) Intermediate (Hourglass) and penultimate layer output of the Hourglass network
        :param true_loss: (Tensor of shape [Batch Size]) Loss computed from HG prediction and ground truth
        :param margin: (scalar) tolerance margin between predicted losses
        :param gt_per_img: (Tensor, shape [Batch Size]) Number of ground truth per image
        :param epoch: (scalar) Epoch, used in learning loss warm start-up
        :return: (Torch scalar tensor) Learning Loss
        '''

        # Concatenate the layers instead of a linear combination
        with torch.no_grad():
            if self.learnloss_original:
                # hg_depth == 4 means depth is {1, 2, 3, 4}. If we want depth 5, range --> (1, 4+2)
                # encodings = torch.cat([hg_encodings[depth] for depth in range(1, self.hg_depth + 2)], dim=-1)
                encodings = hg_encodings['penultimate']

            else:
                # No longer concatenating, will now combine features through convolutional layers
                encodings = torch.cat([hg_encodings['feature_5'].reshape(self.batch_size, hg_encodings['feature_5'].shape[1], -1),               # 64 x 64
                                       hg_encodings['feature_4'].reshape(self.batch_size, hg_encodings['feature_4'].shape[1], -1),               # 32 x 32
                                       hg_encodings['feature_3'].reshape(self.batch_size, hg_encodings['feature_3'].shape[1], -1),               # 16 x 16
                                       hg_encodings['feature_2'].reshape(self.batch_size, hg_encodings['feature_2'].shape[1], -1),               # 8 x 8
                                       hg_encodings['feature_1'].reshape(self.batch_size, hg_encodings['feature_1'].shape[1], -1)], dim=2)       # 4 x 4

        emperical_loss, encodings = self.learnloss_network(encodings)
        emperical_loss = emperical_loss.squeeze()

        assert emperical_loss.shape == true_loss.shape, "Mismatch in Batch size for true and emperical loss"

        with torch.no_grad():
            # Scale the images as per the number of joints
            # To prevent DivideByZero. PyTorch does not throw an exception to DivideByZero
            gt_per_img = torch.sum(gt_per_img, dim=1)
            gt_per_img += 0.1
            if self.learnloss_obj == 'prob':
                true_loss = true_loss / gt_per_img

            # Splitting into pairs: (i, i+half)
            half_split = true_loss.shape[0] // 2

            true_loss_i = true_loss[: half_split]
            true_loss_j = true_loss[half_split: 2 * half_split]

        emp_loss_i = emperical_loss[: (emperical_loss.shape[0] // 2)]
        emp_loss_j = emperical_loss[(emperical_loss.shape[0] // 2): 2 * (emperical_loss.shape[0] // 2)]

        # Loss according to CVPR '19
        if self.learnloss_obj == 'pair':
            loss_sign = torch.sign(true_loss_i - true_loss_j)
            loss_emp = (emp_loss_i - emp_loss_j)

            # Learning Loss objective
            llal_loss = torch.max(torch.zeros(half_split, device=loss_sign.device), (-1 * (loss_sign * loss_emp)) + margin)

        # Loss according to CVPR '21
        elif self.learnloss_obj == 'prob':
            with torch.no_grad():
                true_loss_ = torch.cat([true_loss_i.reshape(-1, 1), true_loss_j.reshape(-1, 1)], dim=1)
                true_loss_scaled = true_loss_ / torch.sum(true_loss_, dim=1, keepdim=True)

            emp_loss_ = torch.cat([emp_loss_i.reshape(-1, 1), emp_loss_j.reshape(-1, 1)], dim=1)
            emp_loss_logsftmx = torch.nn.LogSoftmax(dim=1)(emp_loss_)
            llal_loss = torch.nn.KLDivLoss(reduction='batchmean')(input=emp_loss_logsftmx, target=true_loss_scaled)

        else:
            raise NotImplementedError('Currently only "pair" or "prob" supported. ')

        if self.learnloss_warmup <= epoch:
            return torch.mean(llal_loss)
        else:
            return 0.0 * torch.mean(llal_loss)

class Metric(object):
    def __init__(self, network, dataset_obj, conf):
        '''
        Class for Testing the model:
            1. Compute ground truth and predictions
            2. Computing metrics: PCK@0.x
        :param network: (torch.nn) Hourglass network to compute predictions
        :param dataset_obj: (Dataset object) Handles data to be fed to PyTorch DataLoader
        :param conf: (Object of ParseConfig) Configuration for the experiment
        '''

        self.dataset_obj = dataset_obj
        self.dataset_obj.input_dataset(validate=True)

        self.network = network
        self.model_save_path = conf.model_save_path
        self.viz=conf.args['misc']['viz']                         # Controls visualization
        self.conf = conf
        self.epoch = conf.model_load_epoch

        self.ind_to_jnt = {0: 'head', 1: 'neck', 2: 'lsho', 3: 'lelb', 4: 'lwri', 5: 'rsho', 6: 'relb', 7: 'rwri',
                           8: 'lhip', 9: 'lknee', 10: 'lankl', 11: 'rhip', 12: 'rknee', 13: 'rankl'}

        if conf.num_hm == 16:
            self.ind_to_jnt[14] = 'pelvis'
            self.ind_to_jnt[15] = 'thorax'

        self.torch_dataloader = torch.utils.data.DataLoader(self.dataset_obj, conf.batch_size, shuffle=False,
                                                            num_workers=0)

    def inference(self):
        '''
        Returns model inferences
        :return: (dict) images, heatmaps and other information to obtain U, V
        '''

        self.network.eval()
        logging.info("Starting model inference")

        image_ = None
        outputs_ = None
        scale_ = None
        num_gt_ = None
        dataset_ = None
        name_ = None
        gt_ = None
        normalizer_ = None

        with torch.no_grad():
            for (images, _, gt, name, dataset, num_gt, split, _, scale_params, normalizer, joint_exist) in tqdm(
                    self.torch_dataloader):

                assert split[0] == 1, "Validation split should be 1."

                outputs, hourglass_features = self.network(images)
                outputs = outputs[:, -1].detach()

                try:
                    image_ = torch.cat((image_, images.clone()), dim=0)
                    outputs_ = torch.cat((outputs_, outputs.cpu().clone()), dim=0)
                    scale_['scale_factor'] = torch.cat((scale_['scale_factor'], scale_params['scale_factor']), dim=0)
                    scale_['padding_u'] = torch.cat((scale_['padding_u'], scale_params['padding_u']), dim=0)
                    scale_['padding_v'] = torch.cat((scale_['padding_v'], scale_params['padding_v']), dim=0)
                    num_gt_ = torch.cat((num_gt_, num_gt), dim=0)
                    dataset_ = dataset_ + dataset
                    name_ = name_ + name
                    gt_ = torch.cat((gt_, gt), dim=0)
                    normalizer_ = torch.cat((normalizer_, normalizer), dim=0)

                except TypeError:
                    image_ = images.clone()
                    outputs_ = outputs.cpu().clone()
                    scale_ = copy.deepcopy(scale_params)
                    num_gt_ = num_gt
                    dataset_ = dataset
                    name_ = name
                    gt_ = gt
                    normalizer_ = normalizer

                del images, outputs

        #     import pickle
        #     with open('output.pickle', 'wb') as handle1:
        #         pickle.dump(outputs_.numpy(), handle1, protocol=pickle.HIGHEST_PROTOCOL) # for Run_Base2

        #     with open('gt.pickle', 'wb') as handle2:
        #         pickle.dump(gt_.numpy(), handle2, protocol=pickle.HIGHEST_PROTOCOL) # for Run_Base2

        # with open('output_numpy.pickle', 'wb') as handle3:
        #     pickle.dump(outputs_.numpy(), handle3, protocol=pickle.HIGHEST_PROTOCOL) # for Run_Base2

        # with open('output_numpy.pickle', 'wb') as handle4:
        #     pickle.dump(gt_.numpy(), handle4, protocol=pickle.HIGHEST_PROTOCOL) # for Run_Base2

        scale_['scale_factor'] = scale_['scale_factor'].numpy()
        scale_['padding_u'] = scale_['padding_u'].numpy()
        scale_['padding_v'] = scale_['padding_v'].numpy()

        model_inference = {'image': image_.numpy(), 'heatmap': outputs_.numpy(),
                           'scale': scale_, 'num_gt': num_gt_, 'dataset': dataset_,
                           'name': name_, 'gt': gt_.numpy(), 'normalizer': normalizer_.numpy()}

        # import pickle
        # with open('model_pickle_1.pickle', 'wb') as handle:
        #     pickle.dump(model_inference, handle, protocol=pickle.HIGHEST_PROTOCOL) # 都是0 for run_Base1實驗

        return model_inference

    def keypoint(self, infer):
        '''
        Scales the joints from heatmap to actual U, V on unscaled image
        Returns ground truth and predictions CSV
        :param infer: (dict) Dictionary returned by inference
        :return: (pd.DataFrame, pd.DataFrame) GT and Pred CSV
        '''

        image = infer['image']
        heatmap = infer['heatmap']
        scale = infer['scale']
        dataset = infer['dataset']
        name = infer['name']
        gt = infer['gt']
        normalizer = infer['normalizer']

        hm_uv_stack = []

        csv_columns = ['name', 'dataset', 'normalizer', 'joint', 'uv']

        gt_csv = []
        pred_csv = []

        # Iterate over all heatmaps to obtain predictions
        for i in range(image.shape[0]):

            heatmap_ = heatmap[i]

            gt_uv = gt[i]
            hm_uv = self.dataset_obj.estimate_uv(hm_array=heatmap_, pred_placeholder=-np.ones_like(gt_uv))
            hm_uv_stack.append(hm_uv)

            # Scaling the point ensures that the distance between gt and pred is same as the scale of normalization
            scale_factor = scale['scale_factor'][i]
            padding_u = scale['padding_u'][i]
            padding_v = scale['padding_v'][i]

            # Scaling ground truth
            gt_uv_correct = np.copy(gt_uv)
            hm_uv_correct = np.copy(hm_uv)

            gt_uv_correct[:, :, 1] -= padding_v
            gt_uv_correct[:, :, 0] -= padding_u
            gt_uv_correct /= np.array([scale_factor, scale_factor, 1]).reshape(1, 1, 3)

            # Scaling predictions
            hm_uv_correct[:, :, 1] -= padding_v
            hm_uv_correct[:, :, 0] -= padding_u
            hm_uv_correct /= np.array([scale_factor, scale_factor, 1]).reshape(1, 1, 3)

            assert gt_uv_correct.shape == hm_uv_correct.shape, "Mismatch in gt ({}) and prediction ({}) shape".format(
                gt_uv_correct.shape, hm_uv_correct.shape)

            # Iterate over joints
            for jnt in range(gt_uv_correct.shape[1]):
                gt_entry = {
                    'name': name[i],
                    'dataset': dataset[i],
                    'normalizer': normalizer[i],
                    'joint': self.ind_to_jnt[jnt],
                    'uv': gt_uv_correct[:, jnt, :].astype(np.float32)
                }

                pred_entry = {
                    'name': name[i],
                    'dataset': dataset[i],
                    'normalizer': normalizer[i],
                    'joint': self.ind_to_jnt[jnt],
                    'uv': hm_uv_correct[:, jnt, :].astype(np.float32)
                }

                gt_csv.append(gt_entry)
                pred_csv.append(pred_entry)

        # Visualize images on the 256, 256 images
        if self.viz:
            hm_uv = np.stack(hm_uv_stack, axis=0)
            self.visualize_predictions(image=image, name=name, dataset=dataset, gt=gt, pred=hm_uv)

        pred_csv = pd.DataFrame(pred_csv, columns=csv_columns)
        gt_csv = pd.DataFrame(gt_csv, columns=csv_columns)

        pred_csv.sort_values(by='dataset', ascending=True, inplace=True)
        gt_csv.sort_values(by='dataset', ascending=True, inplace=True)

        assert len(pred_csv.index) == len(gt_csv.index), "Mismatch in number of entries in pred and gt dataframes."

        pred_csv.to_csv(self.model_save_path.format("pred.csv"), index=False)
        gt_csv.to_csv(self.model_save_path.format("gt.csv"), index=False)
        logging.info('Pandas dataframe saved successfully.')

        return gt_csv, pred_csv

    def visualize_predictions(self, image=None, name=None, dataset=None, gt=None, pred=None):
        """
        Helper function to visualize predictions
        """
        dataset_viz = {}
        dataset_viz['img'] = image
        dataset_viz['name'] = name
        dataset_viz['split'] = np.ones(image.shape[0])
        dataset_viz['dataset'] = dataset
        dataset_viz['bbox_coords'] = np.zeros([image.shape[0], 4, 4])
        dataset_viz['num_persons'] = np.ones([image.shape[0], 1])
        dataset_viz['gt'] = gt
        dataset_viz['pred'] = pred

        dataset_viz = self.dataset_obj.recreate_images(gt=True, pred=True, external=True, ext_data=dataset_viz)
        visualize_image(dataset_viz, bbox=False, uv=True)

        return None

    def compute_metrics(self, gt_df=None, pred_df=None):
        '''
        Loads the ground truth and prediction CSVs into memory.
        Evaluates Precision, FPFN metrics for the prediction and stores them into memory.
        :return: None
        '''

        # Ensure that same datasets have been loaded
        assert all(pred_df['dataset'].unique() == gt_df['dataset'].unique()), \
            "Mismatch in dataset column for gt and pred"

        logging.info('Generating evaluation metrics for dataset:')
        # Iterate over unique datasets
        for dataset_ in gt_df['dataset'].unique():
            logging.info(str(dataset_))

            # Separate out images based on dataset
            pred_ = pred_df.loc[pred_df['dataset'] == dataset_]
            gt_ = gt_df.loc[gt_df['dataset'] == dataset_]

            # Compute scores
            pck_df = PercentageCorrectKeypoint(pred_df=pred_, gt_df=gt_, config=self.conf,
                                               jnts=list(self.ind_to_jnt.values()), data_name=dataset_)

            # Save the tables
            if dataset_ == 'mpii':
                metric_ = 'PCKh'
            else:
                metric_ = 'PCK'

            pck_df.to_csv(self.model_save_path.format("{}_{}.csv".format(metric_, dataset_)), index=False)

        print("Metrics computation completed.")

    def eval(self):
        '''
        Control flow to obtain predictions and corresponding metrics from Test()
        '''
        model_inference = self.inference()
        gt_csv, pred_csv = self.keypoint(model_inference)
        self.compute_metrics(gt_df=gt_csv, pred_df=pred_csv)

def config():
    conf = ParseConfig()

    if conf.success:
        logging.info('Successfully loaded config')
    else:
        logging.warn('Could not load configuration! Exiting.')
        exit()

    return conf

def load_models(conf=None, load_hg=True, load_learnloss=True, best_model=None, hg_param=None, model_dir=None):
    '''
    Initialize or load model(s): Hourglass, Learning Loss network

    :param conf: (Object of type ParseConfig) Contains the configuration for the experiment
    :param load_hg: (bool) Load Hourglass network
    :param load_learnloss: (bool) Load learning Loss network
    :param best_model: (bool) Load best model
    :param hg_param: (recheck type) Parameters for the Hourglass network
    :param model_dir: (string) Directory containing the model
    :return: (torch.nn x 2) Hourglass network, Learning Loss network
    '''

    epoch = conf.model_load_epoch

    # Learn Loss model - Load or train from scratch, will be defined even if not needed
    if load_learnloss:
        logging.info('Loading Learning Loss model from: ' + model_dir)
        learnloss_ = LearnLossActive(conf.learning_loss_fc, conf.args['hourglass']['inp_dim'], 4,
                                     conf.learning_loss_original)

        if best_model:
            if conf.resume_training:
                path_ = '_hg'  # *_hg will be the Learning Loss model at the epoch where HG gave best results
            else:
                path_ = ''  # best Learning Loss model
            learnloss_.load_state_dict(torch.load(
                model_dir
                + 'model_checkpoints/best_model_learnloss_{}'.format(conf.learning_loss_obj)
                + path_
                + '.pth', map_location='cpu'))
        else:
            learnloss_.load_state_dict(torch.load(model_dir + 'model_checkpoints/model_epoch_{}_learnloss.pth'.format(epoch), map_location='cpu'))
    else:
        logging.info('Defining the Learning Loss module. Training from scratch!')
        learnloss_ = LearnLossActive(conf.learning_loss_fc, conf.args['hourglass']['inp_dim'], 4,
                                     conf.learning_loss_original)

    # Hourglass MODEL - Load or train from scratch
    if load_hg:
        # Load model
        logging.info('Loading Hourglass model from: ' + model_dir)
        net_ = Hourglass(nstack=hg_param['nstack'], inp_dim=hg_param['inp_dim'], oup_dim=hg_param['oup_dim'],
                         bn=hg_param['bn'], increase=hg_param['increase'])

        if best_model:
            net_.load_state_dict(torch.load(os.path.join(model_dir, 'model_checkpoints/best_model.pth'), map_location='cpu'))
            logging.info("Successfully loaded Model(0929)")
        else:
            net_.load_state_dict(torch.load(os.path.join(model_dir, 'model_checkpoints/model_epoch_{}.pth'.format(epoch)), map_location='cpu'))

        logging.info("Successfully loaded Model")

    else:
        # Define model and train from scratch
        logging.info('Defining the network - Stacked Hourglass. Training from scratch!')
        net_ = Hourglass(nstack=hg_param['nstack'], inp_dim=hg_param['inp_dim'], oup_dim=hg_param['oup_dim'],
                         bn=hg_param['bn'], increase=hg_param['increase'])

    # Multi-GPU / Single GPU
    logging.info("Using " + str(torch.cuda.device_count()) + " GPUs")
    net = net_
    learnloss = learnloss_

    if torch.cuda.device_count() > 1:
        # Hourglass net has cuda definitions inside __init__(), specify for learnloss
        learnloss.cuda(torch.device('cuda:1'))
    else:
        # Hourglass net has cuda definitions inside __init__(), specify for learnloss
        learnloss.cuda(torch.device('cuda:0'))
    logging.info('Successful: Model transferred to GPUs.')

    return net, learnloss

def define_hyperparams(conf, net, learnloss):
    '''
    Defines the hyperparameters of the experiment

    :param conf: (Object of type ParseConfig) Contains the configuration for the experiment
    :param net: (torch.nn) HG model
    :return: (dict) hyperparameter dictionary
    '''
    logging.info('Initializing the hyperparameters for the experiment.')
    hyperparameters = dict()
    hyperparameters['optimizer_config'] = {
                                           'lr': conf.lr,
                                           'weight_decay': conf.weight_decay
                                          }
    hyperparameters['loss_params'] = {'size_average': True}
    hyperparameters['num_epochs'] = conf.epochs
    hyperparameters['start_epoch'] = 0  # Used for resume training

    # Parameters declared to the optimizer
    if conf.train_learning_loss:
        logging.info('Parameters of Learning Loss and Hourglass networks passed to Optimizer.')
        params_list = [{'params': net.parameters()},
                       {'params': learnloss.parameters()}]
    else:
        logging.info('Parameters of Hourglass passed to Optimizer')
        params_list = [{'params': net.parameters()}]

    hyperparameters['optimizer'] = torch.optim.Adam(params_list, **hyperparameters['optimizer_config'])

    if conf.resume_training:
        logging.info('Loading optimizer state dictionary')
        if conf.best_model:
            optim_dict = torch.load(conf.model_load_path + 'model_checkpoints/optim_best_model.tar')

        else:
            assert type(conf.model_load_epoch) == int, "Load epoch for optimizer not specified"
            optim_dict = torch.load(conf.model_load_path + 'model_checkpoints/optim_epoch_{}.tar'.format(
                conf.model_load_epoch))

        # If the previous experiment used learn_loss, ensure the llal model is loaded, with the correct optimizer
        assert optim_dict['learn_loss'] == conf.model_load_learnloss, "Learning Loss model needed to resume training"

        hyperparameters['optimizer'].load_state_dict(optim_dict['optimizer_load_state_dict'])
        logging.info('Optimizer state loaded successfully.\n')

        logging.info('Optimizer and Training parameters:\n')
        for key in optim_dict:
            if key == 'optimizer_load_state_dict':
                logging.info('Param group length: {}'.format(len(optim_dict[key]['param_groups'])))
            else:
                logging.info('Key: {}\tValue: {}'.format(key, optim_dict[key]))

        logging.info('\n')

        if conf.resume_training:
            hyperparameters['start_epoch'] = optim_dict['epoch']

    hyperparameters['loss_fn'] = torch.nn.MSELoss(reduction='none')

    return hyperparameters

def debug_viz(data_obj):
    '''
    Small code snippet to visualize heatmaps
    :return:
    '''
    for i in range(30, 40):
        _, hm, _, _, _, _, _, _, _ = data_obj.__getitem__(i)
        fig, ax = plt.subplots(3, 5)
        for j in range(hm.shape[0]):
            ax[j // 5, j % 5].imshow(hm[j])
            ax[j // 5, j % 5].set_title('Joint: {}'.format(j))
        plt.show()

def main():
    '''

    :return:
    '''
    # Load configuration file
    conf  = config()
    args = conf.args

    # Loading MPII, LSPET
    logging.info('Loading MPII, LSPET, LSP')
    mpii_dict, max_persons_in_mpii = load_hp_dataset(mpii=True, conf=conf)
    lspet_dict = load_hp_dataset(lspet=True, conf=conf)
    lsp_dict = load_hp_dataset(lsp=True, conf=conf)
    args['mpii_params']['max_persons'] = max_persons_in_mpii

    # Defining the network
    hg_param = args['hourglass']
    network, learnloss = load_models(conf=conf, load_hg=conf.model_load_hg, load_learnloss=conf.model_load_learnloss,
                                     best_model=conf.best_model, hg_param=hg_param, model_dir=conf.model_load_path)

    # Defining the Active Learning library
    active_learning_obj = ActiveLearning(conf=conf, hg_network=network, learnloss_network=learnloss)

    # Defining DataLoader
    logging.info('Defining DataLoader.')
    dataset_lspet_lsp_mpii = Dataset_MPII_LSPET_LSP(mpii_dict=mpii_dict, lspet_dict=lspet_dict, lsp_dict=lsp_dict,
                                                    activelearning_obj=active_learning_obj, conf=conf,
                                                    getitem_dump=conf.model_save_path, **args)

    # Defining Hyperparameters
    hyperparameters = define_hyperparams(conf, network, learnloss)

    # Tensorboard
    writer = SummaryWriter(log_dir=os.path.join(conf.model_save_path[:-20], 'tensorboard'))

    if conf.train:
        train_obj = Train(network=network, learnloss=learnloss, hyperparameters=hyperparameters,
                          dataset_obj=dataset_lspet_lsp_mpii, conf=conf, tb_writer=writer)
        train_obj.train_model()

        # Reload the best model for metric evaluation
        network, learnloss = load_models(conf=conf, load_hg=True, load_learnloss=False, best_model=True,
                                         hg_param=hg_param, model_dir=conf.model_save_path[:-20])

    if conf.metric:
        metric_obj = Metric(network=network, dataset_obj=dataset_lspet_lsp_mpii, conf=conf)
        print("I read the model!")
        metric_obj.eval()

    #if args['misc']['viz']:
    #    visualize_image(dataset_lspet_lsp_mpii.recreate_images(gt=True, train=True), bbox=True)

if __name__ == "__main__":
    main()