{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":7342653,"sourceType":"datasetVersion","datasetId":4263396},{"sourceId":7359260,"sourceType":"datasetVersion","datasetId":4274535}],"dockerImageVersionId":30627,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n \nimport warnings\n \nwarnings.filterwarnings(action='ignore')\n \nimport pandas as pd\nimport librosa\nimport numpy as np\n \nfrom sklearn.utils import shuffle\nfrom PIL import Image\nfrom tqdm import tqdm\n \n# Global vars\nRANDOM_SEED = 1337\nSAMPLE_RATE = 32000\nSIGNAL_LENGTH = 5  # seconds\nSPEC_SHAPE = (224, 224)  # height x width\nFMIN = 20\nFMAX = 16000\n \n \n# Load metadata file\ntrain = pd.read_csv('/kaggle/input/bird-sound-labels/train_metadata.csv', )\n\nbirds_count = {}\nfor bird_species, count in zip(train.primary_label.unique(),\n                               train.groupby('primary_label')['primary_label'].count().values):\n    birds_count[bird_species] = count\nmost_represented_birds = [key for key, value in birds_count.items()]\n \nTRAIN = train.query('primary_label in @most_represented_birds')\nLABELS = sorted(TRAIN.primary_label.unique())\n \n# Let's see how many species and samples we have left\nprint('NUMBER OF SPECIES IN TRAIN DATA:', len(LABELS))\nprint('NUMBER OF SAMPLES IN TRAIN DATA:', len(TRAIN))\nprint('LABELS:', most_represented_birds)\n# Shuffle the training data and limit the number of audio files to MAX_AUDIO_FILES\nTRAIN = shuffle(TRAIN, random_state=RANDOM_SEED)\n \n \n# Define a function that splits an audio file,\n# extracts spectrograms and saves them in a working directory\ndef get_spectrograms(filepath, primary_label, output_dir):\n    # Open the file with librosa (limited to the first 15 seconds)\n    sig, rate = librosa.load(filepath, sr=SAMPLE_RATE, offset=None, duration=15)\n \n    # Split signal into five second chunks\n    sig_splits = []\n    for i in range(0, len(sig), int(SIGNAL_LENGTH * SAMPLE_RATE)):\n        split = sig[i:i + int(SIGNAL_LENGTH * SAMPLE_RATE)]\n \n        # End of signal?\n        if len(split) < int(SIGNAL_LENGTH * SAMPLE_RATE):\n            break\n \n        sig_splits.append(split)\n \n    # Extract mel spectrograms for each audio chunk\n    s_cnt = 0\n    saved_samples = []\n    for chunk in sig_splits:\n \n        hop_length = int(SIGNAL_LENGTH * SAMPLE_RATE / (SPEC_SHAPE[1] - 1))\n        mel_spec = librosa.feature.melspectrogram(y=chunk,\n                                                  sr=SAMPLE_RATE,\n                                                  n_fft=2048,\n                                                  hop_length=hop_length,\n                                                  n_mels=SPEC_SHAPE[0],\n                                                  fmin=FMIN,\n                                                  fmax=FMAX)\n \n        mel_spec = librosa.power_to_db(mel_spec, ref=np.max)\n \n        # Normalize\n        mel_spec -= mel_spec.min()\n        mel_spec /= mel_spec.max()\n \n        # Save as image file\n        save_dir = os.path.join(output_dir, primary_label)\n        if not os.path.exists(save_dir):\n            os.makedirs(save_dir)\n        save_path = os.path.join(save_dir, filepath.rsplit(os.sep, 1)[-1].rsplit('.', 1)[0] +\n                                 '_' + str(s_cnt) + '.png')\n        im = Image.fromarray(mel_spec * 255.0).convert(\"L\")\n        im.save(save_path)\n \n        saved_samples.append(save_path)\n        s_cnt += 1\n \n    return saved_samples\n \n \nprint('FINAL NUMBER OF AUDIO FILES IN TRAINING DATA:', len(TRAIN))\n# Parse audio files and extract training samples\ninput_dir = '/kaggle/input/birdclef2023-pure/birdCLEF2023-pure/train_audio/train_audio'\noutput_dir = '/kaggle/working/melspectrogram_dataset/'\nsamples = []\nwith tqdm(total=len(TRAIN)) as pbar:\n    for idx, row in TRAIN.iterrows():\n        pbar.update(1)\n \n        if row.primary_label in most_represented_birds:\n            audio_file_path = os.path.join(input_dir, row.filename)\n            samples += get_spectrograms(audio_file_path, row.primary_label, output_dir)\n# print(samples)\nstr_samples = ','.join(samples)\nTRAIN_SPECS = shuffle(samples, random_state=RANDOM_SEED)\nfilename = open('a.txt', 'w')\nfilename.write(str_samples)\nfilename.close()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport warnings\n \nwarnings.filterwarnings(action='ignore')\nfrom sklearn.model_selection import train_test_split\nimport shutil\n \nfilename = open('a.txt', 'r')\nstr_samples = filename.read()\nfilename.close()\nstr_samples = str_samples.replace(\"\\\\\", \"/\")\nsamples = str_samples.split(',')\ntrainval_files, test_files = train_test_split(samples, test_size=0.3, random_state=42)\ntrain_dir = '/kaggle/working/train/'\nval_dir = '/kaggle/working/val/'\n \n \ndef copyfiles(file, dir):\n    filelist = file.split('/')\n    filename = filelist[-1]\n    lable = filelist[-2]\n    cpfile = dir + \"/\" + lable\n    if not os.path.exists(cpfile):\n        os.makedirs(cpfile)\n    cppath = cpfile + '/' + filename\n    shutil.copy(file, cppath)\n \n \nfor file in trainval_files:\n    copyfiles(file, train_dir)\nfor file in test_files:\n    copyfiles(file, val_dir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.optim as optim\nimport torch\nimport torch.nn as nn\nimport torch.nn.parallel\nfrom torch.autograd import Variable\nimport torch.optim\nimport torch.utils.data\nimport torch.utils.data.distributed\nimport torchvision.transforms as transforms\nimport torchvision.datasets as datasets\nfrom torchvision import models\nimport os\nimport time\n# 设置超参数\nmomentum = 0.9\nBATCH_SIZE = 64\nclass_num = 264\nEPOCHS = 12\nlr = 0.001\nuse_gpu = True\nnet_name = 'densenet121'\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n# 数据预处理\n \ntransform = transforms.Compose([\n    transforms.Resize(224),\n    transforms.ToTensor(),\n    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])\n])\ndataset_train = datasets.ImageFolder('/kaggle/working/train/', transform)\ndataset_val = datasets.ImageFolder('/kaggle/working/train/', transform)\n# 对应文件夹的label\nprint(dataset_train.class_to_idx)\ndset_sizes = len(dataset_train)\ndset_sizes_val = len(dataset_val)\nprint(\"dset_sizes_val Length:\", dset_sizes_val)\ntrain_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)\ntest_loader = torch.utils.data.DataLoader(dataset_val, batch_size=BATCH_SIZE, shuffle=True)\n \ndef exp_lr_scheduler(optimizer, epoch, init_lr=0.001, lr_decay_epoch=10):\n    \"\"\"Decay learning rate by a f#            model_out_path =\"./model/W_epoch_{}.pth\".format(epoch)\n#            torch.save(model_W, model_out_path) actor of 0.1 every lr_decay_epoch epochs.\"\"\"\n    lr = init_lr * (0.8 ** (epoch // lr_decay_epoch))\n    print('LR is set to {}'.format(lr))\n    for param_group in optimizer.param_groups:\n        param_group['lr'] = lr\n    return optimizer\n\n\n\ndef train_model(model_ft, criterion, optimizer, lr_scheduler, num_epochs=50):\n    train_loss = []\n    since = time.time()\n    best_acc = 0.0\n    model_ft.train(True)\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n        optimizer = lr_scheduler(optimizer, epoch)\n        running_loss = 0.0\n        running_corrects = 0\n        count = 0\n        for data in train_loader:\n            inputs, labels = data\n            labels = torch.squeeze(labels.type(torch.LongTensor))\n            if use_gpu:\n                inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())\n            else:\n                inputs, labels = Variable(inputs), Variable(labels)\n            outputs = model_ft(inputs)\n            loss = criterion(outputs, labels)\n            _, preds = torch.max(outputs.data, 1)\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n            count += 1\n            if count % 30 == 0 or outputs.size()[0] < BATCH_SIZE:\n                print('Epoch:{}: loss:{:.3f}'.format(epoch, loss.item()))\n                train_loss.append(loss.item())\n            running_loss += loss.item() * inputs.size(0)\n            running_corrects += torch.sum(preds == labels.data)\n        epoch_loss = running_loss / dset_sizes\n        epoch_acc = running_corrects.double() / dset_sizes\n        print('Loss: {:.4f} Acc: {:.4f}'.format(\n            epoch_loss, epoch_acc))\n        if epoch_acc > best_acc:\n            best_acc = epoch_acc\n            best_model_wts = model_ft.state_dict()\n \n    # save best model\n    save_dir = 'model'\n    os.makedirs(save_dir, exist_ok=True)\n    model_ft.load_state_dict(best_model_wts)\n    model_out_path = save_dir + \"/\" + net_name + '.pth'\n    torch.save(model_ft, model_out_path)\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(\n        time_elapsed // 60, time_elapsed % 60))\n\n\n \n# 下载并加载预训练模型\nmodel = models.densenet121(pretrained=True)\n# 修改最后线性层的输出通道数\nmodel.fc = nn.Linear(1024,264)\ncriterion = nn.CrossEntropyLoss()\nif use_gpu:\n    model = model.cuda()\n    criterion = criterion.cuda()\noptimizer = optim.Adam((model.parameters()), lr=lr)\n\n# 模型的训练\ntrain_model(model, criterion, optimizer, exp_lr_scheduler, num_epochs=EPOCHS)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport zipfile\nimport datetime\n\ndef file2zip(packagePath, zipPath):\n    zip = zipfile.ZipFile(zipPath, 'w', zipfile.ZIP_DEFLATED)\n    for path, dirNames, fileNames in os.walk(packagePath):\n        fpath = path.replace(packagePath, '')\n        for name in fileNames:\n            fullName = os.path.join(path, name)\n            name = fpath + '\\\\' + name\n            zip.write(fullName, name)\n    zip.close()\n\n\n\n# 文件夹路径\npackagePath = '/kaggle/working/'\nzipPath = '/kaggle/working/model.zip'\nif os.path.exists(zipPath):\n    os.remove(zipPath)\nfile2zip(packagePath, zipPath)\nprint(\"打包完成\")\nprint(datetime.datetime.utcnow())\nfrom IPython.display import FileLink\nFileLink('model.zip')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}