{"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":3649,"databundleVersionId":46718,"sourceType":"competition"}],"dockerImageVersionId":30733,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# モジュールのインポート\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom PIL import Image\nimport os\nimport random\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.datasets as datasets\nfrom torchvision.models import vit_b_16\nfrom torchvision import transforms\n\n# ハイパーパラメータの調整\nbatch_size = 64\nlearning_rate = 1e-4\nnum_epochs = 5\nimg_size = 224  # ViTモデルに合わせて224に変更\n\n# 乱数シードを固定\nrandom_seed = 42\nrandom.seed(random_seed)\nnp.random.seed(random_seed)\nos.environ[\"PYTHONHASHSEED\"] = str(random_seed)\ntorch.manual_seed(random_seed)\ntorch.cuda.manual_seed(random_seed)\ntorch.cuda.manual_seed_all(random_seed)\ntorch.backends.cudnn.deterministic = True\ntorch.backends.cudnn.benchmark = False\ntorch.use_deterministic_algorithms(False)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 画像のデータ拡張\ntrain_transforms = transforms.Compose(\n    [\n        transforms.Resize((img_size, img_size)),\n        transforms.RandomRotation(20),\n        transforms.RandomHorizontalFlip(0.5),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ]\n)\ntest_transforms = transforms.Compose(\n    [\n        transforms.Resize((img_size, img_size)),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ]\n)\n# 訓練，検証用，テストデータの読み込み\ntrain_dataset = datasets.CIFAR10(root='./data', train=True, transform=train_transforms, download=True)\nvalid_dataset = datasets.CIFAR10(root='./data', train=False, transform=test_transforms, download=True)\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)\nvalid_loader = DataLoader(valid_dataset, batch_size=batch_size, shuffle=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# モデルの読み込み (この場合はVision Transformer)\nclass VisionTransformer(nn.Module):\n    def __init__(self, num_classes):\n        super(VisionTransformer, self).__init__()\n        self.model = vit_b_16(weights=\"DEFAULT\")\n        self.in_features = self.model.heads.head.in_features\n        self.model.heads.head = nn.Linear(self.in_features, num_classes)\n        \n    def forward(self, x):\n        x = self.model(x)\n        return x\n\n# 実行時にgpuを用いるようにする\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n\n# モデル，オプティマイザ，損失関数の定義\nmodel = VisionTransformer(num_classes=10).to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\ncriterion = nn.CrossEntropyLoss().to(device)\nscheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 訓練時の処理\nbest_epoch = 0\nbest_acc = 0.0\nfor epoch in range(1, num_epochs + 1):\n    print(\"-\" * 40)\n    print(f\"Epoch: {epoch}\")\n    epoch_loss = 0.0\n    epoch_corrects = 0\n    model.train()\n    for batch_in, batch_out in tqdm(train_loader):\n        batch_in = batch_in.to(device)\n        batch_out = batch_out.to(device)\n\n        y_pred = model(batch_in)\n        preds = torch.argmax(y_pred, 1)\n        loss = criterion(y_pred, batch_out)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        epoch_loss += loss.item() * batch_in.size(0)\n        epoch_corrects += torch.sum(preds == batch_out.data)\n\n    epoch_loss = epoch_loss / len(train_loader.dataset)\n    epoch_acc = epoch_corrects / len(train_loader.dataset)\n\n    print(f\"Train loss: {epoch_loss:.4f}\")\n    print(f\"Train acc: {epoch_acc:.4f}\")\n\n    # 過学習を防ぐための検証用\n    with torch.no_grad():\n        epoch_loss = 0.0\n        epoch_corrects = 0\n        model.eval()\n        for batch_in, batch_out in tqdm(valid_loader):\n            batch_in = batch_in.to(device)\n            batch_out = batch_out.to(device)\n\n            y_pred = model(batch_in)\n            preds = torch.argmax(y_pred, 1)\n            loss = criterion(y_pred, batch_out)\n\n            epoch_loss += loss.item() * batch_in.size(0)\n            epoch_corrects += torch.sum(preds == batch_out.data)\n\n    epoch_loss = epoch_loss / len(valid_loader.dataset)\n    epoch_acc = epoch_corrects / len(valid_loader.dataset)\n    \n    scheduler.step()\n\n    print(f\"Valid loss: {epoch_loss:.4f}\")\n    print(f\"Valid acc: {epoch_acc:.4f}\")\n\n    if epoch_acc >= best_acc:\n        best_epoch = epoch\n        best_acc = epoch_acc\n        torch.save(model, \"./model.pt\")\n\n    print(f\"Best epoch: {best_epoch}\")\n    print(f\"Best acc: {best_acc:.4f}\")\n    print(\"-\" * 40)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ファイルの解凍\n!pip install py7zr\n\nimport py7zr\n\nwith py7zr.SevenZipFile('/kaggle/input/cifar-10/test.7z', mode='r') as z:\n    z.extractall('/kaggle/working/')\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ファイル作成\ntest_filenames = [os.path.join('/kaggle/working/test', f) for f in os.listdir('/kaggle/working/test')]\ntest_filenames.sort(key=lambda x: int(x.split('/')[-1].split('.')[0]))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# データセットの定義\nclass CIFAR10(Dataset):\n    def __init__(self, filenames, transforms):\n        self.filenames = filenames\n        self.transforms = transforms\n        \n    def __len__(self):\n        return len(self.filenames)\n    \n    def __getitem__(self, idx):\n        img = Image.open(self.filenames[idx])\n        transformed_img = self.transforms(img)\n        return transformed_img\n\n# テストデータの処理\ntest_dataset = CIFAR10(test_filenames, test_transforms)\n\ntest_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# CIFAR10のクラスの定義\nclasses = ('airplane', \n           'automobile', \n           'bird',\n           'cat',\n           'deer',\n           'dog', \n           'frog', \n           'horse', \n           'ship',\n           'truck')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# csvファイルの読み込み\nsample = pd.read_csv('/kaggle/input/cifar-10/sampleSubmission.csv')\n# 一番精度がよかったエポックのモデルを呼び出す\nmodel = torch.load('./model.pt').to(device)\nresult = []\n\n# テストデータなので，no_gradで処理 (重みを変えない)\nwith torch.no_grad():\n    model.eval()\n    for batch_in in tqdm(test_loader):\n        batch_in = batch_in.to(device)\n        \n        y_pred = model(batch_in)\n        preds = torch.argmax(y_pred, 1)\n        preds = preds.cpu().numpy()\n        result.extend([classes[i] for i in preds])\n\nsample['label'] = result\nsample.to_csv('./predict.csv', index=False)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# データを削除 (不要のため)\nimport shutil\n\nshutil.rmtree('/kaggle/working/data')\nshutil.rmtree('/kaggle/working/test')","metadata":{},"execution_count":null,"outputs":[]}]}