"""
Investment project SPI report functions.

Service Performance Indicator report should have following metrics:

SPI1_START  - investment project created on date
SPI1_END    - earliest one of 8 SPI interactions
SPI2_START  - earliest one of 2 SPI interactions that starts SPI 2
SPI2_END    - when project manager was first assigned, only project managers from IST
SPI3        - formatted list of propositions, only created by IST
SPI5_START  - when project has been moved to won
SPI5_END    - earliest interaction when aftercare was offered, only for new investor,
              only for IST managed projects
"""
from dateutil.parser import parse as dateutil_parse
from django.db.models import Q

from datahub.core.constants import InvestmentProjectStage as Stage, Service
from datahub.core.csv import csv_iterator
from datahub.core.query_utils import (
    get_array_agg_subquery,
    get_full_name_expression,
    JSONBBuildObject,
)
from datahub.interaction.models import Interaction
from datahub.investment.project.constants import InvestorType
from datahub.investment.project.models import InvestmentProject
from datahub.investment.project.proposition.constants import PropositionStatus
from datahub.investment.project.proposition.models import Proposition
from datahub.metadata.models import Team
from datahub.metadata.query_utils import get_service_name_subquery

SPI1_END_SERVICE_IDS = {
    Service.investment_enquiry_requested_more_information.value.id,
    Service.investment_enquiry_confirmed_prospect.value.id,
    Service.investment_enquiry_assigned_to_ist_cmc.value.id,
    Service.investment_enquiry_assigned_to_ist_sas.value.id,
    Service.investment_enquiry_assigned_to_hq.value.id,
    Service.investment_enquiry_transferred_to_lep.value.id,
    Service.investment_enquiry_transferred_to_da.value.id,
    Service.investment_enquiry_transferred_to_lp.value.id,
}

SPI2_START_SERVICE_IDS = {
    Service.investment_enquiry_assigned_to_ist_cmc.value.id,
    Service.investment_enquiry_assigned_to_ist_sas.value.id,
}

SPI5_END_SERVICE_IDS = {
    Service.investment_ist_aftercare_offered.value.id,
}

ALL_SPI_SERVICE_IDS = SPI1_END_SERVICE_IDS | SPI2_START_SERVICE_IDS | SPI5_END_SERVICE_IDS

def format_date(d):
    """Date format used in the report."""
    if isinstance(d, str):
        d = dateutil_parse(d)
    return d.isoformat()

def _filter_row_dicts(rows, field_titles):
    """Filter row dicts to exclude keys which are not present in field_titles."""
    for row in rows:
        yield {
            key: value
            for key, value in row.items()
            if key in field_titles
        }

def write_report(file):
    """Write CSV report."""
    spi_report = SPIReport()
    # ensure that rows only contain keys defined in field_titles
    for line in csv_iterator(
        _filter_row_dicts(spi_report.rows(), spi_report.field_titles),
        spi_report.field_titles,
    ):
        file.write(line)

class SPIReport:
    """SPI Report."""

    SPI1_START = 'Project created on'
    SPI1_END = 'Enquiry processed'
    SPI1_END_INTERACTION_TYPE = 'Enquiry type'
    SPI1_END_BY = 'Enquiry processed by'
    SPI1_END_BY_ID = 'Enquiry processed by ID'

    SPI2_START = 'Assigned to IST'
    SPI2_END = 'Project manager assigned'
    SPI2_END_BY = 'Project manager assigned by'

    SPI3 = 'Propositions'

    SPI5_START = 'Project moved to won'
    SPI5_END = 'Aftercare offered on'

    SPI_PROJECT_ID = 'Project ID'
    SPI_DH_ID = 'Data Hub ID'
    SPI_NAME = 'Project name'

    field_titles = {
        SPI_DH_ID: SPI_DH_ID,
        SPI_PROJECT_ID: SPI_PROJECT_ID,
        SPI_NAME: SPI_NAME,
        SPI1_START: SPI1_START,
        SPI1_END: SPI1_END,
        SPI1_END_INTERACTION_TYPE: SPI1_END_INTERACTION_TYPE,
        SPI1_END_BY: SPI1_END_BY,
        SPI2_START: SPI2_START,
        SPI2_END: SPI2_END,
        SPI2_END_BY: SPI2_END_BY,
        SPI5_START: SPI5_START,
        SPI5_END: SPI5_END,
        SPI3: SPI3,
    }

    # TODO: SPI1_END_BY_ID is not present in the CSV report, but is required by
    # InvestmentProjectActivity endpoint. Once the CSV report gets deprecated it should
    # be possible to clean it up.
    default_fields = [*field_titles.keys(), SPI1_END_BY_ID]

    MAPPINGS = (
        (SPI1_END_SERVICE_IDS, SPI1_END),
        (SPI2_START_SERVICE_IDS, SPI2_START),
        (SPI5_END_SERVICE_IDS, SPI5_END),
    )

    def __init__(self, proposition_formatter=None):
        """Initialise the SPI Report."""
        self.proposition_formatter = proposition_formatter

    def _get_spi_interactions(self, investment_project):
        """
        Gets SPI interactions for given Investment Project.

        Takes earliest interaction for each SPI, if available.
        """
        if investment_project.spi_interactions is None:
            return {}

        data = {}
        for interaction in investment_project.spi_interactions:
            for service_ids, field_name in self.MAPPINGS:
                if (
                    str(interaction['service_id']) in service_ids
                    and field_name not in data
                ):
                    data[field_name] = {
                        'created_by_id': interaction['created_by_id'],
                        'created_by_name': interaction['created_by_name'],
                        'service_name': interaction['service_name'],
                        'created_on': format_date(interaction['created_on']),
                    }

        return data

    def _has_ist_project_manager(self, investment_project):
        """Checks if investment project has an IST project manager."""
        project_manager = investment_project.project_manager
        return (
            project_manager
            and project_manager.dit_team
            and Team.Tag.INVESTMENT_SERVICES_TEAM in project_manager.dit_team.tags
        )

    def _find_when_project_moved_to_won(self, investment_project):
        """
        Finds when project has been moved to Won stage.

        Earliest date counts.
        """
        stage_log = investment_project.stage_log.filter(
            stage_id=Stage.won.value.id,
        ).order_by('created_on').first()

        return stage_log.created_on if stage_log else None

    def _format_propositions(self, propositions):
        """
        Formats propositions.

        Propositions need to be presented in the cell in following format:

        deadline;ongoing;;adviser.name;deadline;completed;modified_on;adviser.name...
        """
        formatted = []
        for proposition in propositions:
            formatted.append(dateutil_parse(proposition['deadline']).strftime('%Y-%m-%d'))
            formatted.append(proposition['status'])
            if proposition['status'] == PropositionStatus.ONGOING:
                modified_on = ''
            else:
                modified_on = dateutil_parse(proposition['modified_on']).isoformat()
            formatted.append(modified_on)
            formatted.append(proposition['adviser_name'])

        return ';'.join(formatted)

    def _enrich_row(self, investment_project, spi_data=None):
        """Enriches the spi report with investment project details."""
        if spi_data is None:
            spi_data = {}

        spi_data.update({field: '' for field in self.default_fields if field not in spi_data})

        spi_data[self.SPI_DH_ID] = str(investment_project.id)
        spi_data[self.SPI_PROJECT_ID] = investment_project.project_code
        spi_data[self.SPI_NAME] = investment_project.name
        return spi_data

    def get_spi1(self, investment_project, spi_interactions):
        """Update data with SPI 1 values."""
        data = {}

        data[self.SPI1_START] = format_date(investment_project.created_on)
        if self.SPI1_END in spi_interactions:
            spi_interaction = spi_interactions[self.SPI1_END]
            data[self.SPI1_END] = spi_interaction['created_on']
            data[self.SPI1_END_INTERACTION_TYPE] = spi_interaction['service_name']
            data[self.SPI1_END_BY] = spi_interaction['created_by_name']
            data[self.SPI1_END_BY_ID] = spi_interaction['created_by_id']

        return data

    def get_spi2(self, investment_project, spi_interactions):
        """Update data with SPI 2 dates and adviser."""
        data = {}

        has_ist_pm = self._has_ist_project_manager(investment_project)

        if self.SPI2_START in spi_interactions:
            data[self.SPI2_START] = spi_interactions[self.SPI2_START]['created_on']

        if has_ist_pm and investment_project.project_manager_first_assigned_on:
            data[self.SPI2_END] = format_date(investment_project.project_manager_first_assigned_on)
            data[self.SPI2_END_BY] = investment_project.project_manager_first_assigned_by

        return data

    def get_spi3(self, investment_project):
        """Update data with SPI 3 propositions."""
        data = {}

        spi_propositions = investment_project.spi_propositions or []

        formatter = (
            self.proposition_formatter
            if self.proposition_formatter else self._format_propositions
        )

        data[self.SPI3] = formatter(spi_propositions)
        return data

    def get_spi5(self, investment_project, spi_interactions):
        """Update data with SPI 5 dates."""
        data = {}

        has_ist_pm = self._has_ist_project_manager(investment_project)
        new_investor_id = InvestorType.new_investor.value.id
        is_new_investor = str(investment_project.investor_type_id) == new_investor_id

        if has_ist_pm and is_new_investor:
            moved_to_won = self._find_when_project_moved_to_won(investment_project)
            if moved_to_won:
                data[self.SPI5_START] = format_date(moved_to_won)

            if self.SPI5_END in spi_interactions:
                data[self.SPI5_END] = spi_interactions[self.SPI5_END]['created_on']

        return data

    def get_spi_data_for_investment_project(self, investment_project):
        """Gets all SPI data for investment project."""
        spi_interaction_dates = self._get_spi_interactions(investment_project)

        data = {}
        data.update(self.get_spi1(investment_project, spi_interaction_dates))
        data.update(self.get_spi2(investment_project, spi_interaction_dates))
        data.update(self.get_spi3(investment_project))
        data.update(self.get_spi5(investment_project, spi_interaction_dates))

        return data

    def get_row(self, investment_project):
        """Gets SPI report row for given investment project."""
        spi_data = self.get_spi_data_for_investment_project(investment_project)
        spi_data = self._enrich_row(investment_project, spi_data)
        return spi_data

    def rows(self):
        """Return SPI report iterator."""
        for investment_project in get_spi_report_queryset().iterator():
            yield self.get_row(investment_project)

def get_spi_report_queryset():
    """Get SPI Report queryset."""
    return InvestmentProject.objects.select_related(
        'investmentprojectcode',
        'project_manager__dit_team',
    ).annotate(
        spi_propositions=get_array_agg_subquery(
            Proposition,
            'investment_project',
            JSONBBuildObject(
                deadline='deadline',
                status='status',
                adviser_id='adviser_id',
                adviser_name=get_full_name_expression('adviser'),
                modified_on='modified_on',
            ),
            ordering=('created_on',),
        ),
        spi_interactions=get_array_agg_subquery(
            Interaction,
            'investment_project',
            JSONBBuildObject(
                service_id='service_id',
                service_name=get_service_name_subquery('service'),
                created_by_id='created_by_id',
                created_by_name=get_full_name_expression('created_by'),
                created_on='created_on',
            ),
            filter=Q(service_id__in=ALL_SPI_SERVICE_IDS),
            ordering=('created_on',),
        ),
    ).order_by('created_on')


import tensorflow.keras as keras
import numpy as np
from PIL import Image
from config.enum import ObjDetection
import data.normalize as normalize

class DFImageGeneratorByPath(keras.utils.Sequence):
    def __init__(
            self,
            dataset: list,
            batch_size: int = 8,
            target_size=(256, 256),
            n_channel=3,
            classes: list = [],
            need_augment=False
    ):
        self.dataset = dataset
        self.batch_size = batch_size
        self.target_size = target_size
        self.n_channel = n_channel
        self.augmenter = DERandAugment()
        self.classes = classes
        self.need_augment = need_augment
        return

    def __len__(self):
        return int(np.ceil(len(self.dataset) / self.batch_size))

    def __getitem__(self, idx):
        batch = self.dataset[idx * self.batch_size:(idx + 1) * self.batch_size]

        n_data = len(batch)

        batch_images = np.zeros(shape=(n_data,) + self.target_size + (self.n_channel,))
        batch_label = np.zeros(shape=n_data)
        batch_bbox = np.zeros((n_data,) + (4,), dtype=np.float)

        for i in range(n_data):
            image = Image.open(batch[i]["path"])
            annotations = [
                {
                    ObjDetection.BBOX: batch[i]["bounding_box"],
                    ObjDetection.LABEL: batch[i]["category"]
                }
            ]

            # image = image.crop(annotations[0][ObjDetection.BBOX])
            image, annotations = normalize.resize(image=image, annotations=annotations, target_size=self.target_size)
            if self.need_augment:
                image, annotations = self.augmenter.transform(image=image, annotations=annotations)

            image, annotations = normalize.scale_to_unit(image=image, annotations=annotations)

            batch_images[i] = image
            batch_label[i] = self.classes.index(annotations[0][ObjDetection.LABEL])
            batch_bbox[i] = annotations[0][ObjDetection.BBOX]

        return batch_images, batch_label
        # return batch_images, [batch_label, batch_bbox]

    def on_epoch_end(self):
        return

import utils.visualize as visualize
import data.loader as loader
from augmentation.transform import DERandAugment
from tensorflow.keras.applications.densenet import DenseNet121

train_set, dev_set, test_set = loader.get_deep_fashion_annotations_by_category_type()
# train_set, dev_set, test_set = loader.get_deep_fashion_annotations()

classes = [item["category"] for item in train_set] + [item["category"] for item in dev_set] + [item["category"] for item in test_set]
classes = np.array(list(set(classes)))
np.save("classes.npy", classes)
classes = classes.tolist()

train_gen = DFImageGeneratorByPath(
    train_set,
    classes=classes,
    need_augment=True
)

dev_gen = DFImageGeneratorByPath(
    dev_set,
    classes=classes
)

test_gen = DFImageGeneratorByPath(
    test_set,
    classes=classes
)

def build_model():
    model_resnet = DenseNet121(include_top=False, pooling='avg')
    # model_resnet = ResNet50(weights='imagenet', include_top=False, pooling='avg')
    # for layer in model_resnet.layers[:-12]:
        # 6 - 12 - 18 have been tried. 12 is the best.
        # print(layer)
        # layer.trainable = False

    x = model_resnet.output # (None, 2048)
    # print(len(model_resnet.layers))
    # return
    # x = keras.layers.Dense(512, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001))(x)
    y = keras.layers.Dense(3, activation='softmax', name='img')(x)

    # x_bbox = model_resnet.output
    # x_bbox = keras.layers.Dense(512, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001))(x_bbox)
    # x_bbox = keras.layers.Dense(128, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001))(x_bbox)
    # bbox = keras.layers.Dense(4, kernel_initializer='normal', name='bbox')(x_bbox)

    final_model = keras.models.Model(
        inputs=model_resnet.input,
        outputs=y
        #outputs=[y, bbox]
    )

    opt = keras.optimizers.Adam()
    # opt = keras.optimizers.Adam(lr=0.0001, )
    final_model.compile(optimizer=opt,
                        loss={
                            'img': 'sparse_categorical_crossentropy',
                    #        'bbox': 'mean_squared_error'
                        },
                        metrics={
                            'img': [
                                'accuracy',
                                # 'sparse_top_k_categorical_accuracy'
                            ],  # default: top-5
                     #       'bbox': ['mse']
                        }
                        )
    return final_model

def experiment():

    lr_reducer = keras.callbacks.ReduceLROnPlateau(
        monitor='val_loss',
        patience=12,
        factor=0.5,
        verbose=1
    )

    # # tensorboard = keras.callbacks.TensorBoard(log_dir='./logs')
    early_stopper = keras.callbacks.EarlyStopping(monitor='val_loss',
                                                  patience=30,
                                                  verbose=1)
    checkpoint = keras.callbacks.ModelCheckpoint(filepath='model.h5')
    final_model = build_model()
    # final_model.evaluate(dev_gen)
    # return
    #final_model.load_weights("model.h5")
    final_model.fit_generator(
        train_gen,
        epochs=200,
        validation_data=dev_gen,
        verbose=1,
        shuffle=True,
        callbacks=[lr_reducer, early_stopper, checkpoint],
        workers=1
    )

    final_model.save("demo_detector.h5")

    print("FINISH TRAINING")

    scores = final_model.evaluate_generator(
        test_gen,
        verbose=1
    )

    return

def test_model():
    model = keras.models.load_model("model.h5")
    model.evaluate_generator(dev_gen, verbose=1)

    for example in train_gen:
        result = model.predict(example[0][0:1])
        print(result)
        visualize.show_image(
            image=example[0][0],
            annotations=[
                {
                    ObjDetection.BBOX: result[1][0]*256
                }
            ]
        )
        break
    return

experiment()
test_model()

# augmenter = DERandAugment()
print(len(train_set), len(dev_set), len(test_set))

for images, labels in DFImageGeneratorByPath(
# for images, (labels, bboxs) in DFImageGeneratorByPath(
    dataset=dev_set,
    classes=classes
):
    for i in range(len(images)):
        image = images[i]
        annotations = [
                {
                    ObjDetection.BBOX: [0,0,0,0],
                    ObjDetection.LABEL: labels[i],
                }
            ]

        visualize.show_image(image, annotations)
        # image = image.crop(annotations[0][ObjDetection.BBOX])
        # visualize.show_image(image, annotations)


from flask import Flask, render_template, request
from PIL import Image
import cv2
import glob
import json
import os
import shutil
import numpy as np

from PIL import Image

#det

import argparse
import glob
import multiprocessing as mp
import os
import time

import cv2
import tqdm
from adet.config import get_cfg
from detectron2.data.detection_utils import read_image
from detectron2.utils.logger import setup_logger
from demo.predictor import VisualizationDemo

#rec

from vietocr.vietocr.tool.predictor import Predictor
from vietocr.vietocr.tool.config import Cfg
import cv2
import os
from PIL import Image
import argparse
from tqdm import tqdm

app = Flask(__name__)

#setup det sss
mp.set_start_method("spawn", force=True)
cfg = get_cfg()
config_file = './configs/BAText/VinText/attn_R_50.yaml'
opts = []
confidence_threshold = 0.3
cfg.merge_from_file(config_file)
cfg.merge_from_list(opts)

cfg.MODEL.RETINANET.SCORE_THRESH_TEST = confidence_threshold
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = confidence_threshold
cfg.MODEL.FCOS.INFERENCE_TH_TEST = confidence_threshold
cfg.MODEL.PANOPTIC_FPN.COMBINE.INSTANCES_CONFIDENCE_THRESH = confidence_threshold
cfg.freeze()
demo = VisualizationDemo(cfg)

#set rec

cfg_name = 'vgg_transformer'
config = Cfg.load_config_from_name(cfg_name)
#    cfg_name = 'vgg_transformer'
weights = './vietocr/weights/vietocr.pth'
# path_img = path_image
device = 'cuda:0'
# path_output = './result'

config['vocab'] = 'aAàÀảẢãÃáÁạẠăĂằẰẳẲẵẴắẮặẶâÂầẦẩẨẫẪấẤậẬbBcCdDđĐeEèÈẻẺẽẼéÉẹẸêÊềỀểỂễỄếẾệỆfFgGhHiIìÌỉỈĩĨíÍịỊjJkKlLmMnNoOòÒỏỎõÕóÓọỌôÔồỒổỔỗỖốỐộỘơƠờỜởỞỡỠớỚợỢpPqQrRsStTuUùÙủỦũŨúÚụỤưƯừỪửỬữỮứỨựỰvVwWxXyYỳỲỷỶỹỸýÝỵỴzZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~° ' + '̉'+ '̀' + '̃'+ '́'+ '̣'
config['device'] = device
config['weights'] = weights

detector = Predictor(config)

def detect(path_test, output):

    filename = path_test.split('/')[-1].split('.')[0]
    # output = './result'
    path_out = os.path.join(output, f'res_{filename}.txt')
    img = read_image(path_test, format="BGR")
    _, predictions = demo.run_on_image(img, path_test, path_out, confidence_threshold)

    return predictions

def reg(path_image, path_output):

	predictions = detect(path_image, path_output)

	filename = path_image.split('/')[-1].split('.')[0]
    #filename = 'reg_'+filename

	img = cv2.imread(path_image, 0)
	out_txt = open(os.path.join(path_output, f'{filename}.txt'), 'w', encoding="utf-8")
	if len(predictions) == 0:
		out_txt.close()
		return None
	else :
		for line in predictions:
			prob_detect = line[1]
			bbox = line[0].strip()
			bbox = bbox.split(',')
			bbox = [int(ele) for ele in bbox]
			top = min(bbox[1:8:2])
			bottom = max(bbox[1:8:2])
			left = min(bbox[0:7:2])
			right = max(bbox[0:7:2])

			bxxout = [left, top, right, bottom]

			if top == 0: top = 1
			if left == 0: left = 1
			x = int((left + right)/2)
			y = int((top+ bottom)/2)
			height = bottom - y
			width = right - x
			crop_img = img[y - height: y + height, x - width: x + width]
			try:
				crop_img = cv2.cvtColor(crop_img, cv2.COLOR_BGR2RGB)
			except:
				continue

			im_pil = Image.fromarray(crop_img)
			pred, prob = detector.predict(im_pil , return_prob = True)

			content = ' '.join([str(p) for p in bxxout]) + ' ' + pred + '\n'
			out_txt.write(content)

		out_txt.close()

@app.route('/', methods=['Get','POST'])
def index():
	if os.path.exists("static"):
		shutil.rmtree("static")
	return render_template('index.html')

@app.route("/label", methods=['POST'])
def home():
	img_files = request.files.getlist("img_files")
	for file in img_files:
		filename = file.filename.replace("(","").replace(")","").replace(" ","")
		if not os.path.exists("static/images"):
				os.makedirs("static/images")
		file.save(os.path.join("static/images", filename))

	if not os.path.exists('static/labels'):
		os.makedirs('static/labels')

	global width, height, image_path,ratio
	image_path = sorted(glob.glob("static/images/*.jpg") + glob.glob("static/images/*.jpeg") + glob.glob("static/images/*.png"))
	#

	for path in image_path:

		reg(path, 'static/labels')

	width = 720
	height = 960

	all_polygons = []
	for i,image in enumerate(image_path):
		img = cv2.imread(image)
		#img = img.resize()
		h, w,_ = img.shape
		ratio_w = w/width
		ratio_h = h/height
		polygon = []
		txt_path = str(f"static/labels/{image.split('/')[-1].split('.')[0]}.txt")
		with open(txt_path, 'r') as f:
			lines = f.readlines()

		if len(lines) != 0:
			for line in lines:
				x1 = int(int(line.split(' ')[0]) / ratio_w)
				y1 = int(int(line.split(' ')[1]) / ratio_h)
				x2 = int(int(line.split(' ')[2]) / ratio_w)
				y2 = int(int(line.split(' ')[3]) / ratio_h)
				text = line.split(' ')[4].strip()

				rectangles = {'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2,'text':text}
				#print(list(map(lambda x: x * ratio, rectangles.values())))
				polygon.append(rectangles)
			all_polygons.append(polygon)
		else :
			all_polygons.append([])
	return render_template("label.html",image0=image_path[0], image_path=image_path, width_canvas=width,height_canvas=height,all_polygons=all_polygons)

if __name__ == "__main__":
	app.run(debug=True, host="0.0.0.0", port=8080)


# coding:utf-8
"""
See the following papers for more information on neural translation models.
 * http://arxiv.org/abs/1409.3215 <Sequence to Sequence Learning with Neural Networks>
 * http://arxiv.org/abs/1409.0473 <Neural Machine Translation by Jointly Learning to Align and Translate>
 * http://arxiv.org/abs/1412.2007 <On Using Very Large Target Vocabulary for Neural Machine Translation>
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import math
import os
import random
import sys
import time
import logging

import numpy as np
from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

import data_utils
import seq2seq_model

tf.app.flags.DEFINE_float("learning_rate", 0.5, "Learning rate.")

# 最近三次step如果效果不好就把learning_rate乘以learning_rate_decay_factor
tf.app.flags.DEFINE_float("learning_rate_decay_factor", 0.9,
                          "Learning rate decays by this much.")

# 为了避免梯度爆炸或梯度消失，目的让权重的更新限制在一定范围内
tf.app.flags.DEFINE_float("max_gradient_norm", 5.0,
                          "Clip gradients to this norm.")

tf.app.flags.DEFINE_integer("batch_size", 1,
                            "Batch size to use during training.")
tf.app.flags.DEFINE_integer("size", 1024, "Size of each model layer.")
tf.app.flags.DEFINE_integer("num_layers", 3, "Number of layers in the model.")
tf.app.flags.DEFINE_integer("input_vocab_size", 50, "input vocabulary size.")
tf.app.flags.DEFINE_integer("output_vocab_size", 50, "output vocabulary size.")

# 保存训练样本和测试样本
tf.app.flags.DEFINE_string("data_dir", "./data/", "Data directory")

# 保存checkpoint数据
tf.app.flags.DEFINE_string("train_dir", "./model/", "Training directory.")

tf.app.flags.DEFINE_integer("max_train_data_size", 0,
                            "Limit on the size of training data (0: no limit).")
tf.app.flags.DEFINE_integer("steps_per_checkpoint", 1,
                            "How many training steps to do per checkpoint.")
tf.app.flags.DEFINE_boolean("decode", False,
                            "Set to True for interactive decoding.")
tf.app.flags.DEFINE_boolean("self_test", False,
                            "Run a self-test if this is set to True.")

FLAGS = tf.app.flags.FLAGS

_buckets = [(5, 5)]

def read_data(source_path, target_path, max_size=None):
  """Read data from source and target files and put into buckets.

  Args:
    source_path: path to the files with token-ids for the source language.
    target_path: path to the file with token-ids for the target language;
      it must be aligned with the source file: n-th line contains the desired
      output for n-th line from the source_path.
    max_size: maximum number of lines to read, all other will be ignored;
      if 0 or None, data files will be read completely (no limit).

  Returns:
    data_set: a list of length len(_buckets); data_set[n] contains a list of
      (source, target) pairs read from the provided data files that fit
      into the n-th bucket, i.e., such that len(source) < _buckets[n][0] and
      len(target) < _buckets[n][1]; source and target are lists of token-ids.
  """
  data_set = [[] for _ in _buckets]
  with tf.gfile.GFile(source_path, mode="r") as source_file:
    with tf.gfile.GFile(target_path, mode="r") as target_file:
      source, target = source_file.readline(), target_file.readline()
      counter = 0
      while source and target and (not max_size or counter < max_size):
        counter += 1
        if counter % 10 == 0:
          print("  reading data line %d" % counter)
          sys.stdout.flush()
        source_ids = [int(x) for x in source.split()]
        target_ids = [int(x) for x in target.split()]
        target_ids.append(data_utils.EOS_ID)
        for bucket_id, (source_size, target_size) in enumerate(_buckets):
          if len(source_ids) < source_size and len(target_ids) < target_size:
            data_set[bucket_id].append([source_ids, target_ids])
            break
        source, target = source_file.readline(), target_file.readline()
  return data_set

def create_model(session, forward_only):
  """Create translation model and initialize or load parameters in session."""
  dtype = tf.float32
  model = seq2seq_model.Seq2SeqModel(
      FLAGS.input_vocab_size,
      FLAGS.output_vocab_size,
      _buckets,
      FLAGS.size,
      FLAGS.num_layers,
      FLAGS.max_gradient_norm,
      FLAGS.batch_size,
      FLAGS.learning_rate,
      FLAGS.learning_rate_decay_factor,
      forward_only=forward_only,
      dtype=dtype)
  ckpt = tf.train.get_checkpoint_state(FLAGS.train_dir)
  if ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path):
    print("Reading model parameters from %s" % ckpt.model_checkpoint_path)
    model.saver.restore(session, ckpt.model_checkpoint_path)
  else:
    print("Created model with fresh parameters.")
    session.run(tf.global_variables_initializer())
  return model

def train():
  input_train, output_train, input_dev, output_dev, _, _ = data_utils.prepare_wmt_data(
          FLAGS.data_dir, FLAGS.input_vocab_size, FLAGS.output_vocab_size)

  with tf.Session() as sess:
    # Create model.
    print("Creating %d layers of %d units." % (FLAGS.num_layers, FLAGS.size))
    model = create_model(sess, False)

    # Read data into buckets and compute their sizes.
    print ("Reading development and training data (limit: %d)."
           % FLAGS.max_train_data_size)
    dev_set = read_data(input_dev, output_dev)
    train_set = read_data(input_train, output_train, FLAGS.max_train_data_size)
    train_bucket_sizes = [len(train_set[b]) for b in xrange(len(_buckets))]
    train_total_size = float(sum(train_bucket_sizes))

    # A bucket scale is a list of increasing numbers from 0 to 1 that we'll use
    # to select a bucket. Length of [scale[i], scale[i+1]] is proportional to
    # the size if i-th training bucket, as used later.
    train_buckets_scale = [sum(train_bucket_sizes[:i + 1]) / train_total_size
                           for i in xrange(len(train_bucket_sizes))]

    # This is the training loop.
    step_time, loss = 0.0, 0.0
    current_step = 0
    previous_losses = []
    while True:
      # Choose a bucket according to data distribution. We pick a random number
      # in [0, 1] and use the corresponding interval in train_buckets_scale.
      random_number_01 = np.random.random_sample()
      bucket_id = min([i for i in xrange(len(train_buckets_scale))
                       if train_buckets_scale[i] > random_number_01])

      # Get a batch and make a step.
      start_time = time.time()
      encoder_inputs, decoder_inputs, target_weights = model.get_batch(
          train_set, bucket_id)
      _, step_loss, _ = model.step(sess, encoder_inputs, decoder_inputs,
                                   target_weights, bucket_id, False)
      step_time += (time.time() - start_time) / FLAGS.steps_per_checkpoint
      loss += step_loss / FLAGS.steps_per_checkpoint
      current_step += 1

      # Once in a while, we save checkpoint, print statistics, and run evals.
      if current_step % FLAGS.steps_per_checkpoint == 0:
        # Print statistics for the previous epoch.
        perplexity = math.exp(float(loss)) if loss < 300 else float("inf")
        print ("global step %d learning rate %.4f step-time %.2f perplexity "
               "%.2f" % (model.global_step.eval(), model.learning_rate.eval(),
                         step_time, perplexity))
        # Decrease learning rate if no improvement was seen over last 3 times.
        if len(previous_losses) > 2 and loss > max(previous_losses[-3:]):
          sess.run(model.learning_rate_decay_op)
        previous_losses.append(loss)
        # Save checkpoint and zero timer and loss.
        checkpoint_path = os.path.join(FLAGS.train_dir, "translate.ckpt")
        model.saver.save(sess, checkpoint_path, global_step=model.global_step)
        step_time, loss = 0.0, 0.0
        # Run evals on development set and print their perplexity.
        for bucket_id in xrange(len(_buckets)):
          if len(dev_set[bucket_id]) == 0:
            print("  eval: empty bucket %d" % (bucket_id))
            continue
          encoder_inputs, decoder_inputs, target_weights = model.get_batch(
              dev_set, bucket_id)
          _, eval_loss, _ = model.step(sess, encoder_inputs, decoder_inputs,
                                       target_weights, bucket_id, True)
          eval_ppx = math.exp(float(eval_loss)) if eval_loss < 300 else float(
              "inf")
          print("  eval: bucket %d perplexity %.2f" % (bucket_id, eval_ppx))
        sys.stdout.flush()

def decode():
  with tf.Session() as sess:
    # Create model and load parameters.
    model = create_model(sess, True)
    model.batch_size = 1  # We decode one sentence at a time.

    # Load vocabularies.
    en_vocab_path = os.path.join(FLAGS.data_dir,
                                 "vocab%d.input" % FLAGS.input_vocab_size)
    fr_vocab_path = os.path.join(FLAGS.data_dir,
                                 "vocab%d.output" % FLAGS.output_vocab_size)
    en_vocab, _ = data_utils.initialize_vocabulary(en_vocab_path)
    _, rev_fr_vocab = data_utils.initialize_vocabulary(fr_vocab_path)

    # Decode from standard input.
    sys.stdout.write("> ")
    sys.stdout.flush()
    sentence = sys.stdin.readline()
    while sentence:
      # Get token-ids for the input sentence.
      token_ids = data_utils.sentence_to_token_ids(tf.compat.as_bytes(sentence), en_vocab)
      # Which bucket does it belong to?
      bucket_id = len(_buckets) - 1
      for i, bucket in enumerate(_buckets):
        if bucket[0] >= len(token_ids):
          bucket_id = i
          break
      else:
        logging.warning("Sentence truncated: %s", sentence)

      # Get a 1-element batch to feed the sentence to the model.
      encoder_inputs, decoder_inputs, target_weights = model.get_batch(
          {bucket_id: [(token_ids, [])]}, bucket_id)
      # Get output logits for the sentence.
      _, _, output_logits = model.step(sess, encoder_inputs, decoder_inputs,
                                       target_weights, bucket_id, True)
      # This is a greedy decoder - outputs are just argmaxes of output_logits.
      outputs = [int(np.argmax(logit, axis=1)) for logit in output_logits]
      # If there is an EOS symbol in outputs, cut them at that point.
      if data_utils.EOS_ID in outputs:
        outputs = outputs[:outputs.index(data_utils.EOS_ID)]
      # Print out French sentence corresponding to outputs.
      print(" ".join([tf.compat.as_str(rev_fr_vocab[output]) for output in outputs]))
      print("> ", end="")
      sys.stdout.flush()
      sentence = sys.stdin.readline()

def self_test():
  """Test the translation model."""
  with tf.Session() as sess:
    print("Self-test for neural translation model.")
    # Create model with vocabularies of 10, 2 small buckets, 2 layers of 32.
    model = seq2seq_model.Seq2SeqModel(10, 10, [(3, 3), (6, 6)], 32, 2,
                                       5.0, 32, 0.3, 0.99, num_samples=8)
    sess.run(tf.global_variables_initializer())

    # Fake data set for both the (3, 3) and (6, 6) bucket.
    data_set = ([([1, 1], [2, 2]), ([3, 3], [4]), ([5], [6])],
                [([1, 1, 1, 1, 1], [2, 2, 2, 2, 2]), ([3, 3, 3], [5, 6])])
    for _ in xrange(5):  # Train the fake model for 5 steps.
      bucket_id = random.choice([0, 1])
      encoder_inputs, decoder_inputs, target_weights = model.get_batch(
          data_set, bucket_id)
      model.step(sess, encoder_inputs, decoder_inputs, target_weights,
                 bucket_id, False)

def main(_):
  if FLAGS.self_test:
    self_test()
  elif FLAGS.decode:
    decode()
  else:
    train()

if __name__ == "__main__":
  tf.app.run()


from copy import deepcopy
import os
import torch
from engine.optimizer.default import HYPER_DICT
from train import get_hyperparams_str
torch.set_num_threads(4)
from torch.utils.data import DataLoader
import numpy as np
from engine.tools.utils import makedirs, set_random_seed
from engine.config import default
from engine.datasets.utils import TensorDataset
from engine.model.head import make_classifier_head
from engine.model.logit import LogitHead
from engine.optimizer.optim import build_optimizer
from engine.optimizer.scheduler import build_lr_scheduler
from features import get_text_features_path, get_image_features_path, get_test_features_path

RESULT_DIR = "./imagenet_esc_results/"

ESC_DIR = f"{default.DATA_DIR}/esc-50/"

SHOTS = [1, 2, 4] # for both image and audio

SPLITS = [0, 1, 2, 3, 4] # for both image and audio; make sure imagenet has seed 4 and 5  featuresavailable

TASKS = ['image', 'audio'] # classification task to perform

clip_encoder = "RN50" # AudioCLIP uses a frozen RN50 model
image_layer_idx = 0
text_layer_idx = 0
text_augmentation = "classname"
image_augmentation = "none"
classifier_head = "linear"
logit = 4.60517
hyperparams_audio = "audio"
result_dir = os.path.join(RESULT_DIR, hyperparams_audio)
makedirs(result_dir)

CLASS_MAP = {
    'imagenet_27': {
        'dataset': 'imagenet',
        'class_map': {
            7: "rooster",  # rooster
            8: "hen",  # hen
            19: "chirping_birds",  # chickadee
            31: "frog",  # tree frog
            175: "dog",  # Otterhound
            285: "cat",  # Egyptian cat
            308: "insects",  # fly
            312: "crickets",  # cricket
            341: "pig",  # pig
            349: "sheep",  # big-horn sheep
            404: "airplane",  # airliner
            466: "train",  # high-speed train
            473: "can_opening",  # can opener
            491: "chainsaw",  # chainsaw
            497: "church_bells",  # church bells
            508: "keyboard_typing",  # computer keyboard
            530: "clock_alarm",  # digital clock
            556: "crackling_fire",  # fire screen
            673: "mouse_click",  # computer mouse
            861: "toilet_flush",  # toilet seat
            882: "vacuum_cleaner",  # vacuum cleaner
            892: "clock_tick",  # wall clock
            896: "water_drops",  # sink
            897: "washing_machine",  # washing machine
            898: "drinking_sipping",  # water bottle
            899: "pouring_water",  # water jug
            977: "sea_waves",  # sandbar
        }
    },
    'imagenet_19': {
        'dataset': 'imagenet',
        'class_map': {
            7: "rooster",  # rooster
            8: "hen",  # hen
            19: "chirping_birds",  # chickadee
            31: "frog",  # tree frog
            175: "dog",  # Otterhound
            285: "cat",  # Egyptian cat
            308: "insects",  # fly
            312: "crickets",  # cricket
            341: "pig",  # pig
            349: "sheep",  # big-horn sheep
            404: "airplane",  # airliner
            466: "train",  # high-speed train
            491: "chainsaw",  # chainsaw
            508: "keyboard_typing",  # computer keyboard
            530: "clock_alarm",  # digital clock
            673: "mouse_click",  # computer mouse
            882: "vacuum_cleaner",  # vacuum cleaner
            892: "clock_tick",  # wall clock
            897: "washing_machine",  # washing machine
        }
    },
}

# del CLASS_MAP['imagenet_27']
# del CLASS_MAP['imagenet_19']

def train(logit_head,
          image_loader, val_loader, audio_loader, test_loader,
          optimizer, scheduler, criterion, iters,
          eval_freq=100, device="cuda"):
    if image_loader is None and audio_loader is None:
        raise ValueError("Both image_loader and audio_loader are None")
    if image_loader is not None:
        image_loader_iter = iter(image_loader)
    else:
        image_loader_iter = None
    if audio_loader is not None:
        audio_loader_iter = iter(audio_loader)
    else:
        audio_loader_iter = None

    best_val_dict = {
        "iter": None,
        "val_acc": None,
        "image_encoder": None,
        "logit_head": None,
    }

    for i in range(iters):
        logit_head.train()
        if image_loader_iter is not None:
            try:
                image_feature, image_label = next(image_loader_iter)
            except StopIteration:
                image_loader_iter = iter(image_loader)
                image_feature, image_label = next(image_loader_iter)
            image_feature = image_feature.to(device)
            image_label = image_label.to(device)
        else:
            image_feature = None

        if audio_loader_iter is not None:
            try:
                audio_feature, audio_label = next(audio_loader_iter)
            except StopIteration:
                audio_loader_iter = iter(audio_loader)
                audio_feature, audio_label = next(audio_loader_iter)
            audio_feature = audio_feature.to(device)
            audio_label = audio_label.to(device)
        else:
            audio_feature = None

        if image_feature is not None and audio_feature is not None:
            feature = torch.cat([image_feature, audio_feature], dim=0)
            label = torch.cat([image_label, audio_label], dim=0)
        elif image_feature is not None:
            feature = image_feature
            label = image_label
        elif audio_feature is not None:
            feature = audio_feature
            label = audio_label
        else:
            raise ValueError("Both image_feature and audio_feature are None")

        optimizer.zero_grad()
        logit = logit_head(feature)
        loss = criterion(logit, label)
        # loss.backward(retain_graph=True)
        loss.backward()
        optimizer.step()
        scheduler.step()

        if i % eval_freq == 0:
            val_acc = validate(logit_head, val_loader, device=device)
            test_acc = validate(logit_head, test_loader, device=device)
            if best_val_dict["val_acc"] is None or val_acc > best_val_dict["val_acc"]:
                best_val_dict["iter"] = i
                best_val_dict["val_acc"] = val_acc
                best_val_dict['test_acc'] = test_acc
                best_val_dict["logit_head"] = deepcopy(logit_head.state_dict())

    val_acc = validate(logit_head, val_loader, device=device)
    test_acc = validate(logit_head, test_loader, device=device)
    print(f"Best val acc: {best_val_dict['val_acc']:.4f} at iter {best_val_dict['iter']} with test acc {best_val_dict['test_acc']:.4f}")
    return best_val_dict

def validate(logit_head, val_loader, device="cuda"):
    logit_head.eval()
    val_acc = 0
    val_count = 0.
    for image_feature, image_label in val_loader:
        image_feature = image_feature.to(device)
        image_label = image_label.to(device)
        # import pdb; pdb.set_trace()
        logit = logit_head(image_feature)
        pred = torch.argmax(logit, dim=1)
        val_acc += torch.sum(pred == image_label).item()
        val_count += image_label.size(0)
    val_acc /= val_count
    return val_acc

def evaluate(clip_encoder, classifier_head, logit, zero_shot_dataset, test_dataset):
    # Create the zero-shot model and evaluate test accuracy
    head, _, _ = make_classifier_head(
        classifier_head,
        clip_encoder,
        "zeroshot", # meaning zero-shot initialization here
        zero_shot_dataset
    )
    eval_head = LogitHead(
        head,
        logit_scale=logit
    ).cuda().eval()

    test_loader = DataLoader(
        test_dataset,
        batch_size=32,
        shuffle=False,
        num_workers=0,
        pin_memory=True,
    )
    test_acc = validate(eval_head, test_loader, device="cuda")
    test_acc = float(test_acc)
    print(f"Test Acc: {test_acc}")
    return test_acc

def transform_features(features, sorted_classes):
    # first filter out the classes that are not in sorted_classes
    new_features = None
    new_labels = None
    for i in range(features['features'].shape[0]):
        if features['labels'][i] in sorted_classes:
            if new_features is None:
                new_features = features['features'][i].unsqueeze(0)
                new_labels = features['labels'][i].unsqueeze(0)
            else:
                new_features = torch.cat((new_features, features['features'][i].unsqueeze(0)), 0)
                new_labels = torch.cat((new_labels, features['labels'][i].unsqueeze(0)), 0)

    # transform new_labels to be the index of sorted_classes
    for i in range(len(new_labels)):
        new_labels[i] = sorted_classes.index(new_labels[i])
    features['features'] = new_features
    features['labels'] = new_labels
    return features

def transform_audio_features(features, class_map, sorted_classes):
    labelname_to_label = {}
    for image_class, labelname in class_map.items():
        labelname_to_label[labelname] = sorted_classes.index(image_class)

    # first filter out the classes that are not in sorted_classes
    new_audio_feature = {
        'features': None,
        'labels': None,
    }
    new_features = None
    new_labels = []
    for i in range(features['features'].shape[0]):
        if features['labelnames'][i] in labelname_to_label:
            if new_features is None:
                new_features = features['features'][i].unsqueeze(0)
                new_labels = [labelname_to_label[features['labelnames'][i]]]
            else:
                new_features = torch.cat((new_features, features['features'][i].unsqueeze(0)), 0)
                new_labels = new_labels + [labelname_to_label[features['labelnames'][i]]]

    new_audio_feature['features'] = new_features
    new_audio_feature['labels'] = torch.Tensor(new_labels).long()
    return new_audio_feature

def take_indices(features, indices):
    new_features = {
        'features': features['features'][indices],
        'labels': features['labels'][indices],
    }
    return new_features

def construct_few_shot_dataset(train_features, shot_num):
    assert shot_num >= 1 and shot_num <= 4
    train_indices = []
    val_indices = []
    labels = train_features['labels'].unique()
    for label in labels:
        label_indices = torch.where(train_features['labels'] == label)[0]
        train_indices = train_indices + label_indices[:shot_num].tolist()
        val_indices = val_indices + label_indices[shot_num:2*shot_num].tolist()
    assert len(train_indices) == len(labels) * shot_num
    assert len(val_indices) == len(labels) * shot_num
    new_train_features = {
        'train': take_indices(train_features, train_indices),
        'val': take_indices(train_features, val_indices),
    }
    return new_train_features

def main():
    if torch.cuda.is_available():
        torch.backends.cudnn.benchmark = True

    audio_features_path = os.path.join(ESC_DIR, 'features.pt')
    assert os.path.exists(audio_features_path), \
        f"Audio features not found at {audio_features_path}. Please run python audio_features.py under audioclip/."
    audio_features = torch.load(audio_features_path)

    for dataset in CLASS_MAP:
        print(f"Dataset: {dataset}")
        result_dict_path = os.path.join(result_dir, f"{dataset}_result_all.pt")

        if os.path.exists(result_dict_path):
            continue
        else:
            result_dict = {
                task: {
                    'zero_shot': {},
                    'linear_prob': {},
                    'audiovisual_linear_prob': {}, # task modality + audio or image
                    'plustext_linear_prob': {}, # task modality + text
                    'allmodal_linear_prob': {}, # all three modality
                }
                for task in TASKS
            }

        original_dataset = CLASS_MAP[dataset]['dataset']
        class_map = CLASS_MAP[dataset]['class_map']
        sorted_classes = sorted(list(class_map.keys()))

        for task in TASKS:
            dataset_dir = os.path.join(result_dir, dataset)
            makedirs(dataset_dir)
            task_dir = os.path.join(dataset_dir, task)
            makedirs(task_dir)

            for split_index in SPLITS:
                split_dir = os.path.join(task_dir, f"split_{split_index}")
                makedirs(split_dir)

                ### Construct test set
                if task == 'image':
                    # load image testset
                    test_features_path = get_test_features_path(
                        original_dataset,
                        default.FEATURE_DIR,
                        clip_encoder,
                        image_layer_idx
                    )
                    assert os.path.exists(test_features_path), \
                        f"Image features not found at {test_features_path}. Please run python features.py"
                    test_features = torch.load(test_features_path)

                    test_features = transform_features(test_features, sorted_classes)
                elif task == 'audio':
                    test_features = {
                        'features': None,
                        'labels': None,
                    }
                    for test_split_index in SPLITS:
                        if test_split_index != split_index:
                            transformed_audio_features = transform_audio_features(
                                audio_features[test_split_index], class_map, sorted_classes)
                            if test_features['features'] is None:
                                test_features['features'] = transformed_audio_features['features']
                                test_features['labels'] = transformed_audio_features['labels']
                            else:
                                test_features['features'] = torch.cat(
                                    (test_features['features'], transformed_audio_features['features']))
                                test_features['labels'] = torch.cat(
                                    (test_features['labels'], transformed_audio_features['labels']))

                test_dataset = TensorDataset(
                    test_features['features'],
                    test_features['labels']
                )
                print(f"{task} dataset has {len(test_dataset)} test examples ({dataset})")

                # 1: zero-shot-classifier with text
                result_dict[task]['zero_shot'][split_index] = {}
                text_features_path = get_text_features_path(
                    original_dataset,
                    default.FEATURE_DIR,
                    clip_encoder,
                    text_layer_idx,
                    text_augmentation
                )
                assert os.path.exists(text_features_path), \
                    f"Text features not found at {text_features_path}. Please run python features.py"

                text_features = torch.load(text_features_path)
                text_features['features'] = torch.nn.functional.normalize(text_features['features'], dim=1)
                text_features = transform_features(text_features, sorted_classes)
                text_dataset = TensorDataset(
                    text_features['features'], text_features['labels']
                )
                test_acc = evaluate(clip_encoder, classifier_head, logit, text_dataset, test_dataset)
                result_dict[task]['zero_shot'][split_index]['text'] = test_acc
                print(f"Zero-shot-text-classifier for {task} classification with template {text_augmentation}: {test_acc} ({dataset}-{split_index})")

                for shot_num in SHOTS:
                    ### Construct train set for {task} modality
                    if task == 'image':
                        other = 'audio'
                        train_features_path = get_image_features_path(
                            original_dataset,
                            shot_num,
                            split_index+1,
                            default.FEATURE_DIR,
                            clip_encoder,
                            image_layer_idx,
                            "none", # meaning center crop
                        )
                        assert os.path.exists(train_features_path), \
                            f"Image features not found at {train_features_path}. Please run python features.py"
                        train_features = torch.load(train_features_path)
                        train_features['train'] = transform_features(train_features['train'], sorted_classes)
                        train_features['val'] = transform_features(train_features['val'], sorted_classes)
                    elif task == 'audio':
                        other = 'image'
                        train_features = transform_audio_features(
                            audio_features[split_index], class_map, sorted_classes)
                        train_features = construct_few_shot_dataset(train_features, shot_num)

                    # normalize both train and val features
                    train_features['train']['features'] = torch.nn.functional.normalize(train_features['train']['features'], dim=1)
                    train_features['val']['features'] = torch.nn.functional.normalize(train_features['val']['features'], dim=1)
                    train_dataset = TensorDataset(
                        train_features['train']['features'], train_features['train']['labels'])
                    val_dataset = TensorDataset(
                        train_features['val']['features'], train_features['val']['labels'])
                    print(f"{task} dataset has {len(train_dataset)} train examples and {len(val_dataset)} val examples ({dataset}-{split_index})")

                    result_dict[task]['zero_shot'][split_index][shot_num] = {}

                    # 2: zero-shot-classifier with {task} modality
                    test_acc = evaluate(clip_encoder, classifier_head, logit, train_dataset, test_dataset)
                    result_dict[task]['zero_shot'][split_index][shot_num][task] = test_acc
                    print(f"Zero-shot-{task}-classifier for {task} classification: {test_acc} ({dataset}-{split_index})")

                    result_dict[task]['zero_shot'][split_index][shot_num][other] = {}

                    # 3: linear classifier with {task}-modal or cross-modal classifier
                    for seed_idx in SPLITS:
                        if seed_idx >= 0:
                            print("Setting fixed seed: {}".format(seed_idx))
                            set_random_seed(seed_idx)

                        if task == 'image':
                            ### Construct a one-shot audio dataset
                            other_features = transform_audio_features(
                                audio_features[seed_idx], class_map, sorted_classes)
                            other_features = construct_few_shot_dataset(other_features, 1)['train']
                        elif task == 'audio':
                            ### Load a one-shot image dataset
                            other_features_path = get_image_features_path(
                                original_dataset,
                                1,
                                seed_idx+1,
                                default.FEATURE_DIR,
                                clip_encoder,
                                image_layer_idx,
                                "none",
                            )
                            assert os.path.exists(other_features_path), \
                                f"Image features not found at {other_features_path}. Please run python features.py"
                            other_features = torch.load(other_features_path)
                            other_features = transform_features(other_features['train'], sorted_classes)

                        # normalize other features
                        other_features['features'] = torch.nn.functional.normalize(other_features['features'], dim=1)

                        all_features = {}
                        # concatenate other with text features
                        all_features['features'] = torch.cat(
                            (other_features['features'], text_features['features']), dim=0)
                        all_features['labels'] = torch.cat(
                            (other_features['labels'], text_features['labels']), dim=0)

                        other_dataset = TensorDataset(
                            other_features['features'], other_features['labels']
                        )
                        all_dataset = TensorDataset(
                            all_features['features'], all_features['labels']
                        )

                        # 4: zero-shot-classifier with {other} modality
                        test_acc = evaluate(clip_encoder, classifier_head, logit, other_dataset, test_dataset)
                        result_dict[task]['zero_shot'][split_index][shot_num][other][seed_idx] = test_acc
                        print(f"Zero-shot-{other}-classifier for {task} classification: {test_acc} ({dataset}-{split_index})")

                        hyperparams = HYPER_DICT[hyperparams_audio]
                        # Caveat: Not filtering out invalid batch sizes
                        VALID_BATCH_SIZES = hyperparams['batch_size']

                        def get_experiment_count(hyperparams):
                            count = 1
                            count *= len(hyperparams['lr'])
                            count *= len(hyperparams['weight_decay'])
                            count *= len(VALID_BATCH_SIZES)
                            count *= len(hyperparams['max_iter'])
                            return count
                        experiment_count = get_experiment_count(hyperparams)
                        cur_count = 0

                        # sweep through hyperparameters
                        for lr in hyperparams['lr']:
                            for wd in hyperparams['weight_decay']:
                                for batch_size in VALID_BATCH_SIZES:
                                    for iters in hyperparams['max_iter']:
                                        cur_count += 1

                                        hyperparams_str = get_hyperparams_str(
                                            hyperparams['optim'], lr, wd, batch_size, iters)

                                        # check if experiment has been done
                                        print(f"[{cur_count}/{experiment_count}]: {hyperparams_str}. Running")

                                        train_mode_dict = {
                                            'linear_prob': ('none', 0., 0., 0.),
                                            'audiovisual_linear_prob': ('zeroshot', 0.5, 0., 0.),
                                            'plustext_linear_prob': ('zeroshot', 0., 0., 0.5),
                                            'allmodal_linear_prob': ('zeroshot', 0., 0.5, 0.),
                                        }
                                        for train_mode in train_mode_dict.keys():
                                            head_type, other_batch_ratio, all_batch_ratio, text_batch_ratio = train_mode_dict[train_mode]

                                            if all_batch_ratio > 0:
                                                zeroshot_dataset = all_dataset
                                            elif text_batch_ratio > 0:
                                                zeroshot_dataset = text_dataset
                                            elif other_batch_ratio > 0:
                                                zeroshot_dataset = other_dataset
                                            else:
                                                zeroshot_dataset = other_dataset # won't be used for init because head_type is 'none'
                                            head, _, _ = make_classifier_head(
                                                                classifier_head,
                                                                clip_encoder,
                                                                head_type,
                                                                zeroshot_dataset
                                                         )
                                            logit_head = LogitHead(
                                                head,
                                                logit_scale=logit,
                                            ).train().cuda()

                                            # Create the optimizer
                                            params_groups = [
                                                {'params': logit_head.parameters()},
                                            ]
                                            optimizer = build_optimizer(params_groups, hyperparams['optim'], lr, wd)
                                            scheduler = build_lr_scheduler(
                                                optimizer,
                                                hyperparams['lr_scheduler'],
                                                hyperparams['warmup_iter'],
                                                iters,
                                                warmup_type=hyperparams['warmup_type'],
                                                warmup_lr=hyperparams['warmup_min_lr']
                                            )
                                            criterion = torch.nn.CrossEntropyLoss()
                                            all_batch_size = int(batch_size * all_batch_ratio)
                                            other_batch_size = int(batch_size * other_batch_ratio)
                                            text_batch_size = int(batch_size * text_batch_ratio)

                                            if all_batch_ratio > 0:
                                                assert other_batch_ratio == 0
                                                assert text_batch_ratio == 0
                                                train_batch_size = batch_size - all_batch_size
                                            elif text_batch_ratio > 0:
                                                assert other_batch_ratio == 0
                                                assert all_batch_ratio == 0
                                                train_batch_size = batch_size - text_batch_size
                                            else:
                                                assert text_batch_ratio == 0
                                                assert all_batch_ratio == 0
                                                train_batch_size = batch_size - other_batch_size

                                            other_loader = None
                                            if other_batch_ratio > 0:
                                                other_loader = DataLoader(
                                                    other_dataset,
                                                    batch_size=other_batch_size,
                                                    shuffle=True,
                                                    num_workers=0,
                                                    pin_memory=True,
                                                    drop_last=True,
                                                )
                                            elif all_batch_ratio > 0:
                                                other_loader = DataLoader(
                                                    all_dataset,
                                                    batch_size=all_batch_size,
                                                    shuffle=True,
                                                    num_workers=0,
                                                    pin_memory=True,
                                                    drop_last=True,
                                                )
                                            elif text_batch_ratio > 0:
                                                other_loader = DataLoader(
                                                    text_dataset,
                                                    batch_size=text_batch_size,
                                                    shuffle=True,
                                                    num_workers=0,
                                                    pin_memory=True,
                                                    drop_last=True,
                                                )

                                            train_loader = None
                                            if train_batch_size > 0:
                                                train_loader = DataLoader(
                                                    train_dataset,
                                                    batch_size=train_batch_size,
                                                    shuffle=True,
                                                    num_workers=0,
                                                    pin_memory=True,
                                                    drop_last=True,
                                                )

                                            val_loader = DataLoader(
                                                val_dataset,
                                                batch_size=batch_size,
                                                shuffle=False,
                                                num_workers=0,
                                                pin_memory=True,
                                            )

                                            test_loader = DataLoader(
                                                test_dataset,
                                                batch_size=batch_size,
                                                shuffle=False,
                                                num_workers=0,
                                                pin_memory=True,
                                            )

                                            best_val_dict = train(
                                                logit_head,
                                                train_loader, val_loader, other_loader, test_loader,
                                                optimizer, scheduler, criterion, iters,
                                                eval_freq=100
                                            )

                                            if not split_index in result_dict[task][train_mode]:
                                                result_dict[task][train_mode][split_index] = {}
                                            if not shot_num in result_dict[task][train_mode][split_index]:
                                                result_dict[task][train_mode][split_index][shot_num] = {}
                                            if not seed_idx in result_dict[task][train_mode][split_index][shot_num]:
                                                result_dict[task][train_mode][split_index][shot_num][seed_idx] = {
                                                    'all': {},
                                                    'best': {},
                                                }
                                            result_dict[task][train_mode][split_index][shot_num][seed_idx]['all'][hyperparams_str] = {
                                                "val_acc": best_val_dict["val_acc"],
                                                "test_acc": best_val_dict["test_acc"],
                                            }
                                            print(f"Test acc {dataset} {train_mode} {split_index} {shot_num} {seed_idx} {hyperparams_str}: {best_val_dict['test_acc']}")

                        for train_mode in train_mode_dict.keys():
                            best_val_acc = 0.
                            for hyperparams_str in result_dict[task][train_mode][split_index][shot_num][seed_idx]['all'].keys():
                                val_acc = result_dict[task][train_mode][split_index][shot_num][seed_idx]['all'][hyperparams_str]["val_acc"]
                                if val_acc > best_val_acc:
                                    best_val_acc = val_acc
                                    best_test_acc = result_dict[task][train_mode][split_index][shot_num][seed_idx]['all'][hyperparams_str]["test_acc"]
                                    best_hyperparams_str = hyperparams_str
                            result_dict[task][train_mode][split_index][shot_num][seed_idx]['best'] = {
                                "val_acc": best_val_acc,
                                "test_acc": best_test_acc,
                                "hyperparams_str": best_hyperparams_str,
                            }
        torch.save(result_dict, result_dict_path)

    METHODS = ['linear_prob',
               'audiovisual_linear_prob',
               'plustext_linear_prob',
               'allmodal_linear_prob',
               'zero_shot_text',
               'zero_shot_image',
               'zero_shot_audio',
    ]
    # Take average
    for dataset in CLASS_MAP:
        print(f"Dataset: {dataset}")
        result_dict_path = os.path.join(result_dir, f"{dataset}_result_all.pt")

        assert os.path.exists(result_dict_path), f"Result dict not found: {result_dict_path}"
        result_dict = torch.load(result_dict_path)

        avg_dict = {
            task: {}
            for task in result_dict.keys()
        }

        for task in result_dict.keys():
            if task == 'audio':
                other = 'image'
            else:
                other = 'audio'

            for shot_num in SHOTS:
                avg_dict[task][shot_num] = {
                    method: {'mean': None, 'std': None}
                    for method in METHODS
                }

                zero_shot_tasks = []
                zero_shot_others = []
                linear_probs = []
                audiovisual_linear_probs = []
                allmodal_linear_probs = []
                plustext_linear_probs = []
                win = 0
                for split_index in SPLITS:
                    zero_shot_text = result_dict[task]['zero_shot'][split_index]['text']
                    zero_shot_task = result_dict[task]['zero_shot'][split_index][shot_num][task]
                    zero_shot_tasks.append(zero_shot_task)
                    for seed_idx in SPLITS:
                        zero_shot_other = result_dict[task]['zero_shot'][split_index][shot_num][other][seed_idx]
                        zero_shot_others.append(zero_shot_other)
                        linear_prob = result_dict[task]['linear_prob'][split_index][shot_num][seed_idx]['best']['test_acc']
                        linear_probs.append(linear_prob)
                        audiovisual_linear_prob = result_dict[task]['audiovisual_linear_prob'][split_index][shot_num][seed_idx]['best']['test_acc']
                        audiovisual_linear_probs.append(audiovisual_linear_prob)
                        plustext_linear_prob = result_dict[task]['plustext_linear_prob'][split_index][shot_num][seed_idx]['best']['test_acc']
                        plustext_linear_probs.append(plustext_linear_prob)
                        allmodal_linear_prob = result_dict[task]['allmodal_linear_prob'][split_index][shot_num][seed_idx]['best']['test_acc']
                        allmodal_linear_probs.append(allmodal_linear_prob)
                        methods = {
                            'linear_prob': linear_prob,
                            'audiovisual_linear_prob': audiovisual_linear_prob,
                            'plustext_linear_prob': plustext_linear_prob,
                            'allmodal_linear_prob': allmodal_linear_prob,
                            'zero_shot_text': zero_shot_text,
                            'zero_shot_image': zero_shot_task if task == 'image' else zero_shot_other,
                            'zero_shot_audio': zero_shot_task if task == 'audio' else zero_shot_other,
                        }
                        if methods['audiovisual_linear_prob'] > methods['linear_prob']:
                            win += 1
                print(f"Audiovisual linear prob outperforms unimodal linear prob: {win}/{len(SPLITS)*len(SPLITS)} for {task} {shot_num}-shot")
                avg_dict[task][shot_num]['zero_shot_text'] = {'mean': zero_shot_text, 'std': 0.0}
                if task == 'audio':
                    zero_shot_images = zero_shot_others
                    zero_shot_audios = zero_shot_tasks
                else:
                    zero_shot_images = zero_shot_tasks
                    zero_shot_audios = zero_shot_others
                avg_dict[task][shot_num]['zero_shot_image'] = {'mean': np.mean(zero_shot_images), 'std': np.std(zero_shot_images)}
                avg_dict[task][shot_num]['zero_shot_audio'] = {'mean': np.mean(zero_shot_audios), 'std': np.std(zero_shot_audios)}
                avg_dict[task][shot_num]['linear_prob'] = {'mean': np.mean(linear_probs), 'std': np.std(linear_probs)}
                avg_dict[task][shot_num]['plustext_linear_prob'] = {'mean': np.mean(plustext_linear_probs), 'std': np.std(plustext_linear_probs)}
                avg_dict[task][shot_num]['audiovisual_linear_prob'] = {'mean': np.mean(audiovisual_linear_probs), 'std': np.std(audiovisual_linear_probs)}
                avg_dict[task][shot_num]['allmodal_linear_prob'] = {'mean': np.mean(allmodal_linear_probs), 'std': np.std(allmodal_linear_probs)}

    import json
    print(json.dumps(avg_dict, indent=2))

if __name__ == "__main__":
    main()


# 自定义进程
from multiprocessing import Process
from time import sleep

class MyProcess(Process):
    def __init__(self, name, s):  # 自定义要传递的参数！
        super(MyProcess, self).__init__()
        self.name = name
        self.s = s

    # 重写run方法
    def run(self):
        n = 1
        while True:
            print(f'进程：{self.name}---->n: {n}')
            sleep(self.s)  # 使用传进来的参数
            n += 1

if __name__ == "__main__":
    p1 = MyProcess('进程1',1) # 创建自定义进程，并传递参数
    p2 = MyProcess('进程2',2)
    p1.start()  # 开始执行进程
    p2.start()

基础语法/自定义进程.py


from django.urls import path
from . import views

urlpatterns = [
  path('', views.home, name='home'),
  path('about/', views.about, name='about'),
  path('lego/', views.lego_index, name='index'),
  path('lego/<int:lego_id>/', views.lego_detail, name='detail'),
  path('lego/create/', views.LegoCreate.as_view(), name='lego_create'),
  path('lego/<int:pk>/update/', views.LegoUpdate.as_view(), name='lego_update'),
  path('lego/<int:pk>/delete/', views.LegoDelete.as_view(), name='lego_delete'),
  path('lego/<int:lego_id>/add_building/', views.add_building, name='add_building'),
  path('lego/<int:lego_id>/assoc_builder/<int:builder_id>/', views.assoc_builder, name='assoc_builder'),
  path('lego/<int:lego_id>/unassoc_builder/<int:builder_id>/', views.unassoc_builder, name='unassoc_builder'),
  path('builders/', views.BuilderList.as_view(), name='builders_index'),
  path('builders/<int:pk>/', views.BuilderDetail.as_view(), name='builders_detail'),
  path('builders/create/', views.BuilderCreate.as_view(), name='builders_create'),
  path('builders/<int:pk>/update/', views.BuilderUpdate.as_view(), name='builders_update'),
  path('builders/<int:pk>/delete/', views.BuilderDelete.as_view(), name='builders_delete'),
]


"""empty message

Revision ID: 274704865593
Revises: 073946a9e623
Create Date: 2020-12-23 15:11:29.167730

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql

# revision identifiers, used by Alembic.
revision = '274704865593'
down_revision = '073946a9e623'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_index(op.f('ix_history_called_on'), 'history', ['called_on'], unique=False)
    op.create_index(op.f('ix_history_backup_called_on'), 'history_backup', ['called_on'], unique=False)
    op.create_index(op.f('ix_history_test_called_on'), 'history_test', ['called_on'], unique=False)
    op.alter_column('telefonica', 'phone',
               existing_type=mysql.VARCHAR(length=50),
               nullable=False)
    op.alter_column('telefonica_backup', 'phone',
               existing_type=mysql.VARCHAR(length=50),
               nullable=False)
    op.alter_column('telefonica_test', 'phone',
               existing_type=mysql.VARCHAR(length=50),
               nullable=False)
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('telefonica_test', 'phone',
               existing_type=mysql.VARCHAR(length=50),
               nullable=True)
    op.alter_column('telefonica_backup', 'phone',
               existing_type=mysql.VARCHAR(length=50),
               nullable=True)
    op.alter_column('telefonica', 'phone',
               existing_type=mysql.VARCHAR(length=50),
               nullable=True)
    op.drop_index(op.f('ix_history_test_called_on'), table_name='history_test')
    op.drop_index(op.f('ix_history_backup_called_on'), table_name='history_backup')
    op.drop_index(op.f('ix_history_called_on'), table_name='history')
    # ### end Alembic commands ###


import warnings
from typing import List, Optional, Union, cast

import torch

import theseus.constants
from torchlie.functional import SE3 as SE3_base

from .lie_group import LieGroup
from .lie_group_check import _LieGroupCheckContext, no_lie_group_check
from .point_types import Point3
from .so3 import SO3

class SE3(LieGroup):
    def __init__(
        self,
        x_y_z_quaternion: Optional[torch.Tensor] = None,
        tensor: Optional[torch.Tensor] = None,
        name: Optional[str] = None,
        dtype: Optional[torch.dtype] = None,
        strict_checks: bool = False,
        disable_checks: bool = False,
    ):
        if x_y_z_quaternion is not None and tensor is not None:
            raise ValueError("Please provide only one of x_y_z_quaternion or tensor.")
        if x_y_z_quaternion is not None:
            dtype = x_y_z_quaternion.dtype
        super().__init__(
            tensor=tensor,
            name=name,
            dtype=dtype,
            strict_checks=strict_checks,
            disable_checks=disable_checks,
        )
        if x_y_z_quaternion is not None:
            self.update_from_x_y_z_quaternion(x_y_z_quaternion=x_y_z_quaternion)

    @staticmethod
    def rand(
        *size: int,
        generator: Optional[torch.Generator] = None,
        dtype: Optional[torch.dtype] = None,
        device: theseus.constants.DeviceType = None,
        requires_grad: bool = False,
    ) -> "SE3":
        if len(size) != 1:
            raise ValueError("The size should be 1D.")
        tensor = SE3_base.rand(
            *size,
            generator=generator,
            dtype=dtype,
            device=device,
            requires_grad=requires_grad,
        )
        return SE3(tensor=tensor, disable_checks=True)

    @staticmethod
    def randn(
        *size: int,
        generator: Optional[torch.Generator] = None,
        dtype: Optional[torch.dtype] = None,
        device: theseus.constants.DeviceType = None,
        requires_grad: bool = False,
    ) -> "SE3":
        if len(size) != 1:
            raise ValueError("The size should be 1D.")
        tensor = SE3_base.randn(
            *size,
            generator=generator,
            dtype=dtype,
            device=device,
            requires_grad=requires_grad,
        )
        return SE3(tensor=tensor, disable_checks=True)

    @staticmethod
    def _init_tensor() -> torch.Tensor:  # type: ignore
        return torch.eye(3, 4).view(1, 3, 4)

    def dof(self) -> int:
        return 6

    def __repr__(self) -> str:
        return f"SE3(tensor={self.tensor}, name={self.name})"

    def __str__(self) -> str:
        with torch.no_grad():
            return f"SE3(matrix={self.tensor}), name={self.name})"

    def _adjoint_impl(self) -> torch.Tensor:
        return SE3_base.adj(self.tensor)

    def _project_impl(
        self, euclidean_grad: torch.Tensor, is_sparse: bool = False
    ) -> torch.Tensor:
        self._project_check(euclidean_grad, is_sparse)
        if is_sparse:
            return SE3_base.left_project(self.tensor, euclidean_grad)
        else:
            ret = self.tensor.new_zeros(euclidean_grad.shape[:-2] + torch.Size([6]))
            temp = torch.einsum(
                "...jk,...ji->...ik", euclidean_grad, self.tensor[:, :, :3]
            )
            ret[..., :3] = temp[..., 3]
            ret[..., 3] = temp[..., 2, 1] - temp[..., 1, 2]
            ret[..., 4] = temp[..., 0, 2] - temp[..., 2, 0]
            ret[..., 5] = temp[..., 1, 0] - temp[..., 0, 1]

            return ret

    @staticmethod
    def _check_tensor_impl(tensor: torch.Tensor) -> bool:
        if tensor.ndim != 3 or tensor.shape[1:] != (3, 4):
            raise ValueError("SE3 data tensors can only be 3x4 matrices.")
        try:
            SE3_base.check_group_tensor(tensor)
        except ValueError:
            return False
        return True

    @staticmethod
    def x_y_z_unit_quaternion_to_SE3(x_y_z_quaternion: torch.Tensor) -> "SE3":
        if x_y_z_quaternion.ndim == 1:
            x_y_z_quaternion = x_y_z_quaternion.unsqueeze(0)

        if x_y_z_quaternion.ndim != 2 and x_y_z_quaternion.shape[1] != 7:
            raise ValueError("x_y_z_quaternion can only be 7-D vectors.")

        ret = SE3()

        batch_size = x_y_z_quaternion.shape[0]
        ret.tensor = torch.empty(batch_size, 3, 4).to(
            device=x_y_z_quaternion.device, dtype=x_y_z_quaternion.dtype
        )
        ret[:, :, :3] = SO3.unit_quaternion_to_SO3(x_y_z_quaternion[:, 3:]).tensor
        ret[:, :, 3] = x_y_z_quaternion[:, :3]

        return ret

    @staticmethod
    def _hat_matrix_check(matrix: torch.Tensor):
        if matrix.ndim != 3 or matrix.shape[1:] != (4, 4):
            raise ValueError("Hat matrices of SE3 can only be 4x4 matrices")

        checks_enabled, silent_unchecks = _LieGroupCheckContext.get_context()
        if checks_enabled:
            return SE3_base.check_hat_tensor(matrix)
        elif not silent_unchecks:
            warnings.warn(
                "Lie group checks are disabled, so the skew-symmetry of hat matrices is "
                "not checked for SE3.",
                RuntimeWarning,
            )

    @staticmethod
    def exp_map(
        tangent_vector: torch.Tensor, jacobians: Optional[List[torch.Tensor]] = None
    ) -> "SE3":
        if tangent_vector.ndim != 2 or tangent_vector.shape[1] != 6:
            raise ValueError("Tangent vectors of SE3 can only be 6D vectors.")
        return SE3(
            tensor=SE3_base.exp(tangent_vector, jacobians=jacobians),
            disable_checks=True,
        )

    @staticmethod
    def normalize(tensor: torch.Tensor) -> torch.Tensor:
        if tensor.ndim != 3 or tensor.shape[1:] != (3, 4):
            raise ValueError("SE3 data tensors can only be 3x4 matrices.")
        return SE3_base.normalize(tensor)

    def _log_map_impl(
        self, jacobians: Optional[List[torch.Tensor]] = None
    ) -> torch.Tensor:
        return SE3_base.log(self.tensor, jacobians=jacobians)

    def _compose_impl(self, se3_2: LieGroup) -> "SE3":
        return SE3(
            tensor=SE3_base.compose(self.tensor, se3_2.tensor), strict_checks=False
        )

    def _inverse_impl(self, get_jacobian: bool = False) -> "SE3":
        return SE3(tensor=SE3_base.inv(self.tensor), disable_checks=True)

    def to_matrix(self) -> torch.Tensor:
        ret = self.tensor.new_zeros(self.shape[0], 4, 4)
        ret[:, :3] = self.tensor
        ret[:, 3, 3] = 1
        return ret

    # The quaternion takes the [w x y z] convention
    def update_from_x_y_z_quaternion(self, x_y_z_quaternion: torch.Tensor):
        self.update(SE3.x_y_z_unit_quaternion_to_SE3(x_y_z_quaternion))

    def update_from_rot_and_trans(self, rotation: SO3, translation: Point3):
        if rotation.shape[0] != translation.shape[0]:
            raise ValueError("rotation and translation must have the same batch size.")

        if rotation.dtype != translation.dtype:
            raise ValueError("rotation and translation must be of the same type.")

        if rotation.device != translation.device:
            raise ValueError("rotation and translation must be on the same device.")

        self.tensor = torch.cat(
            (rotation.tensor, translation.tensor.unsqueeze(2)), dim=2
        )

    @staticmethod
    def hat(tangent_vector: torch.Tensor) -> torch.Tensor:
        return SE3_base.hat(tangent_vector)

    @staticmethod
    def vee(matrix: torch.Tensor) -> torch.Tensor:
        return SE3_base.vee(matrix)

    def _copy_impl(self, new_name: Optional[str] = None) -> "SE3":
        # if self.tensor is a valid SE3, so is the copy
        return SE3(tensor=self.tensor.clone(), name=new_name, disable_checks=True)

    # only added to avoid casting downstream
    def copy(self, new_name: Optional[str] = None) -> "SE3":
        return cast(SE3, super().copy(new_name=new_name))

    def _transform_shape_check(self, point: Union[Point3, torch.Tensor]):
        err_msg = (
            f"SE3 can only transform vectors of shape [{self.shape[0]}, 3] or [1, 3], "
            f"but the input has shape {point.shape}."
        )

        if isinstance(point, torch.Tensor):
            if not point.ndim == 2 or point.shape[1] != 3:
                raise ValueError(err_msg)
        elif point.dof() != 3:
            raise ValueError(err_msg)
        if (
            point.shape[0] != self.shape[0]
            and point.shape[0] != 1
            and self.shape[0] != 1
        ):
            raise ValueError(err_msg)

    def transform_from(
        self,
        point: Union[Point3, torch.Tensor],
        jacobians: Optional[List[torch.Tensor]] = None,
    ) -> Point3:
        self._transform_shape_check(point)
        p = point if isinstance(point, torch.Tensor) else point.tensor
        return Point3(SE3_base.transform(self.tensor, p, jacobians=jacobians))

    def transform_to(
        self,
        point: Union[Point3, torch.Tensor],
        jacobians: Optional[List[torch.Tensor]] = None,
    ) -> Point3:
        self._transform_shape_check(point)
        p = point if isinstance(point, torch.Tensor) else point.tensor
        return Point3(SE3_base.untransform(self.tensor, p, jacobians=jacobians))

    # The returned tensor will have 7 elements, [x, y, z, qw, qx, qy, qz] where
    # [x y z] corresponds to the translation and [qw qx qy qz] to the quaternion
    # using the [w x y z] convention
    def to_x_y_z_quaternion(self) -> torch.Tensor:
        ret = self.tensor.new_zeros(self.shape[0], 7)
        ret[:, :3] = self.tensor[:, :, 3]
        ret[:, 3:] = SO3(
            tensor=self.tensor[:, :, :3], disable_checks=True
        ).to_quaternion()
        return ret

    def rotation(self) -> SO3:
        return SO3(tensor=self.tensor[:, :, :3], disable_checks=True)

    def translation(self) -> Point3:
        with no_lie_group_check(silent=True):
            return Point3(tensor=self.tensor[:, :, 3].view(-1, 3))

    # calls to() on the internal tensors
    def to(self, *args, **kwargs):
        super().to(*args, **kwargs)

rand_se3 = SE3.rand
randn_se3 = SE3.randn


from project_app.views import *
from django.urls import path
from django.urls import path, include
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'login',UserViewSet,basename="login")
router.register(r'projects',ProjectViewSet,basename="project")
router.register(r'lists',ListViewSet,basename="list")
router.register(r'cards',CardViewSet,basename="card")
router.register(r'comments',CommentViewSet,basename="comment")
urlpatterns = router.urls
urlpatterns = [
    path('', include(router.urls)),
    path('get_oauth_token/', new_token),
    path('send_token_request/', login_redirect),
    path('logout_user/', logout_user),
    path('projects/create/',create_project),
    path('create_list/',create_list),
    path('create_card/',create_card),
    path('create_comment/',create_comment),
    path('create_project/',create_project),
    path('add_members/<int:project_id>/', addMember, name='add_members'),
    path('get_project_by_name/', get_project_by_name, name='get_project_by_name'),
    path('users/disable/', UserViewSet.as_view({'post': 'disable_user'}), name='disable-user'),
    path('users/change_user_role/', UserViewSet.as_view({'post': 'change_user_role'}), name='change_user_role'),

]


import requests
import json
from bs4 import BeautifulSoup

def parse_venue_location(location):
    try:
        [city, venue_name] = location.split(':')
        city = city.strip()
        venue_name = venue_name.strip()
    except Exception:
        city = location
        venue_name = location

    return [city, venue_name]

def extract_venue_details(venue):
    venue_details = venue[0].h2.text
    [city, venue_name] = parse_venue_location(venue_details)

    return [city, venue_name, venue[0].h4.text]

def parse_event(text):
    event_soup = BeautifulSoup(text, 'html.parser')

    info = event_soup.find_all('div', ['event-information'])
    venue = event_soup.find_all('div', ['venue-details'])

    [city, venue_name, date] = extract_venue_details(venue)

    return {
        'name': info[0].h1.text,
        'date': date,
        'venue': venue_name,
        'city': city,
        'artists': info[0].h4.text
    }

def scrape_event(url):
    event_request = requests.get(url)

    return parse_event

def scrape_page(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.text, 'html.parser')
    event_links = soup.find_all('a', ['event_link'])
    parsedData = []

    for link in event_links:
        data = scrape_event(link.attrs['href'])

        #it's easier to get the price from the listings
        event = link.parent.parent
        try:
            price = event.find_all('div', ['searchResultsPrice'])[0].text
        except Exception:
            price = '??'

        data['price'] = price
        parsedData.append(data)

    next_link = soup.find_all('a', ['nextlink'])

    return [parsedData, next_link]

def dump_concerts(data):
    with open('concert.json', 'a') as outfile:
        json.dump(parsedData, outfile, sort_keys=True, indent=4, ensure_ascii=False)

if __name__ == '__main__':

    [parsedData, next_link] = scrape_page('http://www.wegottickets.com/searchresults/all')
    dump_concerts(parsedData)

    while(len(next_link)):
        [parsedData, next_link] = scrape_page(next_link[0].attrs['href'])
        dump_concerts(parsedData)


# 과제3 loss, r2출력
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.metrics import r2_score
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from tensorflow.python.ops.gen_data_flow_ops import resource_accumulator_apply_gradient_eager_fallback
import numpy as np
# 데이터를 0 ~ 1사이의 값을 가진 데이터로 전처리를 하고 모델을 돌렸더니 정확도가 올라간다.
datasets = load_boston()
x = datasets.data
y = datasets.target

print(np.min(x), np.max(x)) # 100부터 시작한다고 하면 기준점이 명확하지 않음.
# 컬럼이 13개이기 때문에 컬럼마다 최소값 최대값이 다르기 때문에 별도로 따로 따로 해주는 것이 맞음.
#
# 데이터 전처리
x = x/711
x = x/np.max(x)
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=66, train_size=0.7, shuffle=True)

model = Sequential()
model.add(Dense(128, activation='relu', input_dim=13))
model.add(Dense(64, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(1))

model.compile(loss="mse", optimizer="adam", loss_weights=1)
model.fit(x_train, y_train, epochs=100, batch_size=1)

loss = model.evaluate(x_test, y_test)
print('loss : ', loss)

y_predict = model.predict(x)
print('6의 예측 값 : ', y_predict)

r2 = r2_score(y, y_predict)
print('r2 score : ', r2)

# B = 흑인의 비율
# input 13, output 1(506)

# 완료하시오.


"""bot_interface.py contains StyleTransferBot class."""

import telebot
import requests

class StyleTransferBot(telebot.TeleBot):
    """Style Transfer Bot class.

    Args:
        token: telegram bot token given by @BotFather
        host: host with a model running, 127.0.0.1 by default
    """

    def __init__(self, token, host="http://127.0.0.1:1489"):
        """Initialize the user_styles dict and create a bot instance.

        Args:
            token: telegram bot token given by @BotFather
            host: host with a model running, 127.0.0.1 by default
        """
        super().__init__(token)
        self.host = host
        self.user_styles = {}

        @self.message_handler(commands=['start'])
        def start_message(message):
            """Define bot actions on /start command.

            Args:
                message (telebot.types.Message): The structure containing telegram message and its info

            Returns:
                None
            """
            self.send_message(
                message.chat.id,
                (
                    "Hi, this is Style Transfer Bot!\n"
                    "You can specify a style to transfer using /choose_style command and "
                    "/stylize_content to choose a content image to apply the last specified style"
                 )
            )

        @self.message_handler(commands=['choose_style'])
        def request_style(message):
            """Define bot actions on /choose_style command.

            Args:
                message (telebot.types.Message): The structure containing telegram message and its info

            Returns:
                None
            """
            self.send_message(message.chat.id, "Load style image, please.")
            self.register_next_step_handler(message, specify_style)

        @self.message_handler(commands=['stylize_content'])
        def request_content(message):
            """Define bot actions on /stylize_content command.

            Args:
                message (telebot.types.Message): The structure containing telegram message and its info

            Returns:
                None
            """
            if message.chat.id not in self.user_styles:
                request_style(message)
                return

            self.send_message(message.chat.id, "Load an image you want to stylize.")
            self.register_next_step_handler(message, stylize_content)

        def specify_style(message):
            """Put a photo sent by user into user_styles dictionary.

            Args:
                message (telebot.types.Message): The structure containing telegram message and its info

            Returns:
                None
            """
            try:
                file_info = self.get_file(message.photo[-1].file_id)
                style_image = self.download_file(file_info.file_path)
                self.user_styles[message.chat.id] = style_image
                request_content(message)
            except (TypeError, AttributeError, IndexError) as e:
                print(f"Exception occurred: {e}")
                self.send_message(
                    message.chat.id,
                    "Oops... something went unexpected. Try to load image or specify style."
                )

        def stylize_content(message):
            """Take a content image from user's message and runs neural network on it.

            Args:
                message (telebot.types.Message): The structure containing telegram message and its info

            Returns:
                None
            """
            try:
                file_info = self.get_file(message.photo[-1].file_id)
                content_image = self.download_file(file_info.file_path)
                style_image = self.user_styles[message.chat.id]
                self.send_message(message.chat.id, "Wait a sec...")
                response = requests.post(
                    files={"content": content_image, "style": style_image},
                    url=f'{self.host}/generate'
                )
                stylized_image = response.content
                self.send_photo(message.chat.id, stylized_image)
                self.send_message(message.chat.id, "Voila!")
                request_content(message)
            except (TypeError, AttributeError, IndexError) as e:
                print(f"Exception occurred: {e}")
                self.send_message(
                    message.chat.id,
                    "Oops... something went unexpected. Try to load image or specify style."
                )