{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport time\nfrom fastai.vision.all import *\nimport zipfile\nimport albumentations as Alb","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# データセットの展開\nwith zipfile.ZipFile('../input/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('.')\nwith zipfile.ZipFile('../input/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as zip_ref:\n    zip_ref.extractall('.')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 不良画像の削除\nbad_images = [\n    'dog.10797.jpg', 'dog.10747.jpg', 'dog.10237.jpg', 'dog.9517.jpg',\n    'dog.8736.jpg', 'dog.5604.jpg', 'dog.1043.jpg', 'cat.4338.jpg',\n    'dog.10161.jpg', 'dog.10190.jpg'\n]\nfor img in bad_images:\n    os.remove(f'./train/{img}')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# データセットの読み込み\ntpath = \"./train\"\nftrain = get_image_files(tpath)\nprint('Train set size:', len(ftrain))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# データ拡張の定義\nclass AlbTransform(Transform):\n    def __init__(self, aug): self.aug = aug\n    def encodes(self, img: PILImage):\n        aug_img = self.aug(image=np.array(img))['image']\n        return PILImage.create(aug_img)\n\n# Albumentationsのデータ拡張（ぼかし処理含む）\ndef get_augs():\n    return Alb.Compose([\n        Alb.ShiftScaleRotate(rotate_limit=20, border_mode=0, value=(0,0,0)),\n        Alb.Transpose(),\n        Alb.Flip(),\n        Alb.RandomRotate90(),\n        Alb.RandomBrightnessContrast(),\n        Alb.HueSaturationValue(hue_shift_limit=5, sat_shift_limit=5, val_shift_limit=5),\n        Alb.CoarseDropout(),\n        \n        # ぼかし処理の追加（どちらかを確率で適用）\n        Alb.OneOf([\n            Alb.Blur(blur_limit=3, p=0.5),              # 平均ぼかし\n            Alb.GaussianBlur(blur_limit=(3, 5), p=0.5)  # ガウスぼかし\n        ], p=0.5)  # このOneOf自体を50%の確率で適用\n    ])\n\n# 画像1枚ごとの前処理\nitem_tfms = [Resize(224), AlbTransform(get_augs())]\n\n# バッチ単位での標準化と追加変換\nbatch_tfms = [Normalize.from_stats(*imagenet_stats), *aug_transforms()]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# データローダーの作成\ndls = ImageDataLoaders.from_name_re(\n    path=tpath, fnames=ftrain, pat=r'(.+)\\.\\d+.jpg$', valid_pct=0.1, \n    item_tfms=item_tfms, batch_tfms=batch_tfms, bs=64, shuffle=True\n)\n\nprint('train items:', len(dls.train.items), 'validation items:', len(dls.valid.items))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# モデルの作成\nlearn = cnn_learner(dls, resnet50, metrics=[error_rate, accuracy])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 学習率のスケジューリングを追加\nlearn.fit_one_cycle(5, lr_max=slice(1e-3, 1e-2))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# テストデータの準備\nftest = get_image_files('test')\nprint('Testing', len(ftest), 'items')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# テストデータローダーの作成\ntst_dl = dls.test_dl(ftest, with_labels=False, shuffle=False)\ntst_dl.show_batch(max_n=12)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 推論の実行\nstartTime = time.time()\npreds = learn.tta(dl=tst_dl, n=5, use_max=False)\nprint('TTA in:', time.time()-startTime, 'secs')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 結果の保存\nsubm_df = pd.DataFrame()\nsubm_df['id'] = [item.stem for item in tst_dl.items]\nsubm_df['label'] = preds[0][:,1].clip(0.005, 0.995)\nsubm_df.to_csv('submission.csv', header=True, index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ソフトマックスを使用した予測結果の保存\nsubm_df['label'] = torch.softmax(preds[0], dim=1)[:, 1]\nsubm_df.to_csv('submission-softmax.csv', header=True, index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 推論結果の可視化\ntst_dl.show_batch(max_n=12)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# クリーンアップ\nfrom shutil import rmtree\nrmtree('./train', ignore_errors=True)\nrmtree('./test', ignore_errors=True)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}