{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!nvidia-smi","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:37:50.082644Z","iopub.execute_input":"2021-06-03T07:37:50.082979Z","iopub.status.idle":"2021-06-03T07:37:50.818876Z","shell.execute_reply.started":"2021-06-03T07:37:50.082946Z","shell.execute_reply":"2021-06-03T07:37:50.817746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set environment\nimport sys, os\nIN_COLAB  = 'google.colab' in sys.modules\nIN_KAGGLE = 'kaggle_web_client' in sys.modules\nLOCAL     = not (IN_KAGGLE or IN_COLAB)\nprint(f'IN_COLAB:{IN_COLAB}, IN_KAGGLE:{IN_KAGGLE}, LOCAL:{LOCAL}')","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:37:50.820531Z","iopub.execute_input":"2021-06-03T07:37:50.820785Z","iopub.status.idle":"2021-06-03T07:37:50.826760Z","shell.execute_reply.started":"2021-06-03T07:37:50.820760Z","shell.execute_reply":"2021-06-03T07:37:50.825866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# For Colab\n# ==================\nif IN_COLAB:\n    # mount googledrive\n    from google.colab import drive\n    drive.mount('/content/drive')\n    # copy kaggle.json from googledrive\n    ! pip install --upgrade --force-reinstall --no-deps  kaggle > /dev/null\n    ! mkdir ~/.kaggle\n    ! cp \"/content/drive/MyDrive/kaggle/kaggle.json\" ~/.kaggle/\n    ! chmod 600 ~/.kaggle/kaggle.json\n    \n    if not os.path.exists(\"/content/input/train_short_audio\"):\n        !mkdir input\n        !kaggle competitions download -c birdclef-2021\n        !unzip /content/birdclef-2021.zip -d input","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:37:50.828116Z","iopub.execute_input":"2021-06-03T07:37:50.828356Z","iopub.status.idle":"2021-06-03T07:37:50.841563Z","shell.execute_reply.started":"2021-06-03T07:37:50.828328Z","shell.execute_reply":"2021-06-03T07:37:50.840639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Libraries","metadata":{}},{"cell_type":"code","source":"if IN_KAGGLE:\n    !pip install ../input/torchlibrosa/torchlibrosa-0.0.5-py3-none-any.whl\n    !pip install colorednoise\nelif IN_COLAB:\n    !pip install -q pysndfx SoundFile audiomentations timm torchlibrosa colorednoise","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:37:50.843018Z","iopub.execute_input":"2021-06-03T07:37:50.843294Z","iopub.status.idle":"2021-06-03T07:38:04.185802Z","shell.execute_reply.started":"2021-06-03T07:37:50.843268Z","shell.execute_reply":"2021-06-03T07:38:04.184625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nif IN_KAGGLE:\n    sys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\n\nimport os\nimport math\nimport time\nimport random\nfrom os.path import join as pjoin\nfrom glob import glob\n\nimport numpy as np\nimport pandas as pd\nfrom matplotlib import pyplot as plt\nimport seaborn as sns\nimport librosa\nimport soundfile as sf\nfrom pathlib import Path\nimport colorednoise as cn\nfrom IPython.display import Audio, IFrame, display # jupyterで再生につかう\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import f1_score\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.optim import Adam, SGD\nimport torchvision.models as models\nfrom torch.nn.parameter import Parameter\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts, CosineAnnealingLR, ReduceLROnPlateau\n\nfrom torchlibrosa.stft import LogmelFilterBank, Spectrogram\nfrom torchlibrosa.augmentation import SpecAugmentation\n\nimport timm\nimport warnings \nfrom tqdm.notebook import tqdm\nimport joblib\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:38:04.188943Z","iopub.execute_input":"2021-06-03T07:38:04.189373Z","iopub.status.idle":"2021-06-03T07:38:08.681095Z","shell.execute_reply.started":"2021-06-03T07:38:04.189331Z","shell.execute_reply":"2021-06-03T07:38:08.679999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## CFG","metadata":{}},{"cell_type":"code","source":"class CFG:\n    debug = True\n    inference_soundscape = True\n    exp_name = \"test\"\n    seed = 29\n    n_fold = 5\n    trn_fold = [0]\n    target_col = 'primary_label'\n    train_datadir = Path(\"../input/birdclef-2021/train_short_audio\")\n    period = 5\n    img_size = 224\n    criterion ='BCEWithLogitsLoss'\n    model_name = 'rexnet_200' \n    #['rexnet_200' 'tf_efficientnet_b3', 'resnet18', 'densenet121''vit_deit_small_patch16_224' \n    # ''vit_deit_tiny_patch16_224', 'vit_deit_small_patch16_224','vit_deit_base_patch16_224',',]\n    target_size = 397\n    label_smoothing = 0.0\n    mixup_proba = 0.5\n    transforms = {\n            \"train\": [{\"name\": \"NoiseInjection\", \"params\":{\"max_noise_level\": 0.04}},\n                      {\"name\": \"PinkNoise\", \"params\":{\"min_snr\": 10.0}},\n                      {\"name\": \"SpecifiedNoise\", \"params\":{\"noise_folder_path\": \"\", \"min_snr\":0.5, \"max_snr\":0.8 }},\n                      #{\"name\": \"PitchShift\", \"params\":{\"max_range\": 3}},\n                      {\"name\": \"RandomVolume\", \"params\":{\"limit\": 4}},\n                      {\"name\": \"Normalize\"}],\n            \"valid\": [{\"name\": \"Normalize\"}]\n        }\n    # Audio Params\n    sample_rate = 32000\n    n_mels = 128\n    fmin = 20\n    fmax = 16000\n    n_fft = 2048\n    hop_length = n_fft//4\n    spec_aggreagation = 'deltas' #['repeat3', 'deltas']\n    \n    epochs = 30\n    # scheduler/optimizer\n    scheduler = 'CosineAnnealingWarmRestarts' # ['ReduceLROnPlateau', 'CosineAnnealingLR', 'CosineAnnealingWarmRestarts']\n    #factor=0.2 # ReduceLROnPlateau\n    #patience=4 # ReduceLROnPlateau\n    #eps=1e-6 # ReduceLROnPlateau\n    #T_max=10 # CosineAnnealingLR\n    T_0=30 # CosineAnnealingWarmRestarts\n    lr=1e-4\n    min_lr=1e-6\n    weight_decay=1e-6  \n    # train\n    gradient_accumulation_steps=1\n    apex = False\n    max_grad_norm = 1000\n    print_freq = 100\n    # model\n    pretrained = True\n    in_channels = 3\n    # Split\n    split = \"StratifiedKFold\"\n    split_params = {\n        \"n_splits\": 5,\n        \"shuffle\": True,\n        \"random_state\": 29\n    }\n    # DataLoader\n    loader = {\n        \"train\": {\n            \"batch_size\": 32,\n            \"num_workers\": 4,\n            \"shuffle\": True,\n            \"pin_memory\": True,\n            \"drop_last\": True\n        },\n        \"valid\": {\n            \"batch_size\": 64,\n            \"num_workers\": 4,\n            \"shuffle\": False,\n            \"pin_memory\": True,\n            \"drop_last\": False\n        }\n    }","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:38:08.682609Z","iopub.execute_input":"2021-06-03T07:38:08.682855Z","iopub.status.idle":"2021-06-03T07:38:08.692139Z","shell.execute_reply.started":"2021-06-03T07:38:08.682831Z","shell.execute_reply":"2021-06-03T07:38:08.691334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if LOCAL:\n    CFG.train_datadir = Path(\"F:/Kaggle/BirdCLEF2021/data/input/resample\")\n    CFG.loader[\"train\"][\"batch_size\"] = 32\n    CFG.loader[\"train\"][\"num_workers\"] = 0\n    CFG.loader[\"valid\"][\"num_workers\"] = 0\nelif IN_COLAB:\n    CFG.train_datadir = Path(\"/content/input/train_short_audio\")","metadata":{"execution":{"iopub.status.busy":"2021-06-03T07:38:08.693580Z","iopub.execute_input":"2021-06-03T07:38:08.693843Z","iopub.status.idle":"2021-06-03T07:38:08.707787Z","shell.execute_reply.started":"2021-06-03T07:38:08.693817Z","shell.execute_reply":"2021-06-03T07:38:08.706884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TARGETS = [\n        'acafly', 'acowoo', 'aldfly', 'ameavo', 'amecro',\n        'amegfi', 'amekes', 'amepip', 'amered', 'amerob',\n        'amewig', 'amtspa', 'andsol1', 'annhum', 'astfly',\n        'azaspi1', 'babwar', 'baleag', 'balori', 'banana',\n        'banswa', 'banwre1', 'barant1', 'barswa', 'batpig1',\n        'bawswa1', 'bawwar', 'baywre1', 'bbwduc', 'bcnher',\n        'belkin1', 'belvir', 'bewwre', 'bkbmag1', 'bkbplo',\n        'bkbwar', 'bkcchi', 'bkhgro', 'bkmtou1', 'bknsti', 'blbgra1',\n        'blbthr1', 'blcjay1', 'blctan1', 'blhpar1', 'blkpho',\n        'blsspa1', 'blugrb1', 'blujay', 'bncfly', 'bnhcow', 'bobfly1',\n        'bongul', 'botgra', 'brbmot1', 'brbsol1', 'brcvir1', 'brebla',\n        'brncre', 'brnjay', 'brnthr', 'brratt1', 'brwhaw', 'brwpar1',\n        'btbwar', 'btnwar', 'btywar', 'bucmot2', 'buggna', 'bugtan',\n        'buhvir', 'bulori', 'burwar1', 'bushti', 'butsal1', 'buwtea',\n        'cacgoo1', 'cacwre', 'calqua', 'caltow', 'cangoo', 'canwar',\n        'carchi', 'carwre', 'casfin', 'caskin', 'caster1', 'casvir',\n        'categr', 'ccbfin', 'cedwax', 'chbant1', 'chbchi', 'chbwre1',\n        'chcant2', 'chispa', 'chswar', 'cinfly2', 'clanut', 'clcrob',\n        'cliswa', 'cobtan1', 'cocwoo1', 'cogdov', 'colcha1', 'coltro1',\n        'comgol', 'comgra', 'comloo', 'commer', 'compau', 'compot1',\n        'comrav', 'comyel', 'coohaw', 'cotfly1', 'cowscj1', 'cregua1',\n        'creoro1', 'crfpar', 'cubthr', 'daejun', 'dowwoo', 'ducfly', 'dusfly',\n        'easblu', 'easkin', 'easmea', 'easpho', 'eastow', 'eawpew', 'eletro',\n        'eucdov', 'eursta', 'fepowl', 'fiespa', 'flrtan1', 'foxspa', 'gadwal',\n        'gamqua', 'gartro1', 'gbbgul', 'gbwwre1', 'gcrwar', 'gilwoo',\n        'gnttow', 'gnwtea', 'gocfly1', 'gockin', 'gocspa', 'goftyr1',\n        'gohque1', 'goowoo1', 'grasal1', 'grbani', 'grbher3', 'grcfly',\n        'greegr', 'grekis', 'grepew', 'grethr1', 'gretin1', 'greyel',\n        'grhcha1', 'grhowl', 'grnher', 'grnjay', 'grtgra', 'grycat',\n        'gryhaw2', 'gwfgoo', 'haiwoo', 'heptan', 'hergul', 'herthr',\n        'herwar', 'higmot1', 'hofwoo1', 'houfin', 'houspa', 'houwre',\n        'hutvir', 'incdov', 'indbun', 'kebtou1', 'killde', 'labwoo', 'larspa',\n        'laufal1', 'laugul', 'lazbun', 'leafly', 'leasan', 'lesgol', 'lesgre1',\n        'lesvio1', 'linspa', 'linwoo1', 'littin1', 'lobdow', 'lobgna5', 'logshr',\n        'lotduc', 'lotman1', 'lucwar', 'macwar', 'magwar', 'mallar3', 'marwre',\n        'mastro1', 'meapar', 'melbla1', 'monoro1', 'mouchi', 'moudov', 'mouela1',\n        'mouqua', 'mouwar', 'mutswa', 'naswar', 'norcar', 'norfli', 'normoc', 'norpar',\n        'norsho', 'norwat', 'nrwswa', 'nutwoo', 'oaktit', 'obnthr1', 'ocbfly1',\n        'oliwoo1', 'olsfly', 'orbeup1', 'orbspa1', 'orcpar', 'orcwar', 'orfpar',\n        'osprey', 'ovenbi1', 'pabspi1', 'paltan1', 'palwar', 'pasfly', 'pavpig2',\n        'phivir', 'pibgre', 'pilwoo', 'pinsis', 'pirfly1', 'plawre1', 'plaxen1',\n        'plsvir', 'plupig2', 'prowar', 'purfin', 'purgal2', 'putfru1', 'pygnut',\n        'rawwre1', 'rcatan1', 'rebnut', 'rebsap', 'rebwoo', 'redcro', 'reevir1',\n        'rehbar1', 'relpar', 'reshaw', 'rethaw', 'rewbla', 'ribgul', 'rinkin1',\n        'roahaw', 'robgro', 'rocpig', 'rotbec', 'royter1', 'rthhum', 'rtlhum',\n        'ruboro1', 'rubpep1', 'rubrob', 'rubwre1', 'ruckin', 'rucspa1', 'rucwar',\n        'rucwar1', 'rudpig', 'rudtur', 'rufhum', 'rugdov', 'rumfly1', 'runwre1',\n        'rutjac1', 'saffin', 'sancra', 'sander', 'savspa', 'saypho', 'scamac1',\n        'scatan', 'scbwre1', 'scptyr1', 'scrtan1', 'semplo', 'shicow', 'sibtan2',\n        'sinwre1', 'sltred', 'smbani', 'snogoo', 'sobtyr1', 'socfly1', 'solsan',\n        'sonspa', 'soulap1', 'sposan', 'spotow', 'spvear1', 'squcuc1', 'stbori',\n        'stejay', 'sthant1', 'sthwoo1', 'strcuc1', 'strfly1', 'strsal1', 'stvhum2',\n        'subfly', 'sumtan', 'swaspa', 'swathr', 'tenwar', 'thbeup1', 'thbkin',\n        'thswar1', 'towsol', 'treswa', 'trogna1', 'trokin', 'tromoc', 'tropar',\n        'tropew1', 'tuftit', 'tunswa', 'veery', 'verdin', 'vigswa', 'warvir',\n        'wbwwre1', 'webwoo1', 'wegspa1', 'wesant1', 'wesblu', 'weskin', 'wesmea',\n        'westan', 'wewpew', 'whbman1', 'whbnut', 'whcpar', 'whcsee1', 'whcspa',\n        'whevir', 'whfpar1', 'whimbr', 'whiwre1', 'whtdov', 'whtspa', 'whwbec1',\n        'whwdov', 'wilfly', 'willet1', 'wilsni1', 'wiltur', 'wlswar', 'wooduc',\n        'woothr', 'wrenti', 'y00475', 'yebcha', 'yebela1', 'yebfly', 'yebori1',\n        'yebsap', 'yebsee1', 'yefgra1', 'yegvir', 'yehbla', 'yehcar1', 'yelgro',\n        'yelwar', 'yeofly1', 'yerwar', 'yeteup1', 'yetvir']","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-06-03T07:38:08.709949Z","iopub.execute_input":"2021-06-03T07:38:08.710932Z","iopub.status.idle":"2021-06-03T07:38:08.729661Z","shell.execute_reply.started":"2021-06-03T07:38:08.710903Z","shell.execute_reply":"2021-06-03T07:38:08.728624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Directory & LoadData","metadata":{}},{"cell_type":"code","source":"if IN_KAGGLE:\n    INPUT_DIR = Path('../input/birdclef-2021/')\n    OUTPUT_DIR = './'\n    train = pd.read_csv('../input/birdclef-2021/train_metadata.csv')\n    train = train[['primary_label', 'filename']]\n    test = pd.read_csv('../input/birdclef-2021/test.csv')\n    train_HL = pd.read_csv( '../input/bird2-hl-list/30HL_146classes.csv')\n    train_HL = train_HL[[\"primary_label\", \"secondary_labels\", \"filename\", \"begin\", \"end\"]]\n    BGN_DIR = '../input/birdclef-bgn'\nelif IN_COLAB:\n    INPUT_DIR = Path('/content/input/')\n    OUTPUT_DIR = f'/content/drive/MyDrive/kaggle/BirdClef2021/data/output/{CFG.exp_name}/'\n    train = pd.read_csv('/content/input/train_metadata.csv')\n    train = train[['primary_label', 'filename']]\n    test = pd.read_csv('/content/input/test.csv')\n    train_HL = pd.read_csv( '/content/drive/MyDrive/kaggle/BirdClef2021/data/input/30HL_146classes.csv')\n    train_HL = train_HL[[\"primary_label\", \"secondary_labels\", \"filename\", \"begin\", \"end\"]]\n    BGN_DIR = '/content/drive/MyDrive/kaggle/BirdClef2021/data/input/bgn'\nif LOCAL:\n    INPUT_DIR = Path(\"F:/Kaggle/BirdCLEF2021/data/input/\")\n    OUTPUT_DIR = f'F:/Kaggle/BirdCLEF2021/data/output/{CFG.exp_name}/'\n    train = pd.read_csv('F:/Kaggle/BirdCLEF2021/data/input/resample/train_mod.csv')\n    train = train[['primary_label', 'resampled_filename']]\n    train.columns = ['primary_label', 'filename']\n    test = pd.read_csv('F:/Kaggle/BirdCLEF2021/data/input/test.csv')\n    train_HL = pd.read_csv( 'F:/Kaggle/BirdCLEF2021/data/input/30HL_146classes.csv')\n    train_HL = train_HL[[\"primary_label\", \"secondary_labels\", \"filename\", \"begin\", \"end\"]]\n    BGN_DIR = 'F:/Kaggle/BirdCLEF2021/data/input/bgn'\n\nCFG.transforms[\"train\"][2][\"params\"][\"noise_folder_path\"] = BGN_DIR\n# get train soundscapes\nTS_clips = []\nDATADIR = INPUT_DIR / \"train_soundscapes/\"\nall_audios = list(DATADIR.glob(\"*.ogg\"))\nfor audio in all_audios:\n    clip, _ = sf.read(audio)\n    TS_clips.append(clip)\n    \nif not os.path.exists(OUTPUT_DIR):\n    os.makedirs(OUTPUT_DIR)\n\nif CFG.debug:\n    CFG.epochs = 2\n    train = train.sample(n=1000, random_state=CFG.seed).reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:53.266323Z","iopub.execute_input":"2021-05-22T11:01:53.266666Z","iopub.status.idle":"2021-05-22T11:02:09.519172Z","shell.execute_reply.started":"2021-05-22T11:01:53.266631Z","shell.execute_reply":"2021-05-22T11:02:09.518463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Utils","metadata":{}},{"cell_type":"code","source":"def set_seed(seed=42):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\ndef init_logger(log_file = f'{OUTPUT_DIR}train.log'):\n    from logging import getLogger, INFO, FileHandler,  Formatter,  StreamHandler\n    logger = getLogger(__name__)\n    logger.setLevel(INFO)\n    handler1 = StreamHandler()\n    handler1.setFormatter(Formatter(\"%(message)s\"))\n    handler2 = FileHandler(filename=log_file)\n    handler2.setFormatter(Formatter(\"%(message)s\"))\n    logger.addHandler(handler1)\n    logger.addHandler(handler2)\n    return logger\n\nLOGGER = init_logger()\nset_seed(seed=CFG.seed)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.521258Z","iopub.execute_input":"2021-05-22T11:02:09.521594Z","iopub.status.idle":"2021-05-22T11:02:09.53213Z","shell.execute_reply.started":"2021-05-22T11:02:09.521557Z","shell.execute_reply":"2021-05-22T11:02:09.531393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Log config\nLOGGER.info(f\"exp_name:{CFG.exp_name}\")\nLOGGER.info(f\"train_period:{CFG.period}\")\nLOGGER.info(f\"model_name:{CFG.model_name}\")\nLOGGER.info(f\"spec_aggreagation:{CFG.spec_aggreagation}\")\nLOGGER.info(f\"epochs:{CFG.epochs}\")\nLOGGER.info(f\"lr:{CFG.lr}\")\nLOGGER.info(f\"min_lr:{CFG.min_lr}\")\nbs=CFG.loader[\"train\"][\"batch_size\"]\nLOGGER.info(f\"batch_size:{bs}\")","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.533997Z","iopub.execute_input":"2021-05-22T11:02:09.53425Z","iopub.status.idle":"2021-05-22T11:02:09.55756Z","shell.execute_reply.started":"2021-05-22T11:02:09.534226Z","shell.execute_reply":"2021-05-22T11:02:09.551984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## CV split","metadata":{}},{"cell_type":"code","source":"folds = train.copy()\nFold = StratifiedKFold(**CFG.split_params)\nfor n, (tr_idx, val_idx) in enumerate(Fold.split(folds, folds[CFG.target_col])):\n    folds.loc[val_idx, 'fold'] = int(n)\nfolds['fold'] = folds['fold'].astype(int)\n# # check the propotion\nfold_proportion = pd.pivot_table(folds, index=CFG.target_col, columns=\"fold\", aggfunc=len)\nprint(fold_proportion.shape)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.559185Z","iopub.execute_input":"2021-05-22T11:02:09.559513Z","iopub.status.idle":"2021-05-22T11:02:09.612417Z","shell.execute_reply.started":"2021-05-22T11:02:09.559478Z","shell.execute_reply":"2021-05-22T11:02:09.609864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fold_proportion","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.613487Z","iopub.execute_input":"2021-05-22T11:02:09.613847Z","iopub.status.idle":"2021-05-22T11:02:09.639115Z","shell.execute_reply.started":"2021-05-22T11:02:09.61382Z","shell.execute_reply":"2021-05-22T11:02:09.638214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset","metadata":{}},{"cell_type":"code","source":"class WaveformDataset(Dataset):\n    def __init__(self,\n                 df: pd.DataFrame,\n                 df_HL: pd.DataFrame,\n                 datadir: Path,\n                 img_size=224,\n                 waveform_transforms=None,\n                 period=20,\n                 validation=False):\n        self.df = df\n        self.df_HL = df_HL\n        self.datadir = datadir\n        self.img_size = img_size\n        self.waveform_transforms = waveform_transforms\n        self.period = period\n        self.validation = validation\n        self.y = np.array([TARGETS.index(c) for c in df[CFG.target_col]])\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx: int):\n        \"\"\"\n        HLされているデータの場合、その範囲でランダムに5秒Clip\n        HLされていないときと、validationのときは冒頭5秒Clip\n        \"\"\"\n        sample = self.df.loc[idx, :]\n        wav_name = sample['filename']\n        ebird_code = sample[CFG.target_col]\n        \n        y, sr = sf.read(self.datadir / ebird_code / wav_name)\n        # search hl\n        row = self.df_HL[self.df_HL['filename'] == wav_name]\n        # 5秒以下の場合は周囲を埋める\n        if (len(row) > 0) &  (not self.validation):\n            begin = row[\"begin\"].values[0].astype(int)\n            end = row[\"end\"].values[0].astype(int)\n            if end - begin < 5:\n                y_sec = len(y)//sr\n                missing = self.period - (end - begin)\n                new_begin = max(begin - missing, 0)\n                new_end = min(end + missing, y_sec)\n                y = y[new_begin*sr: new_end*sr]\n            else:\n                y = y[begin*sr: end*sr]\n        \n        len_y = len(y)\n        effective_length = sr * self.period\n        if len_y < effective_length:\n            new_y = np.zeros(effective_length, dtype=y.dtype)\n            if (len(row) > 0) &  (not self.validation):\n                start = np.random.randint(effective_length - len_y)\n            else:\n                start = 0\n            new_y[start:start + len_y] = y\n            y = new_y.astype(np.float32)\n        elif len_y > effective_length:\n            if (len(row) > 0) &  (not self.validation):\n                start = np.random.randint(len_y - effective_length)\n            else:\n                start = 0\n            y = y[start:start + effective_length].astype(np.float32)\n        else:\n            y = y.astype(np.float32)\n        y = np.nan_to_num(y)\n\n        if self.waveform_transforms:\n            y = self.waveform_transforms(y)\n\n        y = np.nan_to_num(y)\n        \n        labels = np.zeros(len(TARGETS), dtype=float)\n        labels[TARGETS.index(ebird_code)] = 1.0\n        \n        return{\n            'waveforms': y,\n            'targets': labels\n        }\n","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.642214Z","iopub.execute_input":"2021-05-22T11:02:09.642475Z","iopub.status.idle":"2021-05-22T11:02:09.659061Z","shell.execute_reply.started":"2021-05-22T11:02:09.642451Z","shell.execute_reply":"2021-05-22T11:02:09.658061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train_dataset = WaveformDataset(train,\n#                                 CFG.train_datadir,\n#                                 img_size=CFG.img_size,\n#                                 waveform_transforms=None,\n#                                 period=CFG.period,\n#                                 validation=True)\n# \n# data = train_dataset[0]\n# print(data['waveforms'].shape, data['targets'].shape)\n# plt.plot(data['waveforms'])\n# plt.show()\n# Audio(data=data['waveforms'], rate=32000)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.660788Z","iopub.execute_input":"2021-05-22T11:02:09.661221Z","iopub.status.idle":"2021-05-22T11:02:09.670891Z","shell.execute_reply.started":"2021-05-22T11:02:09.661184Z","shell.execute_reply":"2021-05-22T11:02:09.669565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## WaveformTransforms","metadata":{}},{"cell_type":"code","source":"# https://www.kaggle.com/hidehisaarai1213/pytorch-training-birdclef2021-starter\ndef get_transforms(phase: str):\n    transforms = CFG.transforms\n    if transforms is None:\n        return None\n    else:\n        if transforms[phase] is None:\n            return None\n        trns_list = []\n        for trns_conf in transforms[phase]:\n            trns_name = trns_conf[\"name\"]\n            trns_params = {} if trns_conf.get(\"params\") is None else \\\n                trns_conf[\"params\"]\n            if globals().get(trns_name) is not None:\n                trns_cls = globals()[trns_name]\n                trns_list.append(trns_cls(**trns_params))\n\n        if len(trns_list) > 0:\n            return Compose(trns_list)\n        else:\n            return None\n\n# Base Class\n# -------------------------------------------------\nclass AudioTransform:\n    def __init__(self, always_apply=False, p=0.5):\n        self.always_apply = always_apply\n        self.p = p\n\n    def __call__(self, y: np.ndarray):\n        if self.always_apply:\n            return self.apply(y)\n        else:\n            if np.random.rand() < self.p:\n                return self.apply(y)\n            else:\n                return y\n\n    def apply(self, y: np.ndarray):\n        raise NotImplementedError\n        \nclass Normalize:\n    def __call__(self, y: np.ndarray):\n        max_vol = np.abs(y).max()\n        y_vol = y * 1 / max_vol\n        return np.asfortranarray(y_vol)\n\nclass Compose:\n    def __init__(self, transforms: list):\n        self.transforms = transforms\n\n    def __call__(self, y: np.ndarray):\n        for trns in self.transforms:\n            y = trns(y)\n        return y\n    \nclass NoiseInjection(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, max_noise_level=0.5, sr=32000):\n        super().__init__(always_apply, p)\n\n        self.noise_level = (0.0, max_noise_level)\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        noise_level = np.random.uniform(*self.noise_level)\n        noise = np.random.randn(len(y))\n        augmented = (y + noise * noise_level).astype(y.dtype)\n        return augmented\n\n# GaussianNoiseSNRとも\nclass GaussianNoise(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, min_snr=5, max_snr=20, sr=32000):\n        super().__init__(always_apply, p)\n\n        self.min_snr = min_snr\n        self.max_snr = max_snr\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        snr = np.random.uniform(self.min_snr, self.max_snr)\n        a_signal = np.sqrt(y ** 2).max()\n        a_noise = a_signal / (10 ** (snr / 20))\n\n        white_noise = np.random.randn(len(y))\n        a_white = np.sqrt(white_noise ** 2).max()\n        augmented = (y + white_noise * 1 / a_white * a_noise).astype(y.dtype)\n        return augmented\n\nclass PinkNoise(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, min_snr=5, max_snr=20, sr=32000):\n        super().__init__(always_apply, p)\n\n        self.min_snr = min_snr\n        self.max_snr = max_snr\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        snr = np.random.uniform(self.min_snr, self.max_snr)\n        a_signal = np.sqrt(y ** 2).max()\n        a_noise = a_signal / (10 ** (snr / 20))\n\n        pink_noise = cn.powerlaw_psd_gaussian(1, len(y))\n        a_pink = np.sqrt(pink_noise ** 2).max()\n        augmented = (y + pink_noise * 1 / a_pink * a_noise).astype(y.dtype)\n        return augmented\n    \ndef _db2float(db: float, amplitude=True):\n    if amplitude:\n        return 10**(db / 20)\n    else:\n        return 10 ** (db / 10)\n\n\ndef volume_down(y: np.ndarray, db: float):\n    \"\"\"\n    Low level API for decreasing the volume\n    Parameters\n    ----------\n    y: numpy.ndarray\n        stereo / monaural input audio\n    db: float\n        how much decibel to decrease\n    Returns\n    -------\n    applied: numpy.ndarray\n        audio with decreased volume\n    \"\"\"\n    applied = y * _db2float(-db)\n    return applied\n\n\ndef volume_up(y: np.ndarray, db: float):\n    \"\"\"\n    Low level API for increasing the volume\n    Parameters\n    ----------\n    y: numpy.ndarray\n        stereo / monaural input audio\n    db: float\n        how much decibel to increase\n    Returns\n    -------\n    applied: numpy.ndarray\n        audio with increased volume\n    \"\"\"\n    applied = y * _db2float(db)\n    return applied\n\n\nclass RandomVolume(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, limit=10):\n        super().__init__(always_apply, p)\n        self.limit = limit\n\n    def apply(self, y: np.ndarray, **params):\n        db = np.random.uniform(-self.limit, self.limit)\n        if db >= 0:\n            return volume_up(y, db)\n        else:\n            return volume_down(y, db)\n        \n# https://www.kaggle.com/vladimirsydor/4-th-place-solution-inference-and-training-tips/data?scriptVersionId=42796948\nclass SpecifiedNoise(AudioTransform):\n    def __init__(self, noise_folder_path, always_apply=False, p=0.5, min_snr=0.0, max_snr=1.0, sr=32000):\n        super().__init__(always_apply, p)\n        filenames = glob(pjoin(noise_folder_path, '*/*.wav'))\n        self.noises = [librosa.load(noise_path, sr=sr)[0] for noise_path in filenames]\n        self.noises = [librosa.util.normalize(noise) for noise in self.noises]\n        self.noises = [noise[:CFG.period*sr] for noise in self.noises]\n        self.min_snr = min_snr\n        self.max_snr = max_snr\n        self.sr = sr\n\n    def apply(self, y:np.ndarray, **params):\n        alpha = np.random.uniform(low=self.min_snr, high=self.max_snr)\n        noise = self.noises[np.random.randint(low=0, high=len(self.noises))]\n        augmented = y*(1 - alpha) + noise * alpha\n\n        return augmented","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.673431Z","iopub.execute_input":"2021-05-22T11:02:09.674325Z","iopub.status.idle":"2021-05-22T11:02:09.704443Z","shell.execute_reply.started":"2021-05-22T11:02:09.674276Z","shell.execute_reply":"2021-05-22T11:02:09.703561Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Criterion","metadata":{}},{"cell_type":"code","source":"def get_criterion():\n    if CFG.criterion=='BCEWithLogitsLoss':\n        criterion = nn.BCEWithLogitsLoss(reduction=\"mean\").to(device)\n    else:\n        raise NotImplementedError\n    return criterion","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.705815Z","iopub.execute_input":"2021-05-22T11:02:09.706152Z","iopub.status.idle":"2021-05-22T11:02:09.718151Z","shell.execute_reply.started":"2021-05-22T11:02:09.706117Z","shell.execute_reply":"2021-05-22T11:02:09.717425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Scheduler","metadata":{}},{"cell_type":"code","source":"def get_scheduler(optimizer):\n    if CFG.scheduler=='ReduceLROnPlateau':\n        scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=CFG.factor, patience=CFG.patience, verbose=True, eps=CFG.eps)\n    elif CFG.scheduler=='CosineAnnealingLR':\n        scheduler = CosineAnnealingLR(optimizer, T_max=CFG.T_max, eta_min=CFG.min_lr, last_epoch=-1)\n    elif CFG.scheduler=='CosineAnnealingWarmRestarts':\n        scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=CFG.T_0, T_mult=1, eta_min=CFG.min_lr, last_epoch=-1)\n    return scheduler","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.719264Z","iopub.execute_input":"2021-05-22T11:02:09.71959Z","iopub.status.idle":"2021-05-22T11:02:09.72791Z","shell.execute_reply.started":"2021-05-22T11:02:09.719551Z","shell.execute_reply":"2021-05-22T11:02:09.726818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check scheduler\nmodel = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2))\noptimizer = Adam(model.parameters(), lr=CFG.lr, weight_decay=CFG.weight_decay, amsgrad=False)\nscheduler = get_scheduler(optimizer)\n\nfrom pylab import rcParams\nlrs = []\nfor epoch in range(1, CFG.epochs+1):\n    scheduler.step(epoch-1)\n    lrs.append(optimizer.param_groups[0][\"lr\"])\nrcParams['figure.figsize'] = 20,3\nplt.plot(lrs)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.729631Z","iopub.execute_input":"2021-05-22T11:02:09.730068Z","iopub.status.idle":"2021-05-22T11:02:09.902318Z","shell.execute_reply.started":"2021-05-22T11:02:09.730034Z","shell.execute_reply":"2021-05-22T11:02:09.901686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Torchaudio utils\nhttps://www.kaggle.com/vladimirsydor/4-th-place-solution-inference-and-training-tips","metadata":{}},{"cell_type":"code","source":"def compute_deltas(\n        specgram: torch.Tensor,\n        win_length: int = 5,\n        mode: str = \"replicate\"\n) -> torch.Tensor:\n    r\"\"\"Compute delta coefficients of a tensor, usually a spectrogram:\n\n    .. math::\n       d_t = \\frac{\\sum_{n=1}^{\\text{N}} n (c_{t+n} - c_{t-n})}{2 \\sum_{n=1}^{\\text{N}} n^2}\n\n    where :math:`d_t` is the deltas at time :math:`t`,\n    :math:`c_t` is the spectrogram coeffcients at time :math:`t`,\n    :math:`N` is ``(win_length-1)//2``.\n\n    Args:\n        specgram (Tensor): Tensor of audio of dimension (..., freq, time)\n        win_length (int, optional): The window length used for computing delta (Default: ``5``)\n        mode (str, optional): Mode parameter passed to padding (Default: ``\"replicate\"``)\n\n    Returns:\n        Tensor: Tensor of deltas of dimension (..., freq, time)\n\n    Example\n        >>> specgram = torch.randn(1, 40, 1000)\n        >>> delta = compute_deltas(specgram)\n        >>> delta2 = compute_deltas(delta)\n    \"\"\"\n    device = specgram.device\n    dtype = specgram.dtype\n\n    # pack batch\n    shape = specgram.size()\n    specgram = specgram.reshape(1, -1, shape[-1])\n\n    assert win_length >= 3\n\n    n = (win_length - 1) // 2\n\n    # twice sum of integer squared\n    denom = n * (n + 1) * (2 * n + 1) / 3\n\n    specgram = torch.nn.functional.pad(specgram, (n, n), mode=mode)\n\n    kernel = torch.arange(-n, n + 1, 1, device=device, dtype=dtype).repeat(specgram.shape[1], 1, 1)\n\n    output = torch.nn.functional.conv1d(specgram, kernel, groups=specgram.shape[1]) / denom\n\n    # unpack batch\n    output = output.reshape(shape)\n\n    return output\n\ndef make_delta(input_tensor: torch.Tensor):\n    input_tensor = input_tensor.transpose(3,2)\n    input_tensor = compute_deltas(input_tensor)\n    input_tensor = input_tensor.transpose(3,2)\n    return input_tensor","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.903818Z","iopub.execute_input":"2021-05-22T11:02:09.90417Z","iopub.status.idle":"2021-05-22T11:02:09.914535Z","shell.execute_reply.started":"2021-05-22T11:02:09.904133Z","shell.execute_reply":"2021-05-22T11:02:09.913331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mixup_data(x, y, alpha=0.4):\n    \"\"\"\n    https://github.com/TheoViel/kaggle_birdcall_identification/blob/2de708b9871cf388f91b9b0a33e738a24cca565d/src/training/train.py#L15\n    Applies mixup to a sample\n    Arguments:\n        x {torch tensor} -- Input batch\n        y {torch tensor} -- Labels\n    Keyword Arguments:\n        alpha {float} -- Parameter of the beta distribution (default: {0.4})\n    Returns:\n        torch tensor  -- Mixed input\n        torch tensor  -- Labels of the original batch\n        torch tensor  -- Labels of the shuffle batch\n        float  -- Probability samples by the beta distribution\n    \"\"\"\n    lam = np.random.beta(alpha, alpha) if alpha > 0 else 1\n\n    index = torch.randperm(x.size()[0])#.cuda()\n\n    mixed_x = lam * x + (1 - lam) * x[index, :]\n    y_a, y_b = y, y[index]\n\n    return mixed_x, y_a, y_b, lam","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.916061Z","iopub.execute_input":"2021-05-22T11:02:09.916454Z","iopub.status.idle":"2021-05-22T11:02:09.925138Z","shell.execute_reply.started":"2021-05-22T11:02:09.916415Z","shell.execute_reply":"2021-05-22T11:02:09.924297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"class CustomModel(nn.Module):\n    def __init__(self, model_name=CFG.model_name, pretrained=False, in_channels=1,spec_aggreagation: str='repeat3'):\n        super().__init__()\n        self.model_name = model_name\n        # Spectrogram extractor\n        self.spectrogram_extractor = Spectrogram(n_fft=CFG.n_fft, hop_length=CFG.hop_length,\n                                                 win_length=CFG.n_fft, window=\"hann\", center=True, pad_mode=\"reflect\",\n                                                 freeze_parameters=True)\n\n        # Logmel feature extractor\n        self.logmel_extractor = LogmelFilterBank(sr=CFG.sample_rate, n_fft=CFG.n_fft,\n                                                 n_mels=CFG.n_mels, fmin=CFG.fmin, fmax=CFG.fmax, ref=1.0, amin=1e-10, top_db=None,\n                                                 freeze_parameters=True)\n\n        # Spec augmenter\n        self.spec_augmenter = SpecAugmentation(time_drop_width=64, time_stripes_num=2,\n                                               freq_drop_width=8, freq_stripes_num=2)\n        self.bn0 = nn.BatchNorm2d(CFG.n_mels)\n        \n        self.spec_aggreagation = spec_aggreagation\n\n        self.model = timm.create_model(model_name,\n                                       num_classes=CFG.target_size,\n                                       pretrained=pretrained,\n                                       in_chans=in_channels)\n\n    def forward(self, input):\n        \"\"\"\n        Input: (batch_size, data_length)\n        \"\"\"\n        x = self.spectrogram_extractor(input)# output:(batch_size, 1(channel), time_steps, freq_bins)\n        x = self.logmel_extractor(x)# output:(batch_size, 1(channel), time_steps, mel_bins)\n        if 'vit' in self.model_name:\n            x = F.adaptive_avg_pool2d(x, (CFG.img_size,CFG.img_size)) # (batch_size,channel(1),224,224)\n        x = x.transpose(1, 3)\n        x = self.bn0(x)\n        x = x.transpose(1, 3)\n        if self.training:\n            x = self.spec_augmenter(x)\n        # 1channel => 3channel\n        if self.spec_aggreagation == 'repeat3':\n            x = torch.cat([x,x,x], dim=1)\n        elif self.spec_aggreagation == 'deltas':\n            delta_1 = make_delta(x)\n            delta_2 = make_delta(delta_1)\n            x = torch.cat([x,delta_1,delta_2], dim=1)\n\n        #x = x.transpose(2, 3)\n        # (batch_size, channels, freq, frames)\n\n        x = self.model(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.92731Z","iopub.execute_input":"2021-05-22T11:02:09.927545Z","iopub.status.idle":"2021-05-22T11:02:09.940832Z","shell.execute_reply.started":"2021-05-22T11:02:09.927523Z","shell.execute_reply":"2021-05-22T11:02:09.940075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model(model_name, pretrained=False, in_channels=3, spec_aggreagation='repeat3'):\n\n    model = CustomModel(model_name=model_name,\n                        pretrained=pretrained,\n                        in_channels=in_channels,\n                        spec_aggreagation=spec_aggreagation)\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    model.to(device)\n    model.eval()\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.942341Z","iopub.execute_input":"2021-05-22T11:02:09.942712Z","iopub.status.idle":"2021-05-22T11:02:09.950975Z","shell.execute_reply.started":"2021-05-22T11:02:09.942675Z","shell.execute_reply":"2021-05-22T11:02:09.950284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Helper functions","metadata":{}},{"cell_type":"code","source":"class AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\n\ndef asMinutes(s):\n    m = math.floor(s / 60)\n    s -= m * 60\n    return '%dm %ds' % (m, s)\n\n\ndef timeSince(since, percent):\n    now = time.time()\n    s = now - since\n    es = s / (percent)\n    rs = es - s\n    return '%s (remain %s)' % (asMinutes(s), asMinutes(rs))\n\ndef save(model, optimizer, scheduler, epoch, preds, path):\n    torch.save({'model': model.state_dict(),\n                'optimizer': optimizer.state_dict(),\n                'scheduler': scheduler.state_dict(),\n                'epoch': epoch,\n                'preds': preds},\n                path)\n\n# https://www.kaggle.com/theoviel/training-a-winning-model/notebook?scriptVersionId=42814701\nONE_HOT = np.eye(CFG.target_size)\ndef f1(truth, pred, threshold=0.5, avg=\"samples\"):\n\n    if len(truth.shape) == 1:\n        truth = ONE_HOT[truth]\n    pred = (pred > threshold).astype(int)\n    return f1_score(truth, pred, average=avg)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.96521Z","iopub.execute_input":"2021-05-22T11:02:09.965496Z","iopub.status.idle":"2021-05-22T11:02:09.97684Z","shell.execute_reply.started":"2021-05-22T11:02:09.965471Z","shell.execute_reply":"2021-05-22T11:02:09.976037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"https://www.kaggle.com/yasufuminakama/cassava-resnext50-32x4d-starter-training","metadata":{}},{"cell_type":"code","source":"def train_one_epoch(train_loader, model, criterion, optimizer, epoch, scheduler, device):\n    batch_time = AverageMeter()\n    data_time = AverageMeter()\n    losses = AverageMeter()\n    scores = AverageMeter()\n    # switch to train mode\n    model.train()\n    start = end = time.time()\n    global_step = 0\n    \n    for step, data in enumerate(train_loader):\n        waveforms = data['waveforms']\n        labels = data['targets']\n        # measure data loading time\n        data_time.update(time.time() - end)\n        \n        waveforms = waveforms.to(device)\n        labels = labels.to(device)\n        batch_size = labels.size(0)\n        \n        if np.random.rand() < CFG.mixup_proba:\n            waveforms, y_a, y_b, _ = mixup_data(waveforms, labels, alpha=0.4)\n            labels = torch.clamp(y_a + y_b, 0, 1)\n        \n        y_preds = model(waveforms)\n        loss = criterion(y_preds, labels)\n        # record loss\n        losses.update(loss.item(), batch_size)\n        if CFG.gradient_accumulation_steps > 1:\n            loss = loss / CFG.gradient_accumulation_steps\n        if CFG.apex:\n            with amp.scale_loss(loss, optimizer) as scaled_loss:\n                scaled_loss.backward()\n        else:\n            loss.backward()\n        grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), CFG.max_grad_norm)\n        if (step + 1) % CFG.gradient_accumulation_steps == 0:\n            optimizer.step()\n            optimizer.zero_grad()\n            global_step += 1\n        # measure elapsed time\n        batch_time.update(time.time() - end)\n        end = time.time()\n        if step % CFG.print_freq == 0 or step == (len(train_loader)-1):\n            print('Epoch: [{0}][{1}/{2}] '\n                  'Data {data_time.val:.3f} ({data_time.avg:.3f}) '\n                  'Elapsed {remain:s} '\n                  'Loss: {loss.val:.4f}({loss.avg:.4f}) '\n                  'Grad: {grad_norm:.4f}  '\n                  #'LR: {lr:.6f}  '\n                  .format(\n                   epoch+1, step, len(train_loader), batch_time=batch_time,\n                   data_time=data_time, loss=losses,\n                   remain=timeSince(start, float(step+1)/len(train_loader)),\n                   grad_norm=grad_norm,\n                   #lr=scheduler.get_lr()[0],\n                   ))\n    return losses.avg\n\ndef valid_fn(valid_loader, model, criterion, device):\n    batch_time = AverageMeter()\n    data_time = AverageMeter()\n    losses = AverageMeter()\n    scores = AverageMeter()\n    # switch to evaluation mode\n    model.eval()\n    preds = np.empty((0, CFG.target_size))\n    start = end = time.time()\n    for step, data in enumerate(valid_loader):\n        waveforms = data['waveforms']\n        labels = data['targets']\n        # measure data loading time\n        data_time.update(time.time() - end)\n        waveforms = waveforms.to(device)\n        labels = labels.to(device)\n        batch_size = labels.size(0)\n        # compute loss\n        with torch.no_grad():\n            y_preds = model(waveforms)\n            preds = np.concatenate([preds, torch.sigmoid(y_preds).cpu().numpy()])\n        loss = criterion(y_preds, labels)\n        losses.update(loss.item(), batch_size)\n        if CFG.gradient_accumulation_steps > 1:\n            loss = loss / CFG.gradient_accumulation_steps\n        # measure elapsed time\n        batch_time.update(time.time() - end)\n        end = time.time()\n        if step % CFG.print_freq == 0 or step == (len(valid_loader)-1):\n            print('EVAL: [{0}/{1}] '\n                  'Data {data_time.val:.3f} ({data_time.avg:.3f}) '\n                  'Elapsed {remain:s} '\n                  'Loss: {loss.val:.4f}({loss.avg:.4f}) '\n                  .format(\n                   step, len(valid_loader), batch_time=batch_time,\n                   data_time=data_time, loss=losses,\n                   remain=timeSince(start, float(step+1)/len(valid_loader)),\n                   ))\n    return losses.avg, preds","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:09.97816Z","iopub.execute_input":"2021-05-22T11:02:09.978563Z","iopub.status.idle":"2021-05-22T11:02:09.998872Z","shell.execute_reply.started":"2021-05-22T11:02:09.978529Z","shell.execute_reply":"2021-05-22T11:02:09.997882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TestDataset(Dataset):\n    def __init__(self, df: pd.DataFrame, clip: np.ndarray,\n                 waveform_transforms=None):\n        self.df = df\n        self.clip = clip\n        self.waveform_transforms=waveform_transforms\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx: int):\n        SR = 32000\n        sample = self.df.loc[idx, :]\n        row_id = sample.row_id\n        \n        end_seconds = int(sample.seconds)\n        start_seconds = int(end_seconds - 5)\n        \n        start_index = SR * start_seconds\n        end_index = SR * end_seconds\n        \n        y = self.clip[start_index:end_index].astype(np.float32)\n        \n        y = np.nan_to_num(y)\n\n        if self.waveform_transforms:\n            y = self.waveform_transforms(y)\n\n        y = np.nan_to_num(y)\n        \n        return y, row_id\n\ndef prediction_for_clip(test_df: pd.DataFrame,\n                        clip: np.ndarray,\n                        model,\n                        threshold=0.5):\n    \"\"\"\n    [input]test_df:audiofile一個分のdataframe\n           clip:音声データ\n           model:モデルのインスタンス\n           threshold:\n           \n    [output]preds:ndarray(120,397)\n    \"\"\"\n    model.eval()\n    preds = np.empty((0, len(TARGETS)))\n    dataset = TestDataset(df=test_df,\n                          clip=clip,\n                          waveform_transforms=None)\n    loader = DataLoader(dataset, batch_size=120, shuffle=False)\n    \n    for image, row_id in loader:\n        row_id = row_id[0]\n        image = image.to(device)\n        model = model.to(device)\n        with torch.no_grad():\n            y_pred = model(image)\n            preds = np.concatenate([preds, torch.sigmoid(y_pred).cpu().numpy()])\n        \n    return preds  \n\ndef post_process_site_12(preds, threshold=0.5, maxpreds=3):\n    \"\"\"\n    input: preds(120, 397)\n    \"\"\"\n    preds = preds * (preds >= threshold)   # remove preds < threshold\n\n    next_preds = np.concatenate([preds[1:], np.zeros((1, preds.shape[-1]))])   # pred corresponding to next window\n    prev_preds = np.concatenate([np.zeros((1, preds.shape[-1])), preds[:-1]])  # pred corresponding to previous window\n    \n    score = preds + 0.5 * next_preds + 0.5 * prev_preds  # Aggregating with neighbouring predictions\n    \n    n_birds = (score >= threshold).sum(-1)   # Counting birds\n    n_birds = np.clip(n_birds, 0, maxpreds)  # keep at most maxpreds birds\n    \n    labels = [np.argsort(- score[i])[:n_birds[i]] for i in range(len(preds))]  # Getting the n_birds most likely class indices\n    \n    class_labels = [\" \".join([TARGETS[l] for l in label]) for label in labels]  # Getting class names\n    \n    return class_labels\n\ndef reformat_preds(preds, df):\n    prediction_df = pd.DataFrame({\n        'row_id': df['row_id'].values,\n        'birds': preds\n    })\n    \n    prediction_df['birds'] = prediction_df['birds'].replace([''],'nocall')\n    \n    return prediction_df\n\ndef get_metrics(s_true, s_pred):\n    s_true = set(s_true.split())\n    s_pred = set(s_pred.split())\n    n, n_true, n_pred = len(s_true.intersection(s_pred)), len(s_true), len(s_pred)\n    \n    prec = n/n_pred\n    rec = n/n_true\n    f1 = 2*prec*rec/(prec + rec) if prec + rec else 0\n    \n    return {\"f1\": f1, \"prec\": prec, \"rec\": rec, \"n_true\": n_true, \"n_pred\": n_pred, \"n\": n}\n    \ndef inference_voting(test_audios, clips, model, threshold=0.5):\n    pred_dfs = []\n    for (audio_path, clip) in zip(test_audios, clips):\n        # 1clip分のdfを作成\n        seconds = []\n        row_ids = []\n        for second in range(5, 605, 5):\n            row_id = \"_\".join(audio_path.name.split(\"_\")[:2]) + f\"_{second}\"\n            seconds.append(second)\n            row_ids.append(row_id)\n        \n        test_df = pd.DataFrame({\n            \"row_id\": row_ids,\n            \"seconds\": seconds\n        })\n        \n        # prediction\n        preds = prediction_for_clip(test_df, clip, model, threshold) #ndarray(120,397)\n        # postprocess\n        preds_pp = post_process_site_12(preds, threshold=threshold)\n        #print(\"Predicted classes :\", preds_pp)\n        pred_df = reformat_preds(preds_pp, test_df)\n        pred_dfs.append(pred_df)\n    \n    sub = pd.concat(pred_dfs, axis=0, sort=False).reset_index(drop=True)\n    return sub\n\ndef test_fn(all_audios,TS_clips,model):\n    # inference for train soundscape\n    submission = inference_voting(test_audios=all_audios,clips=TS_clips,model=model)\n    submission.to_csv(OUTPUT_DIR+\"submission.csv\", index=False)\n    sub_target = pd.read_csv(INPUT_DIR / 'train_soundscape_labels.csv')\n    sub_target = sub_target.merge(submission, how=\"left\", on=\"row_id\")\n    # get metrics\n    df_metrics = pd.DataFrame([get_metrics(s_true, s_pred) for s_true, s_pred in zip(sub_target.birds_x, sub_target.birds_y)])\n    TS_f1 = df_metrics.mean()[0]\n    TS_prec = df_metrics.mean()[1]\n    TS_rec = df_metrics.mean()[2]\n    return TS_f1, TS_prec, TS_rec","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:10.000389Z","iopub.execute_input":"2021-05-22T11:02:10.00078Z","iopub.status.idle":"2021-05-22T11:02:10.026415Z","shell.execute_reply.started":"2021-05-22T11:02:10.00069Z","shell.execute_reply":"2021-05-22T11:02:10.025543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train loop","metadata":{}},{"cell_type":"code","source":"def train_loop(folds: pd.DataFrame, fold_num: int = 0):\n    LOGGER.info(f\"========== fold: {fold_num} training ==========\")\n    ### dataset\n    tr_index = folds[folds[\"fold\"] != fold_num].index\n    vl_index = folds[folds[\"fold\"] == fold_num].index\n    \n    train_folds = folds.loc[tr_index].reset_index(drop=True)\n    valid_folds = folds.loc[vl_index].reset_index(drop=True)\n    \n    train_dataset = WaveformDataset(train_folds,\n                                    train_HL,\n                                    CFG.train_datadir,\n                                    img_size=CFG.img_size,\n                                    waveform_transforms=get_transforms(\"train\"),\n                                    period=CFG.period,\n                                    validation=False)\n    valid_dataset = WaveformDataset(valid_folds,\n                                    train_HL,\n                                    CFG.train_datadir,\n                                    img_size=CFG.img_size,\n                                    waveform_transforms=get_transforms(\"valid\"),\n                                    period=CFG.period,\n                                    validation=True)\n    ### dataloader\n    train_loader = DataLoader(train_dataset, **CFG.loader['train'])\n    valid_loader = DataLoader(valid_dataset, **CFG.loader['valid'])\n    \n    ### model\n    model = get_model(model_name=CFG.model_name, pretrained=CFG.pretrained, in_channels=CFG.in_channels, spec_aggreagation=CFG.spec_aggreagation)\n    model.to(device)\n    ### optimizer\n    optimizer = Adam(model.parameters(), lr=CFG.lr, weight_decay=CFG.weight_decay, amsgrad=False)\n    ### get scheduler\n    scheduler = get_scheduler(optimizer)\n    if CFG.apex:\n        model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0)\n    ### criterion\n    criterion = get_criterion()\n    \n    # ====================================================\n    # loop\n    # ====================================================\n    cols = ['epoch','avg_train_loss','avg_val_loss','micro_f1','samples_f1','TS_f1', 'TS_prec', 'TS_rec']\n    df_log = pd.DataFrame(index=[], columns=cols)\n\n    best_score = 0.\n    best_f1_train_soundscape = 0.\n    best_loss = np.inf\n    \n    for epoch in range(CFG.epochs):\n        start_time = time.time()\n        # train\n        avg_loss = train_one_epoch(train_loader, model, criterion, optimizer, epoch, scheduler, device)\n        # eval\n        avg_val_loss, preds = valid_fn(valid_loader, model, criterion, device)\n        #test\n        TS_f1, TS_prec, TS_rec = test_fn(all_audios, TS_clips, model)\n        # scoring\n        print(f'pred max{np.amax(preds)}')\n        micro_f1 = f1(valid_dataset.y, preds, avg=\"micro\")\n        samples_f1 = f1(valid_dataset.y, preds)\n        \n        if isinstance(scheduler, ReduceLROnPlateau):\n            scheduler.step(avg_val_loss)\n        elif isinstance(scheduler, CosineAnnealingLR):\n            scheduler.step()\n        elif isinstance(scheduler, CosineAnnealingWarmRestarts):\n            scheduler.step()\n\n        elapsed = time.time() - start_time\n        \n        # LINEにおくる\n        #send_line_notification(f'[GPU]Epoch {epoch+1} - val_loss: {avg_val_loss}')\n        LOGGER.info(f'Epoch {epoch+1} - micro_f1:{micro_f1:.4f},samples_f1{samples_f1:.4f}')\n        LOGGER.info(f'Epoch {epoch+1} - TS_f1:{TS_f1:.4f},TS_prec:{TS_prec:.4f},TS_rec:{TS_rec:.4f}')\n        LOGGER.info(f'Epoch {epoch+1} - avg_train_loss: {avg_loss:.4f}  avg_val_loss: {avg_val_loss:.4f}  time: {elapsed:.0f}s')\n        record = pd.Series([epoch+1, avg_loss,avg_val_loss,micro_f1,samples_f1,TS_f1, TS_prec, TS_rec], index=df_log.columns)\n        df_log = df_log.append(record, ignore_index=True)\n        df_log.to_csv(OUTPUT_DIR+\"log.csv\", index=False)\n\n        if avg_val_loss < best_loss:\n            best_loss = avg_val_loss\n            LOGGER.info(f'Epoch {epoch+1} - Save Best Score: {best_loss:.4f} Model')\n            save(model, optimizer, scheduler, epoch+1, preds,\n                 path=OUTPUT_DIR+f'{CFG.model_name}_fold{fold_num}_best_loss.pth')\n        if best_f1_train_soundscape < TS_f1:\n            best_f1_train_soundscape = TS_f1\n            save(model, optimizer, scheduler, epoch+1, preds,\n                 path=OUTPUT_DIR+f'{CFG.model_name}_fold{fold_num}_best_f1.pth')\n\n    save(model, optimizer, scheduler, epoch+1, preds,\n         path=OUTPUT_DIR+f'{CFG.model_name}_fold{fold_num}_last.pth')\n\n    return valid_folds","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:10.027782Z","iopub.execute_input":"2021-05-22T11:02:10.02815Z","iopub.status.idle":"2021-05-22T11:02:10.048964Z","shell.execute_reply.started":"2021-05-22T11:02:10.028115Z","shell.execute_reply":"2021-05-22T11:02:10.04811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def main():\n    for fold in range(CFG.n_fold):\n        if fold in CFG.trn_fold:\n            _oof_df = train_loop(folds, fold)\n\nif __name__ == '__main__':\n    main()","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:02:10.050459Z","iopub.execute_input":"2021-05-22T11:02:10.051024Z","iopub.status.idle":"2021-05-22T11:05:02.436579Z","shell.execute_reply.started":"2021-05-22T11:02:10.050989Z","shell.execute_reply":"2021-05-22T11:05:02.435533Z"},"trusted":true},"execution_count":null,"outputs":[]}]}