{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-07-26T06:27:26.910547Z","iopub.execute_input":"2023-07-26T06:27:26.910965Z","iopub.status.idle":"2023-07-26T06:27:26.924237Z","shell.execute_reply.started":"2023-07-26T06:27:26.910932Z","shell.execute_reply":"2023-07-26T06:27:26.922924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 学習データとテストデータのダウンロード\n目次へ戻る\n\n「dogs-vs-cats-redux-kernels-edition」を Input に設置して，train.zip と test.zip を解凍．\nOutput に解凍結果を train と test　のディレクトリに保存","metadata":{}},{"cell_type":"code","source":"import zipfile\nimport glob\nimport os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport collections\nfrom PIL import Image\n\ntrain_dir = 'train'\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as train_zip:\n    train_zip.extractall('')\n\ntrain_list = glob.glob(os.path.join(train_dir,'*.jpg'))\nprint(f\"Train Data: {len(train_list)}\")\n\nbase_dir = '/kaggle/working'\ntrain_dir = os.path.join(base_dir, 'train')\n\ntest_dir = 'test'\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as test_zip:\n    test_zip.extractall('')\n\ntest_list = glob.glob(os.path.join(test_dir,'*.jpg'))\nprint(f\"Test Data: {len(test_list)}\")\n\nbase_dir = '/kaggle/working'\ntest_dir = os.path.join(base_dir, 'test')","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:27:26.926807Z","iopub.execute_input":"2023-07-26T06:27:26.927527Z","iopub.status.idle":"2023-07-26T06:27:40.164455Z","shell.execute_reply.started":"2023-07-26T06:27:26.927474Z","shell.execute_reply":"2023-07-26T06:27:40.162650Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"実行結果補足メモ：\nTrain Data: 25000\n→「dogs-vs-cats-redux-kernels-edition」に 学習データ が 25000件，存在する．\nTest Data: 12500\n→「dogs-vs-cats-redux-kernels-edition」に テストデータ が 12500件，存在する．","metadata":{}},{"cell_type":"markdown","source":"# ダウンロードデータの確認\n学習データとテストデータの中身を1つ確認","metadata":{}},{"cell_type":"code","source":"print(f'学習データ数：{len(train_list)}', f'先頭のデータ：{train_list[0]}')\nprint(f'テストデータ数：{len(test_list)}', f'先頭のデータ：{test_list[0]}')","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:27:40.166168Z","iopub.execute_input":"2023-07-26T06:27:40.166674Z","iopub.status.idle":"2023-07-26T06:27:40.174379Z","shell.execute_reply.started":"2023-07-26T06:27:40.166638Z","shell.execute_reply":"2023-07-26T06:27:40.172448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"学習データの中身をランダムに9つを表示","metadata":{}},{"cell_type":"markdown","source":"実行結果補足メモ：\n学習データには，犬と猫のラベル付けされた画像パスを持つ\nテストデータには，ラベル付けされていない画像パスを持つ\n\nラベル付けとは，画像に犬か猫かの情報を付与すること","metadata":{}},{"cell_type":"code","source":"labels = [path.split('/')[-1].split('.')[0] for path in train_list]\nrandom_idx = np.random.randint(1, len(train_list), size=9)\nfig, axes = plt.subplots(3, 3, figsize=(16, 12))\n\nfor idx, ax in enumerate(axes.ravel()):\n    img = Image.open(train_list[idx])\n    ax.set_title(labels[idx])\n    ax.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:27:40.177736Z","iopub.execute_input":"2023-07-26T06:27:40.178184Z","iopub.status.idle":"2023-07-26T06:27:43.856075Z","shell.execute_reply.started":"2023-07-26T06:27:40.178150Z","shell.execute_reply":"2023-07-26T06:27:43.854583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# データ分析","metadata":{}},{"cell_type":"markdown","source":"犬と猫のラベル比","metadata":{}},{"cell_type":"code","source":"c = collections.Counter(labels)\nprint(c)\n\nplt.xlabel('labels')\nplt.ylabel('counts')\n\nleft = np.array([0, 1])\nlabel = ['dog', 'cat']\nheight = np.array([c['dog'], c['cat']])\nplt.bar(left, height, tick_label=label)","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:27:43.857622Z","iopub.execute_input":"2023-07-26T06:27:43.858047Z","iopub.status.idle":"2023-07-26T06:27:44.112047Z","shell.execute_reply.started":"2023-07-26T06:27:43.858010Z","shell.execute_reply":"2023-07-26T06:27:44.110323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"実行結果補足メモ：\nCounter({'cat':12500, 'dog':12500}) は猫のラベルを持つ画像が 12500件，犬のラベルを持つ画像が 12500件，存在するということを表す．\nまた，上記のヒストグラムはそれを視覚的に表したものである．","metadata":{}},{"cell_type":"markdown","source":"# 学習データ と 検証データ と テストデータ の生成\n目次へ戻る\n\n2019年にGoogle社によって開発された事前学習済みモデル「EfficientNet」 と呼ばれる畳み込みニューラルネットワーク（CNN）を用いて，学習・分類を行うために入力データを作成する．\nダウンロードした学習データを，CNN用の学習データと検証データに分ける．\nその際に，画像データを縦横のサイズを224(px)に変換し，色の白黒（グレースケール）化を行う．\n画像サイズの変換理由は，今回使う事前学習済みモデル「EfficientNet」の推奨画像サイズが縦横 224(px)となっているため．\n色をRGBではなく，グレースケールで表すのはKaggleの実行可能メモリ数に収めるため．\nまた，画像ラベルの dog：0 cat：1 とするのは文字のまま入力することができないため．","metadata":{}},{"cell_type":"code","source":"from PIL import ImageFile\nfrom sklearn.model_selection import train_test_split\n\nclasses = {'dog':0, 'cat':1} # ラベルのdogを0，catを1とする\nimage_size = 224 # 画像サイズ 224px\ndim = 1 # 色の種類(0-255で白黒を表す)\n\nX_train = [] # 学習データの特徴量\ny_train = [] # 学習データのラベル\nX_test  = [] # テストデータの特徴量\n\n# 学習データと検証データの作成\ntrain_labels = [path.split('/')[-1].split('.')[0] for path in train_list]\nfor i, img in enumerate(train_list) :\n    image = Image.open(img)\n    image = image.convert(\"L\") # グレースケール化\n    image = image.resize((image_size, image_size)) # 画像サイズの変換\n    data = np.asarray(image)\n    X_train.append(data)\n    y_train.append(classes[train_labels[i]])\nX_train = np.array(X_train)\ny_train = np.array(y_train)\n# 学習データと検証データに分ける\nX_train, X_val, y_train, y_val = train_test_split(X_train, y_train, train_size=0.7, shuffle=True, random_state=0)\n\n# テストデータの作成\nfor i, img in enumerate(test_list) :\n    image = Image.open(img)\n    image = image.convert(\"L\") # グレースケール化\n    image = image.resize((image_size, image_size)) # 画像サイズの変換\n    data = np.asarray(image)\n    X_test.append(data)\nX_test  = np.array(X_test)","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:27:44.113917Z","iopub.execute_input":"2023-07-26T06:27:44.114278Z","iopub.status.idle":"2023-07-26T06:29:34.559393Z","shell.execute_reply.started":"2023-07-26T06:27:44.114248Z","shell.execute_reply":"2023-07-26T06:29:34.558187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('学習・検証・テストデータ')\nprint(f'学習データ数：{len(X_train)} 検証データ数:{len(X_val)} テストデータ数：{len(X_test)}')\nprint(f'学習ラベル数：{len(y_train)} 検証ラベル数:{len(y_val)}')\nprint('1つのデータ')\nprint(f'学習の次元数：{X_train[0].shape} 検証の次元数：{X_val[0].shape} テストの次元数：{X_test[0].shape}')\nprint(f'学習ラベル：{y_train[0]} 検証ラベル：{y_val[0]}')\n\n# メモリ確保のため変数の削除\ndel train_list\ndel train_labels\ndel image\ndel data","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:34.562443Z","iopub.execute_input":"2023-07-26T06:29:34.563090Z","iopub.status.idle":"2023-07-26T06:29:34.576211Z","shell.execute_reply.started":"2023-07-26T06:29:34.563054Z","shell.execute_reply":"2023-07-26T06:29:34.575053Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"学習・検証・テストデータ\n学習データ数：17500 検証データ数:7500 テストデータ数：12500\n学習ラベル数：17500 検証ラベル数:7500\n1つのデータ\n学習の次元数：(224, 224) 検証の次元数：(224, 224) テストの次元数：(224, 224)\n学習ラベル：1 検証ラベル：0","metadata":{}},{"cell_type":"markdown","source":"# 学習データの確認\nCNNへ入力する学習データ\n学習データの中身を1つ確認","metadata":{}},{"cell_type":"code","source":"# 学習データの中身を1つ確認\nprint(f'データの中身:\\n{X_train[0]}')\nplt.imshow(X_train[0])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:34.577989Z","iopub.execute_input":"2023-07-26T06:29:34.579044Z","iopub.status.idle":"2023-07-26T06:29:34.921457Z","shell.execute_reply.started":"2023-07-26T06:29:34.578995Z","shell.execute_reply":"2023-07-26T06:29:34.920324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"実行結果補足メモ：\nデータの中身は224×224(px)の白黒(0-255)のデータを持つ","metadata":{}},{"cell_type":"markdown","source":"CNNへ入力する学習データの犬と猫のラベル比","metadata":{}},{"cell_type":"code","source":"c = collections.Counter(y_train)\n# 0:犬 1:猫\nprint(c)\n\nplt.xlabel('labels')\nplt.ylabel('counts')\nleft = np.array([0, 1])\nlabel = ['dog', 'cat']\nheight = np.array([c[0], c[1]])\nplt.bar(left, height, tick_label=label)","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:34.923031Z","iopub.execute_input":"2023-07-26T06:29:34.924099Z","iopub.status.idle":"2023-07-26T06:29:35.114061Z","shell.execute_reply.started":"2023-07-26T06:29:34.924059Z","shell.execute_reply":"2023-07-26T06:29:35.112696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"実行結果補足メモ：\nCounter({'cat':8812, 'dog':8688}) は猫のラベルを持つ画像が 8812件，犬のラベルを持つ画像が 8688件，存在するということを表す．\nまた，上記のヒストグラムはそれを視覚的に表したものである．","metadata":{}},{"cell_type":"markdown","source":"# モデル構築\n事前学習済みモデル「EfficientNetB0」を用いて画像分類モデルを構築する．\n「EfficientNetB0」を元に出力層に，「GlobalAveragePooling2D」と「Dense」を加える．\n\n学習パラメータ：\n損失関数：sparse_categorical_crossentropy\n最適化関数：Adam\n学習率：1e-5\nバッチサイズ：32\nエポック数：10\n\n訓練データ：X_train, y_train, X_val，y_val\nテストデータ：X_test","metadata":{}},{"cell_type":"code","source":"from keras.models import Sequential ,Model\nfrom keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D\nfrom keras.layers import Input, Activation, Dropout, Flatten, Dense\nfrom keras.optimizers import RMSprop\nimport tensorflow as tf\nfrom sklearn.metrics import accuracy_score\n\nimport keras\nimport numpy as np","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:35.120159Z","iopub.execute_input":"2023-07-26T06:29:35.120993Z","iopub.status.idle":"2023-07-26T06:29:35.129223Z","shell.execute_reply.started":"2023-07-26T06:29:35.120940Z","shell.execute_reply":"2023-07-26T06:29:35.128023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model(image_size, num_classes):\n    # 画像を受け取る層\n    inputs = Input(shape = image_size)\n    # EfficientNetB0\n    x = tf.keras.applications.efficientnet.EfficientNetB0(include_top = False)(inputs)\n    # １次元に変換する層\n    x = GlobalAveragePooling2D()(x) # CNNの出力を横並びにするのではなく、加算\n    \n    # 最終出力層\n    outputs = Dense(units = num_classes, activation = \"softmax\")(x)\n\n    # 定義した層を使ってモデル作成\n    model = Model(inputs = inputs, outputs = outputs)\n    # 最適化手法と損失関数を定義\n    model.compile(\n        optimizer = tf.keras.optimizers.Adam(learning_rate = 1e-5),\n        loss = \"sparse_categorical_crossentropy\",\n        metrics=['accuracy']\n    )\n    return model\n\n# モデルの呼び出し\ntf.keras.backend.clear_session()\nmodel = get_model((image_size, image_size, dim), 2)\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:35.130720Z","iopub.execute_input":"2023-07-26T06:29:35.131083Z","iopub.status.idle":"2023-07-26T06:29:39.552437Z","shell.execute_reply.started":"2023-07-26T06:29:35.131051Z","shell.execute_reply":"2023-07-26T06:29:39.550834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 学習\n分類モデルへの入力データセットの作成","metadata":{}},{"cell_type":"code","source":"# 分類モデルへの入力データ用の作成\nBATCH_SIZE = 32 # 学習バッチサイズ\n\ntrain_dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train)).batch(BATCH_SIZE)\n# メモリ確保のため変数の削除\ndel X_train\ndel y_train\n\ntest_dataset = tf.data.Dataset.from_tensor_slices((X_val, y_val)).batch(BATCH_SIZE)\ndel X_val # メモリ確保のため変数の削除\n\ntrain_dataset = train_dataset.shuffle(12345)","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:39.554235Z","iopub.execute_input":"2023-07-26T06:29:39.554778Z","iopub.status.idle":"2023-07-26T06:29:42.068277Z","shell.execute_reply.started":"2023-07-26T06:29:39.554741Z","shell.execute_reply":"2023-07-26T06:29:42.066863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"学習の実行","metadata":{}},{"cell_type":"code","source":"#　学習中で最も損失が低いものを保存\ncheckpoint = tf.keras.callbacks.ModelCheckpoint(\n    \"best_weight.h5\",     # ファイル名\n    monitor = \"val_loss\", # 参照するloss\n    mode = \"min\",         # monitorが最小のときに保存\n    save_best_only = True,\n    save_weights_only = True\n)\n\n# 学習の実行\nhistory = model.fit(\n    train_dataset,\n    validation_data = test_dataset,\n    epochs = 10,\n    callbacks = [checkpoint]\n)","metadata":{"execution":{"iopub.status.busy":"2023-07-26T06:29:42.069751Z","iopub.execute_input":"2023-07-26T06:29:42.070150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"学習ログ","metadata":{}},{"cell_type":"code","source":"# 学習経過の出力\nplt.plot(history.history[\"loss\"], label = \"train\")\nplt.plot(history.history[\"val_loss\"], label = \"valid\")\nplt.legend()\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# テスト\n検証データでの予測","metadata":{}},{"cell_type":"code","source":"# 学習結果で良いモデルを用いる\nmodel.load_weights(\"best_weight.h5\")\npreds = model.predict(test_dataset)\nprint(f'予測確率[dog：cat]：{preds[0]}')\nprint(f'正解ラベル：{y_val[0]}')\npred_labels = preds.argmax(axis = 1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"検証データでの精度","metadata":{}},{"cell_type":"code","source":"print(accuracy_score(pred_labels, y_val.reshape(-1)))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# テストデータ\nsubmit サンプル\nkaggleで提出データのサンプルと評価方法\n提出物はログの損失に基づいてスコア付けされる．\n\n提出形式はサンプルの通り\n画像ID ＋ ラベルの予測確率","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\ndf = pd.read_csv('/kaggle/input/dogs-vs-cats-redux-kernels-edition/sample_submission.csv')\ndf.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"submit データの作成","metadata":{}},{"cell_type":"code","source":"# モデルの呼び出し\ntf.keras.backend.clear_session()\nmodel = get_model((image_size, image_size, dim), 2)\nmodel.load_weights(\"best_weight.h5\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred = model.predict(X_test)\n\ndf1 = pd.DataFrame(pred, columns=['dog', 'cat'])\nids = [path.split('/')[-1].split('.')[0] for path in test_list]\nsubmit = list(zip(ids, df1['dog'].to_list()))\ndf2 = pd.DataFrame(submit, columns=['id', 'label'])\nprint(df2.head())\ndf2.to_csv('submit_trained.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('submit_trained.csv')\ndf.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Kaggleでのsubmitメモ\nだいたいスコア　0.07　ぐらいを出している\n自身のスコアがランキングに反映されないため，順位はスコアを比較して大体の順位でいいかと思われる。","metadata":{}}]}