{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "Medical AI Course Materials : 08_Sequential_Data_Analysis_with_Deep_Learning.ipynb", "version": "0.3.2", "provenance": [], "collapsed_sections": [] }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.2" } }, "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "qL7KO2SAQHuw" }, "source": [ "# 実践編: ディープラーニングを使ったモニタリングデータの時系列解析" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "6G2qenL-QR4S" }, "source": [ "健康意識の高まりや運動人口の増加に伴って,活動量計などのウェアラブルデバイスが普及し始めています.センサーデバイスから心拍数などの情報を取得することで,リアルタイムに健康状態をモニタリングできる可能性があることから,近年ではヘルスケア領域での活用事例も増えてきています.2018年2月には,Cardiogram社とカリフォルニア大学が共同研究の成果を発表し,心拍数データに対してDeep Learningを適用することで,高精度に糖尿病予備群を予測可能であることを報告し,大きな注目を集めました.また,Apple Watch Series 4には心電図作成の機能が搭載されるなど,センサーデバイスも進歩を続け,より精緻な情報が取得できるようになってきています.こうした背景において,モニタリングデータを収集・解析し,健康管理に繋げていく取り組みは今後益々盛んになっていくものと考えられます.\n", "\n", "\n", "本章では,心電図の信号波形データを対象として,不整脈を検出する問題に取り組みます." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Yf3_nzfOQ4mk" }, "source": [ "## 環境構築" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "oUE1bnmtQ7mW" }, "source": [ "本章では, 下記のライブラリを利用します." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "cX4C1qqERA4F" }, "source": [ "* Cupy\n", "* Chainer\n", "* Scipy\n", "* Matplotlib\n", "* Seaborn\n", "* Pandas\n", "* WFDB\n", "* Scikit-learn\n", "* Imbalanced-learn" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IOG2_VY-RFJw" }, "source": [ "以下のセルを実行 (Shift + Enter) して,必要なものをインストールして下さい. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "colab": {}, "colab_type": "code", "id": "b6zwznd_QUqg" }, "outputs": [], "source": [ "!apt -y -q install tree\n", "!pip install wfdb==2.2.1 scikit-learn==0.20.1 imbalanced-learn==0.4.3" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "EHDRbMEQRQZ3" }, "source": [ "インストールが完了したら以下のセルを実行して,各ライブラリのインポート,及びバージョン確認を行って下さい." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 357 }, "colab_type": "code", "id": "zlyEjUcRRJCL", "outputId": "da1eacb1-5892-4f7c-abef-235c61776aaf" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Platform: Linux-4.14.65+-x86_64-with-Ubuntu-18.04-bionic\n", "Chainer: 5.1.0\n", "NumPy: 1.14.6\n", "CuPy:\n", " CuPy Version : 5.1.0\n", " CUDA Root : /usr/local/cuda\n", " CUDA Build Version : 9020\n", " CUDA Driver Version : 9020\n", " CUDA Runtime Version : 9020\n", " cuDNN Build Version : 7301\n", " cuDNN Version : 7301\n", " NCCL Build Version : 2307\n", "iDeep: 2.0.0.post3\n", "Scipy: 1.1.0\n", "Pandas: 0.22.0\n", "Matplotlib: 2.1.2\n", "Seaborn: 0.7.1\n", "WFDB: 2.2.1\n", "Scikit-learn: 0.20.1\n", "Imbalanced-learn: 0.4.3\n" ] } ], "source": [ "import os\n", "import random\n", "import numpy as np\n", "import chainer\n", "import scipy\n", "import pandas as pd\n", "import matplotlib\n", "import seaborn as sn\n", "import wfdb\n", "import sklearn\n", "import imblearn\n", "\n", "chainer.print_runtime_info()\n", "print(\"Scipy: \", scipy.__version__)\n", "print(\"Pandas: \", pd.__version__)\n", "print(\"Matplotlib: \", matplotlib.__version__)\n", "print(\"Seaborn: \", sn.__version__)\n", "print(\"WFDB: \", wfdb.__version__)\n", "print(\"Scikit-learn: \", sklearn.__version__)\n", "print(\"Imbalanced-learn: \", imblearn.__version__)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "kyyJZRi3Z2AS" }, "source": [ "また,本章の実行結果を再現可能なように,4章 (4.2.4.4) で紹介した乱数シードの固定を行います.\n", "\n", "(以降の計算を行う上で必ず必要となる設定ではありません.)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "colab": {}, "colab_type": "code", "id": "jHUmH48MbFx9" }, "outputs": [], "source": [ "def reset_seed(seed=42):\n", " random.seed(seed)\n", " np.random.seed(seed)\n", " if chainer.cuda.available:\n", " chainer.cuda.cupy.random.seed(seed)\n", "\n", "reset_seed(42)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HAD7xxa6i2cH" }, "source": [ "## 心電図(ECG)と不整脈診断について" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "DJAhIM6pi__I" }, "source": [ "**心電図(Electrocardiogram, ECG)**は,心筋を協調的,律動的に動かすために刺激伝導系で伝達される電気信号を体表から記録したものであり,心電図検査は不整脈や虚血性心疾患の診断において広く用いられる検査です[[1](https://en.wikipedia.org/wiki/Electrocardiography), [2](https://www.ningen-dock.jp/wp/wp-content/uploads/2013/09/d4bb55fcf01494e251d315b76738ab40.pdf)].\n", "\n", "標準的な心電図は,手足からとる心電図(四肢誘導)として,双極誘導($Ⅰ$,$Ⅱ$,$Ⅲ$),及び単極誘導($aV_R$,$aV_L$,$aV_F$)の6誘導,胸部からとる心電図(胸部誘導)として,$V_1$,$V_2$,$V_3$,$V_4$,$V_5$,$V_6$の6誘導,計12誘導から成ります.このうち,特に不整脈のスクリーニングを行う際には,$Ⅱ$誘導と$V_1$誘導に注目して診断が行われるのが一般的とされています.\n", "\n", "心臓が正常な状態では,ECGにおいては規則的な波形が観測され,これを**正常洞調律 (Normal sinus rhythm, NSR)**といいます.\n", "\n", "具体的には,以下の3つの主要な波形で構成されており,\n", "\n", "1. **P波**:心房の脱分極(心房の興奮)\n", "1. **QRS波**:心室の脱分極(心室の興奮)\n", "1. **T波**:心室の再分極(心室興奮の収まり)\n", "\n", "の順番で,下図のような波形が観測されます.\n", "\n", "![正常心電図の概略図](https://github.com/japan-medical-ai/medical-ai-course-materials/raw/master/notebooks/images/monitoring/sinus_rhythm.png)\n", "\n", "([[1](https://en.wikipedia.org/wiki/Electrocardiography)]より引用)\n", "\n", "こうした規則的な波形に乱れが生じ,調律に異常があると判断された場合,不整脈などの疑いがあるため,診断が行われることになります." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "3v2kuCnmRdac" }, "source": [ "## 使用するデータセット" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "eQZ6fRLZCz4H" }, "source": [ "ここでは,ECGの公開データとして有名な[MIT-BIH Arrhythmia Database (mitdb)](https://www.physionet.org/physiobank/database/mitdb/)を使用します.\n", "\n", "47名の患者から収集した48レコードが登録されており,各レコードファイルには約30分間の2誘導($II$,$V_1$)のシグナルデータが格納されています.また,各R波のピーク位置に対してアノテーションが付与されています.(データとアノテーションの詳細については[こちら](https://www.physionet.org/physiobank/database/html/mitdbdir/intro.htm)を御覧ください.)\n", "\n", "データベースは[PhysioNet](https://www.physionet.org/)によって管理されており,ダウンロードや読み込み用のPythonパッケージが提供されているので,今回はそちらを利用してデータを入手します." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "colab": {}, "colab_type": "code", "id": "0tAhl0KJRZ1F" }, "outputs": [], "source": [ "dataset_root = './dataset'\n", "download_dir = os.path.join(dataset_root, 'download')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "R5wT-k6G6h4r" }, "source": [ "まずはmitdbデータベースをダウンロードしましょう.\n", "※実行時にエラーが出た場合は,再度実行して下さい." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 68 }, "colab_type": "code", "id": "hmX3OgAXR0Ug", "outputId": "8cdb6f26-dac5-4ff6-f14e-7610931a9a2c" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created local base download directory: ./dataset/download\n", "Downloading files...\n", "Finished downloading files\n" ] } ], "source": [ "wfdb.dl_database('mitdb', dl_dir=download_dir)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "4Uzp-QZ4D3sP" }, "source": [ "無事ダウンロードが完了すると, `Finished downloading files` というメッセージが表示されます.\n", "\n", "ファイル一覧を確認してみましょう." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 54 }, "colab_type": "code", "id": "djD8QFXESMHn", "outputId": "82c19e77-f2f5-456b-ba68-041c779e55c8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['100.atr', '100.dat', '100.hea', '101.atr', '101.dat', '101.hea', '102.atr', '102.dat', '102.hea', '103.atr', '103.dat', '103.hea', '104.atr', '104.dat', '104.hea', '105.atr', '105.dat', '105.hea', '106.atr', '106.dat', '106.hea', '107.atr', '107.dat', '107.hea', '108.atr', '108.dat', '108.hea', '109.atr', '109.dat', '109.hea', '111.atr', '111.dat', '111.hea', '112.atr', '112.dat', '112.hea', '113.atr', '113.dat', '113.hea', '114.atr', '114.dat', '114.hea', '115.atr', '115.dat', '115.hea', '116.atr', '116.dat', '116.hea', '117.atr', '117.dat', '117.hea', '118.atr', '118.dat', '118.hea', '119.atr', '119.dat', '119.hea', '121.atr', '121.dat', '121.hea', '122.atr', '122.dat', '122.hea', '123.atr', '123.dat', '123.hea', '124.atr', '124.dat', '124.hea', '200.atr', '200.dat', '200.hea', '201.atr', '201.dat', '201.hea', '202.atr', '202.dat', '202.hea', '203.atr', '203.dat', '203.hea', '205.atr', '205.dat', '205.hea', '207.atr', '207.dat', '207.hea', '208.atr', '208.dat', '208.hea', '209.atr', '209.dat', '209.hea', '210.atr', '210.dat', '210.hea', '212.atr', '212.dat', '212.hea', '213.atr', '213.dat', '213.hea', '214.atr', '214.dat', '214.hea', '215.atr', '215.dat', '215.hea', '217.atr', '217.dat', '217.hea', '219.atr', '219.dat', '219.hea', '220.atr', '220.dat', '220.hea', '221.atr', '221.dat', '221.hea', '222.atr', '222.dat', '222.hea', '223.atr', '223.dat', '223.hea', '228.atr', '228.dat', '228.hea', '230.atr', '230.dat', '230.hea', '231.atr', '231.dat', '231.hea', '232.atr', '232.dat', '232.hea', '233.atr', '233.dat', '233.hea', '234.atr', '234.dat', '234.hea']\n" ] } ], "source": [ "print(sorted(os.listdir(download_dir)))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "KgMtCiKq4TcF" }, "source": [ "ファイル名の数字はレコードIDを表しています.各レコードには3種類のファイルがあり,\n", "\n", "- `.dat` : シグナル(バイナリ形式)\n", "- `.atr` : アノテーション(バイナリ形式)\n", "- `.hea` : ヘッダ(バイナリファイルの読み込みに必要)\n", "\n", "となっています." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "AzQYVT4NSmr2" }, "source": [ "## データ前処理" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "1v4SHt1jEAwC" }, "source": [ "ダウンロードしたファイルを読み込み,機械学習モデルへの入力形式に変換する**データ前処理**について説明します.\n", "\n", "本節では,以下の手順で前処理を行います.\n", "\n", "1. レコードIDを事前に 学習用 / 評価用 に分割\n", " - 48レコードのうち,\n", " - ID =(102, 104, 107, 217)のシグナルはペースメーカーの拍動が含まれるため除外します.\n", " - ID = 114のシグナルは波形の一部が反転しているため,今回は除外します.\n", " - ID = (201, 202)は同一の患者から得られたデータのため,202を除外します.\n", " - 上記を除く計42レコードを,学習用とテスト用に分割します(分割方法は[[3](https://ieeexplore.ieee.org/document/1306572)]を参考).\n", "1. シグナルファイル (.dat) の読み込み\n", " - $Ⅱ$誘導シグナルと$V_1$誘導シグナルが格納されていますが,今回は$Ⅱ$誘導のみ利用します.\n", " - サンプリング周波数は360 Hz なので,1秒間に360回のペースで数値が記録されていることになります.\n", "1. アノテーションファイル (.atr) の読み込み\n", " - 各R波ピークの位置 (positions) と,そのラベル (symbols) を取得します.\n", "1. シグナルの正規化\n", " - 平均0,分散1になるように変換を行います.\n", "1. シグナルの分割 (segmentation)\n", " - 各R波ピークを中心として2秒間(前後1秒ずつ)の断片を切り出していきます.\n", "1. 分割シグナルへのラベル付与\n", " - 各R波ピークに付与されているラベルを,下表(※)に従って集約し,今回の解析では正常拍動 (Normal),及び心室異所性拍動 (VEB) に対応するラベルが付与されている分割シグナルのみ学習・評価に利用します.\n", " \n", "※ Association for the Advancement of Medical Instrumentation (AAMI)が推奨している基準([[3](https://ieeexplore.ieee.org/document/1306572)])で,5種類に大別して整理されています.\n", "\n", "![AAMIの分類基準](https://github.com/japan-medical-ai/medical-ai-course-materials/raw/master/notebooks/images/monitoring/aami_standard.png)\n", "\n", "([[4](https://arxiv.org/abs/1810.04121)]より引用)\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "YhdS_lLKMPxW" }, "source": [ "まずは以下のセルを実行して,データ前処理クラスを定義しましょう.\n", "\n", "前処理クラス内では,以下のメンバ関数を定義しています.\n", "\n", "* `__init__()` (コンストラクタ) : 変数の初期化,学習用とテスト用への分割ルール,利用するラベルの集約ルール\n", "* `_load_data()` : シグナル,及びアノテーションの読み込み\n", "* `_normalize_signal()` : `method`オプションに応じてシグナルをスケーリング\n", "* `_segment_data()` : 読み込んだシグナルとアノテーションを,一定幅(`window_size`)で切り出し\n", "* `preprocess_dataset()` : 学習データ,テストデータを作成\n", "* `_preprocess_dataset_core()` : `preprocess_datataset()`内で呼ばれるメインの処理." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": {}, "colab_type": "code", "id": "bX7u2f5eR3VA" }, "outputs": [], "source": [ "class BaseECGDatasetPreprocessor(object):\n", "\n", " def __init__(\n", " self,\n", " dataset_root,\n", " window_size=720, # 2 seconds\n", " ):\n", " self.dataset_root = dataset_root\n", " self.download_dir = os.path.join(self.dataset_root, 'download')\n", " self.window_size = window_size\n", " self.sample_rate = 360.\n", " # split list\n", " self.train_record_list = [\n", " '101', '106', '108', '109', '112', '115', '116', '118', '119', '122',\n", " '124', '201', '203', '205', '207', '208', '209', '215', '220', '223', '230'\n", " ]\n", " self.test_record_list = [\n", " '100', '103', '105', '111', '113', '117', '121', '123', '200', '210',\n", " '212', '213', '214', '219', '221', '222', '228', '231', '232', '233', '234'\n", " ]\n", " # annotation\n", " self.labels = ['N', 'V']\n", " self.valid_symbols = ['N', 'L', 'R', 'e', 'j', 'V', 'E']\n", " self.label_map = {\n", " 'N': 'N', 'L': 'N', 'R': 'N', 'e': 'N', 'j': 'N',\n", " 'V': 'V', 'E': 'V'\n", " }\n", "\n", " def _load_data(\n", " self,\n", " base_record,\n", " channel=0 # [0, 1]\n", " ):\n", " record_name = os.path.join(self.download_dir, str(base_record))\n", " # read dat file\n", " signals, fields = wfdb.rdsamp(record_name)\n", " assert fields['fs'] == self.sample_rate\n", " # read annotation file\n", " annotation = wfdb.rdann(record_name, 'atr')\n", " symbols = annotation.symbol\n", " positions = annotation.sample\n", " return signals[:, channel], symbols, positions\n", "\n", " def _normalize_signal(\n", " self,\n", " signal,\n", " method='std'\n", " ):\n", " if method == 'minmax':\n", " # Min-Max scaling\n", " min_val = np.min(signal)\n", " max_val = np.max(signal)\n", " return (signal - min_val) / (max_val - min_val)\n", " elif method == 'std':\n", " # Zero mean and unit variance\n", " signal = (signal - np.mean(signal)) / np.std(signal)\n", " return signal\n", " else:\n", " raise ValueError(\"Invalid method: {}\".format(method))\n", "\n", " def _segment_data(\n", " self,\n", " signal,\n", " symbols,\n", " positions\n", " ):\n", " X = []\n", " y = []\n", " sig_len = len(signal)\n", " for i in range(len(symbols)):\n", " start = positions[i] - self.window_size // 2\n", " end = positions[i] + self.window_size // 2\n", " if symbols[i] in self.valid_symbols and start >= 0 and end <= sig_len:\n", " segment = signal[start:end]\n", " assert len(segment) == self.window_size, \"Invalid length\"\n", " X.append(segment)\n", " y.append(self.labels.index(self.label_map[symbols[i]]))\n", " return np.array(X), np.array(y)\n", "\n", " def preprocess_dataset(\n", " self,\n", " normalize=True\n", " ):\n", " # preprocess training dataset\n", " self._preprocess_dataset_core(self.train_record_list, \"train\", normalize)\n", " # preprocess test dataset\n", " self._preprocess_dataset_core(self.test_record_list, \"test\", normalize)\n", "\n", " def _preprocess_dataset_core(\n", " self,\n", " record_list,\n", " mode=\"train\",\n", " normalize=True\n", " ):\n", " Xs, ys = [], []\n", " save_dir = os.path.join(self.dataset_root, 'preprocessed', mode)\n", " for i in range(len(record_list)):\n", " signal, symbols, positions = self._load_data(record_list[i])\n", " if normalize:\n", " signal = self._normalize_signal(signal)\n", " X, y = self._segment_data(signal, symbols, positions)\n", " Xs.append(X)\n", " ys.append(y)\n", " os.makedirs(save_dir, exist_ok=True)\n", " np.save(os.path.join(save_dir, \"X.npy\"), np.vstack(Xs))\n", " np.save(os.path.join(save_dir, \"y.npy\"), np.concatenate(ys))\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dxixFnx6EP7H" }, "source": [ "データ保存先のrootディレクトリ(dataset_root)を指定し, `preprocess_dataset()` を実行することで,前処理後のデータがNumpy Array形式で所定の場所に保存されます." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "colab": {}, "colab_type": "code", "id": "zSFRco-FSsmU" }, "outputs": [], "source": [ "BaseECGDatasetPreprocessor(dataset_root).preprocess_dataset()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "2DcLiL-1ZTSk" }, "source": [ "実行後,以下のファイルが保存されていることを確認しましょう.\n", "\n", "* train/X.npy : 学習用シグナル\n", "* train/y.npy : 学習用ラベル\n", "* test/X.npy : 評価用シグナル\n", "* test/y.npy : 評価用ラベル" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 170 }, "colab_type": "code", "id": "6LXhy1nmT-N5", "outputId": "b146cebc-3769-4a35-d7ec-7bb12df85461" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "./dataset/preprocessed\n", "├── test\n", "│   ├── X.npy\n", "│   └── y.npy\n", "└── train\n", " ├── X.npy\n", " └── y.npy\n", "\n", "2 directories, 4 files\n" ] } ], "source": [ "!tree ./dataset/preprocessed" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "nZa7kzJPElNO" }, "source": [ "次に,保存したファイルを読み込み,中身を確認してみましょう." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": {}, "colab_type": "code", "id": "j5vghaTuSzmk" }, "outputs": [], "source": [ "X_train = np.load(os.path.join(dataset_root, 'preprocessed', 'train', 'X.npy'))\n", "y_train = np.load(os.path.join(dataset_root, 'preprocessed', 'train', 'y.npy'))\n", "X_test = np.load(os.path.join(dataset_root, 'preprocessed', 'test', 'X.npy'))\n", "y_test = np.load(os.path.join(dataset_root, 'preprocessed', 'test', 'y.npy'))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "W5ftmdA6zAf2" }, "source": [ "データセットのサンプル数はそれぞれ以下の通りです.\n", "\n", "* 学習用 : 47738個\n", "* 評価用 : 45349個\n", "\n", "各シグナルデータは,2 (sec) * 360 (Hz) = 720次元ベクトルとして表現されています." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 51 }, "colab_type": "code", "id": "Mj4_F6RVTEkd", "outputId": "20482893-6823-4f3f-8b7b-2e3af9bc9a2a" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "X_train.shape = (47738, 720) \t y_train.shape = (47738,)\n", "X_test.shape = (45349, 720) \t y_test.shape = (45349,)\n" ] } ], "source": [ "print(\"X_train.shape = \", X_train.shape, \" \\t y_train.shape = \", y_train.shape)\n", "print(\"X_test.shape = \", X_test.shape, \" \\t y_test.shape = \", y_test.shape)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bNu5vvBL1eD4" }, "source": [ "各ラベルはインデックスで表現されており,\n", "\n", "* 0 : 正常拍動 (Normal)\n", "* 1 : 心室異所性拍動 (VEB)\n", "\n", "となっています.\n", "\n", "学習用データセットに含まれている各ラベル毎のサンプル数をカウントしてみましょう." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "ss6w4JlJTYUH", "outputId": "28a60b36-cc9c-4103-f5ad-1edb7f3c0062" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y_train count each labels: {0: 43995, 1: 3743}\n" ] } ], "source": [ "uniq_train, counts_train = np.unique(y_train, return_counts=True)\n", "print(\"y_train count each labels: \", dict(zip(uniq_train, counts_train)))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "f_vWWbRy4CpZ" }, "source": [ "評価用データについても同様にラベル毎のサンプル数をカウントします." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "YaIUGDSQyvki", "outputId": "7f736fc8-d001-4699-cf58-f9afb1aa2947" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y_test count each labels: {0: 42149, 1: 3200}\n" ] } ], "source": [ "uniq_test, counts_test = np.unique(y_test, return_counts=True)\n", "print(\"y_test count each labels: \", dict(zip(uniq_test, counts_test)))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "L31d0iKKBrvK" }, "source": [ "学習用データ,評価用データ共に,VEBサンプルは全体の10%未満であり,大多数は正常拍動サンプルであることが分かります." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "uyN7nUH1E5uI" }, "source": [ "次に,正常拍動,及びVEBのシグナルデータを可視化してみましょう." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "colab": {}, "colab_type": "code", "id": "TUpalkU0Tao1" }, "outputs": [], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "PXAuekJ6Edq7" }, "source": [ "正常拍動の例を図示したものが以下になります.\n", "\n", "P波 - QRS波 - T波が規則的に出現していることが確認できます." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 282 }, "colab_type": "code", "id": "jOLyInm1TeBW", "outputId": "08b0c373-1001-4832-a6c5-f9890b86f389" }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 16, "metadata": { "tags": [] }, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "idx_n = np.where(y_train == 0)[0]\n", "plt.plot(X_train[idx_n[0]])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dojJ02FNF5u5" }, "source": [ "一方でVEBの波形は規則性が乱れ,R波ピークの形状やピーク間距離も正常例とは異なる性質を示していることが分かります." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 282 }, "colab_type": "code", "id": "f_mYCNzwTlmz", "outputId": "0df4cc1f-9848-4ca0-8f12-ee19a9c586a5" }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 17, "metadata": { "tags": [] }, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAW8AAAD4CAYAAAAjKGdbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJztvXeYJHd1r/9Wp5npyXk2zkbVJuW4\nykIBhCSEZTImCvPDBgzmAvaDgYuNL+aHsbEx9jVYJkkmiiiQUBZCWuW02qDS5t2JOzl27rp/VFVP\n90zPTE+nqto57/Ps8/RUd1efre761KnzPUHRdR1BEATBXXjsNkAQBEFYOiLegiAILkTEWxAEwYWI\neAuCILgQEW9BEAQX4ivXBw0MTOSd1tLYGGRkZLqY5pQEt9gJ7rFV7Cw+brFV7DRoba1Vsm13heft\n83ntNiEn3GInuMdWsbP4uMVWsXORzy3kzaqqvhP4NBAHPq9p2m+LYpUgCIKwIHl73qqqNgP/G7gU\nuBG4uVhGCYIgCAtTiOd9DfCApmkTwATwweKYJAiCICyGkm95vKqqfwVsBZqARuALmqY9ON/r4/GE\n7pYYliAIgoPIumBZiOetAM3AHwGdwMOqqnZqmpb1alDIamxray0DAxN5v79cuMVOcI+tYmfxcYut\nYufM/rNRSLZJP7BL07S4pmmHMEInrQXsTxAEQciRQsT7PuA1qqp6zMXLGmCwOGYJgiAIC5G3eGua\n1g3cCTwJ3AN8VNO0ZLEME7Lz4oFBHn+5124zBEGwmYLyvDVN+ybwzSLZIizCdDjG13+2G4CLd3Sg\nKFnXMQRBWAa4osJSMDjWP5l6HIklbLREEAS7EfF2EeFIPPV4cjpmoyWCINiNiLeLCEVnxHsiJOIt\nCMsZEW8XEYrMhEomRbwFYVkj4u0iQhI2EQTBRMTbRaSHTaJxWbAUhOWMiLeLSA+bxOKSUi8IyxkR\nbxeRnm0ST+Q9mEgQhFMAEW8XEU3ztmMJ8bwFYTkj4u0i4mmCHZewiSAsa0S8XUR6nDsunrcgLGtE\nvF1EunjLgqUgLG9EvF1EepxbPG9BWN6IeLuIuCxYCoJgIuLtIjJj3pIqKAjLGRFvFxFLJKmqMFqw\nS7aJICxvRLxdRCyepKrCazyWsIkgLGtEvF1ELJEkaHrekm0iCMsbEW8XEY8nqQh4UZBsE0FY7oh4\nu4RkUieR1PF7Pfh8HhFvQVjmiHi7BCvG7fd58XoUEknJNhGE5YyIt0uwYtw+r4LXo5AU8RaEZY2I\nt0tIJCzx9uARz1sQlj0i3i7BEmuvV8EjnrdQZmLxpGQ4OQyf3QYIuRG3xNujSMxbKCu6rvPF7z0L\nwOfecy5+n9dmiwQQz9s1WGETr8eDR1FI6iLeQnnoG56ma2CSroFJ9h4ZsdscwUTE2yWkh03E8xbK\nycGusdTj3uEpGy0R0hHxdgmJxEzYRGLeQjnpHZ6eeTw4vcArhXIi4u0SLE/b5/FIqqBQVvqGZgR7\naDxsoyVCOrJg6RISSTPmbWabSNhEKBdjUxH8Pg8Vfi+jkxG7zRFMxPN2CelhE/G8hXIyHY4TrPDR\nUBMQ8XYQIt4uIW553h7xvIXyMh2JE6z00VBTQSiSIBJN2G2SgIi3a7A8b5/Xg1cxxFuXdEGhxOi6\nnvK8m+oqABiUuLcjEPF2CYlkZrYJgGi3UGqi8SSJpE5VpY+OpmoA+oYkXdAJiHi7hJk8byPbJH2b\nIJSKUCQOQLDCR0dzEIDeIUkXdAIFibeqqlWqqh5SVfW9RbJHmIeZCksFj8f42mTRUig1U2FDvKsq\nfKwwxftwzzgvHBiw0yyBwj3vzwLDxTBEWJjErN4m6dsEoVRMTkcBqA36aa2vwudVePHgIP/2s5fZ\nfWjQZuuWN3mLt6qqW4BtwG+LZ44wH7PL4wHpbyKUnPHpGAC1wQAej0JHUzD1XP9wyC6zBAor0vkn\n4CPAe3J5cWNjEF8B3chaW2vzfm85KZWdVcEAAI0NQaqq/AA0NAZprK3Me5/L/ZgWG7fYCbnbqmtG\neGRNRz2trbVcdd5abr9nPwAxvfT/Z7ccUzvszEu8VVV9N/CEpmlHVFXN6T0jI/kvcrS21jIwMJH3\n+8tFKe0cHTO8nKnJCPGYkWc7MDBJPBzLa39yTIuLW+yEpdna3W+8Tk8kGBiY4NLt7UxOhvnFH45w\nvHespP9ntxzTUts534Uh37DJDcDNqqo+CXwA+JyqqtfkuS8hB1IVlt6ZVEGrZF4QSsWEGfOuCxp3\ne36fh2vOWwNAWIp1bCUvz1vTtLdaj1VV/QJwVNO0B4pllDCXVG8Tjycl3pJtIpSaaTNVsNoM1QFU\nBIzwp4i3vUiet0vItmAp2SZCqZkOz+R5W3gUhQq/V8rkbabgroKapn2hCHYIi2B52V5FEc9bKBuh\nSByfV8Hvy/TzKgNewtG4TVYJIJ63a8jwvBXxvIvF/c+e4C+/8VgqtitkMh2JU1XhQzF/cxYVAS/h\nmHjediLi7RIsL9uT7nlLnnfB/PCBA4xNRjnW5/ysBjuwmlLNpjIgYRO7EfF2CZZQe9IrLBMi3oVg\nxXNhZmFOyCRktoOdTaUZ85bOlvYh4u0SEmmet3ULK+dNYQyOzVQIjk9J2GQ2sXiSaDyZ3fOu8KED\n0Zikq9qFiLdL0M1zxGhMZTyWsElhDI7N9KW2ysCFGcamjKk5ddWBOc8FzAXMiMS9bUPE2yUk0sIm\nHkWyTYrByMTMSC9ZsJzLmHk3Ul9dMec5nyne8YR43nYh4u0SkmaRToZ4i+ddEOleoxSczGV80qyu\nzOJ5+7yGdMREvG1DxNslWJXwHo+CItkmRSE9T1kyJ+aS8rxr5oq33xTveFzE2y5EvF3CzIKl8Q9m\nBF3Ij3RvW2K3c5kIme1g00rjLSzPOy4ZT7Yh4u0SrJQsr8eTCptImlZhRES8F8QagVaVJdvE5zN+\ngxI2sQ8Rb5eQ8rw9M6mCEjYpjHTBlrDJXBYSbwmb2I+It0tIpodNUr1N7LTI/Vhhk+pKn3jeWVjQ\n8/ZKtondiHi7hGQqbKKkYt4SNikMy9uuDQYk2yQL05G5HQUtJNvEfkS8XYIVNlGkt0nRCMcSVPi9\nVAa8RMXznkMoEsejKAT8c2XC75MFS7sR8XYJmZ63FOkUg0g0QYXfQ4XfSzSelOM5i1AkQVWFd05H\nQQCf19gmMW/7EPF2CcmMBUtjmzjehRGJJagM+FKTYSTunUnIbAebDQmb2I+It0tIF2+psCwO4WiC\nioCXCr8h3hI6yWQ6kr0dLMiCpRMQ8XYJyaSOwqx+3nKbnze6rhthk4B3ZiajiHeKZNI4Pot53hI2\nsQ8Rb5eQ0PWUaIvnXTjxRJKkrlPpn/G8Jdd7hlB0/jRBAL8U6diOiLdLSCZn8ruVVEtYGw1yOVZq\nYGbYRITIImQNHs4yiAGkPN4JiHi7hGRST3ncUh5fOJaXXelPD5s4f5pOub7z6QUKdGBGvBNSKWYb\nIt4uIZHMEjYR1ztvrPh2IJAeNnG2EIUicT7/7ae57Tf7yvJZML94e61UQfG8bUPE2yXoup6aXTnT\n28ROi9yNlRZoxLytqTDO9rx37emje2CKXXv6Sh6fD0WM/c+bbWKOc5I5qvYh4u0SEkk9VRafGoMm\n6p03kfSYdyrP29met3ZiNPX4WH9pp93PeN7erM+nPG8Jm9iGiLdLSGbJNpGYd/5kxLxdkG0yGYqx\n+9Bg6u+h8fACry6cxWLe1l2geN72IeLtEpLpMW/pbVIwVsy7IuCl0u/sCsvBsRB7Dg8RjSXZtKoe\ngOESi3dogaZUkLZgKamCtpH9mxEcRyI5E/P2SMy7YNLDJgEHl8fvPjTEv/z0pdTfl5zewcHuMYbG\n7PW8Z7JN5EdoF+J5u4RkxoKlsU2XEydvwqmwic/RYZP0UAnA+VvaURToGpwq6ecumm3isbJNxPO2\nCxFvl5DMliooYZO8ibgkbHKk11iYbGuo4uZL1xOs9LGqpZqDXWO8eHBwkXfnz2LibXUVFM/bPkS8\nXYLEvItLasHS4WGTobEQbY1VfPlDO7n50vUAnLW5BYCv37m7ZL+BhQYxgDFLFSTP205EvF1CUp9b\nYSlZWvmTWrB0cLZJNJZgfDpGc11lxvabLl6fetw/PF2Szw5F4ng92QcxwEyqoFRY2oeIt0tIr7Cc\n6W0iXk++RMzGS5UBLwGfBwXned5WOmBzfaZ4+30e3n71ZgCO9ZUm33s6bPTyzjaIAdJj3vIbtAsR\nb5eQTDIn20TyvPMnvTGVoigEAl7Hed6WeLfM8rwBVrZUA9BXIs97OhKftykVGFW+Xo8inreNiHi7\nhGyNqeS8yZ9IWtgEjGIdx3neY9k9b4AVzUEAeodKFzaZb7HSwutVxPO2ERFvF6DrekaFpXUnK2GT\n/IlEE3g9SipfOeD3OE+8rbBJFs+7sbYCv8/DyZFQ0T83nkgSjSXnXay08Hk8UmFpIwUV6aiq+hXg\nMnM//6Bp2s+LYpWQgaXRM71NJNukUMKxBJWBmb4dAb+X6bCzGlMt5HkrikJTXSXDE8Uv1kllmiwQ\nNgHD85awiX3k7XmrqnoVsEPTtJ3A64B/KZpVQgZWLu2cmLfk2OaNNQLNIuDzOq4x1dBYGAXDy85G\nc10FE9Oxos/etAYxLBY28Xk9UqRjI4WETR4F3mw+HgWqVVXN3oJMKAjLw/aYubXieRdOJJZIxbsB\nAj5PajSaUxgaD9NQW5EK7czGCqcUu0nVYjneFsaCpXOO13Ij77CJpmkJwKrRvRW429yWlcbGID5f\n/tre2lqb93vLSSnsnA7HAKis9NHaWkvM9LwrKvwFfd5yPqaRWJKO5kBq3zXVAQDq64NULiJa81FM\nO+OJJCOTUdS1jfPud9PaRv6wu5fJaHLJn73Q67vNOHprc/WCr6sIeJkKx0v6O1rOv9HFKLgxlaqq\nN2OI93ULvW5kJP9V8dbWWgYGStu/uBiUys4pU7zjsQQDAxOMjhon1/R0NO/PW87HNJnUicYSeBVm\n9m16kD19Y9QGA0veZ7HtPNI7TjKp09ZQOe9+G4J+APYeHGDzitzFYzFbe81e4Xo8sfD/SYdYbJHX\nFMBy/o3O3n82Cso2UVX1tcDfANdrmjZWyL6E+bFuTaW3SXFITdEJzPguViWhU4YQH+o2TierBWw2\n1nXU4vMqPLWvv6iDORbrKGjh9SrEJWxiG4UsWNYD/wjcqGnacPFMEmaTnL1gmYp522aSq0kv0LHw\nmyG9aNwZ6YJWCuDq1pp5X1MbDHDxjg76R0K8cKB4TaqmF5kcb+GVVEFbKcTzfivQAvxEVdVHzH9r\ni2SXkEZyjuedud2JHOub4HiJR3Xly+wCHXCe5z24QJpgOhfvWAHMeOrFINcFS59XkWEMNlLIguW3\ngG8V0RZhHlLirVi9TZwdNkkkk/ztd58B4H3Xb+GSM1akbHcC6R0FLSwhd4rnPTgWpjLgpXoR79cq\nk+8dKl5/b2uBPFjpX/B1Pq8HncyOl0L5kApLFzCTKji7t4ltJi3IQ891px5/555XePSlHhutmUvY\nbEqV7nn7fabnHbffk9R1naHxEC31lfM2hrKoqfJTU+Wnt4g9TiZDsdS+F0IGMtiLiLcLSMzyvJ0c\nNuk6OckPHzyQse2RF7rnebU9zCxYZhbpAEUveMmH6UicUCRBS31VTq9vbahkeDxStDuxiencxFtG\nodmLiLcLmL1gqTg020TXdb5mzltc2VLNbZ++im3rGjneP8nEdNRm62bItmCZmgzjgAW4wdHc4t0W\nTXWVxBPJlOgWysR0jKoKb+puZD7E87YXEW8XYDk2Tp+k0z8SYmQiAsBn/uRcPB4llep2pHfcTtMy\nSA0f9qeLtzUZxn4hshYrW3IU71SlZZGGEk+Goot63ZA+kMFZv8Plgoi3C5i9YOnU3iYPPdcFwJ9c\nd1oqzWzDSkO8D/c4R7zDWbJNZsTb/mM6NGakCWbrJpiN1gYjvFKMqTq6rjMZiuVUqDQzCs3+C95y\nRMTbBVge9kyet7XdLovmous6j+/po8Lv5YKt7antG1bWAfDrx48y7pDQSbZsEytsEndAl7yU592Q\nm3ivaTNywU+cnCz4s8PRBPGEnpPnLUOI7UXE2wVYJ4c1/kxx4CSd4fEIoUic0zc2Z5z4NVX+VDrb\nc9qAXeZlkD3mbXqRDsg2mQmb5LZgaRXyHD9ZeF79hJlpUptT2MQ5dyvLERFvFzCnwjI1Scc5J033\noJFnvNoU6nT+4k1nALDn8FBZbZoPq1dMdVoesxW/dYIQHeufoK46sGiOt0Ww0kdrQyXH+ycLvqBb\nC8u5hE18HmuR1/4L3nJExNsFzI55W48dpN2pOG1r41xvsa2hivamIPuOjTgiPpotj9mfSnuz177h\n8TAjExE2rapfNMc7nbVttUyGYoxOFhaamrTSBIOyYOl0RLxdQGJWkY7x2FnZJqly7nkW2U5f30Qk\nmuBAl/39y6ZM8a6umvFsnRICOJhDQ6psrGgxZloWOpB4cglhEydl6CxHRLxdgD4rbAKm5+0gjyc1\n6Xye9LYdG5oA2HfU/h5mk6EYVRW+VLYEpC1Y2ixEB7vyE++2BkO8TxbQehnSCnRy8bw9zsmNX46I\neLuA2RWWYPQ3cZrn7fUoNNRkH9m10RSjo332N6uaDMWoqcqMJzvFizzYPYbXo9DZMX83wWy0Nxnh\nKmvtIV8mQmbMuyqHVEHrmDkgQ2c5IuLtAmZ3FQSjRN5B2s3QWJimuop5GxRVV/ppbajkmM3ibeUx\n18wSp5lqQfsOaiSW4MTJSdZ11KZa1ObKuo5aqiq8vPBqYRk9luddm4Pn7RPP21ZEvF3A7MZUYC1Y\nOuOkicUTjE1FFy0qWdVSw2QoZmup/FQ4Tjyh01CTKd5WKbidmRNHe8dJJPXUXcpS8Pu8bFxVz5CZ\nspkvS1uwdMY6wXJFxNsFZA2bOCjmnWte8opmIy7bO1S8DnhLZdQs358d3nGCEB3pNe5K8hFvgKZa\n4+JptSjIh4lQFI+iLNrLG9Ji3hI2sQURbxcwO88bDC/cIdpNnynGljjPx6pWIwf8UI99GSejk5Z4\nZ3reVgjAzvht96BRIbm6dW6ufC401RoXpJHJ/MV7fCpKbdCfU5qik5p5LUdEvF1AImu2iTN6m0Ri\nCR4yW752LCLeOzY0oygUdWTXUhmZx/N2QoVlz+AUXo9CW5Zc+VxoNMV7OM8GVUldZ2QiQlOOPVVS\nvU3E87YFEW8XMHsAsfXYCTHv37/Yw94jwyjAxpUL3+7XBQNsXt3Aoa6xlAdcbubr2OezucJS13V6\nBqfpaA5mpDAuBevi2ZPnVJ3xqSjxhJ5zK1rxvO1FxNsFpDxvb1rMG8URvU2svO3Pvuc86qoXTy+7\ncGsbOvC7p46X2LLsDJqVoC0Nmd6t3amCw+MRIrEEq7K0F8iVVI+T/vwaVA2lCq2yp3vORoYx2IuI\ntwuwMiB8aR6ZUWFpl0UG8UQS7cQo7U1B1q+oy+k9l5y+gpb6Su5/9gTjU+XPOhkYDaMo0FQ3e8HS\n3lLvV46PABQk3lUVPtoaqzhxMr8eJ9bE+taG3MI2MozBXkS8XUD2mLf92SYnTk4SiSbYurYh5/cE\n/F6uPHsVug57j5S32jKeSHK8f4JVLdVzQhNWJo9d4r1rTx8AF23vKGg/a9uMdMzh8aWHpXqHjXDL\niqaF1y4svOJ524qItwvIFjZxQszb6qOxum1p1YCnrTHEvhgtTJdC18Ak0XiSTavnXmwURcHrseeC\nGE8kOdQ9xqrW6py93vmw0gwfer5rye/tHTS+z47m3Lx/r0NaCixXRLxdQNYFSwd43oOjZvw4x77T\nFu1mNoV1m14uBszZkPN5lh6PYkvOcs/glHFRyTO/O52rzl5FRcDLPU8d5wnTm8+VEycnqanyz0mj\nnA+psLQXEW8XYMW802/1FQeUx1uZG605TnyxqKnyU1Xho7/M4m0tyM2XCmeId/kPqjUBZ+0S72Cy\nEfB7ufa81QA88mJ3zu8LReKcHA2xpq0m51a00tvEXkS8XcC8MW+b1XuxNrDzoSgKzXWVDI8XZ2Bu\nrlif11yfPZvCZ1PYxBLvNW21RdnfLZdvZG17DUd6x3O+k7Bs6GzP3QZJFbQXEW8XkDVV0AEx74HR\nEPXVAQL+pTVRAqivCRCOJlLzJMuB1bbWqZ73qjwrK7Oxpq2GeELPOTSVuoC05+79W3eCIt72IOLt\nAqyTIyNVUFGw8241kUwyPB7JeUjubBrMnPCxMjapGhoLE/B55h004LVBvHVd58TJSVobKqnKoZ9I\nrlhzQ3tybBFrLT6vzHGxEtIHEEvYxA5EvF1A1pawHnsHEPcPh0jqemoIwFKpMxfFxgsc27UUhsbD\nNNdXzhvT9XqUsnuRY1NRJkOxVIFNsVi1RPG22gbMzn9fCCe00V3OiHi7AMuzcVKe94GuUQA2rc4v\nQ6LR7C1i5RaXmlAkzlQ4vmB83o70y5l4d3HF2/Kgcx3OMDIRxuf1ZMz1XAyfLFjaioi3C4hni3kr\nCjr2ed/WLMrNeYr36RuaAbjr8aP05tmLYynMLFbOL95ej6fsYZNiL1ZaNNUbYZgDXWM5XeSHJyI0\n1gaWNPRYxqDZi4i3C7BOjtldBcG+dMEDXaNUV/pSsdWl0t4U5KaL1zE4FuauXUeLa1wWrMXKhTxv\nI2xSXi+yKyXexVusBOPO7MKtbYxMRHjp4MJdHEOROGOT0SUXCHkdMjpuuSLibQN7jwzz/Xu1nMMe\nM2GT9N4mhnrbkXEyMhFhYDTMplX1GQMilsrNl62nqsLH0d7SV1qmmi4t6HmXN2wyGYrx8uEhqip8\ncxplFYMrzloFwB33v0psgVa33QPGnc9S4+4zwxjE87YDEe8yk0zq/NOPX+SRF7pTt8y5vAfmxrzT\nnysnB7vNkMma3HuaZMOjKHS219A3PF3Q6K5cGMzB8/aUecHyvmdOMBWOc+15qwu6CM5HZ0ctZ21q\nYWQiksomyYYVtlpqU6xUV0HxvG1BxLvMpE9PH8qxSGW+3iZQfs/7eP8Ez2kngfzj3emsM7sR/vOP\nX2QqHCt4f/MxNE8f73TKmSo4GYrxGzNcdOG29pJ9zpbORoAF1xWGzUyTXPt4W9jdiXG5U7zEUmFB\nXj48xKMv9vBc2nRvqzfIYsxXYQmUNdd7eDzMF77zDGAM7F3XkVsb2IWwBjgc6hnnJw8d5H2v31rw\nPrMxNB7G61HmTNBJp5yNqY70jgOwtr2GFUvIrV4q1mi6vgXmho5MGBc2axJPrngUBY+iEBPP2xby\nFm9VVb8GXATowMc0TXumaFadYoSjcb5+5+45HspAjuOq5uttAqBTPq8n/cJz+obm1MT1Qjj7tBbe\ncMk6fv34UbTjowXvbz4GR8M01lZk5MrPxuMxMniSSX3B1xWDIz2GeN98yfqSfs6KHKbrWOmEC13Y\n5sPv8xCPi+dtB3mdfaqqXgFs1jRtJ3Ar8PWiWnWK0XVyikRSZ21bDX98xQb+7tYLgDw8b6+9MW8r\nRr+1s5E/vmJDUfbpURTeeNkGtq9r5ORoiIkSVFyOTUUZm4ouGtMtZ3/qvUeHUZTC1w0Wo6mukoDP\nw9P7T/LZ257isd29JJJ6KkNEOz7Coe5x2hqq8qrw9Ps8ROPla3EgzJCv63Q18EsATdP2A42qqhZ+\nD32KYvWtvvb8Ndywcx2rWqqpqvCmFtEWI5HUUSBjUUtJxbyLbu689A1N41EU/vItZxb9Vn/buiYA\nnnnlZFH3C7DfHNW2bpFpPzPZE8UPA0SiidT6RDyR5HDPOJ3ttUsqiskHj6JQbX5Gz+AU379X4x2f\nu5tPfONxugen+J/7DwDwvtdvyWv/Ab9nwUwWoXTkGzbpAJ5L+3vA3DY+3xsaG4P4fEtvYGTR2lrc\nIoZSkc3OAXOqyZlb2lPPdzRX0zs4RUtLDi04FQW/z5Ox72ClcUI2NgZpXmI/7YVsXYiBsRAdzUFW\ndBS+UDmbm67YxM8ePcwT+/p562sz496FfPeDoyG+ddc+AM7fsWLBfVVZx7SpJi9Rnb3ve588yvYN\nzVQGfPzZlx/ijVds5NY37OBY7ziJpM5pnU1l+V1/7G1n888/eJ6G2gqO902kvO7P3fYUAK+9qJNL\nz12b174rAz5CkXjJ/h9uPu9LTbEWLBcNEI6MzL9gshitrbUMDJR36ko+zGfnq8eG8XkVKj2knm+o\nDnCkZ5zDx4epCy7c/D4UjuPzejL2HY0ZqXWDg5Mko0tPs1vqMY3FE4xNRlnZXF2y7+KMDc28eHCQ\nR589zlYzS6LQ797KjAFoqw0suK+4eft/8uQ4oUW+k9nMtrPr5CTf+OlLAPzZG3cA8MvfH+INOzt5\n4iWjz3bzIvYUi7XNQf7lo5eSTOp8++79jE3H2Ht4CDA85zdfviFvOzyKQjiaKMn/w+3nfTH3n418\nwyY9GJ62xUqgN899ndIkkkm6BqZY2VKdyouFmSGvg6OLh05iiSS+WYuD5Y55j5gNpJaakbAUrj7X\nGCLwvd+9UrSyfyu/+dYbtmYc/2wUs+jkWP/Mydw9MJPPf6xvgp88fBCfV+E8ta3gz1kKHo/CB27c\nxpc/fCn/661n4fUo3HrDtoIWZyVsYh/5ivd9wJsAVFU9B+jRNM35l0gb6BuaJhZPsnZWk3srp3Yg\nh0XLeDyJf5bwWJGWcpw2w+Nh+sxshVKK9/b1TVywtY2TI6EM8cuXiekoP/v9YWBmbuZCWOJdjAti\negHWvqMjqcd33K8Riyd5/w1bS3osF2P7+ib+4xNXcP6Wwi4gfq+HeCJpe295Oxg3O0LaRV7irWna\nLuA5VVV3YWSafLioVp1CHJ9nxNUasxT5vmeOL/rDX8jz1kvsee89Msyn/+8T/MtPdwPQ3phfC9hc\n2W4uXP74wYPcfp+W97SdI73jfOzrjwHQ1liVU98OywONF+GYHk+7+FgVqQCHuseprvRx4dbSFebk\nSjFSPf1+s7+JS7zvSCzBl+94jtvv0+bc3b10cJDf7DqaU6+W8akon/yPXXz1hy9kfb4cDePyjnlr\nmvbXxTTkVOVEvyneszzvTavrqarwcaR3gl/+4TC3XL5x3n3E4knqgrPEu0wVlg8+15XxGYV6aoth\nTaLXToyinRhlKpzgQ2/YtuSIAQ7oAAAcfklEQVT9/Oz3h1KPP3rL6Tm9p1iedzKpc7w/s/VBTZU/\n5aVtXFW/pO59Tsa6I4zGk3lNVCo3B7vGeNX8d/GOjlSR2MuHh/jXOw0HpTboT/WFsZgMxaip8nO0\nbxxdh1dPjBJPJDl+cpJ7njjKeZuamQrH+M7dr9AzOMXgWIibLl7HTSXM45fy+BIyFY7x1P5+vB5l\nTr9mn9fDJ95yJpB5W52NeCI5x0sqR8xb13W0EzOFM3VBPxWB0p6gq1urM47Vs/v7GJtaWu53PJHk\nYNcYq1qr+a9PX8mqHBsupcZ6FXhM9x0bZjoSZ13HzAX78jNX8sm3ncWlp6/gHddsLmj/TsISbLfE\nvV9N+z2nd1v8xaOHU48P9WQmze3a08tf/OsfePSlHv7uu8/yxe89m/He/7jzJf77N/t4al8/z786\nQN/wNPGEzq8eO8rT+/v555+8WJLjI+XxJeSO+15lZCLCG83uebPZuKqeFc1B+oam0XU9qzem6zqx\neBK/N/O5lHiX0PEen4oSisQ5e3MLm1bXc9amltJ9mInf5+Vv328UMd31+BF+8YcjHO0d58wFPjuR\nTPLigSE622voHpxKeVBbOxszqlIXw5PqT53fiabrOqFIgp88ZHj977j2NL50u5FRu7a9hm3rmlL5\n7KcKllMRc0mhzivHZxwlq5vl6GSEo30TbO1s5EDXWOpuGYx2uT98wMiF/+49r6TtZ5S2hipuvXEr\n/3DH8zy+py+1TvO6C9fy8qEhugen+N7vNEKROKFoHL9vaRlMiyHiXSIGR0M8ta+fdR213LCzc97X\ndTQF6R2aZiIUy5oyaHmBsz1vxfyzVJ63ruvsOWIUt6xorub6C+f/P5QKq1d479A0p2/Uic9za37f\nMyf46cOHWNlSnWpABXDTxeuW9HneAkJRv33sMN++ay9R08Paub2dTavq+at3nM3RvgnO3ty65H26\nAet3GXWQ5z0xHeWHDx7g5kvW094UJKnrfPNXe1MFYOtX1DIZirHnyDD/9rPdqT4z29Y1EorE6RqY\nJJ5IcuDEKL9+/ChT4eypuGs7atm8uoF3v34r3797P10DU3R21PKWqzaxcWU9//6LlwlF4tQF/Yum\nA+eDiHeJeGp/PwBXnb1qQe+vvWmmcVC2L9i63Zqd5pZasCxRb5O7nzyWytS4YGt5U9osOswqzq6B\nSb5z936e2NPPn960jQu3taPrOrv29BGNJ/nNrmNA5rzGD928ndolnjCFTIb57m/3pQRs27rGVIMt\ndW0j6trGJe/PLVSaYbRwxDme989+f4gn9/YzOhHh0+84hyO94xmVuxtW1hOLJxkY7eGFA0b4w+f1\ncPbmVgZGQxztm+Cux49mDAl53+u38J27X2FrZyNnb27h3qePc935awB4zXlreOXIENFYkteca8TK\nt6+f+c5zDdstlVNKvBPJJHc9fpRYIskbLl7PK8dH6BqY5PUXdZZ1gWgqHONnvz+Mz6twrrqwx9Vh\niffwdNZ0Nqtj2/wx72JYPMN9Tx/nRw8dTP399qs3z1lsLRcrmoLUBv3s2tOX2nb3k8c4f0sbDzx7\nIsPOS09fwWMvG6UGN+zs5II8sjk8eeZ5j09HCUcN8dq0qp73v37xnPJThdoq4wJpZ8rcbHrMDopj\nU1GSSZ2fm06IgrEgfsVZK4lEE7xybISGmgA7NjRz4bZ2Whuq2Ly6gUdf6s0Q7ndeexqXnbGSTavq\naamvwu/zcM15a1LPN9dX8aGbd2TYUBnwpRquXXv+GkqBa8U7FImTSOrc8+Qx2puCJBJJbr/v1dTz\nsXiSB57tAqA2GGDvkWEaayt429Uzi0W6rhONJbMuwlnxy2Dl0g/RN3+1F4Ad65tTZezzYYl3/zzN\n8q0UrNmpgqmwSYHZJrquc/t9rzIxHeV912/NEMTXXbi2ZD+8XPB4FM7Y1Mrju3tS206cnOQDX3l4\nzmtvvLiTbesaeenQUN4255ttcszs0f6GS9bxxsuK07DLLVhtBCZCxW8oli8jZnrp+FSUh1/oZv+x\nEeqCfv7xzy/Gn9ai48sf2jnnvWdvbqUueJBEUueibR28/drNKUdpqf18br50PZefuZKmBQaAFIKr\nxDsWT3Csb5KHX+jiib39qe1+n2dOXqUl3JC50PCac1bR1hhE13W+8fOX0Y6P8qm3n01nR6Z3+eBz\nXfzggQN84X3nZ3ieQ2NhKgJeKvxe/us3+2ioCfC212zG41F4dn8/x7pHU7HiN105f/qfhSXeJ05O\n8pOHDjI0Hua9129hIhSjraFqxvOeJ2xSaMz75EiIR17onrP9ou3t3HK5/UL09teq7Dk8yM7tHcTj\nSR54buZ7vea81Zy5qQVd12lrDNLWGOSi7R0L7G1h8qmwHJuMpC7Wxehv7jZqgoZ4O8XzjkQTDJm9\nhKbCce575jhgtCjw59BbKVjp46sfvgSPRyl4upGiKCUTbnCZeN/5yGHuf/ZExrb66kAqlayxtoL3\nvE7l9ntfTU2pufrc1TyYdsL/9Tef5IyNzVx/4dpUvOurP3qBv7v1wlTF22Qoxg/MFeZde/pY216L\nrusc7hnny//zPMFKH1efu5pnzThaU20lWzob+LvvPpv6nJsuXpfTcN7aoJ9ghY89R4ZTov/MKydR\ngL98y5k0mDbNW6RToOfdlVa6/Zxm9Ot++9WbbfW40+nsqONrH7kUMO5OLPH+m3edS2dHbVHDE/m0\nhP3PX+1l2hzhtn7l8hPvWtPznpx2hnjPrlgeGA2zqrV6SesObgl5uUK8h8fD/PsvXk6JC4DPq/AP\nH9zJoZ4x/uuufZy9uYX337CVyoCP1objDI2Haa6r4J3XnsaWtY001AT4P2ba1u5DQ+w+ZDTm2drZ\nyP5jI3z5f57j8+89n6lwnP/85Z7U5/QMTfG7p47z68ePsGVtI4mkzsR0jF/+4UjqNfc8dSwjy8Hr\nUbggx9FWiqKwoiXIoe7M3FIdePiFbl5vZqpUzPIaPEUqKLGKSVY0G1kvHU1Bdu7I33stJe1NQTas\nrKPC72XjquJ3NrQuiLm2hE3Pg7/2grXUVxc/o8Dp1Jr/55HJiM2WGIyadrQ1VHHSFPIVTaWtCrYL\nV4j3f9z5Ukq4t69rpK0xyA07O2mqq6S5vpLztrRl3OLcfOl6en+1lw+Z3dysRcOP3HI63/j5y6nX\nnbamgY+/+Uw+e9uTDIyG+eoPX6R7cCpVHlsb9LPn8DB7Dhse8YtpifkA1ZU+du7o4IFnu3jw+S58\nXoVPv+McKgPeJQ1zveXyjfznr/Zw6w3b+Pqdu1Nx7ANdY4ybDaFmx97n620yOhnh6f0nueyMFVlz\ny4fGwtRVBxgZD/NPP36Rvaa3/1fvOIfDPeNs7WwseSFOIXzmT86lVGvPS415Wx73jvVNfOTNZzE0\nlNtA6VOJlrpKKgLejNxoO7EuIls6G1LiPbtA7lTB8eL9q8eO8NReI9ugrbGKt11z2hxhnB2bUtc2\n8rWPXjpnX+ec1sq3//o1fPhrjxKKxHnTFRvx+zx86YMX8cl/35XRDOnWG7ZyoGuUR1/KbJZ4zXmr\neengIAOjYaoqfOzc3pGKr6/tqGNTHh7h1s5G/vUvLgPgix+4gOdfHWB4IsLDz3dzx/3GImz1LPHO\n1tskFk/yudueYiocZ2I6SiKhs3NHB2vaatB1nTvuf5WHn+/muvPX4PN7U8K9cWUdddUBztpc+iKc\nQinleLKlDtS1OkK2NwZLPjbNqXg8Cp1tNRzoHiMcjVMZsFdSxkxnZ0tnY+rc3bGh2U6TSoYrxBuM\ndB2rZWihfOrtZzE+FWWTOf3c6/Fwy+UbePiFbrata0otNDbUVqR+AF+89QIqAl6a6ypZ0RTk9vte\n5axNLazrqKWzvZbjJye4sQh9DFY0V3PDzmoi0QS7Dw6mFl9mZ61k623y4sHBVEHBb58wcp9/9/Rx\n/vUvLuVLdzyfymh5en9/avDA26/ezPk25XE7jaWmClrrKkudun6qsW5FHa92jXG8fzKn7o2l5OSI\n4W2vbq3hz964g9CsNgWnEo4X78+++zyeOzDIpaevKNo+s2UFXHbmSi47c2XGtm2djXz4j06nviaQ\nkWh/5dmraK6vYsvaBhRF4W/efa7R9nV1Y9GaslcEvJxzWltqgXY+z9sKzz65ty81MWY2v37sKP3D\n02ztNCrIjvZNMDoZ5axNLY5ZmHQCSw2bDJrrHC3LXbxNcTzaN2GreOu6zt6jw9RU+VnZXM3qEhXH\nOAXHL6tuWFnHn7/pTFvisIpiFNnMDoUoisIZG5tTpdo+ryev4a2LcfqGmT4Y1bPGcll36UldJxJN\n8L3faYDRrfCi7ZmLpQ8+30XA5+FjbzqDnWmpdFvW2uslOY2lpgpai9TL3fO2smwO94wt8srSMjIR\nYWQigrqmYVmEsRzveS9n0r2Y2ZkMSlqe9/5jI0RiCW68uJNbLt/IoZ4xXjo4RDgax4qqbFhZR8Dv\n5fytbbx4cBC/38v5Dugp7SSWGjYZHDNu0ZtLmMvrBtoaqqip8nO4Z94RtmXBSv1dt+LUDJPMRsTb\nwQT8Xr765xfTOzQ9J9nfEhodI50RYL05HX3jynr+7eOXcbh7nC/dYaRHnmuO3GqoqeBTbz/bNfMB\ny4nP7EGTa9hkaCxMwOehNljaCfBOR1EUNqysY/ehIcamoralTN77tFGQc8ZG5y+8FwPHh02WO011\nlWxfP7eNaCpsktTpNcU7vXzXY55QzXUVdDQFueyM4q0ZnKostSXswFiYloaqU2awQiFsMB0Hq0Nf\nuRmfijI4Fub0Dc2nbGrgbMTzdimKNbIrkWTf0REqAt45C2cej8IX3n8BPo/HFVNO7CYV886hanU6\nHCMUibN5dfGLhdyItaDfOzRVlr7vs7Fmhp6qmSXZEPF2KVa2yffvNQbaXnrGiqxlvdWLNMYSZlhK\nS9gBM8e7tX7x2ZjLgRXNRhVj71D2BmulxirIaW9aPt+HhE1ciiXesXiS5rpK3vaaU2e0ll0sJVUw\ntVi5zDNNLNoaq/B5FdsqLa3vo2UZXUxFvF1Keph1TVtNXq1rhUyWMj0+5Xk3iHiDkS67bkUdx09O\n2NJhcOb7EPEWHE56HmspcsyXI94lZJtYt+nLydNbjDM3NqPr8MCszp/l4GjvONWVPhpqlk9zMBFv\nl5Lez6WqQhYji4HV2yQX8d5/dJiKgJdVrUtr0H8qc9kZRoXy8TKHTsbMTJONq+qXVeaPiLdLEc+7\n+FgXxPgiLWEHx0L0j4TYurbRNb2fy0Ft0E9VhXdOT+1Sc6jbqOzcuMz6qcsvz6WkV/9WOriFq5vI\n1fN+5ZjRw3vrulN3sHA+KIpCa0MVA6OhgoeELAVLvPPp6OlmRLxdSmbYRDzvYpBrb5P9x0YA2HoK\nT4XPl7aGKqLxJKOT5Ztpeah7DEVZfpOMRLxdSnpsr8rmHsqnCrn2NjnUM0Z1pY+VEu+eQ2ujsYBb\nrtBJKBLnSN8Ea1prbO8lXm5EvF2KJ+2bq5QFy6KQS563ruuMTERobagqeEDtqUibmapn9dUuNS8f\nHiIWT3L2aa1l+TwnIeLtUjzieRcdK1VwIc87FIkTiyeX5bzKXEiJd5k8byuzZTm2NxbxdileyTYp\nOrnEvMemjFhufU1FWWxyG+UOm/QMmk3ZljAz9lRBznqXkj6cQfK8i0MuXQWthbjlVAyyFJpqK/F6\nFE6OzO1xMhmK8V937cPrUfjILacXZWBCz+AUtUE/dcHl932I5+1SatN+rJXieReFXGLeY+Z0cgmb\nZMfjUWhvCtI7ND0nXfCO+zRePjzEiwcHOdJXeOvYSCzBwGiIlc3Lz+sGEW/Xkj4AQGLexSGXlrAS\nNlmc1a3VhM3RfPc8dYx4IknP4BRP7z+Zes2Dz3YV/Dm9Q1PowMplGDIBCZu4lvTKPr9PrsHFwJND\nS9ixSUu8xfOej86OWp7ef5JHX+oBjIVgq+vfh27ezm+fOMaT+/pprq/kjZetTy0UL5VD3Yb3vpx6\neKcj4i0IJrmETUanJGyyGFeetQrt+CijExGOn5zkRw8eAIxjds5prYxPRfnBAwf47RPHmArFePfr\ntiz5M5JJnSf39QHYOrHeTvISb1VVfcB/AxvNfXxS07THimmYsDiff+95xOPlK0M+1VEUBY+iLJxt\nYnne1RI2mY+qCh8ff/OZAPzowQPc94zRZfD6izrxeT2cv7WdHzxgCPojL/Zw3QVraamvXFKfmIee\n7+JQ9zjnqa20NwWL/59wAfl63u8CpjRNu1RV1e3Ad4ALimeWkAvrOpZXOXA58HgWEe+pKNWVPglV\n5cjbrt7M9ReupXtwiq2dRjuB+uoAn3vPeTy2u5eHX+jmM996kot3dPCBG7flvN/7njlBhd/Lu16r\nlsp0x5PvL/AO4BPm4wGguTjmCIK9eL3Kotkmsli5NOprKti2rimjpcP6FXVcdfaq1N+79vQRisRz\n2t/EtNECVl3bkJF1tdzIy/PWNC0GWOMyPg78YLH3NDYG8fnyz0dubXXHooRb7AT32FpOO31eD4pH\nyfqZsXiCqXCcTWsasj7vluMJzrC1tbWWt12r8qP7NQBOTkQ5b3XjnNfMpvfgAADquiZH/D/AnuO5\nqHirqvoB4AOzNv9vTdPuVVX1w8A5wE2L7WckS9J+rrS21jIwMJH3+8uFW+wE99habjs9CkSi8ayf\naWVMVAW8c553y/EEZ9l63bmrWNlYyT//5CWe3dtLZ8tM/Ho+O/cfGgSgIeh3xP+j1MdzvgvDouKt\nadptwG2zt6uqeiuGaL/R9MQFwfUsFPMeHjcyTZpqZW5lMTEm4IB2fDSn1/cNG45gxzJdqLTIK+at\nquoG4EPALZqmhYtrkiDYh9czf8x7eNz4qTfXScy7mFRV+Ohsr+Vg9xhP7O1b9PX9w8YdUHujiHc+\nfABjkfJuVVUfMf8t35UD4ZTBu4DnPWSKd1OdeN7F5r3Xb6Ey4OX2ezVGzRYE89E/PE1d0E+wcnmX\nqeS7YPkZ4DNFtkUQbMfj8ZCIZc96sMImzSLeRWdtey1vvHQ9P3roIC+8OsBV56zO+rp4IsnAWGjZ\njTzLhiSrCkIavgXCJuJ5l5ZzzIEKDzzXxfh09jFqfUPT6DrLtjAnHRFvQUjDWLDM3hJ2aDxMVYV3\n2d+ul4qWhiquOmcVvUPT/PIPR7K+5oUDZprgMi2JT0fEWxDSWDjbJCxed4l55zWnUVcd4Jn9/cTi\ncy+ie48Moyhw9ublN/ZsNiLegpDGfGGTcDROKJKgQaorS4rHo3Dh1namwnF+/vCB1HZd1/nRgwd4\ntWuMNW01cveDiLcgZODxKCQS+pxBAuNmH+8G6SZYcq47fw1VFT5+9vABegan+O0TR3lOG0g1uLri\nzJX2GugQ5PIlCGn4fR50jDmWPu9MLw5rCEOd9PEuOc31lVxz7mru2nWUz972VMZzf3rjNnbu6LDJ\nMmchnrcgpOE325LOjrdKK9jyctMl67jsrFUZ2647f40IdxrieQtCGn6/0TwtGk9SlabTqfFnEjYp\nCz6vh0/9ybm89coN9A5PU13pX/bl8LMR8RaENAJmn+5YLJGx3RJvmRpfPhRFIVjpZ+NKKcjJhoRN\nBCENa8hCLJEZNhk3x5/ViectOAQRb0FIwxLvvuFpvvKD59l9aAiQmLfgPES8BSENS7zvfOQQrxwf\n5bbf7ANgdCqK3+ehqiL/gSKCUExEvAUhjYA57cnqGT0ZinGkd5zB0RDNdZUZo7wEwU5EvAUhDWvB\nMr1G585HDjEVjrOiWbIdBOcg2SaCkIYvbSr8qpZq4okk+4+NALCiudouswRhDuJ5C0IagTTxbqgJ\ncMbGltTf6lrpZCc4BxFvQUjDinkDNNRUcMVZK/F6FJrrKqUNqeAoJGwiCGlUBNLEu7aClS3V/P2f\nXkhtVYCAXzJNBOcg4i0IaTSlDRe22r8u90G3gjORsIkgpJE+bEFK4QUnI+ItCGnUVvlTj9e219po\niSAsjIRNBCENRVH4o8vW4/V6aG2ostscQZgXEW9BmMVNl6y32wRBWBQJmwiCILgQEW9BEAQXIuIt\nCILgQkS8BUEQXIiItyAIggsR8RYEQXAhIt6CIAguRMRbEATBhSh6+sgQQRAEwRWI5y0IguBCRLwF\nQRBciIi3IAiCCxHxFgRBcCEi3oIgCC5ExFsQBMGFiHgLgiC4EEcPY1BV9WvARYAOfEzTtGdsNgkA\nVVV3AL8CvqZp2jdUVV0D3A54gV7gXZqmRVRVfSfwcSAJfEvTtP8us51fAS7D+J7/AXjGaXaqqhoE\nvgu0A5XAF4GXnGZnmr1VwB7TzgedaKeqqlcCPwX2mpteBr7iUFvfCXwaiAOfB3Y7zU5VVW8F3pW2\n6TzgEuD/YmjTbk3T/sx87aeAN5vb/1bTtLtLZZdji3RUVb0C+JSmaTeqqroV+LamaTsdYFc18Bvg\nAMaX9g1VVb8D3K1p2k9VVf0ScAL4PvA8cAEQxRDOyzVNGy6TnVdhHL/Xq6raDLyAITZOs/OtQKem\naV9RVbUTuB943Gl2ptn7f4DrgH8HrnCinaZ4f0TTtDelbXPib7QZeAI4F6gB/hbwO83OWTZfAbwF\n2AZ8WtO0Z1RV/QHGBecV4E5gJ1AP/AHYrmlaohS2ODlscjXwSwBN0/YDjaqq1tlrEgAR4PVAT9q2\nK4Ffm4/vAq4BLgSe0TRtTNO0EIYgXVJGOx/F8AAARoFqJ9qpadqPNU37ivnnGqDLiXYCqKq6BeOk\n/a25yZF2zsOVOM/Wa4AHNE2b0DStV9O0DzrUznQ+D/z/wPq0SIBl51XAPZqmRTVNGwCOYfxeSoKT\nwyYdwHNpfw+Y28btMcdA07Q4EFdVNX1ztaZpEfPxSWAFhq0Daa+xtpcF82o/Zf55K3A38Fqn2Wmh\nquouYDVwI8YJ7UQ7/wn4CPAe82/Hfe9pbFNV9ddAE4ZH60Rb1wFB085G4As4004AVFU9H+NOIA6M\nZLFniOx2vlwKe5zsec9GsduAHJnPTlvsV1X1Zgzx/sispxxlp6ZpFwNvAO6YZYMj7FRV9d3AE5qm\nHVmiPXYczwMYgn0zxoXmv8l01JxiqwI0A7cA7wW+gwO/+zQ+gLE+Mxtb7HSyePdgXHEtVmIsYDiR\nSXMhC2AVhu2z7be2lw1VVV8L/A1wvaZpY060U1XVc80FXzRNexFDZCacZidwA3CzqqpPYpzEn8OB\nxxNA07RuMxyla5p2COjDCDs6zdZ+YJemaXHTzgmc+d1bXAnswvCum7PYU1Y7nSze9wFvAlBV9Ryg\nR9O0CXtNmpcHgD82H/8x8DvgKeB8VVUbVFWtwYjR/aFcBqmqWg/8I3Bj2sKO4+wELgf+l2lzO8bC\nlePs1DTtrZqmna9p2kXAbRjZJo6zE4wMDlVVP2k+7sDI5PmOA229D3iNqqoec/HSkd89gKqqK4FJ\nM54dA15RVfVS8+lbTDsfAm5QVTVgvn4VsK9UNjk22wRAVdUvY5zcSeDDmqa9ZLNJqKp6Lkbscx0Q\nA7qBd2LcTlViLFK8T9O0mKqqbwI+hZE29G+apv1PGe38IEYM8dW0ze/BEB4n2VmFcVu/BqjCuN1/\nFiPDwDF2zrL5C8BR4F4n2qmqai3wA6ABCGAc0xccauv/hxHWA/h7jEwSJ9p5LvD3mqZdb/69Dfgm\nhgP8lKZpnzC3fxRDD3Tgs5qmPVgqmxwt3oIgCEJ2nBw2EQRBEOZBxFsQBMGFiHgLgiC4EBFvQRAE\nFyLiLQiC4EJEvAVBEFyIiLcgCIIL+X8Nqj03ym2mygAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "idx_s = np.where(y_train == 1)[0]\n", "plt.plot(X_train[idx_s[0]])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "7E6nqH2CIMYR" }, "source": [ "本章の目的は,ECGシグナル特徴をうまく捉え,新たな波形サンプルに対しても高精度に正常/異常を予測するモデルを構築することです.\n", "\n", "次節では,深層学習を利用したモデル構築について説明していきます." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "kQEqTIlmTxPw" }, "source": [ "## 深層学習を用いた時系列データ解析" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "irPb5xvfm_5j" }, "source": [ "### 学習" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Klt1--j8Iw08" }, "source": [ "まず,前節で準備した前処理済みデータをChainerで読み込むためのデータセットクラスを定義します." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "colab": {}, "colab_type": "code", "id": "oR3zBpQlTuWH" }, "outputs": [], "source": [ "class ECGDataset(chainer.dataset.DatasetMixin):\n", "\n", " def __init__(\n", " self,\n", " path\n", " ):\n", " if os.path.isfile(os.path.join(path, 'X.npy')):\n", " self.X = np.load(os.path.join(path, 'X.npy'))\n", " else:\n", " raise FileNotFoundError(\"{}/X.npy not found.\".format(path))\n", " if os.path.isfile(os.path.join(path, 'y.npy')):\n", " self.y = np.load(os.path.join(path, 'y.npy'))\n", " else:\n", " raise FileNotFoundError(\"{}/y.npy not found.\".format(path))\n", "\n", " def __len__(self):\n", " return len(self.X)\n", "\n", " def get_example(self, i):\n", " return self.X[None, i].astype(np.float32), self.y[i]\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "iNR4iHrWIsH3" }, "source": [ "続いて,学習(+予測)に利用するネットワーク構造を定義します.\n", "\n", "今回は,画像認識タスクで有名な,CNNベースの**ResNet34**と同様のネットワーク構造を利用します.[[5](https://arxiv.org/abs/1512.03385)]\n", "\n", "ただし,入力シグナルは1次元配列であることから,ここでは画像解析等で一般的に利用される2D Convolutionではなく,前章の遺伝子解析と同様,1D Convolutionを利用します." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "colab": {}, "colab_type": "code", "id": "i_uVEjDIT4s0" }, "outputs": [], "source": [ "import chainer.functions as F\n", "import chainer.links as L\n", "from chainer import reporter\n", "from chainer import Variable\n", " \n", " \n", "class BaseBlock(chainer.Chain):\n", "\n", " def __init__(\n", " self,\n", " channels,\n", " stride=1,\n", " dilate=1\n", " ):\n", " self.stride = stride\n", " super(BaseBlock, self).__init__()\n", " with self.init_scope():\n", " self.c1 = L.ConvolutionND(1, None, channels, 3, stride, dilate, dilate=dilate)\n", " self.c2 = L.ConvolutionND(1, None, channels, 3, 1, dilate, dilate=dilate)\n", " if stride > 1:\n", " self.cd = L.ConvolutionND(1, None, channels, 1, stride, 0)\n", " self.b1 = L.BatchNormalization(channels)\n", " self.b2 = L.BatchNormalization(channels)\n", "\n", " def __call__(self, x):\n", " h = F.relu(self.b1(self.c1(x)))\n", " if self.stride > 1:\n", " res = self.cd(x)\n", " else:\n", " res = x\n", " h = res + self.b2(self.c2(h))\n", " return F.relu(h)\n", "\n", "\n", "class ResBlock(chainer.Chain):\n", "\n", " def __init__(\n", " self,\n", " channels,\n", " n_block,\n", " dilate=1\n", " ):\n", " self.n_block = n_block\n", " super(ResBlock, self).__init__()\n", " with self.init_scope():\n", " self.b0 = BaseBlock(channels, 2, dilate)\n", " for i in range(1, n_block):\n", " bx = BaseBlock(channels, 1, dilate)\n", " setattr(self, 'b{}'.format(str(i)), bx)\n", "\n", " def __call__(self, x):\n", " h = self.b0(x)\n", " for i in range(1, self.n_block):\n", " h = getattr(self, 'b{}'.format(str(i)))(h)\n", " return h\n", "\n", "\n", "class ResNet34(chainer.Chain):\n", "\n", " def __init__(self):\n", " super(ResNet34, self).__init__()\n", " with self.init_scope():\n", " self.conv1 = L.ConvolutionND(1, None, 64, 7, 2, 3)\n", " self.bn1 = L.BatchNormalization(64)\n", " self.resblock0 = ResBlock(64, 3)\n", " self.resblock1 = ResBlock(128, 4)\n", " self.resblock2 = ResBlock(256, 6)\n", " self.resblock3 = ResBlock(512, 3)\n", " self.fc = L.Linear(None, 2)\n", "\n", " def __call__(self, x):\n", " h = F.relu(self.bn1(self.conv1(x)))\n", " h = F.max_pooling_nd(h, 3, 2)\n", " for i in range(4):\n", " h = getattr(self, 'resblock{}'.format(str(i)))(h)\n", " h = F.average(h, axis=2)\n", " h = self.fc(h)\n", " return h\n", " \n", "\n", "class Classifier(chainer.Chain):\n", "\n", " def __init__(\n", " self,\n", " predictor,\n", " lossfun=F.softmax_cross_entropy\n", " ):\n", " super(Classifier, self).__init__()\n", " with self.init_scope():\n", " self.predictor = predictor\n", " self.lossfun = lossfun\n", "\n", " def __call__(self, *args):\n", " assert len(args) >= 2\n", " x = args[:-1]\n", " t = args[-1]\n", " y = self.predictor(*x)\n", "\n", " # loss\n", " loss = self.lossfun(y, t)\n", " with chainer.no_backprop_mode():\n", " # other metrics\n", " accuracy = F.accuracy(y, t)\n", " # reporter\n", " reporter.report({'loss': loss}, self)\n", " reporter.report({'accuracy': accuracy}, self)\n", "\n", " return loss\n", "\n", " def predict(self, x):\n", " with chainer.function.no_backprop_mode(), chainer.using_config('train', False):\n", " x = Variable(self.xp.asarray(x, dtype=self.xp.float32))\n", " y = self.predictor(x)\n", " return y\n", " " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "n2jCNB2zJCWa" }, "source": [ "学習を実行するための準備として,以下の関数を用意します.\n", "\n", "- `create_train_dataset()`:学習用データセットを `ECGDataset` クラスに渡す\n", "- `create_trainer()`:学習に必要な設定を行い,Trainerオブジェクトを作成\n" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "colab": {}, "colab_type": "code", "id": "YLOg6cJzT8EA" }, "outputs": [], "source": [ "from chainer import optimizers\n", "from chainer.optimizer import WeightDecay\n", "from chainer.iterators import MultiprocessIterator\n", "from chainer import training\n", "from chainer.training import extensions\n", "from chainer.training import triggers\n", "from chainer.backends.cuda import get_device_from_id\n", "\n", "\n", "def create_train_dataset(root_path):\n", " train_path = os.path.join(root_path, 'preprocessed', 'train')\n", " train_dataset = ECGDataset(train_path)\n", "\n", " return train_dataset\n", "\n", "\n", "def create_trainer(\n", " batchsize, train_dataset, nb_epoch=1,\n", " device=0, lossfun=F.softmax_cross_entropy\n", "):\n", " # setup model\n", " model = ResNet34()\n", " train_model = Classifier(model, lossfun=lossfun)\n", "\n", " # use Adam optimizer\n", " optimizer = optimizers.Adam(alpha=0.001)\n", " optimizer.setup(train_model)\n", " optimizer.add_hook(WeightDecay(0.0001))\n", "\n", " # setup iterator\n", " train_iter = MultiprocessIterator(train_dataset, batchsize)\n", "\n", " # define updater\n", " updater = training.StandardUpdater(train_iter, optimizer, device=device)\n", "\n", " # setup trainer\n", " stop_trigger = (nb_epoch, 'epoch')\n", " trainer = training.trainer.Trainer(updater, stop_trigger)\n", " logging_attributes = [\n", " 'epoch', 'iteration',\n", " 'main/loss', 'main/accuracy' \n", " ]\n", " trainer.extend(\n", " extensions.LogReport(logging_attributes, trigger=(2000 // batchsize, 'iteration'))\n", " )\n", " trainer.extend(\n", " extensions.PrintReport(logging_attributes)\n", " )\n", " trainer.extend(\n", " extensions.ExponentialShift('alpha', 0.75, optimizer=optimizer),\n", " trigger=(4000 // batchsize, 'iteration')\n", " )\n", "\n", " return trainer" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "c4xYAJmBgJqY" }, "source": [ "これで学習の準備が整ったので,関数を呼び出してtrainerを作成します." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "colab": {}, "colab_type": "code", "id": "LrhgE0WKUBxz" }, "outputs": [], "source": [ "train_dataset = create_train_dataset(dataset_root)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "colab": {}, "colab_type": "code", "id": "uXfgr6e9UE4w" }, "outputs": [], "source": [ "trainer = create_trainer(256, train_dataset, nb_epoch=1, device=0)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "JdDyLjLNJOFX" }, "source": [ "それでは学習を開始しましょう. (1分30秒程度で学習が完了します.)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 510 }, "colab_type": "code", "id": "aeNkaPdFUIfQ", "outputId": "56e74e4a-0490-49d7-96e6-b8aea04e4890" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "epoch iteration main/loss main/accuracy\n", "\u001b[J0 7 1.1307 0.868304 \n", "\u001b[J0 14 0.273237 0.923549 \n", "\u001b[J0 21 0.0950281 0.96596 \n", "\u001b[J0 28 0.058416 0.982701 \n", "\u001b[J0 35 0.0658751 0.982143 \n", "\u001b[J0 42 0.0506687 0.985491 \n", "\u001b[J0 49 0.057125 0.986607 \n", "\u001b[J0 56 0.063658 0.986607 \n", "\u001b[J0 63 0.0600915 0.981027 \n", "\u001b[J0 70 0.0391555 0.988281 \n", "\u001b[J0 77 0.0325103 0.991629 \n", "\u001b[J0 84 0.0344455 0.987723 \n", "\u001b[J0 91 0.0281526 0.989955 \n", "\u001b[J0 98 0.0266191 0.991629 \n", "\u001b[J0 105 0.0318078 0.990513 \n", "\u001b[J0 112 0.0304052 0.991071 \n", "\u001b[J0 119 0.0293185 0.993304 \n", "\u001b[J0 126 0.0290823 0.989397 \n", "\u001b[J0 133 0.019204 0.996094 \n", "\u001b[J0 140 0.0177221 0.994978 \n", "\u001b[J0 147 0.0218593 0.990513 \n", "\u001b[J0 154 0.019589 0.994978 \n", "\u001b[J0 161 0.0257332 0.991629 \n", "\u001b[J0 168 0.0155559 0.99442 \n", "\u001b[J0 175 0.0161097 0.99442 \n", "\u001b[J0 182 0.0212924 0.992746 \n", "CPU times: user 1min 12s, sys: 14.7 s, total: 1min 27s\n", "Wall time: 1min 27s\n" ] } ], "source": [ "%time trainer.run()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "OBpKeAFpvpWD" }, "source": [ "学習が問題なく進めば,main/accuracyが0.99 (99%)付近まで到達していると思います." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NpgKemAtnV_f" }, "source": [ "### 評価" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dX54l8duJUqC" }, "source": [ "学習したモデルを評価用データに当てはめて識別性能を確認するため,以下の関数を用意します.\n", "\n", "- `create_test_dataset()` : 評価用データの読み込み\n", "- `predict()` : 推論を行い,結果の配列(正解ラベルと予測ラベル)を出力\n", "- `print_confusion_matrix()` : 予測結果から混同行列とよばれる表を出力\n", "- `print_scores()` : 予測結果から予測精度の評価指標を出力" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "colab": {}, "colab_type": "code", "id": "5CtgdOcbdn2i" }, "outputs": [], "source": [ "from chainer import cuda\n", "from sklearn.metrics import classification_report\n", "from sklearn.metrics import accuracy_score\n", "from sklearn.metrics import confusion_matrix\n", "\n", "\n", "def create_test_dataset(root_path):\n", " test_path = os.path.join(root_path, 'preprocessed', 'test')\n", " test_dataset = ECGDataset(test_path)\n", " return test_dataset\n", "\n", " \n", "def predict(trainer, test_dataset, batchsize, device=-1):\n", " model = trainer.updater.get_optimizer('main').target\n", " ys = []\n", " ts = []\n", " for i in range(len(test_dataset) // batchsize + 1):\n", " if i == len(test_dataset) // batchsize:\n", " X, t = zip(*test_dataset[i*batchsize: len(test_dataset)])\n", " else:\n", " X, t = zip(*test_dataset[i*batchsize:(i+1)*batchsize])\n", " X = cuda.to_gpu(np.array(X), device)\n", " y = model.predict(X)\n", " y = cuda.to_cpu(y.data.argmax(axis=1))\n", " ys.append(y)\n", " ts.append(np.array(t))\n", " return np.concatenate(ts), np.concatenate(ys)\n", "\n", " \n", "def print_confusion_matrix(y_true, y_pred):\n", " labels = sorted(list(set(y_true)))\n", " target_names = ['Normal', 'VEB']\n", " cmx = confusion_matrix(y_true, y_pred, labels=labels)\n", " df_cmx = pd.DataFrame(cmx, index=target_names, columns=target_names)\n", " plt.figure(figsize = (5,3))\n", " sn.heatmap(df_cmx, annot=True, annot_kws={\"size\": 18}, fmt=\"d\", cmap='Blues')\n", " plt.show()\n", " \n", "\n", "def print_scores(y_true, y_pred):\n", " target_names = ['Normal', 'VEB']\n", " print(classification_report(y_true, y_pred, target_names=target_names))\n", " print(\"accuracy: \", accuracy_score(y_true, y_pred))\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "MJsomKvlyvr2" }, "source": [ "評価用データセットを用意し," ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "colab": {}, "colab_type": "code", "id": "FNq4f8m3nVBW" }, "outputs": [], "source": [ "test_dataset = create_test_dataset(dataset_root)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "EU-hnKu_yVwF" }, "source": [ "評価用データに対して予測を行います. (17秒程度で予測が完了します)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 51 }, "colab_type": "code", "id": "TFq-W4Bgnjzg", "outputId": "1e6be355-34e8-40e4-83d4-51e6299d852e" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 15.6 s, sys: 2.73 s, total: 18.3 s\n", "Wall time: 18.3 s\n" ] } ], "source": [ "%time y_true_test, y_pred_test = predict(trainer, test_dataset, 256, 0)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "U3GsrOipy4BO" }, "source": [ "それでは予測結果を確認していきましょう.\n", "\n", "まずは, **混同行列** とよばれる,予測の分類結果をまとめた表を作成します.行方向(表側)を正解ラベル,列方向(表頭)を予測ラベルとして,各項目では以下の集計値を求めています.\n", "\n", "* 左上 : 実際に正常拍動であるサンプルが,正常拍動と予測された数\n", "* 右上 : 実際に正常拍動であるサンプルが,VEBと予測された数\n", "* 左下 : 実際にVEBであるサンプルが,正常と予測された数\n", "* 右下 : 実際にVEBであるサンプルが,VEBと予測された数" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 211 }, "colab_type": "code", "id": "o1hGRaQ2HuLN", "outputId": "d961ed23-246e-452c-8893-7d8f2ff32e1b" }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAATcAAADCCAYAAAAsCoUsAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzt3XmcTeUfwPHPndUwGUKWsQ++Ub9U\nQkVFY89S9jVbZUm2Vu2UUmRJ1mwRRYTIvpNIFAmPLNmFMBjMzJ2Z3x/nmuYaM3eMmTFz5vvudV6v\ne5/7nHOeZ3K/99nOOY7Y2FiUUspuvG53AZRSKi1ocFNK2ZIGN6WULWlwU0rZkgY3pZQtaXBTStmS\nT1qfIOCBHrrWJJM6umH47S6CugV5cvg4UrJfcr6zV377IkXHTk9pHtyUUpmMl/ftLkGq0OCmlHLn\nsMdolQY3pZQ7bbkppWzJkeGH05JFg5tSyp223JRStqRjbkopW9KWm1LKljS4KaVsSbulSilb8taW\nm1LKjnQpiFLKlnTMTSllSzrmppSyJW25KaVsScfclFK2pC03pZQtedkjLNijFkqp1KPdUqWULWm3\nVCllS7oURCllRw4vDW5KKRty6JibUsqOHF4a3JRSNuSl3VKllB1pt1QpZUvaLVVK2ZK23JRStnSr\nY24ikh2YAuQHsgEfANuByYAvEAW0NcacFJE2QG8gBhhvjJkoIr6u/YsB0UBHY8wBESkPjAFigR3G\nmG5J1uOWaqGUsh9HMrakNQB+NcY8ATQHhgIfYgWvJ4C5QF8RyQG8C9QAqgF9ROROoDVw3hhTFRgI\nfOw67nCglzGmChAkInWTKoS23JRSbm615WaMmRnvbRHgKNAduOpKOw08CFQGthhjwgBE5CegChAK\nTHXlXQFMEhE/oIQxZosrfQFWUFycWDk0uCml3KTWhIKIbAQKA/WNMeGuNG/gRWAAUAAr0F1zCigY\nP90YEyMisa60czfIm6gsE9zqPX4vfdvXoFypQvj5evPH3mMMn7qS+au2x+WpX+1/vNyhJveVKYwz\nOpr1W/fRb9hc/jp0Ki7P0i978fhDpW94jkFfLqH/6IU3/KzKgyEs+7IXG7btp/bzIxJ8/r8ywUwb\n1BEpUYDyz3zA3r//ucUa29uWzT8zcdwozJ7d+Pn5UbJkKdp1ep5Hqz4el+fKlct8OeYLVi5bQljY\n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\nAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "print_confusion_matrix(y_true_test, y_pred_test)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "V42Ay9Hr1c9X" }, "source": [ "続いて,予測結果から計算される予測精度の評価指標スコアを表示してみましょう.\n", "\n", "特に,以下のスコアに注目してみてください.\n", "\n", "* 適合率 (Precision) : それぞれの予測診断結果 (Normal or VEB) のうち,正しく診断できていた(正解も同じ診断結果であった)割合\n", "* 再現率 (Recall) : それぞれの正解診断結果 (Normal or VEB) のうち,正しく予測できていた(予測も同じ診断結果であった)割合\n", "* F1値 (F1-score) : 適合率と再現率の調和平均\n", "* 正解率 (Accuracy) : 全ての診断結果 (Normal and VEB) のうち,正しく予測できていた(予測も同じ診断結果であった)割合\n", "\n", "また,クラスごとのスコアの下に,複数の平均スコアが表示されていますが,それぞれの意味は以下の通りです.\n", "\n", "* マイクロ平均 (micro avg) : 各クラスを区別せずに,混同行列全体からスコアを算出.計算結果はいずれも正解率と一致\n", "* マクロ平均 (macro avg) : クラスごとに算出されたスコアの単純平均\n", "* 重み付き平均 (weighted avg) : クラスごとに算出されたスコアをサンプル数の比率で重み付けした加重平均\n" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 187 }, "colab_type": "code", "id": "2lzEaH9oyvEP", "outputId": "e8cece60-bce5-489d-b1a6-6eff028d7f9f" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Normal 0.99 0.94 0.96 42149\n", " VEB 0.52 0.90 0.66 3200\n", "\n", " micro avg 0.94 0.94 0.94 45349\n", " macro avg 0.76 0.92 0.81 45349\n", "weighted avg 0.96 0.94 0.94 45349\n", "\n", "accuracy: 0.9351694634942336\n" ] } ], "source": [ "print_scores(y_true_test, y_pred_test)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "PVjh6T9l1hC7" }, "source": [ "サンプル数が多い正常拍動に対する予測スコアは高い値を示す一方で,サンプル数の少ないVEBに対しては,スコアが低くなる傾向があります.今回のデータセットのように,サンプルが占めるクラスの割合が極端に偏っている不均衡データでは,こうした傾向がしばしば観測されることが知られています.\n", "\n", "次節では,このようなクラス不均衡問題への対応をはじめとして,予測モデルを改善するための試行錯誤について幾つか紹介していきます.\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "YZK61esDYVYO" }, "source": [ "## 精度向上に向けて" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "vYgRRiSl0NCG" }, "source": [ "本節では,前節にて構築した学習器に対して,「データセット」「目的関数」「学習モデル」「前処理」といった様々な観点で工夫を行うことで,精度改善に寄与する方法を模索していきます.\n", "\n", "機械学習を用いて解析を行う際には,どの工夫が精度改善に有効なのか予め分からない場合が多く,試行錯誤が必要となります.ただし,手当たり次第の方法を試すことは得策では無いので,対象とするデータセットの性質に基づいて,有効となり得る手段を検討していくことが重要となります.\n", "\n", "まずはじめに,前節でも課題として挙がっていた,クラス不均衡の問題への対処法から検討していきましょう." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "KPTsLjqklF30" }, "source": [ "### クラス不均衡データへの対応" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "nVCVJPDf4PVc" }, "source": [ "前節でも触れたように,**クラス不均衡データ**を用いて学習器を構築する際,大多数を占めるクラスに偏った予測結果となり,少数のクラスに対して精度が低くなってしまう場合があることが一般的に知られています.一方で,(今回のデータセットを含めて)現実世界のタスクにおいては,大多数の正常サンプルの中に含まれる少数の異常サンプルを精度良く検出することが重要であるというケースは少なくありません.こうした状況において,少数クラスの検出に注目してモデルを学習するための方策が幾つか存在します.\n", "\n", "具体的には,\n", "\n", "1. **サンプリング**\n", " - 不均衡データセットからサンプリングを行い,クラス比率のバランスが取れたデータセットを作成.\n", " - **Undersampling** : 大多数の正常サンプルを削減.\n", " - **Oversampling** : 少数の異常サンプルを水増し.\n", "1. **損失関数の重み調整**\n", " - 正常サンプルを異常と誤分類した際のペナルティを小さく,異常サンプルを正常と誤分類した際のペナルティを大きくする.\n", " - 例えば,サンプル数の存在比率の逆数を重みとして利用.\n", "1. **目的関数(損失関数)の変更**\n", " - 異常サンプルに対する予測スコアを向上させるような目的関数を導入.\n", "1. **異常検知**\n", " - 正常サンプルのデータ分布を仮定し,そこから十分に逸脱したサンプルを異常とみなす.\n", "\n", "などの方法があります.本節では,「1.サンプリング」,「3.目的関数の変更」の例を紹介していきます." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "u6tD0TqYYt1D" }, "source": [ "#### サンプリング\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "_enZyrwC-hDg" }, "source": [ "**Undersampling**と**Oversampling**を組み合わせて,データセットの不均衡を解消することを考えます.\n", "\n", "今回は以下のステップでサンプリングを行います.\n", "\n", "1. Undersamplingにより,正常拍動サンプルのみ1/4に削減 (VEBサンプルは全て残す)\n", " * ここでは,単純なランダムサンプリングを採用します.ランダム性があるため,分類にとって重要な(VEBサンプルとの識別境界付近にある)サンプルを削除してしまう可能性があります.\n", " * ランダムサンプリングの問題を緩和する手法も幾つか存在しますが,今回は使用しません.\n", "1. Oversamplingにより,Undersampling後の正常拍動サンプルと同数になるまでVEBサンプルを水増し\n", " * SMOTE (Synthetic Minority Over-sampling TEchnique) という手法を採用します.\n", " * ランダムにデータを水増しする最も単純な方法だと,過学習を引き起こしやすくなります.SMOTEでは,VEBサンプルと,その近傍VEBサンプルとの間のデータ点をランダムに生成してデータに追加していくことで,過学習の影響を緩和しています.\n", "\n", "サンプリングを行うために, `SampledECGDataset` クラスを定義します.\n", "\n", "また,そのクラスを読み込んで学習用データセットオブジェクトを作成する `create_sampled_train_datset()` 関数を用意します.\n" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "colab": {}, "colab_type": "code", "id": "91tUbBvilRxG" }, "outputs": [], "source": [ "from imblearn.datasets import make_imbalance\n", "from imblearn.over_sampling import SMOTE\n", "\n", "\n", "class SampledECGDataset(ECGDataset):\n", "\n", " def __init__(\n", " self,\n", " path\n", " ):\n", " super(SampledECGDataset, self).__init__(path)\n", " _, counts = np.unique(self.y, return_counts=True)\n", " self.X, self.y = make_imbalance(\n", " self.X, self.y,\n", " sampling_strategy={0: counts[0]//4, 1: counts[1]}\n", " )\n", " smote = SMOTE(random_state=42)\n", " self.X, self.y = smote.fit_sample(self.X, self.y)\n", "\n", " \n", "def create_sampled_train_dataset(root_path):\n", " train_path = os.path.join(root_path, 'preprocessed', 'train')\n", " train_dataset = SampledECGDataset(train_path)\n", "\n", " return train_dataset" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "colab": {}, "colab_type": "code", "id": "pdpAAftuwfBD" }, "outputs": [], "source": [ "train_dataset = create_sampled_train_dataset(dataset_root)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "tLJ3AGo9bmNH" }, "source": [ "それでは先程と同様に,trainerを作成して学習を実行してみましょう.(1分程度で学習が完了します.)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 476 }, "colab_type": "code", "id": "UpyvYJMyoxOM", "outputId": "e134c606-8630-448f-e4bd-a62155bdc8cb" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "epoch iteration main/loss main/accuracy\n", "\u001b[J0 7 1.55422 0.71317 \n", "\u001b[J0 14 0.282043 0.902344 \n", "\u001b[J0 21 0.161596 0.939174 \n", "\u001b[J0 28 0.109996 0.960379 \n", "\u001b[J0 35 0.0750687 0.976004 \n", "\u001b[J0 42 0.0759563 0.969866 \n", "\u001b[J0 49 0.0531007 0.979911 \n", "\u001b[J0 56 0.0477525 0.984375 \n", "\u001b[J0 63 0.0657228 0.981585 \n", "\u001b[J0 70 0.0559838 0.979911 \n", "\u001b[J0 77 0.0410638 0.985491 \n", "\u001b[J0 84 0.0311444 0.989397 \n", "\u001b[J1 91 0.0260796 0.993304 \n", "\u001b[J1 98 0.0306111 0.990513 \n", "\u001b[J1 105 0.0267346 0.987165 \n", "\u001b[J1 112 0.0161048 0.995536 \n", "\u001b[J1 119 0.0202833 0.991629 \n", "\u001b[J1 126 0.0112008 0.998326 \n", "\u001b[J1 133 0.0164346 0.99442 \n", "\u001b[J1 140 0.0189331 0.992746 \n", "\u001b[J1 147 0.0153746 0.99442 \n", "\u001b[J1 154 0.0173289 0.994978 \n", "\u001b[J1 161 0.01027 0.996094 \n", "\u001b[J1 168 0.01294 0.995536 \n", "CPU times: user 55.1 s, sys: 13.4 s, total: 1min 8s\n", "Wall time: 1min 8s\n" ] } ], "source": [ "trainer = create_trainer(256, train_dataset, nb_epoch=2, device=0)\n", "%time trainer.run()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "LL0k_u5ubzv0" }, "source": [ "学習が完了したら,評価用データで予測を行い,精度を確認してみましょう." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 51 }, "colab_type": "code", "id": "n3P1Mqnhpkrc", "outputId": "fba2a196-25db-4b98-80dc-3e04d572ee4a" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 15.1 s, sys: 2.91 s, total: 18 s\n", "Wall time: 18 s\n" ] } ], "source": [ "%time y_true_test, y_pred_test = predict(trainer, test_dataset, 256, 0)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 211 }, "colab_type": "code", "id": "ThK6B8xppt8W", "outputId": "62ccc54d-799c-4e97-aca2-90268b75d290" }, "outputs": [ { "data": { "image/png": "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\nAAAASUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "print_confusion_matrix(y_true_test, y_pred_test)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 187 }, "colab_type": "code", "id": "DM8aI7hOpuA1", "outputId": "20ced470-d164-413f-c8ff-d217d35897fe" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Normal 1.00 0.91 0.95 42149\n", " VEB 0.45 0.96 0.61 3200\n", "\n", " micro avg 0.91 0.91 0.91 45349\n", " macro avg 0.72 0.93 0.78 45349\n", "weighted avg 0.96 0.91 0.93 45349\n", "\n", "accuracy: 0.9144854351804891\n" ] } ], "source": [ "print_scores(y_true_test, y_pred_test)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HWg_Xn_Xb77g" }, "source": [ "先程の予測結果と比較して,サンプリングの効果によりVEBサンプルに対する検出精度(特にrecall)が向上しているかを確認してみて下さい.\n", "\n", "(サンプリングのランダム性や,学習の初期値依存性などの影響があるため,必ず精度向上するとは限らないことにご注意下さい.)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "0LtXj5nrpztA" }, "source": [ "#### 損失関数の変更" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "0mF7a6A_h38t" }, "source": [ "続いて,**損失関数を変更**することで,少数の異常サンプルに対して精度向上させる方法を検討します.少数クラスの予測精度向上に注目した損失関数はこれまでに幾つも提案されていますが,今回はその中で,**Focal loss** という損失関数を利用します.\n", "\n", "Focal lossは,画像の物体検知手法の研究論文 [[6](https://arxiv.org/abs/1708.02002)] の中で提案された損失関数です.One-stage物体検知手法において,大量の候補領域の中で実際に物体が存在する領域はたかだか数個であることが多く,クラス不均衡なタスクになっており,学習がうまく進まないという問題があります.こうした問題に対処するために提案されたのがfocal lossであり,以下の式によって記述されます.\n", "\n", "$$\n", "FL(p_t) = - (1 - p_t)^{\\gamma}\\log(p_t)\n", "$$\n", "\n", "ここで$p_t$はSoftmax関数の出力(確率値)です.$\\gamma = 0$の場合,通常のSoftmax cross-entorpy lossと等しくなりますが,$\\gamma > 0$の場合,明確に分類可能な(識別が簡単な)サンプルに対して,相対損失を小さくする効果があります.その結果,分類が難しいサンプルにより注目して学習が進んでいくことが期待されます.\n", "\n", "下図は,正解クラスの予測確率値と,その際の損失の関係をプロットしており,$\\gamma$の値を変化させた場合に,相対損失がどのように下がっていくかを示しています.\n", "\n", "![正解予測確率と損失の関係](https://github.com/japan-medical-ai/medical-ai-course-materials/raw/master/notebooks/images/monitoring/focal_plot.png)\n", "\n", "([[6](https://arxiv.org/abs/1708.02002)]より引用)\n", "\n", "それでは実際に,Focal loss関数を定義してみましょう." ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "colab": {}, "colab_type": "code", "id": "umASFtsw4XyG" }, "outputs": [], "source": [ "from chainer.backends.cuda import get_array_module\n", "\n", "def focal_loss(x, t, class_num=2, gamma=0.5, eps=1e-6):\n", " xp = get_array_module(t)\n", "\n", " p = F.softmax(x)\n", " p = F.clip(p, x_min=eps, x_max=1-eps)\n", " log_p = F.log_softmax(x)\n", " t_onehot = xp.eye(class_num)[t.ravel()]\n", "\n", " loss_sce = -1 * t_onehot * log_p\n", " loss_focal = F.sum(loss_sce * (1. - p) ** gamma, axis=1)\n", "\n", " return F.mean(loss_focal)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "rdc0wPArpvIX" }, "source": [ "前項目で実施したデータサンプリングは行わず,初期(§8.5)の学習時と同様の設定にした上で,損失関数をfocal lossに変更します.\n" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "colab": {}, "colab_type": "code", "id": "Y64crW5o6Cxg" }, "outputs": [], "source": [ "train_dataset = create_train_dataset(dataset_root)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "colab": {}, "colab_type": "code", "id": "Ee4pqByA6Lm9" }, "outputs": [], "source": [ "trainer = create_trainer(256, train_dataset, nb_epoch=1, device=0, lossfun=focal_loss)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "9LjwPBTXqQ_k" }, "source": [ "それでは学習を開始しましょう.(1分30秒ほどで学習が完了します.)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 510 }, "colab_type": "code", "id": "xfgBxkaZ6sGm", "outputId": "0ee18e18-9586-4e92-c81d-6b95aa856de7" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "epoch iteration main/loss main/accuracy\n", "\u001b[J0 7 1.21684 0.876674 \n", "\u001b[J0 14 0.149564 0.957589 \n", "\u001b[J0 21 0.0536211 0.976004 \n", "\u001b[J0 28 0.0491485 0.979353 \n", "\u001b[J0 35 0.0278858 0.987165 \n", "\u001b[J0 42 0.0252027 0.989397 \n", "\u001b[J0 49 0.0311808 0.986607 \n", "\u001b[J0 56 0.0199696 0.989955 \n", "\u001b[J0 63 0.0132789 0.99442 \n", "\u001b[J0 70 0.0140394 0.996094 \n", "\u001b[J0 77 0.0144007 0.993304 \n", "\u001b[J0 84 0.0169302 0.992746 \n", "\u001b[J0 91 0.0165225 0.992746 \n", "\u001b[J0 98 0.0110192 0.996094 \n", "\u001b[J0 105 0.0177556 0.992746 \n", "\u001b[J0 112 0.0139628 0.994978 \n", "\u001b[J0 119 0.0113324 0.994978 \n", "\u001b[J0 126 0.010316 0.996094 \n", "\u001b[J0 133 0.0103831 0.995536 \n", "\u001b[J0 140 0.0128646 0.995536 \n", "\u001b[J0 147 0.0246793 0.992188 \n", "\u001b[J0 154 0.00787007 0.996652 \n", "\u001b[J0 161 0.0168202 0.994978 \n", "\u001b[J0 168 0.00875182 0.996652 \n", "\u001b[J0 175 0.015041 0.993862 \n", "\u001b[J0 182 0.00939075 0.99442 \n", "CPU times: user 1min 4s, sys: 13.7 s, total: 1min 17s\n", "Wall time: 1min 17s\n" ] } ], "source": [ "%time trainer.run()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "EaVcFO7rrWQ2" }, "source": [ "学習が完了したら,評価用データにて予測結果を確認してみましょう." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 51 }, "colab_type": "code", "id": "X3dGV0Z9kWK6", "outputId": "b96537a8-b030-4007-822b-58e5808c2923" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 15.1 s, sys: 2.8 s, total: 17.9 s\n", "Wall time: 17.9 s\n" ] } ], "source": [ "%time y_true_test, y_pred_test = predict(trainer, test_dataset, 256, 0)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 211 }, "colab_type": "code", "id": "CnN8bb_0kWK_", "outputId": "cd31569c-da70-4b96-f5c3-7046273b35ea" }, "outputs": [ { "data": { "image/png": "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\ncaT/B22pbliWe8YjAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "print_confusion_matrix(y_true_test, y_pred_test)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 187 }, "colab_type": "code", "id": "GJ1wY_0ZkWLC", "outputId": "ec43d770-54c0-4929-f231-0263932a7e17" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Normal 0.99 0.95 0.97 42149\n", " VEB 0.57 0.93 0.71 3200\n", "\n", " micro avg 0.95 0.95 0.95 45349\n", " macro avg 0.78 0.94 0.84 45349\n", "weighted avg 0.96 0.95 0.95 45349\n", "\n", "accuracy: 0.9456437848684646\n" ] } ], "source": [ "print_scores(y_true_test, y_pred_test)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "8OpQJTcOrc8s" }, "source": [ "初期モデルの予測結果と,今回の予測結果を比較してみて下さい.\n", "\n", "(余力があれば,$\\gamma$の値を変化させた場合に,予測結果にどのような影響があるか確認してみて下さい.)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "PRMXPtNqvKya" }, "source": [ "### ネットワーク構造の変更" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "yKCFw0pVsiSc" }, "source": [ "続いて,学習に用いる**ネットワーク構造を変更**することを検討します.\n", "\n", "ここでは,最初に用いたResNet34構造に対して以下の拡張を行います.\n", "\n", "1. 1D Convolutionを,**1D Dilated Convolution**に変更\n", " - Dilated Convolutionを用いることで,パラメータ数の増大を抑えながら,より広範囲の特徴を抽出可能になると期待されます(遺伝子解析の際と同様のモチベーション).\n", " - 広範囲の特徴が重要でないタスクの場合には,精度向上に繋がらない(または,場合によっては精度が低下する)可能性もあります.\n", "1. 最終層の手前に全結合層を追加し,**Dropout**を適用\n", " - Dropoutを行うことで,学習器の汎化性能が向上することを期待します.ただし複数の先行研究([[7](https://arxiv.org/abs/1506.02158v6)]など)において,単純に畳み込み層の直後にDropoutを適用するだけでは汎化性能の向上が期待出来ないと報告されていることから,今回は全結合層に適用することにします.\n", "\n", "それでは,上記の拡張を加えたネットワークを定義しましょう.(ResBlockクラスは,初期モデル構築時に定義済み)\n", " " ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "colab": {}, "colab_type": "code", "id": "h5-FR_e5wezQ" }, "outputs": [], "source": [ "class DilatedResNet34(chainer.Chain):\n", "\n", " def __init__(self):\n", " super(DilatedResNet34, self).__init__()\n", " with self.init_scope():\n", " self.conv1 = L.ConvolutionND(1, None, 64, 7, 2, 3)\n", " self.bn1 = L.BatchNormalization(64)\n", " self.resblock0 = ResBlock(64, 3, 1)\n", " self.resblock1 = ResBlock(128, 4, 1)\n", " self.resblock2 = ResBlock(256, 6, 2)\n", " self.resblock3 = ResBlock(512, 3, 4)\n", " self.fc1 = L.Linear(None, 512)\n", " self.fc2 = L.Linear(None, 2)\n", "\n", " def __call__(self, x):\n", " h = F.relu(self.bn1(self.conv1(x)))\n", " h = F.max_pooling_nd(h, 3, 2)\n", " for i in range(4):\n", " h = getattr(self, 'resblock{}'.format(str(i)))(h)\n", " h = F.average(h, axis=2)\n", " h = F.dropout(self.fc1(h), 0.5)\n", " h = self.fc2(h)\n", " return h\n", " " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Ait4aFm7At_G" }, "source": [ "初期(§8.5)の学習時と同様の設定にした上で,ネットワーク構造を `DilatedResNet34` に変更して学習を行います." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "colab": {}, "colab_type": "code", "id": "bGGFdPWIJ_kW" }, "outputs": [], "source": [ "def create_trainer(\n", " batchsize, train_dataset, nb_epoch=1,\n", " device=0, lossfun=F.softmax_cross_entropy\n", "):\n", " # setup model\n", " model = DilatedResNet34()\n", " train_model = Classifier(model, lossfun=lossfun)\n", "\n", " # use Adam optimizer\n", " optimizer = optimizers.Adam(alpha=0.001)\n", " optimizer.setup(train_model)\n", " optimizer.add_hook(WeightDecay(0.0001))\n", "\n", " # setup iterator\n", " train_iter = MultiprocessIterator(train_dataset, batchsize)\n", "\n", " # define updater\n", " updater = training.StandardUpdater(train_iter, optimizer, device=device)\n", "\n", " # setup trainer\n", " stop_trigger = (nb_epoch, 'epoch')\n", " trainer = training.trainer.Trainer(updater, stop_trigger)\n", " logging_attributes = [\n", " 'epoch', 'iteration',\n", " 'main/loss', 'main/accuracy' \n", " ]\n", " trainer.extend(\n", " extensions.LogReport(logging_attributes, trigger=(2000 // batchsize, 'iteration'))\n", " )\n", " trainer.extend(\n", " extensions.PrintReport(logging_attributes)\n", " )\n", " trainer.extend(\n", " extensions.ExponentialShift('alpha', 0.75, optimizer=optimizer),\n", " trigger=(4000 // batchsize, 'iteration')\n", " )\n", "\n", " return trainer" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "colab": {}, "colab_type": "code", "id": "DaMN5SPrJ_on" }, "outputs": [], "source": [ "train_dataset = create_train_dataset(dataset_root)\n", "test_dataset = create_test_dataset(dataset_root)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "colab": {}, "colab_type": "code", "id": "KUidNkHlKTjh" }, "outputs": [], "source": [ "trainer = create_trainer(256, train_dataset, nb_epoch=1, device=0)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "fSRYgJgCBD6Q" }, "source": [ "それでは,これまでと同様に学習を開始しましょう.(1分30秒ほどで学習が完了します.)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 510 }, "colab_type": "code", "id": "kawTWjlNKZTA", "outputId": "8f21e746-e357-4b9e-c83c-aec2a99ef5cb" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "epoch iteration main/loss main/accuracy\n", "\u001b[J0 7 1.06941 0.860491 \n", "\u001b[J0 14 0.204161 0.924665 \n", "\u001b[J0 21 0.164622 0.932478 \n", "\u001b[J0 28 0.103986 0.958147 \n", "\u001b[J0 35 0.0782762 0.973772 \n", "\u001b[J0 42 0.0455737 0.988281 \n", "\u001b[J0 49 0.030971 0.989955 \n", "\u001b[J0 56 0.0431471 0.988839 \n", "\u001b[J0 63 0.0427462 0.985491 \n", "\u001b[J0 70 0.0333034 0.991629 \n", "\u001b[J0 77 0.0239444 0.993862 \n", "\u001b[J0 84 0.0325211 0.989397 \n", "\u001b[J0 91 0.0281632 0.991071 \n", "\u001b[J0 98 0.0222488 0.989955 \n", "\u001b[J0 105 0.0232916 0.992746 \n", "\u001b[J0 112 0.0210675 0.992746 \n", "\u001b[J0 119 0.00808897 0.997768 \n", "\u001b[J0 126 0.0198379 0.991629 \n", "\u001b[J0 133 0.0183009 0.99442 \n", "\u001b[J0 140 0.0103409 0.996652 \n", "\u001b[J0 147 0.0131249 0.995536 \n", "\u001b[J0 154 0.0128261 0.993862 \n", "\u001b[J0 161 0.0152106 0.996652 \n", "\u001b[J0 168 0.00777262 0.996652 \n", "\u001b[J0 175 0.0233488 0.993304 \n", "\u001b[J0 182 0.0204095 0.995536 \n", "CPU times: user 1min, sys: 14.3 s, total: 1min 14s\n", "Wall time: 1min 14s\n" ] } ], "source": [ "%time trainer.run()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "wMPjaOZd4-gR" }, "source": [ "学習が完了したら,評価用データで予測を行い,精度を確認してみましょう." ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 51 }, "colab_type": "code", "id": "C_7Qhz7RPLgP", "outputId": "c555ec9b-12f9-431f-fc4b-88c299f0440d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 15.1 s, sys: 2.8 s, total: 17.9 s\n", "Wall time: 17.9 s\n" ] } ], "source": [ "%time y_true_test, y_pred_test = predict(trainer, test_dataset, 256, 0)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 213 }, "colab_type": "code", "id": "R4C-mFzBPLgQ", "outputId": "4d7bdb71-1467-462a-e1ca-72aa254f88cf" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "print_confusion_matrix(y_true_test, y_pred_test)" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 187 }, "colab_type": "code", "id": "n3z2ygYkPLgU", "outputId": "90a32a02-c957-4f4e-cdec-50ee95013653" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Normal 0.99 0.96 0.98 42149\n", " VEB 0.63 0.91 0.74 3200\n", "\n", " micro avg 0.96 0.96 0.96 45349\n", " macro avg 0.81 0.94 0.86 45349\n", "weighted avg 0.97 0.96 0.96 45349\n", "\n", "accuracy: 0.9553683653443296\n" ] } ], "source": [ "print_scores(y_true_test, y_pred_test)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dc1j5V9tJObY" }, "source": [ "初期モデルの予測結果と,今回の予測結果を比較してみて下さい." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "QUZQOrwaY1iA" }, "source": [ "### ノイズ除去の効果検証" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "0n54KBAxRy0R" }, "source": [ "最後に,心電図に含まれる**ノイズの除去**について検討します.\n", "\n", "心電図波形には,以下のような外部ノイズが含まれている可能性があります.[[8](http://www.iosrjournals.org/iosr-jece/papers/ICETEM/Vol.%201%20Issue%201/ECE%2006-40-44.pdf)]\n", "\n", "* 高周波\n", " * **筋電図ノイズ** (Electromyogram noise)\n", " - 体動により,筋肉の電気的活動が心電図に混入する場合があります.\n", " * **電力線誘導障害** (Power line interference)\n", " - 静電誘導により交流電流が流れ込み,心電図に混入する場合があります.\n", " - 電源配線に電流が流れることで磁力線が発生し,電磁誘導作用により交流電流が流れ込む場合があります.\n", " * **加算性白色ガウスノイズ** (Additive white Gaussian noise)\n", " - 外部環境に由来する様々な要因でホワイトノイズが混入してきます.\n", "* 低周波\n", " * **基線変動** (Baseline wandering)\n", " - 電極の装着不良,発汗,体動などの影響で,基線がゆっくり変動する場合があります.\n", "\n", "心電図を解析する際は,頻脈や徐脈などの異常波形を正確に判別するために,上記のようなノイズを除去する前処理が行われるのが一般的です.\n", "\n", "ノイズを除去する方法は幾つかありますが,最も単純なのは,線形フィルタを適用する方法です.今回は線形フィルタの一つであるバターワースフィルタを用いて,ノイズ除去を試してみましょう." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "oyWFLqKFjoLM" }, "source": [ "`BaseECGDatasetPreprocessor` にシグナルノイズ除去の機能を追加した, `DenoiseECGDatasetPreprocessor` クラスを定義します." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "colab": {}, "colab_type": "code", "id": "JErWrrR07cjB" }, "outputs": [], "source": [ "from scipy.signal import butter, lfilter\n", "\n", "\n", "class DenoiseECGDatasetPreprocessor(BaseECGDatasetPreprocessor):\n", "\n", " def __init__(\n", " self,\n", " dataset_root='./',\n", " window_size=720\n", " ):\n", " super(DenoiseECGDatasetPreprocessor, self).__init__(\n", " dataset_root, window_size)\n", "\n", " def _denoise_signal(\n", " self,\n", " signal,\n", " btype='low',\n", " cutoff_low=0.2,\n", " cutoff_high=25.,\n", " order=5\n", " ):\n", " nyquist = self.sample_rate / 2.\n", " if btype == 'band':\n", " cut_off = (cutoff_low / nyquist, cutoff_high / nyquist)\n", " elif btype == 'high':\n", " cut_off = cutoff_low / nyquist\n", " elif btype == 'low':\n", " cut_off = cutoff_high / nyquist\n", " else:\n", " return signal\n", " b, a = butter(order, cut_off, analog=False, btype=btype)\n", " return lfilter(b, a, signal)\n", "\n", " def _segment_data(\n", " self,\n", " signal,\n", " symbols,\n", " positions\n", " ):\n", " X = []\n", " y = []\n", " sig_len = len(signal)\n", " for i in range(len(symbols)):\n", " start = positions[i] - self.window_size // 2\n", " end = positions[i] + self.window_size // 2\n", " if symbols[i] in self.valid_symbols and start >= 0 and end <= sig_len:\n", " segment = signal[start:end]\n", " assert len(segment) == self.window_size, \"Invalid length\"\n", " X.append(segment)\n", " y.append(self.labels.index(self.label_map[symbols[i]]))\n", " return np.array(X), np.array(y)\n", "\n", " def prepare_dataset(\n", " self,\n", " denoise=False,\n", " normalize=True\n", " ):\n", " if not os.path.isdir(self.download_dir):\n", " self.download_data()\n", "\n", " # prepare training dataset\n", " self._prepare_dataset_core(self.train_record_list, \"train\", denoise, normalize)\n", " # prepare test dataset\n", " self._prepare_dataset_core(self.test_record_list, \"test\", denoise, normalize)\n", "\n", " def _prepare_dataset_core(\n", " self,\n", " record_list,\n", " mode=\"train\",\n", " denoise=False,\n", " normalize=True\n", " ):\n", " Xs, ys = [], []\n", " save_dir = os.path.join(self.dataset_root, 'preprocessed', mode)\n", " for i in range(len(record_list)):\n", " signal, symbols, positions = self._load_data(record_list[i])\n", " if denoise:\n", " signal = self._denoise_signal(signal)\n", " if normalize:\n", " signal = self._normalize_signal(signal)\n", " X, y = self._segment_data(signal, symbols, positions)\n", " Xs.append(X)\n", " ys.append(y)\n", " os.makedirs(save_dir, exist_ok=True)\n", " np.save(os.path.join(save_dir, \"X.npy\"), np.vstack(Xs))\n", " np.save(os.path.join(save_dir, \"y.npy\"), np.concatenate(ys))\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "-ASH3PS2a4td" }, "source": [ "線形フィルタを適用することで,学習モデルが異常拍動のパターンを特徴として捉えやすくなる可能性があります.一方で,異常拍動を検出するにあたって重要な情報も除去されてしまう可能性があることに注意してください.\n", "\n", "また,線形フィルタにおいては,その周波数特性(どの帯域の周波数成分を遮断するか)によって,幾つかの大まかな分類があります.例えば,以下のものがあります.\n", "\n", "\n", "* **ローパスフィルタ (Low-pass filter)** : 低周波成分のみ通過 (高周波成分を遮断)\n", "* **ハイパスフィルタ (High-pass filter)** : 高周波成分のみ通過 (低周波成分を遮断)\n", "* **バンドパスフィルタ(Band-pass filter)** : 特定の帯域成分のみ通過 (低周波,高周波成分を遮断)\n", "\n", "![線形フィルタの周波数特性による分類](https://github.com/japan-medical-ai/medical-ai-course-materials/raw/master/notebooks/images/monitoring/band_form.png)\n", "\n", "([[9](https://en.wikipedia.org/wiki/Filter_%28signal_processing%29)] より引用)\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "PNCCO2nTEOjm" }, "source": [ "mitdbでは,予め0.1 Hz 以下の低周波と,100 Hz 以上の高周波をバンドパスフィルタによって除去済みであるため,ここではさらに,25 Hz のローパス・バターワースフィルタによって高周波ノイズを取り除きます." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "qAPRfmp4kyZz" }, "source": [ "それでは,ノイズ除去オプションを有効にして,前処理を実行してみましょう." ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "colab": {}, "colab_type": "code", "id": "U19pzjkY85IP" }, "outputs": [], "source": [ "DenoiseECGDatasetPreprocessor(dataset_root).prepare_dataset(denoise=True)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "P3GJLKwBZSDj" }, "source": [ "実際に,高周波ノイズ除去後の波形を可視化してみましょう." ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "colab": {}, "colab_type": "code", "id": "RCIkhIvUNhcQ" }, "outputs": [], "source": [ "X_train_d = np.load(os.path.join(dataset_root, 'preprocessed', 'train', 'X.npy'))" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 265 }, "colab_type": "code", "id": "EDsqmOiYOYUL", "outputId": "2ef5a3c4-dc30-4c7a-8d7b-ae43a4b88f24" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "plt.subplots(figsize=(12, 4))\n", "plt.subplot(1, 2, 1)\n", "plt.plot(X_train[idx_n[0]])\n", "plt.subplot(1, 2, 2)\n", "plt.plot(X_train_d[idx_n[0]])\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "yYWeI-n5ccof" }, "source": [ "左図がフィルタリング前の波形,右図がフィルタリング後の波形です.\n", "細かな振動が取り除かれていることが確認できると思います.\n", "\n", "これまでと同様に,ノイズ除去後のデータを用いて学習を行ってみましょう.(1分30秒ほどで学習が完了します.)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "colab": {}, "colab_type": "code", "id": "Yvx5uLSwHz0e" }, "outputs": [], "source": [ "train_dataset = create_train_dataset(dataset_root)\n", "test_dataset = create_test_dataset(dataset_root)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 510 }, "colab_type": "code", "id": "C70lLfAHbOOH", "outputId": "aa399377-2240-48ba-d009-1460328363d6" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "epoch iteration main/loss main/accuracy\n", "\u001b[J0 7 1.21514 0.851562 \n", "\u001b[J0 14 0.283428 0.951451 \n", "\u001b[J0 21 0.157269 0.977679 \n", "\u001b[J0 28 0.141721 0.962612 \n", "\u001b[J0 35 0.0516044 0.986049 \n", "\u001b[J0 42 0.068243 0.987723 \n", "\u001b[J0 49 0.0541831 0.987723 \n", "\u001b[J0 56 0.0363404 0.993304 \n", "\u001b[J0 63 0.0441804 0.992188 \n", "\u001b[J0 70 0.0271119 0.991629 \n", "\u001b[J0 77 0.00849581 0.99721 \n", "\u001b[J0 84 0.0216285 0.996652 \n", "\u001b[J0 91 0.034815 0.990513 \n", "\u001b[J0 98 0.0259185 0.991629 \n", "\u001b[J0 105 0.0240092 0.993862 \n", "\u001b[J0 112 0.00988215 0.99721 \n", "\u001b[J0 119 0.0122308 0.996094 \n", "\u001b[J0 126 0.00706834 0.998326 \n", "\u001b[J0 133 0.0196008 0.994978 \n", "\u001b[J0 140 0.0134032 0.996652 \n", "\u001b[J0 147 0.0330729 0.993304 \n", "\u001b[J0 154 0.0230272 0.993304 \n", "\u001b[J0 161 0.00712667 0.99721 \n", "\u001b[J0 168 0.0140302 0.996094 \n", "\u001b[J0 175 0.00879468 0.995536 \n", "\u001b[J0 182 0.00927302 0.99721 \n", "CPU times: user 1min, sys: 13.8 s, total: 1min 14s\n", "Wall time: 1min 13s\n" ] } ], "source": [ "trainer = create_trainer(256, train_dataset, nb_epoch=1, device=0)\n", "%time trainer.run()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "8dTSeQiViGH_" }, "source": [ "学習が完了したら,評価用データで予測を行い,精度を確認してみましょう." ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 51 }, "colab_type": "code", "id": "5U3EVnexeasF", "outputId": "fef33ce4-d4b7-43e4-d034-623a67f3815b" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 15.2 s, sys: 2.81 s, total: 18 s\n", "Wall time: 18 s\n" ] } ], "source": [ "%time y_true_test, y_pred_test = predict(trainer, test_dataset, 256, 0)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 212 }, "colab_type": "code", "id": "qHnh-vFuelQk", "outputId": "5332be0b-3a02-452b-e233-cfd1cea31f10" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "print_confusion_matrix(y_true_test, y_pred_test)" ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 187 }, "colab_type": "code", "id": "0R_lnZLcIn-y", "outputId": "6307487f-5f11-4297-b771-926a077455b4" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Normal 0.99 0.97 0.98 42149\n", " VEB 0.67 0.93 0.78 3200\n", "\n", " micro avg 0.96 0.96 0.96 45349\n", " macro avg 0.83 0.95 0.88 45349\n", "weighted avg 0.97 0.96 0.97 45349\n", "\n", "accuracy: 0.9632185935742795\n" ] } ], "source": [ "print_scores(y_true_test, y_pred_test)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "TOdAyYBKiAQl" }, "source": [ "高周波のノイズを除去したことで,予測精度がどのように変わったか確認してみましょう." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IUfM-tiaBa2x" }, "source": [ "## おわりに" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "2T86ACWRBehT" }, "source": [ "本章では,ECGの公開データセットを利用して,不整脈検知の問題に取り組みました.\n", "\n", "本講義内容を通じてお伝えしたかったことは,以下となります.\n", "\n", "1. 心電図を解析するにあたって必要となる最低限の知識\n", "1. モニタリングデータを解析するための基本的な前処理手順\n", "1. CNNベースのモデルを利用した学習器の構築\n", "1. データセットの性質を考慮した学習方法や前処理の工夫\n", "\n", "また,精度向上に向けて様々な手法を試してみましたが,現実世界のタスクにおいては,どの工夫が有効に働くか自明で無い場合がほとんどです.従って,試行錯誤を行いながら,その問題設定に適合するやり方を模索していく必要があります.\n", "\n", "さらなる取り組みとしては,例えば下記内容を検討する余地があります.\n", "\n", "* 情報の追加\n", " * $Ⅱ$誘導シグナルに加えて,$V_1$誘導シグナルも同時に入力として与えます.([[10](https://www.kdd.org/kdd2018/files/deep-learning-day/DLDay18_paper_16.pdf)]などで実施)\n", "* 前処理の工夫\n", " * セグメント長の変更\n", " * より長時間のセグメントを入力とすることで,長期的な波形情報を抽出.([[4](https://arxiv.org/abs/1810.04121)]では10秒のセグメントを解析に利用)\n", " * 入力情報が増えることで,却って学習が難しくなってしまう可能性あり.\n", " * リサンプリング\n", " * サンプリング周波数を下げることで,長期的な波形情報を抽出.([[4](https://arxiv.org/abs/1810.04121)]では180 Hzにダウンサンプリング)\n", " * 波形が粗くなることで学習に影響する可能性あり.\n", " * 適切な前処理を行わないと,折り返し雑音と呼ばれる歪みが発生.\n", " * (モデルに入力する前に情報を縮小する処理は,画像解析などの分野では一般的)\n", " * ラベルの追加\n", " * Normal,VEBに加えて,SVEB(上室異所性拍動)等も追加.\n", " * ラベルの与え方の変更\n", " * セグメント範囲内に正常以外のピークラベルが含まれる場合に優先的にそのラベルを付与する,等.\n", "* モデルの変更\n", " * ResNet50,ResNet101,DenseNet121など,より深いネットワーク構造や他のネットワーク構造を利用する.\n", " * 長期的な特徴を抽出するために,CNNの後段にRNNベースの構造(LSTMなど)を組み込む ([[4](https://arxiv.org/abs/1810.04121)]などで実施).\n", "\n", "余力がある方は,是非チャレンジしてみてください.\n", "\n", "また,最近では独自に収集した大規模なモニタリングデータを対象として,研究成果を発表する事例も幾つか出てきています.\n", "\n", "* Cardiogram社とカリフォルニア大学の共同研究で,活動量計から心拍数データを収集し,深層学習を用いて糖尿病予備群を予測するDeepHeartを発表[[11](https://arxiv.org/abs/1802.02511)].\n", "* スタンフォード大学のAndrew Ng.の研究室でも,独自に収集したECGレコードから$14$種類の波形クラス分類を予測するモデルを構築し,医師と比較実験を実施[[12](https://arxiv.org/abs/1707.01836)].\n", "\n", "デバイスの進歩によって簡単に精緻な情報が収集可能になってきていることから,こうした研究は今後益々盛んになっていくと考えられます.\n", "\n", "以上で,モニタリングデータの時系列解析の章は終了となります.お疲れ様でした." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "o3jHP07dN8W9" }, "source": [ "## 参考文献" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Bvr5T47ROAof" }, "source": [ "1. **Electrocardiography** Wikipedia: The Free Encyclopedia. Wikimedia Foundation, Inc. 22 July 2004. Web. 10 Aug. 2004, [[Link](https://en.wikipedia.org/wiki/Electrocardiography)]\n", "1. **心電図健診判定マニュアル**, 日本人間ドック学会, 平成26年4月, [[Link](https://www.ningen-dock.jp/wp/wp-content/uploads/2013/09/d4bb55fcf01494e251d315b76738ab40.pdf)]\n", "1. **Automatic classification of heartbeats using ECG morphology and heartbeat interval features**, Phillip de Chazal et al., June 2004, [[Link](https://ieeexplore.ieee.org/document/1306572)]\n", "1. **Inter-Patient ECG Classification with Convolutional and Recurrent Neural Networks**, Li Guo et al., Sep 2018, [[Link](https://arxiv.org/abs/1810.04121)]\n", "1. **Deep Residual Learning for Image Recognition**, Kaiming He et al., Dec 2015, [[Link](https://arxiv.org/abs/1512.03385)]\n", "1. **Focal Loss for Dense Object Detection**, Tsung-Yi Lin et al., Aug 2017, [[Link](https://arxiv.org/abs/1708.02002)]\n", "1. **Bayesian Convolutional Neural Networks with Bernoulli Approximate Variational Inference**, Yarin Gal et al., Jun 2015, [[Link](https://arxiv.org/abs/1506.02158v6)]\n", "1. **Noise Analysis and Different Denoising Techniques of ECG Signal - A Survey**, Aswathy Velayudhan et al., ICETEM2016, [[Link](http://www.iosrjournals.org/iosr-jece/papers/ICETEM/Vol.%201%20Issue%201/ECE%2006-40-44.pdf)]\n", "1. **Filter (signal processing)**, Wikipedia: The Free Encyclopedia. Wikimedia Foundation, Inc. 22 July 2004. Web. 10 Aug. 2004, [[Link](https://en.wikipedia.org/wiki/Filter_%28signal_processing%29)]\n", "1. **Arrhythmia Detection from 2-lead ECG using Convolutional Denoising Autoencoders**, Keiichi Ochiai et al., KDD2018, [[Link](https://www.kdd.org/kdd2018/files/deep-learning-day/DLDay18_paper_16.pdf)]\n", "1. **DeepHeart: Semi-Supervised Sequence Learning for Cardiovascular Risk Prediction**, Brandon Ballinger et al., Feb 2018, [[Link](https://arxiv.org/abs/1802.02511)]\n", "1. **Cardiologist-Level Arrhythmia Detection with Convolutional Neural Networks**, Pranav Rajpurkar et al., Jul 2017, [[Link](https://arxiv.org/abs/1707.01836)]" ] } ] }