{"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 resnet101\nfrom torchvision import transforms\nimport matplotlib.pyplot as plt\n#ハイパーパラメータの調整\n#画像サイズはデータセットに合わせて32にした\nbatch_size = 64\nlearning_rate = 1e-4\nnum_epochs = 5\nimg_size = 32\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":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# csvファイルの読み込み\nsample = pd.read_csv('/kaggle/input/cifar-10/sampleSubmission.csv')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 画像のデータ拡張\n#画像のリサイズ，ランダム回転，反転の処理\ntrain_transforms = transforms.Compose(\n    [\n        transforms.Resize(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),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ]\n)# Define transforms\ntrain_transforms = transforms.Compose(\n    [\n        transforms.Resize(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),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ]\n)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#訓練，検証用，テストデータの読み込み\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)\n\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)\nvalid_loader = DataLoader(valid_dataset, batch_size=batch_size, shuffle=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision.transforms.functional import to_pil_image\n\n# グレースケール変換の定義\ngray_transform = transforms.Compose([\n    transforms.Grayscale(num_output_channels=3),  # RGB画像として3チャネルを持つグレースケール変換\n    transforms.ToTensor(),\n])\n\n# ランダムに画像を取得する関数\ndef show_random_images(dataset, transform, num_images=100):\n    # データセットからランダムなインデックスを取得\n    indices = np.random.choice(len(dataset), num_images, replace=False)\n    \n    # 画像をPIL Image形式で取得し、グレースケール変換を適用\n    images = [dataset[i][0] for i in indices]\n    gray_images = [gray_transform(to_pil_image(image)) for image in images]\n    \n    # 画像を表示する\n    plt.figure(figsize=(10, 10))\n    for i, image in enumerate(gray_images):\n        plt.subplot(10, 10, i + 1)\n        plt.imshow(image.permute(1, 2, 0).numpy(), cmap='gray')\n        plt.axis('off')\n    plt.show()\n\n# データセットを使用してグレースケール画像を表示\nshow_random_images(train_dataset, gray_transform, num_images=100)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ランダムに画像を取得して表示する関数\ndef show_random_images(dataset, num_images=100):\n    # データセットからランダムなインデックスを取得\n    indices = np.random.choice(len(dataset), num_images, replace=False)\n    \n    # 画像を取得\n    images = [dataset[i][0] for i in indices]\n    \n    # 画像を表示する\n    plt.figure(figsize=(10, 10))\n    for i, image in enumerate(images):\n        plt.subplot(10, 10, i + 1)\n        plt.imshow(image.permute(1, 2, 0).numpy())  # チャネルを最後に移動\n        plt.axis('off')\n    plt.show()\n# データセットを使用して画像を表示\nshow_random_images(train_dataset, num_images=100)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# モデル読み込み(この場合はResNet101(CNNベース))\nclass ResNet101(nn.Module):\n    def __init__(self, num_classes):\n        super(ResNet101, self).__init__()\n        self.model = resnet101(weights=\"DEFAULT\")\n        self.in_features = self.model.fc.in_features\n        self.model.fc = nn.Linear(self.in_features, num_classes)\n        \n    def forward(self, x):\n        x = self.model(x)\n        return x\n# 実行時にgpuを用いるようにする\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n\n#モデル，オプティマイザ，損失関数の定義\nmodel = ResNet101(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)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 訓練時の処理\nbest_epoch = 0\nbest_acc = 0.0\nepoch_train_losses = []  # トレーニングの損失を格納するリスト\nepoch_valid_losses = []  # 検証の損失を格納するリスト\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    epoch_train_losses.append(epoch_loss)  # トレーニング損失をリストに追加\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    epoch_valid_losses.append(epoch_loss)  # 検証損失をリストに追加\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_CNN.pt\")\n\n    print(f\"Best epoch: {best_epoch}\")\n    print(f\"Best acc: {best_acc:.4f}\")\n    print(\"-\" * 40)\n# グラフの表示\nplt.figure(figsize=(10, 5))\nplt.plot(range(1, num_epochs + 1), epoch_train_losses, label='Train Loss')\nplt.plot(range(1, num_epochs + 1), epoch_valid_losses, label='Valid Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.title('Train and Valid Loss Over Epochs(CNN)')\nplt.legend()\nplt.show()","metadata":{},"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/')","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#テストデータの処理\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":"# 一番精度がよかったエポックのモデルを呼び出す\nmodel = torch.load('./model_CNN.pt').to(device)\nresult = []\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_CNN.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]},{"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 = 2  #状況に合わせて変える(今回は時短のため2)\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":{},"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":{},"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)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 訓練時の処理\nbest_epoch = 0\nbest_acc = 0.0\nepoch_train_losses_ViT = []  # トレーニングの損失を格納するリスト\nepoch_valid_losses_ViT = []  # 検証の損失を格納するリスト\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    epoch_train_losses_ViT.append(epoch_loss)  # trainデータ損失をリストに追加\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    epoch_valid_losses_ViT.append(epoch_loss)  # 検証損失をリストに追加\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_ViT.pt\")\n\n    print(f\"Best epoch: {best_epoch}\")\n    print(f\"Best acc: {best_acc:.4f}\")\n    print(\"-\" * 40)\n# グラフの表示\nplt.figure(figsize=(10, 5))\nplt.plot(range(1, num_epochs + 1), epoch_train_losses_ViT, label='Train Loss')\nplt.plot(range(1, num_epochs + 1), epoch_valid_losses_ViT, label='Valid Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.title('Train and Valid Loss Over Epochs(ViT)')\nplt.legend()\nplt.show()","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)\n# CIFAR10のクラスの定義\nclasses = ('airplane', \n           'automobile', \n           'bird',\n           'cat',\n           'deer',\n           'dog', \n           'frog', \n           'horse', \n           'ship',\n           'truck')\n# 一番精度がよかったエポックのモデルを呼び出す\nmodel = torch.load('./model_ViT.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_ViT.csv', index=False)","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":[]}]}