import numpy as np
import cv2
import math
import matplotlib.pyplot as plt
import matplotlib
import scipy.stats as stats
import functions
import fruitsValues

cv2.namedWindow("Fruit Classifier")
vc = cv2.VideoCapture(1)

fruits = ["apples", "bananas", "oranges"]

trains = []

for f in range(0, np.shape(fruits)[0]):
    trains.append(np.load("./data/descriptor_" + str(fruits[f]) + ".npy")[:, :].T)

covs = []

for f in range(0, np.shape(fruits)[0]):
    covs.append(np.cov(trains[f]))

means = []
for f in range(0, np.shape(fruits)[0]):
    means.append(np.mean(trains[f], axis=1))

def discriminant_function(features, mu, cov, prior):
    """ Evaluates the discriminant function d(x)

        Args:
            features: feature vector of dimension n
            mu: mean vector of the class of which is being computed the probability
            cov: covariance matrix with shape (n,n) of the class
            prior: prior probability of class k

        Returns:
            dx: result of discriminant function
    """
    covinv = np.linalg.inv(cov)  # Auxiliar variable
    muTraspuesta = np.transpose(mu)
    featuresTrapuesta = np.transpose(features)

    matrizaux = np.dot(muTraspuesta, covinv)
    segundaParteIndTerm = np.log(np.linalg.det(cov)) + np.dot(matrizaux, mu)
    indpTerm = np.log(prior) - (1 / 2) * segundaParteIndTerm

    matrizaux1 = np.dot(featuresTrapuesta, covinv)
    linear = np.dot(matrizaux1, mu)

    matrizaux2 = np.dot(featuresTrapuesta, covinv)
    quadratic = (-1 / 2) * (np.dot(matrizaux2, features))

    dx = indpTerm + linear + quadratic  # You can divide this computation in as many lines as you need

    return dx

def classify_image(sign_image):
    """ Classify a traffic sign image by its shape using a bayesian classifier

        Args:
            sign_image: Binarized image
    """

    # Compute descriptor
    image, imageRGBbb = functions.computeImage(sign_image)
    descriptor = functions.genDescriptor(image, imageRGBbb)
    print(descriptor)
    # Classify circle test image
    prior = 1 / np.shape(fruits)[0]
    apple = discriminant_function(descriptor, means[0], covs[0], prior)
    # apple = discriminant_function(descriptor, mean_apples, cov_apples, prior)
    print(apple)

    banana = discriminant_function(descriptor, means[1], covs[1], prior)
    # banana = discriminant_function(descriptor, mean_bananas, cov_bananas, prior)
    print(banana)

    orange = discriminant_function(descriptor, means[2], covs[2], prior)
    print(orange)

    # Search the maximum
    classification = max([apple, banana, orange])

    f = fruitsValues.unDefine()
    if classification == apple:
        print("The sign is an apple\n")
        f = fruitsValues.Apple()
    elif classification == banana:
        print("The sign is a banana\n")
        f = fruitsValues.Banana()
    elif classification == orange:
        print("The sign is an orange\n")
        f = fruitsValues.Orange()
    else:
        print("The sign is an error\n")

    return descriptor, f

texto = "?"

while True:
    while True:
        next, frame = vc.read()
        cv2.imshow("Fruit Classifier", frame)
        if cv2.waitKey(1) == 27:
            break

    cv2.imwrite('./imageToCompute.jpg', frame)
    imageToCompute = cv2.imread("./imageToCompute.jpg", cv2.IMREAD_COLOR)
    _, fruta = classify_image(imageToCompute)

    font = cv2.FONT_HERSHEY_TRIPLEX
    tamanoLetra = 2
    grosorLetra = 3

    while True:
        next2, frame2 = vc.read()
        imageRGB = frame2
        image = functions.computeSameSize(imageRGB)
        contours, hierarchy = cv2.findContours(image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
        xMax, yMax, wMax, hMax = 0, 0, 0, 0
        maxCnt = 0
        for cnt in contours:
            x, y, w, h = cv2.boundingRect(cnt)
            if abs(hMax) * abs(wMax) < abs(h) * abs(w) < (np.shape(image)[0] * np.shape(image)[1]):
                xMax, yMax, wMax, hMax = x, y, w, h
                maxCnt = cnt

        colors = (0, 0, 0)

        fruitBoundingBox = image[xMax:xMax + wMax, yMax:yMax + hMax]
        # image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
        cv2.rectangle(imageRGB, (xMax, yMax), (xMax + wMax, yMax + hMax), colors, 5)
        cv2.drawContours(imageRGB, maxCnt, -1, (0, 0, 255), 2, cv2.LINE_AA)

        # Escribir texto
        ubicacionNombre = (xMax, yMax)
        # Nombre
        cv2.putText(imageRGB, fruta.name, ubicacionNombre, font, tamanoLetra, fruta.color, grosorLetra)
        # Valor nutricional
        d = 60
        cv2.putText(imageRGB, "Kcal: " + str(fruta.kcal), (xMax + wMax - fruta.d, yMax), font, 1, fruta.color, 1)
        cv2.putText(imageRGB, "Proteins: " + str(fruta.proteins), (xMax + wMax - fruta.d, yMax - 25), font, 1,
                    fruta.color, 1)
        cv2.putText(imageRGB, "Hydrates: " + str(fruta.hydrates), (xMax + wMax - fruta.d, yMax - 50), font, 1,
                    fruta.color, 1)
        cv2.putText(imageRGB, "Fat: " + str(fruta.fat), (xMax + wMax - fruta.d, yMax - 75), font, 1, fruta.color, 1)
        cv2.imshow("Fruit Classifier", imageRGB)

        if cv2.waitKey(50) >= 0:
            break


import os
import copy
import math
from tqdm import tqdm
import h5py
import tensorflow as tf
import matplotlib.pyplot as plt
import horovod.tensorflow as hvd
import time
import pdb

from utils import data_generator, calc_multi_cls_measures, dict_mean, log_one_step, save_model
from source.loss import HooknetLoss
from callbacks import SaveModelCallback, TensorBoard

def train(model, optimizer, batch_generator, logger, opts):
    train_generator = data_generator(batch_generator, 'training')
    val_generator = data_generator(copy.deepcopy(batch_generator), 'validation')

    if opts.horovod:
        steps_per_epoch_train = int(math.ceil(opts.steps_per_epoch_train) / hvd.size())
        steps_per_epoch_val = int(math.ceil(opts.val_steps) / hvd.size())
    else:
        steps_per_epoch_train = opts.steps_per_epoch_train
        steps_per_epoch_val = opts.val_steps

    if opts.debug:
        steps_per_epoch_train, steps_per_epoch_val = 10, 10

    loss = HooknetLoss(opts.loss_weights)

    for epoch in tqdm(range(opts.epochs)):

        # Perform the training
        train_metrics = []
        for step in tqdm(range(steps_per_epoch_train)):
            train_metric = train_one_step(model, optimizer, loss, train_generator, epoch, step, opts)
            train_metrics.append(train_metric)

        if opts.horovod:
            train_metrics = hvd.allgather_object(train_metrics)
            train_metrics = [item for sublist in train_metrics for item in sublist]
        train_metrics = dict_mean(train_metrics)

        # Perform the logging step every 'log_every' epochs
        if (epoch % opts.validate_every) == 0 or (epoch == opts.epochs - 1):
            val_metrics = []
            for _ in range(steps_per_epoch_val):
                val_metric = val_one_step(model, loss, val_generator, opts)
                val_metrics.append(val_metric)

            if opts.horovod:
                val_metrics = hvd.allgather_object(val_metrics)
                val_metrics = [item for sublist in val_metrics for item in sublist]
            val_metrics = dict_mean(val_metrics)
        else:
            val_metrics = {}

        # Log to tensorboard
        if (opts.horovod and hvd.rank() == 0) or not opts.horovod:
            log_one_step(logger, train_metrics, '/Train', epoch)
            log_one_step(logger, val_metrics, '/Val', epoch)

    save_model(hooknet, opts)

def train_one_step(model, optimizer, loss, train_generator, epoch, step, opts):
    x_batch, y_batch = next(train_generator)
    with tf.GradientTape() as tape:
        probs = model(x_batch, training=True)
        loss_value = loss(probs, y_batch)

    if opts.horovod:
        tape = hvd.DistributedGradientTape(tape)

    grads = tape.gradient(loss_value, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    if opts.horovod and epoch == step == 0:
        hvd.broadcast_variables(model.variables, root_rank=0)
        hvd.broadcast_variables(optimizer.variables(), root_rank=0)

    train_metrics = calc_multi_cls_measures(y_batch, probs, opts)
    train_metrics['loss'] = loss_value.numpy()
    train_metrics['rank'] = hvd.rank()

    return train_metrics

def val_one_step(model, loss, val_generator, opts):
    x_batch, y_batch = next(val_generator)

    probs = model(x_batch, training=True)
    loss_value = loss(probs, y_batch)

    val_metrics = calc_multi_cls_measures(y_batch, probs, opts)
    val_metrics['loss'] = loss_value.numpy()
    val_metrics['rank'] = hvd.rank()

    return val_metrics


from django.shortcuts import render, get_object_or_404, get_list_or_404, redirect
from .models import Customer,Rental,RentalRate,Vehicle,VehicleSize,VehicleType
from .forms import RentalForm,VehicleForm,CustomerForm

# Create your views here.
# def homepage(request):
#     return render(request,'homepage.html',context={})

def rental(request,rental_id):
    rental = get_object_or_404(Rental.objects.get(id=rental_id))
    rentals_data = {'rental':rental}
    return render(request,'rental.html', context = rentals_data )

def rentals(request):
    rental_list = get_list_or_404(Rental.objects.all().latest('return_date'))
    rentals_data = {'rentals':rental_list}
    return render(request,'rentals.html', context =  rentals_data )

def rental_new(request):
    if request.method == 'POST':
        form = RentalForm(request.POST)
        if form.is_valid():
            print(form.cleaned_data)
            rental = Rental.objects.create(**form.cleaned_data)
            return redirect('rental_page',rental.id)
    if request.method == 'GET':
        form = RentalForm()
    return render(request,'rental_new.html', {'form':form})

def customer(request,customer_id):
    customer = get_object_or_404(Customer.objects.get(id=customer_id))
    customer_data = {'customer':customer}
    return render(request,'customer.html', context = customer_data )

def customers(request):
    customers_data = {}
    return render(request,'customers.html', context = customers_data )

def customer_new(request):
    new_customer_data = {}
    form = CustomerForm(request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        customer = Customer.objects.create(**form.cleaned_data)
        return redirect('customer_page',customer.id)
    if request.method == 'GET':
        form = CustomerForm()
    return render(request,'customer_new.html', {'form':form})

def vehicle(request,vehicle_id):
    vehicle = get_object_or_404(Vehicle.objects.get(id= vehicle_id))
    vehicle_data = {' vehicle': vehicle}
    return render(request,'vehicle.html', context = vehicle_data )

def vehicles(request):
    vehicle_list = get_list_or_404(Vehicle.objects.all())
    vehicles_data = {'vehicles':vehicle_list}
    return render(request,'vehicles.html', context = vehicles_data )

def vehicle_new(request):
    if request.method == 'POST':
        form = VehicleForm(request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        vehicle = Vehicle.objects.create(**form.cleaned_data)
        return redirect('vehicle_page',vehicle.id)
    if request.method == 'GET':
        form = VehicleForm()
    return render(request,'vehicle_new.html', {'form':form})


import unittest
from bbolt import BoltDB
from tempfile import mkstemp
import os

class DBTests(unittest.TestCase):
    def setUp(self):
        self.db = BoltDB()
        fd, self.path = mkstemp()
        os.close(fd)
        self.db.open(self.path)

    def test_non_existant(self):
        self.db.create_bucket("bucket-1")
        r = self.db.get("bucket-1", "k1")
        assert r == b''

    def test_rw(self):
        self.db.put("bucket-1", "k1", "f-x")
        k = self.db.get("bucket-1", "k1").decode("utf-8")
        assert k == "f-x"
        pass

    def addCleanup(self, *arg, **kwargs) -> None:
        os.remove(self.path)


from discord import Embed

class EmbedError():
    """Creates and sends an error message to the channel

    :var int colour: The colour we will use for the error messages

    """

    colour = 0xFF2400

    async def send_error(self, channel, title, name, value, embed=None):
        """Send an error message to the channel"""

        if not embed:
            embed = Embed()
        embed.title = title
        embed.color = self.colour
        embed.insert_field_at(index=0, name=name, value=value, inline=False)
        await channel.send(embed=embed)


from logging import getLogger
from pathlib import Path

from watchdog.events import FileSystemEventHandler

logger = getLogger(__name__)

class LogFileEventHandler(FileSystemEventHandler):
    """Event handler for processing log files."""

    def __init__(self, callback, target_file: Path) -> None:
        """Initialize a new LogFileEventHandler instance.

        Parameters
        ----------
        callback (callable): The function to call when processing a log line.
        target_file (Path): The log file to watch for changes.
        """
        self.callback = callback
        self.target_file = target_file

    def initial_read(self):
        """Read and process the initial content of the log file."""
        with self.target_file.open() as file:
            content = file.readlines()
            for line in content:
                self.callback(line)

    def on_modified(self, event):
        """Handle the file modification event."""
        if str(event.src_path) == str(self.target_file):
            with Path(event.src_path).open() as file:
                content = file.readlines()
                for line in content[-1:]:
                    self.callback(line)


import csv
import numpy as np
import matplotlib.pyplot as plt

# Read sensor data
f = open('inputData/Sensor Data 03.csv', 'r')
rdr = csv.reader(f)
xvalues = []
yvalues = []
zvalues = []
isFirstLine = True
for line in rdr:
    if isFirstLine:
        isFirstLine = False
    else:
        xvalues.append(float(line[0].strip(',')))
        yvalues.append(float(line[1].strip(',')))
        zvalues.append(float(line[2].strip(',')))
f.close()
xvalues.pop(0)
yvalues.pop(0)
zvalues.pop(0)
values = []
values.append(xvalues)
values.append(yvalues)
values.append(zvalues)

axis = 0
x = values[axis][0] # 초기 추정값
P = np.array([[10]]) # 초기 추정값에 대한 오차 공분산
A = np.array([[1]]) # 시스템 행렬
H = np.array([[1]]) # 출력 행렬
Q = np.array([[1]]) # 시스템 오차
R = np.array([[10]]) # 측정 오차

z = values[axis]
def SimpleKalman(z):
    global x, P, A, H, Q, R
    # 추값과 오차 공분산 예측
    xp = A.dot(x)
    Pp = A.dot(P).dot(A.T) + Q

    # 칼만 이득 계산
    K = Pp.dot(H.T).dot(np.linalg.inv(H.dot(P).dot(H.T) + R))

    # 추정값 계산
    x = xp + K.dot(z - H.dot(xp))

    # 오차 공분산 계산
    P = Pp - K.dot(H).dot(Pp)

    return x, P, K

z_result = [] # 측정값
est_result = [] # 추정값
Cov_result = []
Kg_result = []

for i in range(len(values[axis])):
    z = values[axis][i]
    est, Cov, Kg = SimpleKalman(z)
    z_result.append(z)
    est_result.append(est[0])
    Cov_result.append(Cov[0, 0])
    Kg_result.append(Kg[0, 0])

vel_z = []
vel_z_value = 0.0
for i in z_result:
    vel_z_value = vel_z_value + i
    vel_z.append(vel_z_value)

vel_est = []
vel_est_value = 0.0
for i in est_result:
    vel_est_value = vel_est_value + i
    vel_est.append(vel_est_value)

fig, ax = plt.subplots()

ax.plot(range(len(values[0])), z_result, label='measure')
ax.plot(range(len(values[0])), est_result, label='estimate')
ax.plot(range(len(values[0])), vel_z, label='vel_z')
ax.plot(range(len(values[0])), vel_est, label='vel_Est')

ax.legend()
plt.show()


import json

from asgiref.sync import async_to_sync
from channels.db import database_sync_to_async
from channels.generic.websocket import WebsocketConsumer

from user.models import User

from .models import Message

class ChatConsumer(WebsocketConsumer):
    def connect(self):  # 사용자가 접속했을 때 동작하는 함수
        self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
        self.room_group_name = "chat_%s" % self.room_name
        async_to_sync(self.channel_layer.group_add)(self.room_group_name, self.channel_name)
        self.accept()

    @database_sync_to_async
    def create_message(data):
        author = User.objects.filter(email=data["from"])[0]

        message = Message.objects.create(user=author, content=data["message"])

        return message

    def disconnect(self, close_code):  # 사용자가 방에서 떠났을 때 동작하는 함수
        async_to_sync(self.channel_layer.group_discard)(self.room_group_name, self.channel_name)

    def chat_message(self, event):  # 실제로 메시지를 전송하는 함수
        message = event["message"]
        self.send(text_data=json.dumps(message))

    def receive(self, text_data):  # 채팅방에 메시지가 전파되었을 때 동작하는 함수
        data = json.loads(text_data)

        message = create_message(data)

        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                "type": "chat_message",
                "message": {
                    "message": {
                        "nickname": message.user.nickname,
                        "content": message.content,
                        "created_at": message.created_at,
                        "updated_at": message.updated_at,
                    },
                },
            },
        )


from __future__ import print_function, division, absolute_import
from functools import partial

import torch
from torch import nn
from torch.nn import functional as F
import torchvision.models as M
import pretrainedmodels
import math
import torch.utils.model_zoo as model_zoo

from .xception import *
from .inceptionv4 import *
from .inceptionresnetv2 import *
from .dpn import *
from .maskLayer import maskLayer

from models.dictLayer import DictLayer
from models.netvlad import NetVladLayer,NetVladLayerV2

from utils import load_model_with_dict_replace,load_model_with_dict,load_model

__all__ = ['SENet', 'senet154', 'se_resnet50', 'se_resnet101', 'se_resnet152',
           'se_resnext50_32x4d', 'se_resnext101_32x4d','vggnetvlad']
from collections import OrderedDict

#===================================================================================================
#===================================================================================================
#basic models
#===================================================================================================
#===================================================================================================
class AvgPool(nn.Module):
    def forward(self, x):
        return F.avg_pool2d(x, x.shape[2:])

#===================================================================================================
#===================================================================================================
#===================================================================================================
def create_net(net_cls, pretrained: bool):
    # if ON_KAGGLE and pretrained:
    #     net = net_cls()
    #     model_name = net_cls.__name__
    #     weights_path = f'../input/{model_name}/{model_name}.pth'
    #     net.load_state_dict(torch.load(weights_path))
    # else:
    net = net_cls(pretrained=pretrained)
    return net

#===================================================================================================
#===================================================================================================
# VGGNet
#===================================================================================================
#===================================================================================================
class VggNetVLAD(nn.Module):
    def __init__(self, net_cls=M.vgg16, pretrained='imagenet', center_num = 64):
        super().__init__()
        basemodel = create_net( net_cls=net_cls, pretrained=pretrained)
        self.net = nn.Sequential(*list(basemodel.features.children())[:-2])
        self.vlad = NetVladLayerV2(num_clusters= center_num, dim = 512)
        self.featLen = center_num*512

    def forward(self, input):
        x = self.net(input)
        x = self.vlad(x)
        return x

    def finetune(self, model_path:str):
        load_model_with_dict(self.net, model_path, 'encoder.', '')
        load_model_with_dict(self.vlad, model_path, 'pool.', '')

    def freeze_net(self):
        for param in self.net.parameters():
            param.requires_grad = False

#===================================================================================================
#===================================================================================================
# CNN Toy
#===================================================================================================
#===================================================================================================
class CnnToyNet(nn.Module):
    def __init__(self, num_classes, img_size=64):
        super().__init__()
        self.net = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.MaxPool2d(2, 2),
            nn.LeakyReLU(),
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.MaxPool2d(2, 2),
            nn.LeakyReLU(),
            nn.Conv2d(64, 32, kernel_size=1, padding=0),
            nn.LeakyReLU(),
            nn.AvgPool2d(3,2,1)
        )
        self._scale = 8
        self._fc_len = img_size // self._scale * img_size // self._scale * 32

        self.fc1 = nn.Linear(self._fc_len, 128)
        self.fc2 = nn.Linear(128, num_classes)

    def forward(self, input):
        x = self.net(input)
        #         print(x.shape)
        x = x.view(x.shape[0],-1)
        feat1 = self.fc1(x)
        leaky_feat1 = F.leaky_relu(feat1)
        feat2 = self.fc2(leaky_feat1)

        return feat1, feat2

# ===================================================================================================
# ===================================================================================================
# CNN Toy + vlad
# ===================================================================================================
# ===================================================================================================
class CnnVladToyNet(nn.Module):
    def __init__(self, num_classes, img_size=64):
        super().__init__()
        last_conv_ch = 32
        self.net = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.MaxPool2d(2, 2),
            nn.LeakyReLU(),
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.MaxPool2d(2, 2),
            nn.LeakyReLU(),
            nn.Conv2d(64, last_conv_ch, kernel_size=1, padding=0),
            nn.LeakyReLU(),
            nn.AvgPool2d(3, 2, 1)
        )
        self._scale = 8
        # self._fc_len = img_size // self._scale * img_size // self._scale * 32

        self.vlad = NetVladLayer(input_channels=last_conv_ch,centers_num=32)
        self.fc2 = nn.Linear(self.vlad.output_features, num_classes)

    def forward(self, input):
        x = self.net(input)
        feat1 = self.vlad(x)
        feat2 = self.fc2(feat1)

        return feat1, feat2
#===================================================================================================
#===================================================================================================
# ResNet and DenseNet
#===================================================================================================
#===================================================================================================
class ResNet(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False, net_cls=M.resnet50, dropout=False):
        super().__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.net.avgpool = AvgPool()
        if dropout:
            self.net.fc = nn.Sequential(
                nn.Dropout(),
                nn.Linear(self.net.fc.in_features, num_classes),
            )
        else:
            self.net.fc = nn.Linear(self.net.fc.in_features, num_classes)

    #freeze param
    def freeze(self):
        for param in self.net.parameters():
            param.requires_grad = False

    def fresh_params(self):
        return self.net.fc.parameters()

    def forward(self, x):
        return self.net(x)

#my_model = nn.Sequential(*list(pretrained_model.children())[:-1])
#resnet+1024fc+128fc+softmax
class ResNetV2(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False, net_cls=M.resnet50, dropout=False,fc_dim = 1024):
        super(ResNetV2,self).__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.net.avgpool = AvgPool()
        if dropout:
            self.net.fc = nn.Sequential(
                nn.Linear(self.net.fc.in_features, fc_dim),
                nn.Dropout(),
                nn.ReLU(),
            )
        else:
            self.net.fc = nn.Sequential(
                nn.Linear(self.net.fc.in_features, fc_dim),
                nn.ReLU(),
                )

        self.last_fc = nn.Linear(fc_dim, num_classes)

    #freeze param
    def freeze(self):
        for param in self.net.parameters():
            param.requires_grad = False

    def fresh_params(self):
        return self.net.fc.parameters()

    def forward(self, x):
        fc1 = self.net(x)
        fc2 = self.last_fc(fc1)
        return fc1,fc2

class ResNetV3(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False, net_cls=M.resnet50, dropout=False,fc_dim_per_class = 10):
        super(ResNetV3,self).__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.net.avgpool = AvgPool()

        if dropout:
            self.net.fc = nn.Sequential(
                nn.Linear(self.net.fc.in_features, 1024),
                nn.Dropout(),
                nn.ReLU(),
            )
        else:
            self.net.fc = nn.Sequential(
                nn.Linear(self.net.fc.in_features, 1024),
                nn.ReLU(),
                )

        self.dict_layer = DictLayer( 1024,  fc_dim_per_class*num_classes , num_classes,alpha=0.1)
        self.last_layer = nn.Linear(fc_dim_per_class*num_classes, num_classes)

    #freeze param
    def freeze(self):
        for param in self.net.parameters():
            param.requires_grad = False

    def fresh_params(self):
        return self.net.fc.parameters()

    def forward(self, x, targets):
        fc1 = self.net(x)
        fc2 = self.dict_layer(fc1,targets)
        fc3 = self.last_layer(fc2)
        loss = self.dict_layer.getLoss()
        return fc2,fc3,loss

class ResNetV4(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False,net_cls=M.resnet50, dropout=False):
        super(ResNetV4,self).__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.net.avgpool = AvgPool()
        if dropout:
            self.net.fc = nn.Sequential(
                nn.Linear(self.net.fc.in_features, 1024),
                nn.Dropout(),
                nn.LeakyReLU(),
            )
        else:
            self.net.fc = nn.Sequential(
                nn.Linear(self.net.fc.in_features, 1024),
                nn.LeakyReLU(),
            )

        self.fc_layer = nn.Linear(1024, 1024)
        self.last_layer = nn.Linear(1024, num_classes)

    #freeze param
    def freeze(self):
        for param in self.net.parameters():
            param.requires_grad = False

    def fresh_params(self):
        return self.net.fc.parameters()

    def forward(self, x):
        fc1 = self.net(x)
        fc2 = self.fc_layer(fc1)
        fc2 = F.leaky_relu(fc2)
        fc3 = self.last_layer(fc2)
        return fc2,fc3

    def finetuning(self,num_classes):
        #only change the last layer
        self.last_layer = nn.Linear(1024,num_classes)

# model.classifier = nn.Sequential(*[model.classifier[i] for i in range(4)])
# print(model.classifier)
# model.classifier = nn.Sequential(*list(model.classifier.children())[:-3])
class ResNetVlad(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False, net_cls=M.resnet50, dropout=False, centerK = 32):
        super(ResNetVlad, self).__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.net = nn.Sequential(*list(self.net.children())[:-2]) #get rid of last 2 layer, and conv is last layer

        self.conv = nn.Conv2d(512,64,(1,1))
        self.netvlad = NetVladLayer(64,centers_num=centerK)
        self.netvladlen = self.netvlad.output_features
        self.last_layer = nn.Linear(self.netvladlen,num_classes)

    # freeze param
    def freeze(self):
        for param in self.net.parameters():
            param.requires_grad = False

    def fresh_params(self):
        return list(self.netvlad.parameters(),self.net.last_layer.parameters())

    def forward(self, x):
        fc1 = self.net(x)
        fc1 = self.conv(fc1)
        fc1 = F.leaky_relu(fc1)

        netvladfeat = self.netvlad(fc1)

        clsfeat = self.last_layer(netvladfeat)
        return netvladfeat, clsfeat

    def finetuning(self, num_classes):
        # only change the last layer
        self.last_layer = nn.Linear(self.netvladlen, num_classes)

##======================================================================================================================
##ResNet50 + BBox from Alibaba Image Search
##======================================================================================================================
class ResNetBBoxMask(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False,net_cls=M.resnet50):
        super(ResNetBBoxMask,self).__init__()
        self.netBBox = create_net(net_cls, pretrained=pretrained)
        self.netBBox.avgpool = AvgPool()
        self.netBBox.fc = nn.Linear(self.netBBox.fc.in_features, 4)

        self.mask_layer = maskLayer()

        self.netCls = create_net(net_cls, pretrained=pretrained)
        self.netCls.avgpool = AvgPool()
        self.netCls.fc = nn.Sequential(
            nn.Linear(self.netCls.fc.in_features, 1024),
            nn.LeakyReLU(),
        )
        self.fc_layer = nn.Linear(1024, 1024)
        self.last_layer = nn.Linear(1024, num_classes)

    def forward(self, x):
        bbox = self.netBBox(x)
        bbox = torch.sigmoid(bbox)

        x_hat = self.mask_layer(bbox,x.shape[3])
        x_hat = x_hat.expand(-1,3,-1,-1)

        next_x = x*x_hat

        fc1 = self.netCls(next_x)
        fc2 = self.fc_layer(fc1)
        fc2 = F.leaky_relu(fc2)
        fc3 = self.last_layer(fc2)
        return fc2,fc3,bbox,x_hat

    def fresh_params(self):
        return self.last_layer.parameters()

    def finetuning(self,num_classes):
        #only change the last layer
        self.last_layer = nn.Linear(1024,num_classes)

class DenseNet(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False, net_cls=M.densenet121):
        super().__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.avg_pool = AvgPool()
        self.net.classifier = nn.Linear(
            self.net.classifier.in_features, num_classes)

    def fresh_params(self):
        return self.net.classifier.parameters()

    def forward(self, x):
        out = self.net.features(x)
        out = F.relu(out, inplace=True)
        out = self.avg_pool(out).view(out.size(0), -1)
        out = self.net.classifier(out)
        return out

class DenseNetV2(nn.Module):
    def __init__(self, num_classes,
                 pretrained=False, net_cls=M.densenet121,dropout=False):
        super().__init__()
        self.net = create_net(net_cls, pretrained=pretrained)
        self.avg_pool = AvgPool()
        # self.net.classifier = nn.Linear(
        #     self.net.classifier.in_features, num_classes)
        if dropout:
            self.net.classifier = nn.Sequential(
                nn.Linear(self.net.classifier.in_features, 1024),
                nn.Dropout(),
                nn.LeakyReLU(),
            )
        else:
            self.net.classifier = nn.Sequential(
                nn.Linear(self.net.classifier.in_features, 1024),
                nn.LeakyReLU(),
            )

        self.fc_layer = nn.Linear(1024, 1024)
        self.last_layer = nn.Linear(1024, num_classes)

    def fresh_params(self):
        return self.net.classifier.parameters()

    def forward(self, x):
        out = self.net.features(x)
        out = F.relu(out, inplace=True)
        out = self.avg_pool(out).view(out.size(0), -1)
        out = self.net.classifier(out)
        out = self.fc_layer(out)
        fc2 = F.leaky_relu(out)
        out = self.last_layer(fc2)
        return out

    def finetuning(self,num_classes):
        #only change the last layer
        self.last_layer = nn.Linear(1024,num_classes)

"""
ResNet code gently borrowed from
https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
"""

pretrained_settings = {
    'senet154': {
        'imagenet': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/senet154-c7b49a05.pth',
            'input_space': 'RGB',
            'input_size': [3, 224, 224],
            'input_range': [0, 1],
            'mean': [0.485, 0.456, 0.406],
            'std': [0.229, 0.224, 0.225],
            'num_classes': 1000
        }
    },
    'se_resnet50': {
        'imagenet': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/se_resnet50-ce0d4300.pth',
            'input_space': 'RGB',
            'input_size': [3, 224, 224],
            'input_range': [0, 1],
            'mean': [0.485, 0.456, 0.406],
            'std': [0.229, 0.224, 0.225],
            'num_classes': 1000
        }
    },
    'se_resnet101': {
        'imagenet': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/se_resnet101-7e38fcc6.pth',
            'input_space': 'RGB',
            'input_size': [3, 224, 224],
            'input_range': [0, 1],
            'mean': [0.485, 0.456, 0.406],
            'std': [0.229, 0.224, 0.225],
            'num_classes': 1000
        }
    },
    'se_resnet152': {
        'imagenet': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/se_resnet152-d17c99b7.pth',
            'input_space': 'RGB',
            'input_size': [3, 224, 224],
            'input_range': [0, 1],
            'mean': [0.485, 0.456, 0.406],
            'std': [0.229, 0.224, 0.225],
            'num_classes': 1000
        }
    },
    'se_resnext50_32x4d': {
        'imagenet': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/se_resnext50_32x4d-a260b3a4.pth',
            'input_space': 'RGB',
            'input_size': [3, 224, 224],
            'input_range': [0, 1],
            'mean': [0.485, 0.456, 0.406],
            'std': [0.229, 0.224, 0.225],
            'num_classes': 1000
        }
    },
    'se_resnext101_32x4d': {
        'imagenet': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/se_resnext101_32x4d-3b2fe3d8.pth',
            'input_space': 'RGB',
            'input_size': [3, 224, 224],
            'input_range': [0, 1],
            'mean': [0.485, 0.456, 0.406],
            'std': [0.229, 0.224, 0.225],
            'num_classes': 1000
        }
    },
}

class SEModule(nn.Module):

    def __init__(self, channels, reduction):
        super(SEModule, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1,
                             padding=0)
        self.relu = nn.ReLU(inplace=True)
        self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1,
                             padding=0)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        module_input = x
        x = self.avg_pool(x)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.sigmoid(x)
        return module_input * x

class Bottleneck(nn.Module):
    """
    Base class for bottlenecks that implements `forward()` method.
    """
    def forward(self, x):
        residual = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)

        out = self.conv3(out)
        out = self.bn3(out)

        if self.downsample is not None:
            residual = self.downsample(x)

        out = self.se_module(out) + residual
        out = self.relu(out)

        return out

class SEBottleneck(Bottleneck):
    """
    Bottleneck for SENet154.
    """
    expansion = 4

    def __init__(self, inplanes, planes, groups, reduction, stride=1,
                 downsample=None):
        super(SEBottleneck, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes * 2, kernel_size=1, bias=False)
        self.bn1 = nn.BatchNorm2d(planes * 2)
        self.conv2 = nn.Conv2d(planes * 2, planes * 4, kernel_size=3,
                               stride=stride, padding=1, groups=groups,
                               bias=False)
        self.bn2 = nn.BatchNorm2d(planes * 4)
        self.conv3 = nn.Conv2d(planes * 4, planes * 4, kernel_size=1,
                               bias=False)
        self.bn3 = nn.BatchNorm2d(planes * 4)
        self.relu = nn.ReLU(inplace=True)
        self.se_module = SEModule(planes * 4, reduction=reduction)
        self.downsample = downsample
        self.stride = stride

class SEResNetBottleneck(Bottleneck):
    """
    ResNet bottleneck with a Squeeze-and-Excitation module. It follows Caffe
    implementation and uses `stride=stride` in `conv1` and not in `conv2`
    (the latter is used in the torchvision implementation of ResNet).
    """
    expansion = 4

    def __init__(self, inplanes, planes, groups, reduction, stride=1,
                 downsample=None):
        super(SEResNetBottleneck, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False,
                               stride=stride)
        self.bn1 = nn.BatchNorm2d(planes)
        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1,
                               groups=groups, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
        self.bn3 = nn.BatchNorm2d(planes * 4)
        self.relu = nn.ReLU(inplace=True)
        self.se_module = SEModule(planes * 4, reduction=reduction)
        self.downsample = downsample
        self.stride = stride

class SEResNeXtBottleneck(Bottleneck):
    """
    ResNeXt bottleneck type C with a Squeeze-and-Excitation module.
    """
    expansion = 4

    def __init__(self, inplanes, planes, groups, reduction, stride=1,
                 downsample=None, base_width=4):
        super(SEResNeXtBottleneck, self).__init__()
        width = int(math.floor(planes * (base_width / 64)) * groups)

        self.conv1 = nn.Conv2d(inplanes, width, kernel_size=1, stride=1, bias=False)
        self.bn1 = nn.BatchNorm2d(width)
        self.conv2 = nn.Conv2d(width, width, kernel_size=3, stride=stride,
                               padding=1, groups=groups, bias=False)
        self.bn2 = nn.BatchNorm2d(width)
        self.conv3 = nn.Conv2d(width, planes * 4, kernel_size=1, bias=False)
        self.bn3 = nn.BatchNorm2d(planes * 4)
        self.relu = nn.ReLU(inplace=True)
        self.se_module = SEModule(planes * 4, reduction=reduction)
        self.downsample = downsample
        self.stride = stride

class SENet(nn.Module):

    def __init__(self, block, layers, groups, reduction, dropout_p=0.2,
                 inplanes=128, input_3x3=True, downsample_kernel_size=3,
                 downsample_padding=1, num_classes=1000):
        """
        Parameters
        ----------
        block (nn.Module): Bottleneck class.
            - For SENet154: SEBottleneck
            - For SE-ResNet models: SEResNetBottleneck
            - For SE-ResNeXt models:  SEResNeXtBottleneck
        layers (list of ints): Number of residual blocks for 4 layers of the
            network (layer1...layer4).
        groups (int): Number of groups for the 3x3 convolution in each
            bottleneck block.
            - For SENet154: 64
            - For SE-ResNet models: 1
            - For SE-ResNeXt models:  32
        reduction (int): Reduction ratio for Squeeze-and-Excitation modules.
            - For all models: 16
        dropout_p (float or None): Drop probability for the Dropout layer.
            If `None` the Dropout layer is not used.
            - For SENet154: 0.2
            - For SE-ResNet models: None
            - For SE-ResNeXt models: None
        inplanes (int):  Number of input channels for layer1.
            - For SENet154: 128
            - For SE-ResNet models: 64
            - For SE-ResNeXt models: 64
        input_3x3 (bool): If `True`, use three 3x3 convolutions instead of
            a single 7x7 convolution in layer0.
            - For SENet154: True
            - For SE-ResNet models: False
            - For SE-ResNeXt models: False
        downsample_kernel_size (int): Kernel size for downsampling convolutions
            in layer2, layer3 and layer4.
            - For SENet154: 3
            - For SE-ResNet models: 1
            - For SE-ResNeXt models: 1
        downsample_padding (int): Padding for downsampling convolutions in
            layer2, layer3 and layer4.
            - For SENet154: 1
            - For SE-ResNet models: 0
            - For SE-ResNeXt models: 0
        num_classes (int): Number of outputs in `last_linear` layer.
            - For all models: 1000
        """
        super(SENet, self).__init__()
        self.inplanes = inplanes
        if input_3x3:
            layer0_modules = [
                ('conv1', nn.Conv2d(3, 64, 3, stride=2, padding=1,
                                    bias=False)),
                ('bn1', nn.BatchNorm2d(64)),
                ('relu1', nn.ReLU(inplace=True)),
                ('conv2', nn.Conv2d(64, 64, 3, stride=1, padding=1,
                                    bias=False)),
                ('bn2', nn.BatchNorm2d(64)),
                ('relu2', nn.ReLU(inplace=True)),
                ('conv3', nn.Conv2d(64, inplanes, 3, stride=1, padding=1,
                                    bias=False)),
                ('bn3', nn.BatchNorm2d(inplanes)),
                ('relu3', nn.ReLU(inplace=True)),
            ]
        else:
            layer0_modules = [
                ('conv1', nn.Conv2d(3, inplanes, kernel_size=7, stride=2,
                                    padding=3, bias=False)),
                ('bn1', nn.BatchNorm2d(inplanes)),
                ('relu1', nn.ReLU(inplace=True)),
            ]
        # To preserve compatibility with Caffe weights `ceil_mode=True`
        # is used instead of `padding=1`.
        layer0_modules.append(('pool', nn.MaxPool2d(3, stride=2,
                                                    ceil_mode=True)))
        self.layer0 = nn.Sequential(OrderedDict(layer0_modules))
        self.layer1 = self._make_layer(
            block,
            planes=64,
            blocks=layers[0],
            groups=groups,
            reduction=reduction,
            downsample_kernel_size=1,
            downsample_padding=0
        )
        self.layer2 = self._make_layer(
            block,
            planes=128,
            blocks=layers[1],
            stride=2,
            groups=groups,
            reduction=reduction,
            downsample_kernel_size=downsample_kernel_size,
            downsample_padding=downsample_padding
        )
        self.layer3 = self._make_layer(
            block,
            planes=256,
            blocks=layers[2],
            stride=2,
            groups=groups,
            reduction=reduction,
            downsample_kernel_size=downsample_kernel_size,
            downsample_padding=downsample_padding
        )
        self.layer4 = self._make_layer(
            block,
            planes=512,
            blocks=layers[3],
            stride=2,
            groups=groups,
            reduction=reduction,
            downsample_kernel_size=downsample_kernel_size,
            downsample_padding=downsample_padding
        )

        self.avg_pool = AvgPool()
        self.dropout = nn.Dropout(dropout_p) if dropout_p is not None else None
        self.last_linear = nn.Linear(512 * block.expansion, num_classes)

    def _make_layer(self, block, planes, blocks, groups, reduction, stride=1,
                    downsample_kernel_size=1, downsample_padding=0):
        downsample = None
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
                nn.Conv2d(self.inplanes, planes * block.expansion,
                          kernel_size=downsample_kernel_size, stride=stride,
                          padding=downsample_padding, bias=False),
                nn.BatchNorm2d(planes * block.expansion),
            )

        layers = []
        layers.append(block(self.inplanes, planes, groups, reduction, stride,
                            downsample))
        self.inplanes = planes * block.expansion
        for i in range(1, blocks):
            layers.append(block(self.inplanes, planes, groups, reduction))

        return nn.Sequential(*layers)

    def features(self, x):

        x = self.layer0(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        return x

    def logits(self, x):
        x = self.avg_pool(x)
        if self.dropout is not None:
            x = self.dropout(x)
        x = x.view(x.size(0), -1)
        x = self.last_linear(x)
        return x

    def forward(self, x):
        x = self.features(x)
        x = self.logits(x)
        return x

def initialize_pretrained_model(model, num_classes, settings):
    # assert num_classes == settings['num_classes'], \
    #     'num_classes should be {}, but is {}'.format(
    #         settings['num_classes'], num_classes)

    pretrained_dict = model_zoo.load_url(settings['url'])
    model_dict = model.state_dict()

    # 将pretrained_dict里不属于model_dict的键剔除掉
    pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict and 'last_linear' not in k}
    # pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}

    # 更新现有的model_dict
    model_dict.update(pretrained_dict)
    # 加载我们真正需要的state_dict
    model.load_state_dict(model_dict)

    model.input_space = settings['input_space']
    model.input_size = settings['input_size']
    model.input_range = settings['input_range']
    model.mean = settings['mean']
    model.std = settings['std']

def senet154(num_classes=1000, pretrained='imagenet'):
    model = SENet(SEBottleneck, [3, 8, 36, 3], groups=64, reduction=16,
                  dropout_p=0.2, num_classes=num_classes)
    if pretrained is not None:
        settings = pretrained_settings['senet154'][pretrained]
        initialize_pretrained_model(model, num_classes, settings)
    return model

def se_resnet50(num_classes=1000, pretrained='imagenet'):
    model = SENet(SEResNetBottleneck, [3, 4, 6, 3], groups=1, reduction=16,
                  dropout_p=None, inplanes=64, input_3x3=False,
                  downsample_kernel_size=1, downsample_padding=0,
                  num_classes=num_classes)
    if pretrained is not None:
        settings = pretrained_settings['se_resnet50'][pretrained]
        initialize_pretrained_model(model, num_classes, settings)
    return model

def se_resnet101(num_classes=1000, pretrained='imagenet'):
    model = SENet(SEResNetBottleneck, [3, 4, 23, 3], groups=1, reduction=16,
                  dropout_p=None, inplanes=64, input_3x3=False,
                  downsample_kernel_size=1, downsample_padding=0,
                  num_classes=num_classes)
    if pretrained is not None:
        settings = pretrained_settings['se_resnet101'][pretrained]
        initialize_pretrained_model(model, num_classes, settings)
    return model

def se_resnet152(num_classes=1000, pretrained='imagenet'):
    model = SENet(SEResNetBottleneck, [3, 8, 36, 3], groups=1, reduction=16,
                  dropout_p=None, inplanes=64, input_3x3=False,
                  downsample_kernel_size=1, downsample_padding=0,
                  num_classes=num_classes)
    if pretrained is not None:
        settings = pretrained_settings['se_resnet152'][pretrained]
        initialize_pretrained_model(model, num_classes, settings)
    return model

def se_resnext50_32x4d(num_classes=1000, pretrained='imagenet'):
    model = SENet(SEResNeXtBottleneck, [3, 4, 6, 3], groups=32, reduction=16,
                  dropout_p=None, inplanes=64, input_3x3=False,
                  downsample_kernel_size=1, downsample_padding=0,
                  num_classes=num_classes)
    if pretrained is not None:
        settings = pretrained_settings['se_resnext50_32x4d'][pretrained]
        initialize_pretrained_model(model, num_classes, settings)
    return model

def se_resnext101_32x4d(num_classes=1000, pretrained='imagenet'):
    model = SENet(SEResNeXtBottleneck, [3, 4, 23, 3], groups=32, reduction=16,
                  dropout_p=None, inplanes=64, input_3x3=False,
                  downsample_kernel_size=1, downsample_padding=0,
                  num_classes=num_classes)

    if pretrained is not None:
        settings = pretrained_settings['se_resnext101_32x4d'][pretrained]
        initialize_pretrained_model(model, num_classes, settings)
    return model

class SE50MSC(nn.Module):

    def __init__(self, num_classes=1000, pretrained='imagenet'):
        super(SE50MSC, self).__init__()
        self.basemodel = se_resnext50_32x4d(num_classes=num_classes, pretrained='imagenet')
        self.basemodel.layer0.conv1 = nn.Sequential()
        self.basemodel.layer0.bn1 = nn.Sequential()

        self.MSC_5x5 = nn.Conv2d(3, 32, 5, stride=2, padding=2, bias=False)
        self.MSC_7x7 = nn.Conv2d(3, 32, 7, stride=2, padding=3, bias=False)
        self.MSC_9x9 = nn.Conv2d(3, 32, 9, stride=2, padding=4, bias=False)
        self.MSC_bn = nn.BatchNorm2d(96)

        self.MSC_conv1x1 = nn.Conv2d(96, 64, 1, stride=1, bias=False)
        self.MSC_conv1x1_bn = nn.BatchNorm2d(64)

    def forward(self, x):
        MSC_5x5 = self.MSC_5x5(x)
        MSC_7x7 = self.MSC_7x7(x)
        MSC_9x9 = self.MSC_9x9(x)
        x = torch.cat([MSC_5x5,MSC_7x7,MSC_9x9],dim=1)

        x = F.relu(self.MSC_bn(x))
        x = self.MSC_conv1x1(x)
        x = F.relu(self.MSC_conv1x1_bn(x))
        x = self.basemodel(x)
        return x

se_resnext50_msc = partial(SE50MSC)
se_resnext50 = partial(se_resnext50_32x4d)
se_resnext101 = partial(se_resnext101_32x4d)
se_resnet152 = partial(se_resnet152)
inception_v4 = partial(inceptionv4)
inception_v4_netvlad = partial(inceptionv4_netvlad)
inception_v4_attention = partial(inceptionv4_attention)
vggnetvlad = partial(VggNetVLAD)

inceptionresnet_v2 = partial(inceptionresnetv2)
dpn_92 = partial(dpn92)
dpn_68b = partial(dpn68b)

resnet18 = partial(ResNet, net_cls=M.resnet18)
resnetvlad18 = partial(ResNetVlad,net_cls=M.resnet18)
resnet18V4 = partial(ResNetV4, net_cls=M.resnet18)
resnet34 = partial(ResNet, net_cls=M.resnet34)
resnet50 = partial(ResNet, net_cls=M.resnet50)
resnet50V2 = partial(ResNetV2, net_cls=M.resnet50)
resnet50V3 = partial(ResNetV3, net_cls=M.resnet50)
resnet50V4 = partial(ResNetV4, net_cls=M.resnet50)
resnet101 = partial(ResNet, net_cls=M.resnet101)
resnet152 = partial(ResNet, net_cls=M.resnet152)

densenet121 = partial(DenseNet, net_cls=M.densenet121)
densenet169 = partial(DenseNet, net_cls=M.densenet169)
densenet201 = partial(DenseNet, net_cls=M.densenet201)
densenet161 = partial(DenseNet, net_cls=M.densenet161)

cnntoynet = partial(CnnToyNet)
cnnvladtoynet = partial(CnnVladToyNet)


# coding=utf-8
import re
import requests
import pandas as pd
from bs4 import BeautifulSoup
from lxml import etree
import time

headers = {
    'cookie': 'sessid=F3C5048F-5EFC-7DC2-D706-171B3F342202; aQQ_ajkguid=E6473576-0CFA-547A-EF66-9729C7E5C2C4; lps=http%3A%2F%2Fwww.anjuke.com%2F%7Chttps%3A%2F%2Fwww.sogou.com%2Flink%3Furl%3DDSOYnZeCC_q7j7wj5mgOqD1S3J7oRWO3; ctid=18; twe=2; __xsptplusUT_8=1; 58tj_uuid=eba8ad5e-f054-41aa-b36a-c28a5c2a062e; init_refer=https%253A%252F%252Fwww.sogou.com%252Flink%253Furl%253DDSOYnZeCC_q7j7wj5mgOqD1S3J7oRWO3; new_uv=1; als=0; new_session=0; wmda_uuid=4007ce9d02b60083c9b2c096f2e5dc8a; wmda_new_uuid=1; wmda_session_id_6289197098934=1545017039830-dffe50e6-70d0-7706; wmda_visited_projects=%3B6289197098934; __xsptplus8=8.1.1545017036.1545017044.3%233%7Cwww.sogou.com%7C%7C%7C%7C%23%23k4--hgzAYsNToYCPD0_3M1ppGohhWYm5%23',
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}

def store_info():
    output_file_name = 'ajk.xlsx'
    df = pd.DataFrame(get_from_ajk())
    df.to_excel(output_file_name, index=False)

def get_detail_from(url):
    time.sleep(3)

    print('正在获取'+url)
    content = requests.get(url,headers=headers)

    soup = BeautifulSoup(content.text, 'lxml')

    detail = {
        'price': soup.select('div.title-basic-info > span')[0].get_text(),
        'type': soup.select('div.title-basic-info > span')[1].get_text(),
        'area': soup.select('div.title-basic-info > span')[2].get_text(),
        'phone': get_ajax_phone(url)
    }

    return detail

def get_from_ajk():
    url = 'https://sz.zu.anjuke.com/fangyuan/shiyan/fx1-p1/'

    content = requests.get(url,headers=headers)

    soup = BeautifulSoup(content.text, 'lxml')

    house_detail_list = []

    for item in soup.select('div.zu-info'):
        href = item.select('a')[0].get('href')
        title = item.select('a')[0].get_text()
        des = item.select('p')[0].get_text()
        location = str(item.select('address.details-item')[0].get_text()).replace(' ', '')

        basic = {
            'href': href,
            'title': title,
            'des': des,
            'location': location
        }

        house_detail = {}
        house_detail.update(basic)
        house_detail.update(get_detail_from(href))
        house_detail_list.append(house_detail)

    return house_detail_list

def get_ajax_phone(j):
    # 定制请求头，必须保存cookie信息，否则无法获取手机号
    headers = {
        'cookie': 'sessid=F3C5048F-5EFC-7DC2-D706-171B3F342202; aQQ_ajkguid=E6473576-0CFA-547A-EF66-9729C7E5C2C4; lps=http%3A%2F%2Fwww.anjuke.com%2F%7Chttps%3A%2F%2Fwww.sogou.com%2Flink%3Furl%3DDSOYnZeCC_q7j7wj5mgOqD1S3J7oRWO3; ctid=18; twe=2; __xsptplusUT_8=1; 58tj_uuid=eba8ad5e-f054-41aa-b36a-c28a5c2a062e; init_refer=https%253A%252F%252Fwww.sogou.com%252Flink%253Furl%253DDSOYnZeCC_q7j7wj5mgOqD1S3J7oRWO3; new_uv=1; als=0; new_session=0; wmda_uuid=4007ce9d02b60083c9b2c096f2e5dc8a; wmda_new_uuid=1; wmda_session_id_6289197098934=1545017039830-dffe50e6-70d0-7706; wmda_visited_projects=%3B6289197098934; __xsptplus8=8.1.1545017036.1545017044.3%233%7Cwww.sogou.com%7C%7C%7C%7C%23%23k4--hgzAYsNToYCPD0_3M1ppGohhWYm5%23',
        'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
    }

    # 随便获取一个详情界面的链接吧
    # j = "https://sz.zu.anjuke.com/fangyuan/1286839211"

    # 获取网页源码
    xq_link = requests.get(j, headers=headers)
    xq_html = etree.HTML(xq_link.text, etree.HTMLParser())

    # 利用正则获取参数
    # 匹配出参数所在的代码
    phone_data1 = xq_html.xpath('/html/body/div[3]/script[9]/text()')
    # 第一个参数
    regexp = r"broker_id:\'(.*?)\',"
    res1 = re.findall(regexp, phone_data1[0])
    req1 = res1[0]
    # print(req1[0])
    # 第二个参数
    regexp = r"token: \'(.*?)\',"
    res2 = re.findall(regexp, phone_data1[0])
    req2 = res2[0]
    # print(req2[0])
    # 第三个参数，发现这个参数是房屋编号，便使用xpath提取出来吧
    phone_data3 = xq_html.xpath('//*[@id="houseCode"]/text()')
    regexp = r'：(.*?)，'
    res3 = re.findall(regexp, phone_data3[0])
    req3 = res3[0]
    # print(req3)

    # 拼凑获取手机号的url
    url = "https://hz.zu.anjuke.com/v3/ajax/getBrokerPhone/?broker_id={}&token={}&prop_id={}"
    # 将刚才的参数填到url中
    phone_url = url.format(req1, req2, req3)
    # 获取手机号
    data1 = requests.get(phone_url, headers=headers)
    # print(data1.text)
    # 手机号码的正则匹配公式
    regexp = r'"val":"(.*?)"}'
    # 正则匹配
    res = re.findall(regexp, data1.text)
    phone = res[0]
    return phone

if __name__ == '__main__':
    print(store_info())


import os

from selenium import webdriver
import time

driver = webdriver.Chrome()
file_path ='file:///' + os.path.abspath("E:/Test_Code/selenium2html/alert.html")
driver.get(file_path)
driver.maximize_window()

driver.find_element_by_id("tooltip").click()
time.sleep(8)
alert = driver.switch_to.alert
text = alert.text
print("text=" + text)
alert.accept()

time.sleep(5)
driver.quit()


import torch
import torch.nn as nn
import torch.nn.functional as F

import numpy as np

class LearnedPositionalEmbedding(nn.Module):
    def __init__(self, d_model, max_len=512):
        super().__init__()

        # Compute the positional encodings once in log space.
        pe = torch.zeros(max_len, d_model).float().to(device='cuda')
        pe.require_grad = True
        pe = pe.unsqueeze(0)
        self.pe=nn.Parameter(pe)
        torch.nn.init.normal_(self.pe,std = d_model ** -0.5)

    def forward(self, x):
        return self.pe[:, :x.size(1)]

class BERTEmbedding3(nn.Module):
    """
    BERT Embedding which is consisted with under features
        1. PositionalEmbedding : adding positional information using sin, cos
        sum of all these features are output of BERTEmbedding
    """

    def __init__(self, input_dim, max_len, dropout=0.1):
        """
        :param vocab_size: total vocab size
        :param embed_size: embedding size of token embedding
        :param dropout: dropout rate
        """
        super().__init__()
        self.learnedPosition = LearnedPositionalEmbedding(d_model=input_dim,max_len=max_len)
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, sequence):
        x = self.learnedPosition(sequence)+sequence
        return self.dropout(x)

class Attention(nn.Module):
    """
    Compute 'Scaled Dot Product Attention
    """

    def forward(self, query, key, value, mask=None, dropout=None):
        scores = torch.matmul(query, key.transpose(-2, -1)) \
                 / math.sqrt(query.size(-1))

        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)

        p_attn = F.softmax(scores, dim=-1)

        if dropout is not None:
            p_attn = dropout(p_attn)

        return torch.matmul(p_attn, value), p_attn

class MultiHeadedAttention(nn.Module):
    """
    Take in model size and number of heads.
    """

    def __init__(self, h, d_model, dropout=0.1):
        super().__init__()
        assert d_model % h == 0

        # We assume d_v always equals d_k
        self.d_k = d_model // h
        self.h = h

        self.linear_layers = nn.ModuleList([nn.Linear(d_model, d_model) for _ in range(3)])
        self.output_linear = nn.Linear(d_model, d_model)
        self.attention = Attention()

        self.dropout = nn.Dropout(p=dropout)

    def forward(self, query, key, value, mask=None):
        batch_size = query.size(0)

        # 1) Do all the linear projections in batch from d_model => h x d_k
        query, key, value = [l(x).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
                             for l, x in zip(self.linear_layers, (query, key, value))]

        # 2) Apply attention on all the projected vectors in batch.
        x, attn = self.attention(query, key, value, mask=mask, dropout=self.dropout)

        # 3) "Concat" using a view and apply a final linear.
        x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.h * self.d_k)

        return self.output_linear(x)

class GELU(nn.Module):
    """
    Paper Section 3.4, last paragraph notice that BERT used the GELU instead of RELU
    """

    def forward(self, x):
        return 0.5 * x * (1 + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3))))

class PositionwiseFeedForward(nn.Module):
    "Implements FFN equation."

    def __init__(self, d_model, d_ff, dropout=0.1):
        super(PositionwiseFeedForward, self).__init__()
        self.w_1 = nn.Linear(d_model, d_ff)
        self.w_2 = nn.Linear(d_ff, d_model)
        self.dropout = nn.Dropout(dropout)
        self.activation = GELU()

    def forward(self, x):
        return self.w_2(self.dropout(self.activation(self.w_1(x))))

class LayerNorm(nn.Module):
    "Construct a layernorm module (See citation for details)."

    def __init__(self, features, eps=1e-6):
        super(LayerNorm, self).__init__()
        self.a_2 = nn.Parameter(torch.ones(features))
        self.b_2 = nn.Parameter(torch.zeros(features))
        self.eps = eps

    def forward(self, x):
        mean = x.mean(-1, keepdim=True)
        std = x.std(-1, keepdim=True)
        return self.a_2 * (x - mean) / (std + self.eps) + self.b_2

class SublayerConnection(nn.Module):
    """
    A residual connection followed by a layer norm.
    Note for code simplicity the norm is first as opposed to last.
    """

    def __init__(self, size, dropout):
        super(SublayerConnection, self).__init__()
        self.norm = LayerNorm(size)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, sublayer):
        "Apply residual connection to any sublayer with the same size."
        return x + self.dropout(sublayer(self.norm(x)))

class TransformerBlock(nn.Module):
    """
    Bidirectional Encoder = Transformer (self-attention)
    Transformer = MultiHead_Attention + Feed_Forward with sublayer connection
    """

    def __init__(self, hidden, attn_heads, feed_forward_hidden, dropout):
        """
        :param hidden: hidden size of transformer
        :param attn_heads: head sizes of multi-head attention
        :param feed_forward_hidden: feed_forward_hidden, usually 4*hidden_size
        :param dropout: dropout rate
        """

        super().__init__()
        self.attention = MultiHeadedAttention(h=attn_heads, d_model=hidden)
        self.feed_forward = PositionwiseFeedForward(d_model=hidden, d_ff=feed_forward_hidden, dropout=dropout)
        self.input_sublayer = SublayerConnection(size=hidden, dropout=dropout)
        self.output_sublayer = SublayerConnection(size=hidden, dropout=dropout)
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, x, mask):
        x = self.input_sublayer(x, lambda _x: self.attention.forward(_x, _x, _x, mask=mask))
        x = self.output_sublayer(x, self.feed_forward)
        return self.dropout(x)

class BERT2(nn.Module):
    """
    BERT model : Bidirectional Encoder Representations from Transformers.
    """

    def __init__(self, input_dim, max_len, hidden=768, n_layers=12, attn_heads=12, dropout=0.1, mask_prob=0.8):
        """
        :param vocab_size: vocab_size of total words
        :param hidden: BERT model hidden size
        :param n_layers: numbers of Transformer blocks(layers)
        :param attn_heads: number of attention heads
        :param dropout: dropout rate
        """

        super().__init__()
        self.hidden = hidden
        self.n_layers = n_layers
        self.attn_heads = attn_heads
        self.max_len=max_len
        self.input_dim=input_dim
        self.mask_prob=mask_prob

        clsToken = torch.zeros(1,1,self.input_dim).float().cuda()
        clsToken.require_grad = True
        self.clsToken= nn.Parameter(clsToken)
        torch.nn.init.normal_(self.clsToken, std = hidden ** -0.5)

        # paper noted they used 4*hidden_size for ff_network_hidden_size
        self.feed_forward_hidden = hidden * 4

        # embedding for BERT, sum of positional, segment, token embeddings
        self.embedding = BERTEmbedding3(input_dim=input_dim, max_len=max_len+1)

        # multi-layers transformer blocks, deep network
        self.transformer_blocks = nn.ModuleList(
            [TransformerBlock(hidden, attn_heads, self.feed_forward_hidden, dropout) for _ in range(n_layers)])

        for module in self.modules():
            if isinstance(module, nn.Embedding):
                #nn.init.normal_(module.weight, mean=0, std=0.02)
                nn.init.uniform_(module.weight, -0.06, 0.06)
            if isinstance(module, nn.Linear):
                nn.init.normal_(module.weight, mean=0, std=0.02)
                if hasattr(module, "bias") and module.bias is not None:
                    nn.init.constant_(module.bias, 0.0)
            if isinstance(module, nn.LayerNorm):
                module.bias.data.zero_()
                module.weight.data.fill_(1.0)

    def forward(self, input_vectors):
        # attention masking for padded token
        # torch.ByteTensor([batch_size, 1, seq_len, seq_len)
        batch_size=input_vectors.shape[0]
        sample=None
        if self.training:
            bernolliMatrix=torch.cat((torch.tensor([1]).float().cuda(), (torch.tensor([self.mask_prob]).float().cuda()).repeat(self.max_len)), 0).unsqueeze(0).repeat([batch_size,1])
            self.bernolliDistributor=torch.distributions.Bernoulli(bernolliMatrix)
            sample=self.bernolliDistributor.sample()
            mask = (sample > 0).unsqueeze(1).repeat(1, sample.size(1), 1).unsqueeze(1)
        else:
            mask=torch.ones(batch_size,1,self.max_len+1,self.max_len+1).cuda()

        # embedding the indexed sequence to sequence of vectors
        x = torch.cat((self.clsToken.repeat(batch_size,1,1),input_vectors),1)
        x = self.embedding(x)

        # running over multiple transformer blocks
        for transformer in self.transformer_blocks:
            x = transformer.forward(x, mask)

        return x, sample

class MaxPool3dSamePadding(nn.MaxPool3d):

    def compute_pad(self, dim, s):
        if s % self.stride[dim] == 0:
            return max(self.kernel_size[dim] - self.stride[dim], 0)
        else:
            return max(self.kernel_size[dim] - (s % self.stride[dim]), 0)

    def forward(self, x):
        # compute 'same' padding
        (batch, channel, t, h, w) = x.size()
        #print t,h,w
        out_t = np.ceil(float(t) / float(self.stride[0]))
        out_h = np.ceil(float(h) / float(self.stride[1]))
        out_w = np.ceil(float(w) / float(self.stride[2]))
        #print out_t, out_h, out_w
        pad_t = self.compute_pad(0, t)
        pad_h = self.compute_pad(1, h)
        pad_w = self.compute_pad(2, w)
        #print pad_t, pad_h, pad_w

        pad_t_f = pad_t // 2
        pad_t_b = pad_t - pad_t_f
        pad_h_f = pad_h // 2
        pad_h_b = pad_h - pad_h_f
        pad_w_f = pad_w // 2
        pad_w_b = pad_w - pad_w_f

        pad = (pad_w_f, pad_w_b, pad_h_f, pad_h_b, pad_t_f, pad_t_b)
        #print x.size()
        #print pad
        x = F.pad(x, pad)
        return super(MaxPool3dSamePadding, self).forward(x)

class Unit3D(nn.Module):

    def __init__(self, in_channels,
                 output_channels,
                 kernel_shape=(1, 1, 1),
                 stride=(1, 1, 1),
                 padding=0,
                 activation_fn=F.relu,
                 use_batch_norm=True,
                 use_bias=False,
                 name='unit_3d'):

        """Initializes Unit3D module."""
        super(Unit3D, self).__init__()

        self._output_channels = output_channels
        self._kernel_shape = kernel_shape
        self._stride = stride
        self._use_batch_norm = use_batch_norm
        self._activation_fn = activation_fn
        self._use_bias = use_bias
        self.name = name
        self.padding = padding

        self.conv3d = nn.Conv3d(in_channels=in_channels,
                                out_channels=self._output_channels,
                                kernel_size=self._kernel_shape,
                                stride=self._stride,
                                padding=0, # we always want padding to be 0 here. We will dynamically pad based on input size in forward function
                                bias=self._use_bias)

        if self._use_batch_norm:
            self.bn = nn.BatchNorm3d(self._output_channels, eps=0.001, momentum=0.01)

    def compute_pad(self, dim, s):
        if s % self._stride[dim] == 0:
            return max(self._kernel_shape[dim] - self._stride[dim], 0)
        else:
            return max(self._kernel_shape[dim] - (s % self._stride[dim]), 0)

    def forward(self, x):
        # compute 'same' padding
        (batch, channel, t, h, w) = x.size()
        #print t,h,w
        out_t = np.ceil(float(t) / float(self._stride[0]))
        out_h = np.ceil(float(h) / float(self._stride[1]))
        out_w = np.ceil(float(w) / float(self._stride[2]))
        #print out_t, out_h, out_w
        pad_t = self.compute_pad(0, t)
        pad_h = self.compute_pad(1, h)
        pad_w = self.compute_pad(2, w)
        #print pad_t, pad_h, pad_w

        pad_t_f = pad_t // 2
        pad_t_b = pad_t - pad_t_f
        pad_h_f = pad_h // 2
        pad_h_b = pad_h - pad_h_f
        pad_w_f = pad_w // 2
        pad_w_b = pad_w - pad_w_f

        pad = (pad_w_f, pad_w_b, pad_h_f, pad_h_b, pad_t_f, pad_t_b)
        #print x.size()
        #print pad
        x = F.pad(x, pad)
        #print x.size()

        x = self.conv3d(x)
        if self._use_batch_norm:
            x = self.bn(x)
        if self._activation_fn is not None:
            x = self._activation_fn(x)
        return x

class InceptionModule(nn.Module):
    def __init__(self, in_channels, out_channels, name):
        super(InceptionModule, self).__init__()

        self.b0 = Unit3D(in_channels=in_channels, output_channels=out_channels[0], kernel_shape=[1, 1, 1], padding=0,
                         name=name+'/Branch_0/Conv3d_0a_1x1')
        self.b1a = Unit3D(in_channels=in_channels, output_channels=out_channels[1], kernel_shape=[1, 1, 1], padding=0,
                          name=name+'/Branch_1/Conv3d_0a_1x1')
        self.b1b = Unit3D(in_channels=out_channels[1], output_channels=out_channels[2], kernel_shape=[3, 3, 3],
                          name=name+'/Branch_1/Conv3d_0b_3x3')
        self.b2a = Unit3D(in_channels=in_channels, output_channels=out_channels[3], kernel_shape=[1, 1, 1], padding=0,
                          name=name+'/Branch_2/Conv3d_0a_1x1')
        self.b2b = Unit3D(in_channels=out_channels[3], output_channels=out_channels[4], kernel_shape=[3, 3, 3],
                          name=name+'/Branch_2/Conv3d_0b_3x3')
        self.b3a = MaxPool3dSamePadding(kernel_size=[3, 3, 3],
                                stride=(1, 1, 1), padding=0)
        self.b3b = Unit3D(in_channels=in_channels, output_channels=out_channels[5], kernel_shape=[1, 1, 1], padding=0,
                          name=name+'/Branch_3/Conv3d_0b_1x1')
        self.name = name

    def forward(self, x):
        b0 = self.b0(x)
        b1 = self.b1b(self.b1a(x))
        b2 = self.b2b(self.b2a(x))
        b3 = self.b3b(self.b3a(x))
        return torch.cat([b0,b1,b2,b3], dim=1)

class InceptionI3d(nn.Module):
    """Inception-v1 I3D architecture.
    The model is introduced in:
        Quo Vadis, Action Recognition? A New Model and the Kinetics Dataset
        Joao Carreira, Andrew Zisserman
        https://arxiv.org/pdf/1705.07750v1.pdf.
    See also the Inception architecture, introduced in:
        Going deeper with convolutions
        Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed,
        Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich.
        http://arxiv.org/pdf/1409.4842v1.pdf.
    """

    # Endpoints of the model in order. During construction, all the endpoints up
    # to a designated `final_endpoint` are returned in a dictionary as the
    # second return value.
    VALID_ENDPOINTS = (
        'Conv3d_1a_7x7',
        'MaxPool3d_2a_3x3',
        'Conv3d_2b_1x1',
        'Conv3d_2c_3x3',
        'MaxPool3d_3a_3x3',
        'Mixed_3b',
        'Mixed_3c',
        'MaxPool3d_4a_3x3',
        'Mixed_4b',
        'Mixed_4c',
        'Mixed_4d',
        'Mixed_4e',
        'Mixed_4f',
        'MaxPool3d_5a_2x2',
        'Mixed_5b',
        'Mixed_5c',
        'Logits',
        'Predictions',
    )

    def __init__(self, num_classes=400, spatial_squeeze=True,
                 final_endpoint='Logits', name='inception_i3d', in_channels=3, dropout_keep_prob=0.5):
        """Initializes I3D model instance.
        Args:
          num_classes: The number of outputs in the logit layer (default 400, which
              matches the Kinetics dataset).
          spatial_squeeze: Whether to squeeze the spatial dimensions for the logits
              before returning (default True).
          final_endpoint: The model contains many possible endpoints.
              `final_endpoint` specifies the last endpoint for the model to be built
              up to. In addition to the output at `final_endpoint`, all the outputs
              at endpoints up to `final_endpoint` will also be returned, in a
              dictionary. `final_endpoint` must be one of
              InceptionI3d.VALID_ENDPOINTS (default 'Logits').
          name: A string (optional). The name of this module.
        Raises:
          ValueError: if `final_endpoint` is not recognized.
        """

        if final_endpoint not in self.VALID_ENDPOINTS:
            raise ValueError('Unknown final endpoint %s' % final_endpoint)

        super(InceptionI3d, self).__init__()
        self._num_classes = num_classes
        self._spatial_squeeze = spatial_squeeze
        self._final_endpoint = final_endpoint
        self.logits = None

        if self._final_endpoint not in self.VALID_ENDPOINTS:
            raise ValueError('Unknown final endpoint %s' % self._final_endpoint)

        self.end_points = {}
        end_point = 'Conv3d_1a_7x7'
        self.end_points[end_point] = Unit3D(in_channels=in_channels, output_channels=64, kernel_shape=[7, 7, 7],
                                            stride=(2, 2, 2), padding=(3,3,3),  name=name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'MaxPool3d_2a_3x3'
        self.end_points[end_point] = MaxPool3dSamePadding(kernel_size=[1, 3, 3], stride=(1, 2, 2),
                                                             padding=0)
        if self._final_endpoint == end_point: return

        end_point = 'Conv3d_2b_1x1'
        self.end_points[end_point] = Unit3D(in_channels=64, output_channels=64, kernel_shape=[1, 1, 1], padding=0,
                                       name=name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Conv3d_2c_3x3'
        self.end_points[end_point] = Unit3D(in_channels=64, output_channels=192, kernel_shape=[3, 3, 3], padding=1,
                                       name=name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'MaxPool3d_3a_3x3'
        self.end_points[end_point] = MaxPool3dSamePadding(kernel_size=[1, 3, 3], stride=(1, 2, 2),
                                                             padding=0)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_3b'
        self.end_points[end_point] = InceptionModule(192, [64,96,128,16,32,32], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_3c'
        self.end_points[end_point] = InceptionModule(256, [128,128,192,32,96,64], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'MaxPool3d_4a_3x3'
        self.end_points[end_point] = MaxPool3dSamePadding(kernel_size=[3, 3, 3], stride=(2, 2, 2),
                                                             padding=0)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_4b'
        self.end_points[end_point] = InceptionModule(128+192+96+64, [192,96,208,16,48,64], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_4c'
        self.end_points[end_point] = InceptionModule(192+208+48+64, [160,112,224,24,64,64], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_4d'
        self.end_points[end_point] = InceptionModule(160+224+64+64, [128,128,256,24,64,64], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_4e'
        self.end_points[end_point] = InceptionModule(128+256+64+64, [112,144,288,32,64,64], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_4f'
        self.end_points[end_point] = InceptionModule(112+288+64+64, [256,160,320,32,128,128], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'MaxPool3d_5a_2x2'
        self.end_points[end_point] = MaxPool3dSamePadding(kernel_size=[2, 2, 2], stride=(2, 2, 2),
                                                             padding=0)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_5b'
        self.end_points[end_point] = InceptionModule(256+320+128+128, [256,160,320,32,128,128], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Mixed_5c'
        self.end_points[end_point] = InceptionModule(256+320+128+128, [384,192,384,48,128,128], name+end_point)
        if self._final_endpoint == end_point: return

        end_point = 'Logits'
        self.avg_pool = nn.AvgPool3d(kernel_size=[2, 7, 7],
                                     stride=(1, 1, 1))
        self.dropout = nn.Dropout(dropout_keep_prob)
        self.logits = Unit3D(in_channels=384+384+128+128, output_channels=self._num_classes,
                             kernel_shape=[1, 1, 1],
                             padding=0,
                             activation_fn=None,
                             use_batch_norm=False,
                             use_bias=True,
                             name='logits')

        self.build()

    def replace_logits(self, num_classes):
        self._num_classes = num_classes
        self.logits = Unit3D(in_channels=384+384+128+128, output_channels=self._num_classes,
                             kernel_shape=[1, 1, 1],
                             padding=0,
                             activation_fn=None,
                             use_batch_norm=False,
                             use_bias=True,
                             name='logits')

    def build(self):
        for k in self.end_points.keys():
            self.add_module(k, self.end_points[k])

    def forward(self, x):
        for end_point in self.VALID_ENDPOINTS:
            if end_point in self.end_points:
                x = self._modules[end_point](x) # use _modules to work with dataparallel

        x = self.logits(self.dropout(self.avg_pool(x)))
        if self._spatial_squeeze:
            logits = x.squeeze(3).squeeze(3)
        # logits is batch X time X classes, which is what we want to work with
        return logits

    def extract_features(self, x):
        for end_point in self.VALID_ENDPOINTS:
            if end_point in self.end_points:
                x = self._modules[end_point](x)
        return self.avg_pool(x)

def _inception(model_path, **kwargs):
    """Constructs a ResNet-18 model.

    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet
    """
    model = InceptionI3d(400, in_channels=3)
    if model_path=='':
        return model
    params = torch.load(model_path)
    model.load_state_dict(params)
    return model

class rgb_I3D64f(nn.Module):
    def __init__(self, modelPath='./weights/rgb_imagenet.pth'):
        super(rgb_I3D64f, self).__init__()
        # self.dp = nn.Dropout(p=0.8)
        self.avgpool = nn.AvgPool3d((1, 7, 7), stride=1)
        self.features=nn.Sequential(*list(_inception(model_path=modelPath).children())[3:])

        # self.fc_action = nn.Linear(1024, num_classes)
        # for param in self.features.parameters():
        #     param.requires_grad = True

        # torch.nn.init.xavier_uniform_(self.fc_action.weight)
        # self.fc_action.bias.data.zero_()

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        # x = x.view(x.size(0), -1)
        # x = self.dp(x)
        # x = self.fc_action(x)
        return x

class rgb_I3D64f_bert2(nn.Module):
    def __init__(self, num_classes, modelPath='./weights/rgb_imagenet.pth', extract=True):
        super(rgb_I3D64f_bert2, self).__init__()
        self.extract = True
        self.eval = True
        self.hidden_size=1024
        self.n_layers=1
        self.attn_heads=8
        self.num_classes=num_classes
        # self.length=length
        self.dp = nn.Dropout(p=0.8)

        self.features=nn.Sequential(*list(_inception(model_path=modelPath).children())[3:])

        for param in self.features.parameters():
            param.requires_grad = True

        self.bert = BERT2(self.hidden_size, 8 , hidden=self.hidden_size, n_layers=self.n_layers, attn_heads=self.attn_heads)
        print(sum(p.numel() for p in self.bert.parameters() if p.requires_grad))
        #
        self.avgpool = nn.AdaptiveAvgPool3d(output_size=(8, 1, 1))

        # used for classification task only
        if self.train:
            self.fc_action = nn.Linear(self.hidden_size, num_classes)
            torch.nn.init.xavier_uniform_(self.fc_action.weight)
            self.fc_action.bias.data.zero_()

    def forward(self, x):
        # print('input\t' + str(np.shape(x)))
        x = self.features(x)
        # print('feature extracted\t' + str(np.shape(x)))
        x = self.avgpool(x)
        # print('average pooled\t' + str(np.shape(x)))
        x = x.view(x.size(0), self.hidden_size,8)
        x = x.transpose(1,2)
        norm = x.norm(p=2, dim = -1, keepdim=True)
        x = x.div(norm)
        input_vectors=x
        # print('transformed\t' + str(np.shape(x)))
        output , maskSample = self.bert(x)
        # print('BERTed\t' + str(np.shape(output)))

        sequenceOut=output[:,1:,:]
        if self.extract:
            return sequenceOut
        else:
            classificationOut = output[:,0,:]
            if eval:
                output=self.dp(classificationOut)
            else:
                output = classificationOut
            # print('BERTed2\t' + str(np.shape(output)))
            x = self.fc_action(output)
            # print('output\t' + str(np.shape(x)))
            # print(np.shape(x))
            return x, input_vectors, sequenceOut, maskSample

    def eval(self):
        self.eval = True

    def train(self):
        self.eval = False


from enum import Enum, auto

class GeometryType(Enum):
    """Enum for geometry types."""

    vertex = auto()
    curve = auto()
    surface = auto()
    volume = auto()

    def get_cubit_string(self):
        """Return the string that represents this item in cubit."""

        if self == self.vertex:
            return "vertex"
        elif self == self.curve:
            return "curve"
        elif self == self.surface:
            return "surface"
        elif self == self.volume:
            return "volume"
        else:
            raise ValueError("Got unexpected type {}!".format(self))

    def get_dat_bc_section_string(self):
        """
        Return the string that represents this item in a dat file section.
        """

        if self == self.vertex:
            return "POINT"
        elif self == self.curve:
            return "LINE"
        elif self == self.surface:
            return "SURF"
        elif self == self.volume:
            return "VOL"
        else:
            raise ValueError("Got unexpected type {}!".format(self))

class FiniteElementObject(Enum):
    """Enum for finite element objects."""

    hex = auto()
    tet = auto()
    face = auto()
    triangle = auto()
    edge = auto()
    node = auto()

    def get_cubit_string(self):
        """Return the string that represents this item in cubit."""

        if self == self.hex:
            return "hex"
        elif self == self.tet:
            return "tet"
        elif self == self.face:
            return "face"
        elif self == self.triangle:
            return "tri"
        elif self == self.edge:
            return "edge"
        elif self == self.node:
            return "node"

    def get_dat_bc_section_string(self):
        """
        Return the string that represents this item in a dat file section.
        Currently this only makes sense for the node type, when explicitly
        defining boundary conditions on nodes.
        """
        if self == self.node:
            return "POINT"
        else:
            raise ValueError("Got unexpected type {}!".format(self))

class CubitItems(Enum):
    """Enum for cubit internal items such as groups."""

    group = auto()

class ElementType(Enum):
    """Enum for finite element shape types."""

    hex8 = auto()
    hex20 = auto()
    hex27 = auto()
    tet4 = auto()
    tet10 = auto()
    hex8sh = auto()
    hex8_fluid = auto()
    quad4 = auto()

    def get_cubit_names(self):
        """
        Get the strings that are needed to mesh and describe this element in
        cubit.
        """

        # Get the element type parameters.
        if self == self.hex8 or self == self.hex8sh or self == self.hex8_fluid:
            cubit_scheme = "Auto"
            cubit_element_type = "HEX8"
        elif self == self.hex20:
            cubit_scheme = "Auto"
            cubit_element_type = "HEX20"
        elif self == self.hex27:
            cubit_scheme = "Auto"
            cubit_element_type = "HEX27"
        elif self == self.tet4:
            cubit_scheme = "Tetmesh"
            cubit_element_type = "TETRA4"
        elif self == self.tet10:
            cubit_scheme = "Tetmesh"
            cubit_element_type = "TETRA10"
        elif self == self.quad4:
            cubit_scheme = "Auto"
            cubit_element_type = "QUAD4"
        else:
            raise ValueError("Got wrong element type {}!".format(self))

        return cubit_scheme, cubit_element_type

    def get_baci_name(self):
        """Get the name of this element in baci."""

        # Get the element type parameters.
        if self == self.hex8:
            return "SOLIDH8"
        elif self == self.hex20:
            return "SOLIDH20"
        elif self == self.hex27:
            return "SOLIDH27"
        elif self == self.tet4:
            return "SOLIDT4"
        elif self == self.tet10:
            return "SOLIDT10"
        elif self == self.hex8sh:
            return "SOLIDSH8"
        elif self == self.hex8_fluid:
            return "FLUID"
        if self == self.quad4:
            return "WALL"
        else:
            raise ValueError("Got wrong element type {}!".format(self))

    def get_baci_section(self):
        """Get the correct section name of this element in baci."""

        if self == self.hex8_fluid:
            return "FLUID"
        elif (
            self == self.hex20
            or self == self.hex8
            or self == self.hex20
            or self == self.hex27
            or self == self.tet4
            or self == self.hex8sh
            or self == self.tet10
            or self == self.quad4
        ):
            return "STRUCTURE"
        else:
            raise ValueError("Got wrong element type {}!".format(self))

    def get_baci_type(self):
        """Get the correct element shape name of this element in baci."""

        if self == self.hex8 or self == self.hex8sh or self == self.hex8_fluid:
            return "HEX8"
        elif self == self.hex20:
            return "HEX20"
        elif self == self.hex27:
            return "HEX27"
        elif self == self.tet4:
            return "TET4"
        elif self == self.tet10:
            return "TET10"
        elif self == self.quad4:
            return "QUAD4"
        else:
            raise ValueError("Got wrong element type {}!".format(self))

    def get_default_baci_description(self):
        """
        Get the default text for the description in baci after the material
        string.
        """

        # Get the element type parameters.
        if self == self.hex8:
            return "KINEM nonlinear EAS none"
        elif (
            self == self.hex20
            or self == self.hex27
            or self == self.tet4
            or self == self.tet10
        ):
            return "KINEM nonlinear"
        elif self == self.hex8sh:
            return "KINEM nonlinear EAS none ANS none THICKDIR auto"
        elif self == self.hex8_fluid:
            return "NA ALE"
        else:
            raise ValueError("Got wrong element type {}!".format(self))

class BoundaryConditionType(Enum):
    """Enum for boundary conditions types."""

    dirichlet = auto()
    neumann = auto()
    point_coupling = auto()
    beam_to_solid_volume_meshtying = auto()
    beam_to_solid_surface_meshtying = auto()
    beam_to_solid_surface_contact = auto()
    solid_to_solid_surface_contact = auto()
    fsi_coupling = auto()
    ale_dirichlet = auto()

    def get_dat_bc_section_header(self, geometry_type):
        """
        Get the header string for the boundary condition input section in the
        dat file.
        """

        if self == self.dirichlet or self == self.neumann:
            if self == self.dirichlet:
                self_string = "DIRICH"
            else:
                self_string = "NEUMANN"

            return "DESIGN {} {} CONDITIONS".format(
                geometry_type.get_dat_bc_section_string(), self_string
            )
        elif (
            self == self.beam_to_solid_volume_meshtying
            and geometry_type == GeometryType.volume
        ):
            return "BEAM INTERACTION/BEAM TO SOLID VOLUME MESHTYING VOLUME"
        elif (
            self == self.beam_to_solid_surface_meshtying
            and geometry_type == GeometryType.surface
        ):
            return "BEAM INTERACTION/BEAM TO SOLID SURFACE MESHTYING SURFACE"
        elif (
            self == self.beam_to_solid_surface_contact
            and geometry_type == GeometryType.surface
        ):
            return "BEAM INTERACTION/BEAM TO SOLID SURFACE CONTACT SURFACE"
        elif self == self.point_coupling and (
            geometry_type == GeometryType.vertex
            or geometry_type == FiniteElementObject.node
        ):
            return "DESIGN POINT COUPLING CONDITIONS"
        elif self == self.solid_to_solid_surface_contact and (
            geometry_type == GeometryType.surface
            or geometry_type == FiniteElementObject.node
        ):
            return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D"
        elif self == self.fsi_coupling and (
            geometry_type == GeometryType.surface
            or geometry_type == FiniteElementObject.node
        ):
            return "DESIGN FSI COUPLING SURF CONDITIONS"
        elif self == self.ale_dirichlet and (
            geometry_type == GeometryType.surface
            or geometry_type == FiniteElementObject.node
        ):
            return "DESIGN SURF ALE DIRICH CONDITIONS"
        else:
            raise ValueError(
                "No implemented case for {} and {}!".format(self, geometry_type)
            )


import numpy as np
import math
from ..miniworld import MiniWorldEnv, Room
from ..entity import Box
from gym import spaces

class Hallway(MiniWorldEnv):
    """
    Environment in which the goal is to go to a red box
    at the end of a hallway
    """

    def __init__(self, length=12, **kwargs):
        assert length >= 2
        self.length = length

        super().__init__(
            max_episode_steps=250,
            **kwargs
        )

        # Allow only movement actions (left/right/forward)
        self.action_space = spaces.Discrete(self.actions.move_forward+1)

    def _gen_world(self):
        # Create a long rectangular room
        room = self.add_rect_room(
            min_x=-1, max_x=-1 + self.length,
            min_z=-2, max_z=2
        )

        # Place the box at the end of the hallway
        self.box = self.place_entity(
            Box(color='red'),
            min_x=room.max_x - 2
        )

        # Place the agent a random distance away from the goal
        self.place_agent(
            dir=self.rand.float(-math.pi/4, math.pi/4),
            max_x=room.max_x - 2
        )

    def step(self, action):
        obs, reward, done, info = super().step(action)

        if self.near(self.box):
            reward += self._reward()
            done = True

        # Added dense reward
        if reward == 0 and done:
            reward = -np.linalg.norm(self.agent.pos - self.box.pos)

        return obs, reward, done, info


from django.db import models

class ChristmasSong(models.Model):
    gift = models.CharField(
      unique=True,
      max_length=126,
      help_text="Gift for the day.",
      )

    def __str__(self):
      return "pk={} gift={}".format(
      self.pk, self.gift
      )

class Country(models.Model):
    iso = models.CharField(
      unique=True,
      max_length=126,
      help_text="ISO two-character id for the country.",
      )

    name = models.CharField(
      max_length=126,
      help_text="Name of the country.",
      )

    def __str__(self):
      return "iso={} name={}".format(
      self.iso, self.name
      )

class BibleBooks(models.Model):
    james = models.CharField(
      max_length=64,
      help_text="King James Bible title for the book.",
      )

    vulgate = models.CharField(
      max_length=64,
      help_text="Vulgate reference for the book.",
      )

    dv = models.CharField(
      max_length=64,
      help_text="Douay Rheims reference for the book.",
      )

    auth = models.CharField(
      max_length=126,
      help_text="Full title reference in the Authorised Version for the book.",
      )

    def __str__(self):
      return "{0}".format(
      self.james
      )

class Color(models.Model):
    name = models.CharField(
      db_index=True,
      unique=True,
      max_length=126,
      help_text="Machine name for the color.",
      )

    title = models.CharField(
      max_length=126,
      help_text="Display for the color.",
      )

    hex = models.CharField(
      max_length=32,
      help_text="Hex code for the color.",
      )

    rgb = models.CharField(
      max_length=32,
      help_text="RGB code for the color.",
      )

    def __str__(self):
      return "name={} title={}".format(
      self.name, self.title
      )

class Tree(models.Model):
    title = models.CharField(
      db_index=True,
      max_length=126,
      help_text="Common name for the tree.",
      )

    latin = models.CharField(
      max_length=126,
      db_index=True,
      unique=True,
      help_text="Latin name for the tree.",
      )

    def __str__(self):
      return "name={} latin={}".format(
      self.title, self.latin
      )

class Mineral(models.Model):
    name = models.CharField(
      max_length=64,
      help_text="Name for the mineral.",
      )

    isvalid = models.BooleanField(
      max_length=126,
      help_text="Is a recognised species of mineral.",
      )

    reason = models.CharField(
      max_length=256,
      help_text="Reason, if given, why not valid.",
      )

    def __str__(self):
      return "name={}".format(
      self.name
      )

class Star(models.Model):
    name = models.CharField(
      db_index=True,
      max_length=126,
      help_text="Common name for the star.",
      )

    distance = models.DecimalField(
      help_text="Distance to the star, in parsecs.",
      max_digits=15,
      decimal_places=10
      )

    magnitude = models.DecimalField(
      help_text="Apparent visual magnitude of the star",
      max_digits=4,
      decimal_places=2
      )

    spectrum = models.CharField(
      max_length=126,
      help_text="Light spectrum for the star.",
      )

    color = models.DecimalField(
      help_text="Color index of the star.",
      max_digits=4,
      decimal_places=3
      )

    def __str__(self):
      return "pk={} name={} distance={} magnitude={}".format(
      self.pk, self.name, self.distance, self.magnitude
      )

class Language(models.Model):
    '''
    Layout from http://www-01.sil.org/iso639-3/download.asp. The Django
    string convention of empty string is used, not null=True. blank=True
    is used to indicate a possible empty value. 'scope' and 'type'
    columns are defined with choices.
    '''
    id = models.CharField(
      db_index=True,
      max_length=3,
      primary_key=True,
      help_text="The three-letter 639-3 identifier.",
      )

    part2B = models.CharField(
      max_length=3,
      blank=True,
      help_text="Equivalent 639-2 identifier of the bibliographic applications code set, if there is one.",
      )

    part2T = models.CharField(
      max_length=3,
      blank=True,
      help_text="Equivalent 639-2 identifier of the terminology applications code set, if there is one.",
      )

    part1 = models.CharField(
      max_length=2,
      blank=True,
      help_text="Equivalent 639-1 identifier, if there is one.",
      )

    INDIVIDUAL = 'I'
    MACROLANGUAGE = 'M'
    SPECIAL = 'S'
    SCOPE_CHOICES = (
        (INDIVIDUAL, 'Individual'),
        (MACROLANGUAGE, 'Macrolanguage'),
        (SPECIAL, 'Special'),
    )
    scope = models.CharField(
      max_length=1,
      choices=SCOPE_CHOICES,
      help_text="I(ndividual), M(acrolanguage), S(pecial).",
      )

    ANCIENT = 'A'
    CONSTRUCTED = 'C'
    EXTINCT = 'E'
    HISTORICAL = 'H'
    LIVING = 'L'
    SPECIAL = 'S'
    TYPE_CHOICES = (
        (ANCIENT, 'Ancient'),
        (CONSTRUCTED, 'Constructed'),
        (EXTINCT, 'Extinct'),
        (HISTORICAL, 'Historical'),
        (LIVING, 'Living'),
        (SPECIAL, 'Special'),
        )
    type = models.CharField(
      max_length=1,
      choices=TYPE_CHOICES,
      help_text="A(ncient), C(onstructed), E(xtinct), H(istorical), L(iving), S(pecial).",
      )

    name = models.CharField(
      "Reference name",
      max_length=150,
      help_text="Reference language name.",
      )

    comment = models.CharField(
      max_length=150,
      blank=True,
      help_text="Comment relating to one or more of the columns.",
      )

    def __str__(self):
      return "id='{}' part1='{}' scope='{}' type='{}' name='{}' comment='{}'".format(
      self.pk, self.part1, self.scope, self.type, self.name, self.comment
      )