{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"scrolled":true,"collapsed":true},"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 in \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 \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"# Change this to True to replicate the result\nCOMPLETE_RUN = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d9c88fb221b74535f3b87aad6bcbdbc8f44ea55b","collapsed":true},"cell_type":"code","source":"import numpy as np\nnp.random.seed(1001)\n\nimport os\nimport shutil\n\nimport IPython\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\nfrom tqdm import tqdm_notebook\nfrom sklearn.cross_validation import StratifiedKFold\n\n%matplotlib inline\nmatplotlib.style.use('ggplot')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d183d12d79782d301ae7ef73f9b6846b8b3de338","collapsed":true},"cell_type":"code","source":"train = pd.read_csv(\"../input/train.csv\")\ntest = pd.read_csv(\"../input/sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"627da3178520df25ad0ea687c82dc8ff69ae2142","collapsed":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6476f9098b27e07745e76b6fadd3e7b0414659c4","collapsed":true},"cell_type":"code","source":"print(\"Number of training examples=\", train.shape[0], \"  Number of classes=\", len(train.label.unique()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"df650f6c516a6ccd820a62073a9c03a2d9a82303","collapsed":true},"cell_type":"code","source":"print(train.label.unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f61d2cb4c8837bca5e3d447cf790e339a267c4df","collapsed":true},"cell_type":"code","source":"category_group = train.groupby(['label', 'manually_verified']).count()\nplot = category_group.unstack().reindex(category_group.unstack().sum(axis=1).sort_values().index)\\\n          .plot(kind='bar', stacked=True, title=\"Number of Audio Samples per Category\", figsize=(16,10))\nplot.set_xlabel(\"Category\")\nplot.set_ylabel(\"Number of Samples\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e5a3c72a0a4dbe136937b76214b7cbe66581b131","collapsed":true},"cell_type":"code","source":"print('Minimum samples per category = ', min(train.label.value_counts()))\nprint('Maximum samples per category = ', max(train.label.value_counts()))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5acbb394571b8f9e146f007e1f18313ef18345c0"},"cell_type":"markdown","source":"### 2. Building a Model using Raw Wave"},{"metadata":{"trusted":true,"_uuid":"21360244df4d9823cfee75f69399c7c6e39813f9","collapsed":true},"cell_type":"code","source":"import librosa\nimport numpy as np\nimport scipy\nfrom keras import losses, models, optimizers\nfrom keras.activations import relu, softmax\nfrom keras.callbacks import (EarlyStopping, LearningRateScheduler,\n                             ModelCheckpoint, TensorBoard, ReduceLROnPlateau)\nfrom keras.layers import (Convolution1D, Dense, Dropout, GlobalAveragePooling1D, \n                          GlobalMaxPool1D, Input, MaxPool1D, concatenate)\nfrom keras.utils import Sequence, to_categorical","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"119c6ecbb5b6d15d2675eec2936a57bf483d19c6"},"cell_type":"code","source":"class Config(object):\n    def __init__(self,\n                 sampling_rate=16000, audio_duration=2, n_classes=41,\n                 use_mfcc=False, n_folds=10, learning_rate=0.0001, \n                 max_epochs=50, n_mfcc=20):\n        self.sampling_rate = sampling_rate\n        self.audio_duration = audio_duration\n        self.n_classes = n_classes\n        self.use_mfcc = use_mfcc\n        self.n_mfcc = n_mfcc\n        self.n_folds = n_folds\n        self.learning_rate = learning_rate\n        self.max_epochs = max_epochs\n\n        self.audio_length = self.sampling_rate * self.audio_duration\n        if self.use_mfcc:\n            self.dim = (self.n_mfcc, 1 + int(np.floor(self.audio_length/512)), 1)\n        else:\n            self.dim = (self.audio_length, 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"8e2c9f199692989aef0e2dea67c6813f8ce0041b"},"cell_type":"code","source":"class DataGenerator(Sequence):\n    def __init__(self, config, data_dir, list_IDs, labels=None, \n                 batch_size=64, preprocessing_fn=lambda x: x):\n        self.config = config\n        self.data_dir = data_dir\n        self.list_IDs = list_IDs\n        self.labels = labels\n        self.batch_size = batch_size\n        self.preprocessing_fn = preprocessing_fn\n        self.on_epoch_end()\n        self.dim = self.config.dim\n\n    def __len__(self):\n        return int(np.ceil(len(self.list_IDs) / self.batch_size))\n\n    def __getitem__(self, index):\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        list_IDs_temp = [self.list_IDs[k] for k in indexes]\n        return self.__data_generation(list_IDs_temp)\n\n    def on_epoch_end(self):\n        self.indexes = np.arange(len(self.list_IDs))\n\n    def __data_generation(self, list_IDs_temp):\n        cur_batch_size = len(list_IDs_temp)\n        X = np.empty((cur_batch_size, *self.dim))\n\n        input_length = self.config.audio_length\n        for i, ID in enumerate(list_IDs_temp):\n            file_path = self.data_dir + ID\n            \n            \n            # Read and Resample the audio\n            data, _ = librosa.core.load(file_path, sr=self.config.sampling_rate,\n                                        res_type='kaiser_fast')\n\n            # Random offset / Padding\n            if len(data) > input_length:\n                max_offset = len(data) - input_length\n                offset = np.random.randint(max_offset)\n                data = data[offset:(input_length+offset)]\n            else:\n                if input_length > len(data):\n                    max_offset = input_length - len(data)\n                    offset = np.random.randint(max_offset)\n                else:\n                    offset = 0\n                data = np.pad(data, (offset, input_length - len(data) - offset), \"constant\")\n                \n            # Normalization + Other Preprocessing\n            if self.config.use_mfcc:\n                data = librosa.feature.mfcc(data, sr=self.config.sampling_rate,\n                                                   n_mfcc=self.config.n_mfcc)\n                data = np.expand_dims(data, axis=-1)\n            else:\n                data = self.preprocessing_fn(data)[:, np.newaxis]\n            X[i,] = data\n\n        if self.labels is not None:\n            y = np.empty(cur_batch_size, dtype=int)\n            for i, ID in enumerate(list_IDs_temp):\n                y[i] = self.labels[ID]\n            return X, to_categorical(y, num_classes=self.config.n_classes)\n        else:\n            return X","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"60e49e262ead9d7b1c1865d6a0e5e2519fd7fc4b"},"cell_type":"code","source":"def audio_norm(data):\n    max_data = np.max(data)\n    min_data = np.min(data)\n    data = (data-min_data)/(max_data-min_data+1e-6)\n    return data-0.5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"21f6d7ed175a48bd0388e0efdd8010312e12fadb"},"cell_type":"code","source":"def get_1d_dummy_model(config):\n    \n    nclass = config.n_classes\n    input_length = config.audio_length\n    \n    inp = Input(shape=(input_length,1))\n    x = GlobalMaxPool1D()(inp)\n    out = Dense(nclass, activation=softmax)(x)\n\n    model = models.Model(inputs=inp, outputs=out)\n    opt = optimizers.Adam(config.learning_rate)\n\n    model.compile(optimizer=opt, loss=losses.categorical_crossentropy, metrics=['acc'])\n    return model\n\ndef get_1d_conv_model(config):\n    \n    nclass = config.n_classes\n    input_length = config.audio_length\n    \n    inp = Input(shape=(input_length,1))\n    x = Convolution1D(16, 9, activation=relu, padding=\"valid\")(inp)\n    x = Convolution1D(16, 9, activation=relu, padding=\"valid\")(x)\n    x = MaxPool1D(16)(x)\n    x = Dropout(rate=0.1)(x)\n    \n    x = Convolution1D(32, 3, activation=relu, padding=\"valid\")(x)\n    x = Convolution1D(32, 3, activation=relu, padding=\"valid\")(x)\n    x = MaxPool1D(4)(x)\n    x = Dropout(rate=0.1)(x)\n    \n    x = Convolution1D(32, 3, activation=relu, padding=\"valid\")(x)\n    x = Convolution1D(32, 3, activation=relu, padding=\"valid\")(x)\n    x = MaxPool1D(4)(x)\n    x = Dropout(rate=0.1)(x)\n    \n    x = Convolution1D(256, 3, activation=relu, padding=\"valid\")(x)\n    x = Convolution1D(256, 3, activation=relu, padding=\"valid\")(x)\n    x = GlobalMaxPool1D()(x)\n    x = Dropout(rate=0.2)(x)\n\n    x = Dense(64, activation=relu)(x)\n    x = Dense(1028, activation=relu)(x)\n    out = Dense(nclass, activation=softmax)(x)\n\n    model = models.Model(inputs=inp, outputs=out)\n    opt = optimizers.Adam(config.learning_rate)\n\n    model.compile(optimizer=opt, loss=losses.categorical_crossentropy, metrics=['acc'])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"b8ffa6342cf5fc14646daef19bb92e32b1869cce"},"cell_type":"code","source":"LABELS = list(train.label.unique())\nlabel_idx = {label: i for i, label in enumerate(LABELS)}\ntrain.set_index(\"fname\", inplace=True)\ntest.set_index(\"fname\", inplace=True)\ntrain[\"label_idx\"] = train.label.apply(lambda x: label_idx[x])\nif not COMPLETE_RUN:\n    train = train[:2000]\n    test = test[:2000]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c98dc7f449a596fafdf6c8ca107183dada6e013f","collapsed":true},"cell_type":"code","source":"config = Config(sampling_rate=16000, audio_duration=2, n_folds=10, learning_rate=0.001, max_epochs=30)\nif not COMPLETE_RUN:\n    config = Config(sampling_rate=100, audio_duration=1, n_folds=2, max_epochs=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0654f376131418cf75af5de0878bf1f7a28383af","collapsed":true},"cell_type":"code","source":"PREDICTION_FOLDER = \"predictions_1d_conv\"\nif not os.path.exists(PREDICTION_FOLDER):\n    os.mkdir(PREDICTION_FOLDER)\nif os.path.exists('logs/' + PREDICTION_FOLDER):\n    shutil.rmtree('logs/' + PREDICTION_FOLDER)\n\nskf = StratifiedKFold(train.label_idx, n_folds=config.n_folds)\n\nfor i, (train_split, val_split) in enumerate(skf):\n    train_set = train.iloc[train_split]\n    val_set = train.iloc[val_split]\n    checkpoint = ModelCheckpoint('best_%d.h5'%i, monitor='val_loss', verbose=1, save_best_only=True)\n    early = EarlyStopping(monitor=\"val_loss\", mode=\"min\", patience=5)\n    tb = TensorBoard(log_dir='./logs/' + PREDICTION_FOLDER + '/fold_%d'%i, write_graph=True)\n\n    callbacks_list = [checkpoint, early, tb]\n    print(\"Fold: \", i)\n    print(\"#\"*50)\n    if COMPLETE_RUN:\n        model = get_1d_conv_model(config)\n    else:\n        model = get_1d_dummy_model(config)\n\n\n    train_generator = DataGenerator(config, '../input/audio_train/', train_set.index, \n                                    train_set.label_idx, batch_size=64,\n                                    preprocessing_fn=audio_norm)\n    \n    val_generator = DataGenerator(config, '../input/audio_train/', val_set.index, \n                                  val_set.label_idx, batch_size=64,\n                                  preprocessing_fn=audio_norm)\n\n    history = model.fit_generator(train_generator, callbacks=callbacks_list, validation_data=val_generator,\n                                  epochs=config.max_epochs, use_multiprocessing=True, workers=6, max_queue_size=20)\n\n    model.load_weights('best_%d.h5'%i)\n\n    # Save train predictions\n    train_generator = DataGenerator(config, '../audio_train/', train.index, batch_size=128,\n                                    preprocessing_fn=audio_norm)\n    predictions = model.predict_generator(train_generator, use_multiprocessing=True, \n                                          workers=6, max_queue_size=20, verbose=1)\n    np.save(PREDICTION_FOLDER + \"/train_predictions_%d.npy\"%i, predictions)\n    \n        # Save test predictions\n    test_generator = DataGenerator(config, '../input/audio_test/', test.index, batch_size=128,\n                                    preprocessing_fn=audio_norm)\n    predictions = model.predict_generator(test_generator, use_multiprocessing=True, \n                                          workers=6, max_queue_size=20, verbose=1)\n    np.save(PREDICTION_FOLDER + \"/test_predictions_%d.npy\"%i, predictions)\n\n    # Make a submission file\n    top_3 = np.array(LABELS)[np.argsort(-predictions, axis=1)[:, :3]]\n    predicted_labels = [' '.join(list(x)) for x in top_3]\n    test['label'] = predicted_labels\n    test[['label']].to_csv(PREDICTION_FOLDER + \"/predictions_%d.csv\"%i)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"51d426076215ec85c1f9c14ac3418b521ea037d7","collapsed":true},"cell_type":"code","source":"!pip install librosa","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"303eebc7f482d68f310ab16b3ad7e89f28b97c31","collapsed":true},"cell_type":"code","source":"!ls","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"a1a639a3f3dc1a6295f49a3905ace9cc6124d87f"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}