# Chap3で使うNN関連のプログラム
import numpy as np
import matplotlib.pyplot as plt
from functions_ch3 import softmax, cross_entropy_error
import time
import sys

class MatMul:
    def __init__(self, W):
        self.params = [W] # わざわざこうしてるのは，layersで処理するときに配列同士の足し算がうまくいかないから（layer毎の分離が出来なくなる）
        self.grads = [np.zeros_like(W)] # こちも同じ理由　レイヤー毎に分離したいので
        self.x = None

    def forward(self, x):
        # 順伝播
        W, = self.params # こうやると中身取り出せます
        out = np.dot(x, W)
        self.x = x
        return out

    def backward(self, dout):
        # 逆伝播
        W, = self.params
        dx = np.dot(dout, W.T)
        dW = np.dot(self.x.T, dout)
        self.grads[0][...] = dW # deepコピーと同じ（アドレス固定する）pythonは値に割り振るのでそれを避ける
        return dx

class SoftmaxWithLoss:
    def __init__(self):
        self.params, self.grads = [], []
        self.y = None  # softmaxの出力
        self.t = None  # 教師ラベル

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x) # softmaxとかは簡単なので別のファイルで（functions.py）

        # 教師ラベルがone-hotベクトルの場合、正解のインデックスに変換
        if self.t.size == self.y.size:
            self.t = self.t.argmax(axis=1)

        loss = cross_entropy_error(self.y, self.t) # （functions.py）
        return loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]

        dx = self.y.copy()
        dx[np.arange(batch_size), self.t] -= 1 # y-tの式を再現
        dx *= dout
        dx = dx / batch_size # これはbatchsizeで伝播させないと，最終的にいろいろ足し算されてしまうのでそれを防いでいるイメージです（バッチの分が入ってしまう）

        return dx

class SimpleCBOW():
    '''
    シンプルなCBOWのクラス作成
    関数としてmatmulを使うことにする
    '''
    def __init__(self, vocab_size, hidden_size): # ここでの注意点は隠れ層は入力層より小さくしないとだめ
        V, H = vocab_size, hidden_size

        # 重みの初期化
        # 後々単語の分散表現として使う
        W_in = 0.01 * np.random.randn(V, H).astype('f')
        W_out = 0.01 * np.random.randn(H, V).astype('f') # 今回は出力はone-hotで出てくるから入力と出力は同じ数！

        # レイヤー作成
        self.in_layer0 = MatMul(W_in) # contextsは2つしかないので，入力の重みは2つ準備
        self.in_layer1 = MatMul(W_in)
        self.out_layer = MatMul(W_out)
        self.loss_layer = SoftmaxWithLoss()

        # リストにまとめます
        layers = [self.in_layer0, self.in_layer1, self.out_layer]
        self.params, self.grads = [], []
        for layer in layers: # さっきの謎に[]でくくってるのはここでその意味を発揮　確か0から作るDL1だとここdictにしてた
            self.params += layer.params # 各レイヤーのものが[[w], [w], ]みたいに収納される！分かりやすい
            self.grads += layer.grads

        # 分散表現に使うもの
        self.words_vecs = W_in

    def forward(self, contexts, target):
        '''
        順伝播
        '''
        # 隠れ層の出力(ここで入力を2つに分けている！！)，バッチで入ってきても6 * 2 * 7　なので
        h0 = self.in_layer0.forward(contexts[:, 0]) # 1列目（前）
        h1 = self.in_layer1.forward(contexts[:, 1]) # 2列目（後ろ）
        # print(contexts)
        # print(contexts[:, 0])
        # sys.exit()
        # 2つの成分を足して2で割る，他にもやり方はある
        h = (h0 + h1) * 0.5
        # 出力のみ
        score = self.out_layer.forward(h)
        # lossも計算
        loss = self.loss_layer.forward(score, target)

        return loss

    def backward(self, dout=1): # 逆伝播は1からスタート　というかなんならいらない笑
        '''
        逆伝播
        '''
        ds = self.loss_layer.backward(dout)
        da = self.out_layer.backward(ds)
        da *= 0.5
        self.in_layer1.backward(da)
        self.in_layer0.backward(da)

        return None

class Trainer:
    '''
    いろいろまとめっちゃった学習クラス
    '''
    def __init__(self, model, optimizer):
        self.model = model # 上記のクラスが入るイメージ
        self.optimizer = optimizer # 今回はadam
        self.loss_list = []
        self.eval_interval = None
        self.current_epoch = 0

    def fit(self, x, t, max_epoch, batch_size, max_grad=None, eval_interval=20): # デフォルト設定いるのか疑問消した
        data_size = len(x) # 行×列の行がでるイメージ
        max_iters = data_size // batch_size # 切り捨て除算らしい
        self.eval_interval = eval_interval
        model, optimizer = self.model, self.optimizer
        total_loss = 0
        loss_count = 0

        start_time = time.time()
        for epoch in range(max_epoch):
            # シャッフル
            idx = np.random.permutation(np.arange(data_size))
            x = x[idx]
            t = t[idx]
            # 単純に混ぜただけ

            for iters in range(max_iters):
                # 順番に取り出していく
                batch_x = x[iters*batch_size:(iters+1)*batch_size]
                batch_t = t[iters*batch_size:(iters+1)*batch_size]

                # 勾配を求め、パラメータを更新
                loss = model.forward(batch_x, batch_t)
                model.backward()
                params, grads = remove_duplicate(model.params, model.grads)  # 共有された重みを1つに集約，下参照
                if max_grad is not None:# RNNで使用
                    clip_grads(grads, max_grad)
                optimizer.update(params, grads) # 片方だけ更新すれば全部更新されます(共有された重みはアドレスを共有しているので)
                total_loss += loss
                loss_count += 1

                # 評価
                if (eval_interval is not None) and (iters % eval_interval) == 0:
                    avg_loss = total_loss / loss_count # そのエポックでのロスの平均
                    elapsed_time = time.time() - start_time # 計算時間の計算
                    print('epoch {0}, iter {1} / {2} , time {3}[s] , loss {4}'
                          .format(self.current_epoch + 1, iters + 1, max_iters, round(elapsed_time, 3), round(avg_loss, 3) ))
                    self.loss_list.append(float(avg_loss)) # epoch毎のロス
                    total_loss, loss_count = 0, 0

            self.current_epoch += 1

    def plot(self, ylim=None):
        x = np.arange(len(self.loss_list))
        if ylim is not None:
            plt.ylim(*ylim)
        plt.plot(x, self.loss_list, label='train')
        plt.xlabel('iterations (x' + str(self.eval_interval) + ')')
        plt.ylabel('loss')
        plt.show()

def remove_duplicate(params, grads):
    '''
    パラメータ配列中の重複する重みをひとつに集約し、
    その重みに対応する勾配を加算する
    加算するのは，今回でいえば共有するものが2つあるからって感じ
    誤差自体というか傾きは重みを共有している分だけ変化することになる（共有するってことはそういうこと），それぞれで更新されるので
    '''
    params, grads = params[:], grads[:]  # copy list

    while True:
        find_flg = False
        L = len(params) #

        for i in range(0, L - 1):
            for j in range(i + 1, L):
                # 重みを共有する場合
                if params[i] is params[j]: # 何番目のレイヤー同士が一緒かをみてる・ここで重みが同じか判定(is 演算子はオブジェクトが同一か判定します)  == は値
                    grads[i] += grads[j]  # 勾配の加算
                    find_flg = True
                    params.pop(j) # 取り除く（レイヤーの集合から）
                    grads.pop(j)
                # 転置行列として重みを共有する場合（weight tying）
                elif params[i].ndim == 2 and params[j].ndim == 2 and \
                     params[i].T.shape == params[j].shape and np.all(params[i].T == params[j]):
                    grads[i] += grads[j].T
                    find_flg = True
                    params.pop(j)
                    grads.pop(j)

                if find_flg: break # popするので，これでよい（各要素の最初の部分だけみることになるけど）
            if find_flg: break

        if not find_flg: break # 共通部分がない場合

    return params, grads

def clip_grads(grads, max_norm):
    '''
    勾配クリッピング
    RNNで使います
    ある勾配より大きくなったらもう使わないってやつ
    '''
    total_norm = 0
    for grad in grads:
        total_norm += np.sum(grad ** 2)
    total_norm = np.sqrt(total_norm)

    rate = max_norm / (total_norm + 1e-6)
    if rate < 1:
        for grad in grads:
            grad *= rate

# optimizer
class Adam:
    '''
    パラメータを更新する手法の1つ
    Adam (http://arxiv.org/abs/1412.6980v8)
    '''
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None

    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = [], []
            for param in params:
                self.m.append(np.zeros_like(param))
                self.v.append(np.zeros_like(param))

        self.iter += 1
        # たぶんだけど，イタレーション回数が増えるにつれて，更新量が小さくなるようにしているはず(下の方のmainで確認済み)
        lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)

        for i in range(len(params)): # 各要素ごとにみる
            self.m[i] += (1 - self.beta1) * (grads[i] - self.m[i])
            self.v[i] += (1 - self.beta2) * (grads[i]**2 - self.v[i])

            params[i] -= lr_t * self.m[i] / (np.sqrt(self.v[i]) + 1e-7)

if __name__ == '__main__':
    # 本当に，更新のたびにadamsのalphaが小さくなってるか確認
    iterations = 100

    lr=0.001
    beta1=0.9
    beta2=0.999
    lr_traj = []

    for i in range(1, iterations):
        # たぶんだけど，イタレーション回数が増えるにつれて，更新量が小さくなるようにしているはず
        lr = lr * np.sqrt(1.0 - beta2**i) / (1.0 - beta1**i)

        lr_traj.append(lr)

    plt.plot(range(1, iterations), lr_traj)
    plt.show()


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:

        stack = [root]
        max_ = 1

        while len(stack) != 0:

            len_ = len(stack)

            for i in range(len_):
                curr = stack.pop(0)

                if curr:
                    stack.append(curr.left)
                    stack.append(curr.right)
                else:
                    stack.append(None)
                    stack.append(None)

            while len(stack) > 0 and not stack[-1]:
                stack.pop(-1)
            while len(stack) > 0 and not stack[0]:
                stack.pop(0)
            max_ = max(max_ , len(stack))
        return max_


add_library('peasycam')  # é preciso baixar/instalar pelo IDE

message = ("Lorem ipsum dolor sit amet,"
         + "consectetur adipiscing elit.")

def setup():
    size(500, 500, P3D)
    cam = PeasyCam(this, 100)
    cam.setMinimumDistance(100)
    cam.setMaximumDistance(200)
    textAlign(CENTER, CENTER)
    textMode(SHAPE)
    fonte = createFont("Tomorrow Light", 12)
    textFont(fonte)

def draw():
    background(200)
    bar(0, 0, 10, 20, 10, 40, 3)
    bar(50, 30, -30, 20, 10, 30, 3)
    bar(20, 0, 0, 50, 50, -30, 3),

def bar(x1, y1, z1, x2, y2, z2, weight=10):
    """Draw a box rotated in 3D like a bar/edge."""
    p1, p2 = PVector(x1, y1, z1), PVector(x2, y2, z2)
    v1 = p2 - p1
    rho = sqrt(v1.x ** 2 + v1.y ** 2 + v1.z ** 2)
    phi, the  = acos(v1.z / rho), atan2(v1.y, v1.x)
    v1.mult(0.5)
    pushMatrix()
    translate(x1 + v1.x, y1 + v1.y, z1 + v1.z)
    rotateZ(the)
    rotateY(phi)
    fill(0, 0, 200)
    box(weight, weight, p1.dist(p2))
    rotateY(HALF_PI)
    if screenY(0, 0, 0) - screenY(0, 6, 0) > 0: rotateX(PI)
    if screenX(0, 0, 0) - screenX(6, 0, 0) > 0: rotateY(PI)

    fill(0)
    text(message, 0, 0)
    popMatrix()


import threading
import time
import cv2
import numpy as np

from util.utils import average_image_size, create_random_4_3_preview_image, convert_ndarray_to_base_64
from data_access.data_transfer_objects import Datasets, DatasetDescriptor

def collection_metadata_description_updater(cron):
    """
    Main routine to update changing dataset description values in a defined circular sheduled time.
    Determines a subset of the dataset description to allow queries on dataset and collection names.

    Args:
        cron: Updater object that holds the data storage implementation
    """
    run = 0
    while True:
        datasetdescriptors = []
        database_collections = cron.dti.get_databases()

        for database_collection in database_collections.databases:
            db = database_collection.database_name
            for collection in database_collection.collection_names:
                col = collection
                print(col)
                number_of_documents, size_mb, created, last_update, preview_image = data_by_collection(cron, db, col)

                datasetdescriptor = DatasetDescriptor(database=db,
                                               collection=col,
                                               number_of_documents=number_of_documents,
                                               usability="",
                                               created_by="",
                                               annotation_types="",
                                               size_mb=size_mb,
                                               created=created,
                                               last_update=last_update,
                                               image="data:image/png;base64," + convert_ndarray_to_base_64(preview_image))
                datasetdescriptors.append(datasetdescriptor)
            if run==0:
                cron.mdti.set_datasets_details(Datasets(datasetdescriptors=datasetdescriptors))
                print("temp descriptors filled")
        if run > 0:
            cron.mdti.set_datasets_details(Datasets(datasetdescriptors=datasetdescriptors))
            print("temp descriptors filled")
        run = run + 1

        datas = cron.mdti.all_dataset_descriptions()
        for data in datas:
            db = data['database']
            col = data['collection']
            number_of_documents, size_mb, created, last_update, preview_image = data_by_collection(cron, db, col)
            cron.mdti.update_dataset_description(db, col, number_of_documents, size_mb, created, last_update)

        time.sleep(86400)

def data_by_collection(cron, db, col):
    """
    Determines per dataset informations like images für previews, timestamps, amounts and sizes
    Args:
        cron: Updater object that holds datastorage
        db: database
        col: collection

    Returns: number_of_documents, size_mb, created, last_update, preview_image

    """
    number_of_documents = cron.dti.count_documents(db, col)

    size_mb = 0
    image_field = ""
    try:
        document = cron.dti.get_document(db, col, 0, "")

        #entry = cron.dbm.db_accessor.get_data(db, col, return_images=True, query={}, doc_count=1, random_sample=True)[0]
        if "image" in document.document:
            image_field = "image"
        if "image_data" in document.document:
            image_field = "image_data"
    except Exception as e:
        pass

    try:
        size_mb_average = average_image_size([cron.dti.get_document(db, col, 0, "").document[image_field] for i in range(5)])
        size_mb = round(number_of_documents * size_mb_average, 2)
    except Exception as e:
        pass

    preview_image = np.zeros((320, 480, 3), dtype=np.uint8)
    preview_image = cv2.putText(preview_image, 'HAS NO IMAGES', (5, 140), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 3, cv2.LINE_AA)
    try:
        entries = [cron.dti.get_document(db, col, 0, "").document for index in range(0, 12)]
        preview_image = create_random_4_3_preview_image([entry[image_field] for entry in entries])
        preview_image = cv2.resize(preview_image, (320, 240), interpolation=cv2.INTER_AREA)
    except Exception as e:
        pass

    last_update = cron.dti.last_update_date(db, col)
    created = cron.dti.create_date(db, col)

    return number_of_documents, size_mb, created, last_update, preview_image

class Updater():
    """Start fo endless running thread to hold dataset description up-to-date"""
    def __init__(self, dti, mdti):
        self.dti = dti
        self.mdti = mdti

    def cycling_updat(self):
        thread = threading.Thread(target=collection_metadata_description_updater, args=(self,))
        thread.start()


import unittest
from data_structures.queue_on_linked_list import *

class QueueOnLinkedListCase(unittest.TestCase):
    def test_queue_and_dequeue(self):
        test_queue = QueueOnLinkedList()

        for value in range(10):
            test_queue.enqueue(value)

        enqueued_values = []
        while True:
            value = test_queue.dequeue()
            if value is None:
                break
            enqueued_values.append(value)

        expected_values = list(range(10))
        self.assertListEqual(expected_values, enqueued_values)

    def test_pick_empty(self):
        test_queue = QueueOnLinkedList()
        self.assertIsNone(test_queue.pick())

    def test_pick_not_empty(self):
        test_queue = QueueOnLinkedList()
        test_queue.enqueue('test')
        self.assertEqual('test', test_queue.pick())

    def test_get_length(self):
        test_queue = QueueOnLinkedList()
        self.assertEqual(0, test_queue.get_length())

        for value in range(10):
            test_queue.enqueue(value)
        self.assertEqual(10, test_queue.get_length())

        for i in range(5):
            test_queue.dequeue()
        self.assertEqual(5, test_queue.get_length())

if __name__ == '__main__':
    unittest.main()


import re
from mmcv.runner import BaseModule, auto_fp16
import torch
import torch.nn.functional as F
import torch.nn as nn
import numpy as np
from torch.nn.modules.pooling import AdaptiveAvgPool2d

class DiscriminatorFeaturesLoss(nn.Module):
    def __init__(self):
        super().__init__()
        # self.l1 = nn.DataParallel(nn.L1Loss())
        self.l1 = nn.L1Loss()

    def forward(self, ds_fake, ds_real):
        """
        :param ds_fake: [D1:[layer1_outs, layer2_outs ...], D2, D3]
        :param ds_real:
        :return:
        """
        loss = 0

        for scale in range(len(ds_real)):
            # last is D_outs, do not use as features
            for l in range(len(ds_real[scale]) - 1):
                loss += self.l1(ds_fake[scale][l], ds_real[scale][l].detach())
        return loss / float(len(ds_real))

class GANLoss(nn.Module):
    def __init__(self, use_lsgan=True, target_real_label=1.0, target_fake_label=0.0,
                 tensor=torch.FloatTensor):
        super(GANLoss, self).__init__()
        self.real_label = target_real_label
        self.fake_label = target_fake_label
        self.real_label_var = None
        self.fake_label_var = None
        self.Tensor = tensor
        if use_lsgan:
            # self.loss = nn.DataParallel(nn.MSELoss())
            self.loss = nn.MSELoss()
        else:
            # self.loss = nn.DataParallel(nn.BCELoss())
            self.loss = nn.BCELoss()
        print(f'===> {self.__class__.__name__} | use_lsgan:{use_lsgan} | loss:{self.loss}')

    def get_target_tensor(self, input, target_is_real):
        target_tensor = None
        if target_is_real:
            create_label = ((self.real_label_var is None) or
                            (self.real_label_var.numel() != input.numel()))
            if create_label:
                real_tensor = self.Tensor(input.shape).fill_(self.real_label)
                self.real_label_var = real_tensor
            target_tensor = self.real_label_var
        else:
            create_label = ((self.fake_label_var is None) or
                            (self.fake_label_var.numel() != input.numel()))
            if create_label:
                fake_tensor = self.Tensor(input.shape).fill_(self.fake_label)
                self.fake_label_var = fake_tensor
            target_tensor = self.fake_label_var
        return target_tensor

    def __call__(self, input, target_is_real):
        if isinstance(input[0], list):
            loss = 0
            for input_i in input:
                pred = input_i[-1]
                target_tensor = self.get_target_tensor(pred, target_is_real).to(pred.device)
                loss += self.loss(pred, target_tensor)
            return loss
        else:
            target_tensor = self.get_target_tensor(input[-1], target_is_real).to(input[-1].device)
            return self.loss(input[-1], target_tensor)

class MultiscaleDiscriminator(nn.Module):
    def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d,
                 use_sigmoid=False, num_D=3, getIntermFeat=True, use_psp=False):
        super(MultiscaleDiscriminator, self).__init__()
        self.num_D = num_D
        self.n_layers = n_layers
        self.getIntermFeat = getIntermFeat

        for i in range(num_D):
            netD = NLayerDiscriminator(input_nc, ndf, n_layers, norm_layer, use_sigmoid, getIntermFeat)
            if getIntermFeat:
                for j in range(n_layers + 2):
                    setattr(self, 'scale' + str(i) + '_layer' + str(j), getattr(netD, 'model' + str(j)))
            else:
                setattr(self, 'layer' + str(i), netD.model)
        self.use_psp = use_psp
        if self.use_psp:
            self.downsample = [
                # nn.AdaptiveAvgPool2d((11, 11)),
                nn.AdaptiveAvgPool2d((6, 6)),
                nn.AdaptiveAvgPool2d((3, 3)),
                nn.AdaptiveAvgPool2d((2, 2)),
                nn.AdaptiveAvgPool2d((1, 1)),
                nn.AdaptiveAvgPool2d((1, 1)), #
            ]
        else:
            self.downsample = nn.AvgPool2d(3, stride=2, padding=[1, 1], count_include_pad=False)

        self.dfloss = DiscriminatorFeaturesLoss()
        self.ganloss = GANLoss()

    def singleD_forward(self, model, input):
        if self.getIntermFeat:
            result = [input]
            for i in range(len(model)):
                result.append(model[i](result[-1]))
            return result[1:]
        else:
            return [model(input)]

    def forward(self, input):
        num_D = self.num_D
        result = []
        input_downsampled = input
        for i in range(num_D):
            if self.getIntermFeat:
                model = [getattr(self, 'scale' + str(num_D - 1 - i) + '_layer' + str(j)) for j in
                         range(self.n_layers + 2)]
            else:
                model = getattr(self, 'layer' + str(num_D - 1 - i))
            result.append(self.singleD_forward(model, input_downsampled))
            if i != (num_D - 1):
                if self.use_psp:
                    input_downsampled = self.downsample[i](input)
                else:
                    input_downsampled = self.downsample(input_downsampled)
        return result

    def D_loss(self, fake, real):
        fake_res = self.forward(fake.detach())
        real_res = self.forward(real.detach())

        fakeloss = self.ganloss(fake_res, target_is_real=False)
        realloss = self.ganloss(real_res, target_is_real=True)
        d_loss = 0.5 * (fakeloss + realloss)

        fake_res = self.forward(fake)
        ganloss = self.ganloss(fake_res, target_is_real=True)
        dfloss = self.dfloss(fake_res, real_res)
        # print(fake_res, len(fake_res))
        # print(real_res, len(real_res), len(real_res[0]))
        # print(d_loss)
        # print(ganloss)
        # print(dfloss)

        losses = dict()
        losses['d_loss'] = d_loss
        losses['ganloss'] = ganloss
        losses['dfloss'] = dfloss

        return losses

    def FPN_D_loss(self, fakes, reals):
        losses = dict()
        losses['d_loss'] = 0
        losses['ganloss'] = 0
        losses['dfloss'] = 0
        n = len(fakes)
        for fake, real in zip(fakes, reals):
            temp_losses = self.D_loss(fake, real)
            losses['d_loss'] += temp_losses['d_loss']
            losses['ganloss'] += temp_losses['ganloss']
            losses['dfloss'] += temp_losses['dfloss']

        losses['d_loss'] /= n
        losses['ganloss'] /= n
        losses['dfloss'] /= n
        return losses

# Defines the PatchGAN discriminator with the specified arguments.
class NLayerDiscriminator(nn.Module):
    def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d, use_sigmoid=False, getIntermFeat=False):
        super(NLayerDiscriminator, self).__init__()
        self.getIntermFeat = getIntermFeat
        self.n_layers = n_layers

        kw = 4
        padw = int(np.ceil((kw - 1.0) / 2))
        sequence = [[nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True)]]

        nf = ndf
        for n in range(1, n_layers):
            nf_prev = nf
            nf = min(nf * 2, 512)
            sequence += [[
                nn.Conv2d(nf_prev, nf, kernel_size=kw, stride=2, padding=padw),
                norm_layer(nf), nn.LeakyReLU(0.2, True)
            ]]

        nf_prev = nf
        nf = min(nf * 2, 512)
        sequence += [[
            nn.Conv2d(nf_prev, nf, kernel_size=kw, stride=1, padding=padw),
            norm_layer(nf),
            nn.LeakyReLU(0.2, True)
        ]]

        sequence += [[nn.Conv2d(nf, 1, kernel_size=kw, stride=1, padding=padw)]]

        if use_sigmoid:
            sequence += [[nn.Sigmoid()]]

        if getIntermFeat:
            for n in range(len(sequence)):
                setattr(self, 'model' + str(n), nn.Sequential(*sequence[n]))
        else:
            sequence_stream = []
            for n in range(len(sequence)):
                sequence_stream += sequence[n]
            self.model = nn.Sequential(*sequence_stream)

    def forward(self, input):
        if self.getIntermFeat:
            res = [input]
            for n in range(self.n_layers + 2):
                model = getattr(self, 'model' + str(n))
                res.append(model(res[-1]))
            return res[1:]
        else:
            return self.model(input)

def test_discriminator():
    pass
    D = MultiscaleDiscriminator(input_nc=256, getIntermFeat=True)
    x = torch.rand(2, 256, 128, 128)
    y = D(x)
    for i in y:
        print(i[0].shape)

if __name__ == '__main__':
    test_discriminator()


import random
nums = random.uniform(0,1)
# print(nums)
num = random.randint(3,5)
# print(num)
num = random.random() # Real Number between 0 and 1
# print(num)
num1 = random.randrange(3)
num2 = random.randrange(3, 9)
num3 = random.randrange(3, 27, 3)
# print(num1, num2, num3)
# print(num3)

a = random.uniform(1, 10)
# print(a)

a = [random.randint(0,9) for i in range(random.randint(0,9))]
# print(a)
a = [5, 8, 3, 1, 6, 3, 2, 3, 5]
random.shuffle(a)
# print(a)
b = random.choice(a)
#print(b)

a_s = random.sample(a,3)
#print(a_s)

import string

s = random.choice(string.ascii_letters)
# print(s)

sr = random.SystemRandom()
# print(sr.random())
# print(sr.randint(3, 9))
# print(sr.randrange(2,12,3))