{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom pydub import AudioSegment\nimport math\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\nfrom tqdm import tqdm\nimport os\n\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\ntrain_df = pd.read_csv('/kaggle/input/ml-olympiad-dialectrecognition/train.csv')\ntrain_df.head(5)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['Path'] =['/kaggle/input/ml-olympiad-dialectrecognition/'+file for file in train_df.FileName]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classes = {\n'Najdi':0,\n'Hijazi':1,\n'Khaliji':2,\n'ModernStandardArabic':3\n}\n\ntrain_df['class']=train_df['SpeakerDialect'].map(classes)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndevice","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import math, random\nimport torch\nimport torchaudio\nfrom torchaudio import transforms\nfrom IPython.display import Audio\n\nclass AudioUtil():\n\n  @staticmethod\n  def open(audio_file,start,end):\n    sig, sr = torchaudio.load(audio_file)\n    sig = sig[:,int(sr*start):int(sr*end)]\n    return (sig, sr)\n\n  @staticmethod\n  def rechannel(aud,sr, new_channel):\n    sig = aud\n\n    if (sig.shape[0] == new_channel):\n      return aud\n\n    if (new_channel == 1):\n      resig = sig[:1, :]\n    else:\n      resig = torch.cat([sig, sig])\n\n    return ((resig, sr))\n\n  @staticmethod\n  def resample(aud,sr, newsr):\n        sig = aud\n\n        if (sr == newsr):\n          return aud\n\n        num_channels = sig.shape[0]\n        resig = torchaudio.transforms.Resample(sr, newsr)(sig[:1,:])\n        if (num_channels > 1):\n          retwo = torchaudio.transforms.Resample(sr, newsr)(sig[1:,:])\n          resig = torch.cat([resig, retwo])\n\n        return ((resig, newsr))\n\n  @staticmethod\n  def pad_trunc(aud,sr, max_ms):\n    sig = aud\n    num_rows, sig_len = sig.shape\n    max_len = sr//1000 * max_ms\n\n    if (sig_len > max_len):\n      sig = sig[:,:max_len]\n\n    elif (sig_len < max_len):\n      pad_begin_len = random.randint(0, max_len - sig_len)\n      pad_end_len = max_len - sig_len - pad_begin_len\n\n      pad_begin = torch.zeros((num_rows, pad_begin_len))\n      pad_end = torch.zeros((num_rows, pad_end_len))\n\n      sig = torch.cat((pad_begin, sig, pad_end), 1)\n      \n    return (sig, sr)\n\n\n  @staticmethod\n  def time_shift(aud,sr, shift_limit):\n    sig = aud\n    _, sig_len = sig.shape\n    shift_amt = int(random.random() * shift_limit * sig_len)\n    return (sig.roll(shift_amt), sr)\n\n  @staticmethod\n  def spectro_gram(aud,sr, n_mels=64, n_fft=1024, hop_len=None):\n    sig = aud\n    top_db = 80\n\n    spec = transforms.MelSpectrogram(sr, n_fft=n_fft, hop_length=hop_len, n_mels=n_mels)(sig)\n\n    spec = transforms.AmplitudeToDB(top_db=top_db)(spec)\n    return (spec)\n\n  @staticmethod\n  def spectro_augment(spec, max_mask_pct=0.1, n_freq_masks=1, n_time_masks=1):\n    _, n_mels, n_steps = spec.shape\n    mask_value = spec.mean()\n    aug_spec = spec\n\n    freq_mask_param = max_mask_pct * n_mels\n    for _ in range(n_freq_masks):\n      aug_spec = transforms.FrequencyMasking(freq_mask_param)(aug_spec, mask_value)\n\n    time_mask_param = max_mask_pct * n_steps\n    for _ in range(n_time_masks):\n      aug_spec = transforms.TimeMasking(time_mask_param)(aug_spec, mask_value)\n    \n    return aug_spec","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader, Dataset, random_split\nimport torchaudio\n\n\nclass SoundDS(Dataset):\n  def __init__(self, df):\n    self.df = df\n    self.data_path = str(df['Path'])\n    self.duration = 10000\n    self.sr = 16000\n    self.channel = 1\n    self.shift_pct = 0.4\n    self.start = df['SegmentStart']\n    self.end = df['SegmentEnd']\n            \n\n  def __len__(self):\n    return len(self.df)    \n    \n\n  def __getitem__(self, idx):\n    \n   \n    audio_file = self.df.loc[idx, 'Path']\n    class_id = self.df.loc[idx, 'class']\n    start = self.df.loc[idx,'SegmentStart']\n    end = self.df.loc[idx,'SegmentEnd']\n    aud,sr = AudioUtil.open(audio_file , start,end)\n\n    reaud = AudioUtil.resample(aud,sr, self.sr)\n    \n    rechan = AudioUtil.rechannel(reaud,sr, self.channel)\n\n    dur_aud,Secod_sr= AudioUtil.pad_trunc(rechan,sr, self.duration)\n    shift_aud,third_sr = AudioUtil.time_shift(dur_aud,sr, self.shift_pct)\n    sgram = AudioUtil.spectro_gram(shift_aud,sr, n_mels=64, n_fft=1024, hop_len=None)\n    aug_sgram = AudioUtil.spectro_augment(sgram, max_mask_pct=0.1, n_freq_masks=2, n_time_masks=2)\n    \n    return aug_sgram, class_id\nfrom torch.utils.data import random_split\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data.dataloader import default_collate\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nmyds = SoundDS(train_df)\n\nnum_items = len(myds)\nnum_train = round(num_items * 0.8)\nnum_val = num_items - num_train\ntrain_ds, val_ds = random_split(myds, [num_train, num_val])\n\ntrain_dl = torch.utils.data.DataLoader(train_ds, batch_size=64, shuffle=True,num_workers=5)\nval_dl = torch.utils.data.DataLoader(val_ds, batch_size=64, shuffle=False,num_workers=5)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import time ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn.functional as F\nfrom torch.nn import init\nfrom torch import nn\n\n\nclass AudioClassifier (nn.Module):\n  \n    def __init__(self):\n        super().__init__()\n        conv_layers = []\n\n        self.conv1 = nn.Conv2d(1, 8, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2))\n        self.relu1 = nn.ReLU()\n        self.bn1 = nn.BatchNorm2d(8)\n        init.kaiming_normal_(self.conv1.weight, a=0.1)\n        self.conv1.bias.data.zero_()\n        conv_layers += [self.conv1, self.relu1, self.bn1]\n\n        self.conv2 = nn.Conv2d(8, 16, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.relu2 = nn.ReLU()\n        self.bn2 = nn.BatchNorm2d(16)\n        init.kaiming_normal_(self.conv2.weight, a=0.1)\n        self.conv2.bias.data.zero_()\n        conv_layers += [self.conv2, self.relu2, self.bn2]\n\n        self.conv3 = nn.Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.relu3 = nn.ReLU()\n        self.bn3 = nn.BatchNorm2d(32)\n        init.kaiming_normal_(self.conv3.weight, a=0.1)\n        self.conv3.bias.data.zero_()\n        conv_layers += [self.conv3, self.relu3, self.bn3]\n\n        self.conv4 = nn.Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n        self.relu4 = nn.ReLU()\n        self.bn4 = nn.BatchNorm2d(64)\n        init.kaiming_normal_(self.conv4.weight, a=0.1)\n        self.conv4.bias.data.zero_()\n        conv_layers += [self.conv4, self.relu4, self.bn4]\n\n        self.ap = nn.AdaptiveAvgPool2d(output_size=1)\n        self.lin = nn.Linear(in_features=64, out_features=4)\n\n        self.conv = nn.Sequential(*conv_layers)\n\n    def forward(self, x):\n        x = self.conv(x)\n\n        x = self.ap(x)\n        x = x.view(x.shape[0], -1)\n\n        x = self.lin(x)\n\n        return x\n\n# Create the model and put it on the GPU if available\nmyModel = AudioClassifier()\nmyModel = myModel.to(device)\nnext(myModel.parameters()).device","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef training(model, train_dl, num_epochs):\n  # Loss Function, Optimizer and Scheduler\n  criterion = nn.CrossEntropyLoss()\n  optimizer = torch.optim.Adam(model.parameters(),lr=0.001)\n  scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.001,\n                                                steps_per_epoch=int(len(train_dl)),\n                                                epochs=num_epochs,\n                                                anneal_strategy='linear')\n  for epoch in range(num_epochs):\n    \n    running_loss = 0.0\n    correct_prediction = 0\n    total_prediction = 0\n    counter = 0\n    start = time.time()\n    origin = time.time()\n    for i, data in enumerate(train_dl):\n        start = time.time()\n        inputs, labels = data[0].to(device), data[1].to(device)\n        \n        inputs_m, inputs_s = inputs.mean(), inputs.std()\n        inputs = (inputs - inputs_m) / inputs_s\n\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        labels =labels.to(torch.int64)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        scheduler.step()\n\n        running_loss += loss.item()\n\n        _, prediction = torch.max(outputs,1)\n        correct_prediction += (prediction == labels).sum().item()\n        total_prediction += prediction.shape[0]\n        counter+=1\n        if i % 10 == 0:    # print every 10 mini-batches\n           print(f'[%d, %5d] loss: %.3f and { origin - time.time()} ' % (epoch + 1, i + 1, running_loss / 10))\n        \n\n    num_batches = len(train_dl)\n    avg_loss = running_loss / num_batches\n    acc = correct_prediction/total_prediction\n    print(f'Epoch: {epoch}, Loss: {avg_loss:.2f}, Accuracy: {acc:.2f}')\n\n  print('Finished Training')\n  ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_epochs=1 \ntraining(myModel, train_dl, num_epochs)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}