{"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"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile # zipファイルの解凍に必要\nimport tensorflow as tf # 機械学習に必要\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator # データの正規化に必要\nfrom tensorflow.keras import layers, models, regularizers # レイヤークラス, 学習モデル\nfrom tensorflow.keras.preprocessing import image # 画像の前処理に必要\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.optimizers import AdamW\nfrom tensorflow.keras.optimizers.schedules import CosineDecay\nfrom tensorflow.keras.applications import EfficientNetV2S # 転移学習\nfrom tensorflow.keras.losses import BinaryCrossentropy\nimport shutil # クラス分けに必要","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMG_SIZE = 384\nBATCH_SIZE = 32\nEPOCHS_0 = 10\nEPOCHS_1 = 20\nVALIDATION_SPLIT = 0.2","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"zip_file = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip'\nout_dir = '/kaggle/working'\n\nwith zipfile.ZipFile(zip_file, 'r') as file:\n    file.extractall(out_dir)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dir = '/kaggle/working/train'\n\ncat_dir = os.path.join(train_dir, 'cats')\ndog_dir = os.path.join(train_dir, 'dogs')\n\nos.makedirs(cat_dir, exist_ok=True)\nos.makedirs(dog_dir, exist_ok=True)\n\nfor file_name in os.listdir(train_dir):\n    file = os.path.join(train_dir, file_name)\n    if not os.path.isfile(file):\n        continue\n\n    if file_name.lower().startswith('cat'):\n        shutil.move(os.path.join(train_dir, file_name), os.path.join(cat_dir, file_name))\n    elif file_name.lower().startswith('dog'):\n        shutil.move(os.path.join(train_dir, file_name), os.path.join(dog_dir, file_name))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    preprocessing_function=tf.keras.applications.efficientnet_v2.preprocess_input,\n    validation_split=VALIDATION_SPLIT,\n    rotation_range=30,\n    zoom_range=0.2,\n    width_shift_range=0.1,\n    height_shift_range=0.1,\n    shear_range=0.1,\n    horizontal_flip=True,\n    brightness_range=(0.8, 1.2),\n    fill_mode='reflect'\n)\n\nval_datagen = ImageDataGenerator(\n    preprocessing_function=tf.keras.applications.efficientnet_v2.preprocess_input,\n    validation_split=VALIDATION_SPLIT\n)\n\ntrain_generator = train_datagen.flow_from_directory(\n    '/kaggle/working/train',\n    target_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    subset='training',\n    shuffle=True\n)\n\nval_generator = val_datagen.flow_from_directory(\n    '/kaggle/working/train',\n    target_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    subset='validation',\n    shuffle=False\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# モデル\nbase_model = EfficientNetV2S(\n    weights='imagenet',\n    include_top=False,\n    input_shape=(IMG_SIZE, IMG_SIZE, 3),\n    pooling='avg'\n)\n\nx = base_model.output\nx = layers.Dropout(0.3)(x)\noutputs = layers.Dense(1, activation='sigmoid')(x)\nmodel = models.Model(inputs=base_model.input, outputs=outputs)\n\nbase_model.trainable = False\n\n# スケジューラー\nlr_schedule = CosineDecay(\n    initial_learning_rate=1e-3,\n    decay_steps=len(train_generator) * EPOCHS_0,\n    alpha=1e-5\n)\n\n# オプティマイザー\noptimizer = AdamW(\n    learning_rate=lr_schedule,\n    weight_decay=1e-5\n)\n\n# コンパイル\nmodel.compile(\n    loss=BinaryCrossentropy(label_smoothing=0.05),\n    optimizer=optimizer,\n    metrics=['accuracy']\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"callbacks = [\n    EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True, verbose=1),\n]\n\nmodel.fit(\n    train_generator,\n    validation_data=val_generator,\n    epochs=EPOCHS_0,\n    callbacks=callbacks\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# モデル\nfor layer in base_model.layers[-20:]:\n    if not isinstance(layer, tf.keras.layers.BatchNormalization):\n        layer.trainable = True\n\n# スケジューラー\nlr_schedule = CosineDecay(\n    initial_learning_rate=1e-5,\n    decay_steps=len(train_generator) * EPOCHS_1,\n    alpha=1e-6\n)\n\n# オプティマイザー\noptimizer = AdamW(\n    learning_rate=lr_schedule,\n    weight_decay=1e-5\n)\n\n# コンパイル\nmodel.compile(\n    loss=BinaryCrossentropy(label_smoothing=0.05),\n    optimizer=optimizer,\n    metrics=['accuracy']\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"callbacks = [\n    EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True, verbose=1),\n]\n\nmodel.fit(\n    train_generator,\n    validation_data=val_generator,\n    epochs=EPOCHS_1,\n    callbacks=callbacks\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# テストデータファイルの解凍\nzip_file = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip'\nout_dir = '/kaggle/working'\n\nwith zipfile.ZipFile(zip_file, 'r') as file:\n    file.extractall(out_dir)\n\n# テストデータの前処理\ntest_datagen = ImageDataGenerator(preprocessing_function=tf.keras.applications.efficientnet_v2.preprocess_input)\ntest_generator = train_datagen.flow_from_directory(\n    '/kaggle/working',\n    target_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode=None,\n    shuffle=False,\n    classes=['test']\n)\n\n# 推論\npred = model.predict(test_generator, verbose=1)\n\n# 出力データの整理\nids = [int(os.path.splitext(os.path.basename(path))[0]) for path in test_generator.filenames]\nlabels = np.clip(pred, 1e-6, 1 - 1e-6).ravel()\nview = list(zip(ids, labels))\nview.sort(key=lambda x: x[0])\n\n# CSV提出\ndf = pd.DataFrame(view, columns=['id', 'label'])\ndf.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}