{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"}],"dockerImageVersionId":30776,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Крок 1: Імпорт бібліотек","metadata":{"_uuid":"ec9480ba-db31-4145-8685-89a6c24a15dc","_cell_guid":"80dc9c6f-335b-4ecd-9593-53ba22e39b98","trusted":true}},{"cell_type":"code","source":"# Перевірка використання GPU\n!nvidia-smi","metadata":{"_uuid":"628bdccf-a14f-4284-bb1c-d052bb13d521","_cell_guid":"74b9b463-66dc-4748-90e6-c004a517c244","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:14.689207Z","iopub.execute_input":"2024-09-29T20:23:14.689597Z","iopub.status.idle":"2024-09-29T20:23:15.749362Z","shell.execute_reply.started":"2024-09-29T20:23:14.689558Z","shell.execute_reply":"2024-09-29T20:23:15.748197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Встановлення необхідних пакетів\n!pip install torch-optimizer","metadata":{"_uuid":"3c77b8a3-9e87-403e-a96c-9278ee2639b1","_cell_guid":"114984b5-19e2-424a-8d6e-dfa1a21c5b56","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:15.752368Z","iopub.execute_input":"2024-09-29T20:23:15.753088Z","iopub.status.idle":"2024-09-29T20:23:27.075346Z","shell.execute_reply.started":"2024-09-29T20:23:15.753046Z","shell.execute_reply":"2024-09-29T20:23:27.074183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Імпорт бібліотек\nimport numpy as np\nimport pandas as pd\nimport os\nimport pydicom\nimport cv2\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models\nfrom albumentations import (\n    Compose, Normalize, HorizontalFlip, VerticalFlip, ShiftScaleRotate, RandomBrightnessContrast,\n    RandomGamma, CoarseDropout, ElasticTransform, GridDistortion\n)\nfrom albumentations.pytorch import ToTensorV2\nfrom sklearn.model_selection import StratifiedKFold\nfrom torch.cuda.amp import GradScaler, autocast\nfrom tqdm import tqdm\nimport warnings\nimport time\nfrom torch_optimizer import Lookahead\n\n# Додайте функцію для моніторингу GPU\ndef print_gpu_status():\n    if torch.cuda.is_available():\n        print(f\"Назва GPU: {torch.cuda.get_device_name(0)}\")\n        print(f\"Використання GPU пам'яті: {torch.cuda.memory_allocated()} bytes\")\n        print(f\"Загальна доступна пам'ять GPU: {torch.cuda.max_memory_allocated()} bytes\")\n        print(f\"Завантаження GPU: {torch.cuda.memory_reserved()} bytes\")\n\n# Вимкнення попереджень\nwarnings.filterwarnings('ignore')\n\n# Додайте моніторинг GPU до навчання\nprint_gpu_status()","metadata":{"_uuid":"ee36633d-b6cf-426c-a120-152d9d065905","_cell_guid":"181462ae-cf55-4815-8853-9e14028c9354","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:27.077197Z","iopub.execute_input":"2024-09-29T20:23:27.078155Z","iopub.status.idle":"2024-09-29T20:23:27.089055Z","shell.execute_reply.started":"2024-09-29T20:23:27.078106Z","shell.execute_reply":"2024-09-29T20:23:27.088196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Перевірка доступності GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Використовується пристрій: {device}\")\n\nif device.type == 'cuda':\n    print(f\"Назва GPU: {torch.cuda.get_device_name(0)}\")\n    print(f\"Кількість доступних GPU: {torch.cuda.device_count()}\")","metadata":{"_uuid":"08b54556-9f7f-4f0f-a4fe-f80d8c2d0273","_cell_guid":"bc4d52ee-bad7-4b44-8163-08575fef4c03","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:27.090291Z","iopub.execute_input":"2024-09-29T20:23:27.090582Z","iopub.status.idle":"2024-09-29T20:23:27.103794Z","shell.execute_reply.started":"2024-09-29T20:23:27.090551Z","shell.execute_reply":"2024-09-29T20:23:27.102891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Клас для завантаження даних та DICOM зображень\nclass SpineDataset(Dataset):\n    def __init__(self, df, transforms=None):\n        self.df = df.reset_index(drop=True)\n        self.transforms = transforms\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        image = self.load_dicom(row['image_path'])\n        x, y = int(row['x']), int(row['y'])\n        roi = self.extract_roi(image, x, y)\n        severity = int(row['severity_encoded'])\n\n        # Додавання каналу та реплікація до 3 каналів\n        roi = roi[..., np.newaxis]\n        roi = np.repeat(roi, 3, axis=2)\n\n        if self.transforms:\n            augmented = self.transforms(image=roi)\n            roi = augmented['image']\n\n        return roi, torch.tensor(severity, dtype=torch.long)\n\n    def load_dicom(self, path):\n        dicom = pydicom.dcmread(path)\n        data = dicom.pixel_array.astype(np.float32)\n        data = data - np.min(data)  # Сдвиг значень до нуля\n        if np.max(data) != 0:\n            data = data / np.max(data)  # Нормалізація до [0, 1]\n        # Застосування CLAHE\n        data = np.clip(data * 255, 0, 255).astype(np.uint8)\n        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))\n        data = clahe.apply(data)\n        return data\n\n    def extract_roi(self, image, x, y, size=64):\n        half_size = size // 2\n        x_min = max(0, x - half_size)\n        y_min = max(0, y - half_size)\n        x_max = min(image.shape[1], x + half_size)\n        y_max = min(image.shape[0], y + half_size)\n        roi = image[y_min:y_max, x_min:x_max]\n        if roi.shape[0] != size or roi.shape[1] != size:\n            roi = cv2.resize(roi, (size, size))\n        return roi","metadata":{"_uuid":"7fd7e6f0-a77e-4802-8621-690d8e5fbf31","_cell_guid":"787987a5-fd78-47ed-a54e-37b04bda9b90","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:27.106900Z","iopub.execute_input":"2024-09-29T20:23:27.107259Z","iopub.status.idle":"2024-09-29T20:23:27.121617Z","shell.execute_reply.started":"2024-09-29T20:23:27.107224Z","shell.execute_reply":"2024-09-29T20:23:27.120823Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Аугментації для тренувальних та валідаційних даних\ntrain_transforms = Compose([\n    ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.1, rotate_limit=15, p=0.5),\n    HorizontalFlip(p=0.5),\n    VerticalFlip(p=0.5),\n    RandomBrightnessContrast(p=0.5),\n    RandomGamma(p=0.5),\n    CoarseDropout(max_holes=1, max_height=16, max_width=16, \n                 min_holes=1, min_height=16, min_width=16, \n                 fill_value=0, p=0.5),  \n    ElasticTransform(alpha=1.0, sigma=50, p=0.5),\n    GridDistortion(p=0.5),\n    Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),\n    ToTensorV2(),\n])\n\nvalid_transforms = Compose([\n    Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),\n    ToTensorV2(),\n])","metadata":{"_uuid":"64106e8c-bfc4-403d-a867-c78e023bbdd4","_cell_guid":"0ab4cf23-d29d-48a6-80d9-2fba5c6b7126","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:27.122788Z","iopub.execute_input":"2024-09-29T20:23:27.123155Z","iopub.status.idle":"2024-09-29T20:23:27.136539Z","shell.execute_reply.started":"2024-09-29T20:23:27.123113Z","shell.execute_reply":"2024-09-29T20:23:27.135817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Шлях до даних\nDATA_DIR = '../input/rsna-2024-lumbar-spine-degenerative-classification/'\n\n# Шляхи до CSV файлів\nTRAIN_CSV = os.path.join(DATA_DIR, 'train.csv')\nTRAIN_LABELS_CSV = os.path.join(DATA_DIR, 'train_label_coordinates.csv')\nTRAIN_SERIES_CSV = os.path.join(DATA_DIR, 'train_series_descriptions.csv')\nSAMPLE_SUBMISSION_CSV = os.path.join(DATA_DIR, 'sample_submission.csv')\n\n# Завантаження CSV файлів\ndf_train = pd.read_csv(TRAIN_CSV)\ndf_train_labels = pd.read_csv(TRAIN_LABELS_CSV)\ndf_train_series = pd.read_csv(TRAIN_SERIES_CSV)\ndf_sample_submission = pd.read_csv(SAMPLE_SUBMISSION_CSV)\n\nprint(f\"Кількість записів у тренувальних мітках: {len(df_train_labels)}\")","metadata":{"_uuid":"e892a070-efbb-4063-bf63-f056f1a9161f","_cell_guid":"402dd297-71fe-4f85-aed4-48234d51b5c3","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:27.137612Z","iopub.execute_input":"2024-09-29T20:23:27.137925Z","iopub.status.idle":"2024-09-29T20:23:27.245915Z","shell.execute_reply.started":"2024-09-29T20:23:27.137894Z","shell.execute_reply":"2024-09-29T20:23:27.245019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Оновлення шляху до зображень з урахуванням підпапок\ndf_train_labels['image_path'] = df_train_labels.apply(\n    lambda row: f\"../input/rsna-2024-lumbar-spine-degenerative-classification/train_images/{row['study_id']}/{row['series_id']}/{row['instance_number']}.dcm\", \n    axis=1\n)","metadata":{"_uuid":"0cd68979-d591-4b21-bc0c-73e992ab84bd","_cell_guid":"b23b5a6d-1c45-4e88-92d6-d7f21a417b82","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:27.247094Z","iopub.execute_input":"2024-09-29T20:23:27.247406Z","iopub.status.idle":"2024-09-29T20:23:28.211476Z","shell.execute_reply.started":"2024-09-29T20:23:27.247374Z","shell.execute_reply":"2024-09-29T20:23:28.210479Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Перевірка існування файлів\ndf_train_labels['file_exists'] = df_train_labels['image_path'].apply(lambda x: os.path.exists(x))\nprint(df_train_labels['file_exists'].value_counts())","metadata":{"_uuid":"656f414e-168c-4020-9cc7-f71d96ce8caa","_cell_guid":"267462e3-1234-4c4f-a19a-ebd9aef4992d","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:28.212905Z","iopub.execute_input":"2024-09-29T20:23:28.213616Z","iopub.status.idle":"2024-09-29T20:23:43.736367Z","shell.execute_reply.started":"2024-09-29T20:23:28.213569Z","shell.execute_reply":"2024-09-29T20:23:43.735401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Виведення кількох прикладів шляхів та їх перевірка\nsample_paths = df_train_labels['image_path'].head(10)\nfor path in sample_paths:\n    if os.path.exists(path):\n        print(f\"File exists: {path}\")\n    else:\n        print(f\"File NOT found: {path}\")","metadata":{"_uuid":"50a96c9b-b757-4f00-b271-5b8bb26e8fd8","_cell_guid":"9c3dba99-e106-4f49-8505-c52fb8e9f8ff","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.737831Z","iopub.execute_input":"2024-09-29T20:23:43.738236Z","iopub.status.idle":"2024-09-29T20:23:43.748605Z","shell.execute_reply.started":"2024-09-29T20:23:43.738193Z","shell.execute_reply":"2024-09-29T20:23:43.747717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df_train_labels.columns)","metadata":{"_uuid":"5e539b02-432e-4200-bf4a-93e499bafc78","_cell_guid":"8a6b1bf2-06bc-41e7-939e-5404f5a0734c","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.749980Z","iopub.execute_input":"2024-09-29T20:23:43.750541Z","iopub.status.idle":"2024-09-29T20:23:43.758115Z","shell.execute_reply.started":"2024-09-29T20:23:43.750498Z","shell.execute_reply":"2024-09-29T20:23:43.757301Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df_train_labels['condition'].unique())","metadata":{"_uuid":"12002b4f-aed9-426b-8bd5-eb9655ba29ba","_cell_guid":"1ae49064-9460-4a32-bf1f-413a7e5fc7af","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.759189Z","iopub.execute_input":"2024-09-29T20:23:43.759487Z","iopub.status.idle":"2024-09-29T20:23:43.771707Z","shell.execute_reply.started":"2024-09-29T20:23:43.759450Z","shell.execute_reply":"2024-09-29T20:23:43.770840Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\n# Створюємо LabelEncoder\nle = LabelEncoder()\n\n# Додаємо новий стовпець з закодованими значеннями\ndf_train_labels['severity_encoded'] = le.fit_transform(df_train_labels['condition'])","metadata":{"_uuid":"7a5a8c9d-d095-4362-ba6f-b4ee9df665b1","_cell_guid":"3ba771fb-f13f-49ea-818a-b8e505de2e66","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.772821Z","iopub.execute_input":"2024-09-29T20:23:43.773079Z","iopub.status.idle":"2024-09-29T20:23:43.790826Z","shell.execute_reply.started":"2024-09-29T20:23:43.773051Z","shell.execute_reply":"2024-09-29T20:23:43.790057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df_train_labels[['condition', 'severity_encoded']].head())","metadata":{"_uuid":"4fecdd74-0a4f-496a-a83a-f969822384d7","_cell_guid":"37479578-1c57-4316-99f0-ce67ff272137","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.795285Z","iopub.execute_input":"2024-09-29T20:23:43.795676Z","iopub.status.idle":"2024-09-29T20:23:43.803927Z","shell.execute_reply.started":"2024-09-29T20:23:43.795617Z","shell.execute_reply":"2024-09-29T20:23:43.802917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df_train_labels[['condition', 'severity_encoded']].head())","metadata":{"_uuid":"46ce5403-fa03-4b44-9f6f-fca9ffc6e58b","_cell_guid":"feae58b8-0f95-431e-b256-04c715cc0049","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.804973Z","iopub.execute_input":"2024-09-29T20:23:43.805327Z","iopub.status.idle":"2024-09-29T20:23:43.814238Z","shell.execute_reply.started":"2024-09-29T20:23:43.805288Z","shell.execute_reply":"2024-09-29T20:23:43.813351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\ndf_train_labels['fold'] = -1\n\nfor fold_num, (train_idx, val_idx) in enumerate(skf.split(df_train_labels, df_train_labels['severity_encoded'])):\n    df_train_labels.loc[val_idx, 'fold'] = fold_num","metadata":{"_uuid":"e7647cb4-f618-4afc-be75-e68134772f9b","_cell_guid":"46bdabb5-524d-4f31-b825-210752ba9871","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.815955Z","iopub.execute_input":"2024-09-29T20:23:43.816238Z","iopub.status.idle":"2024-09-29T20:23:43.836192Z","shell.execute_reply.started":"2024-09-29T20:23:43.816207Z","shell.execute_reply":"2024-09-29T20:23:43.835332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Параметри DataLoader\nbatch_size = 512  # Тестуйте різні розміри залежно від GPU\nnum_workers = 8   # Залежить від вашого CPU\n\nfold = 0  # Вибір фолду для валідації\ntrain_df = df_train_labels[df_train_labels['fold'] != fold].reset_index(drop=True)\nval_df = df_train_labels[df_train_labels['fold'] == fold].reset_index(drop=True)\n\n# Створення датасетів для тренування та валідації\ntrain_dataset = SpineDataset(train_df, transforms=train_transforms)\nval_dataset = SpineDataset(val_df, transforms=valid_transforms)\n\n# Створення DataLoader для тренувальних та валідаційних даних\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers, pin_memory=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=num_workers, pin_memory=True)","metadata":{"_uuid":"de429872-ac2e-4809-93a5-c922a9bfec3f","_cell_guid":"0dc96355-98dd-49c2-ab73-bff91641adec","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.837444Z","iopub.execute_input":"2024-09-29T20:23:43.837894Z","iopub.status.idle":"2024-09-29T20:23:43.861700Z","shell.execute_reply.started":"2024-09-29T20:23:43.837852Z","shell.execute_reply":"2024-09-29T20:23:43.861010Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataloaders = {'train': train_loader, 'val': val_loader}\n\n# Модель ResNet для класифікації\nmodel = models.resnet18(pretrained=True)\nmodel.fc = nn.Linear(model.fc.in_features, len(df_train_labels['severity_encoded'].unique()))  # Враховуємо кількість класів\n\n# Перенесення моделі на GPU\nmodel = model.to(device)\n\n# Оптимізатор та scheduler\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\nscheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\nscaler = GradScaler()  # Змішана точність для прискорення на GPU","metadata":{"_uuid":"592deaf5-c298-4100-b20e-c3fbcd10cfd4","_cell_guid":"97e63c40-b08a-479c-9337-491c47894482","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:43.862630Z","iopub.execute_input":"2024-09-29T20:23:43.862920Z","iopub.status.idle":"2024-09-29T20:23:44.130004Z","shell.execute_reply.started":"2024-09-29T20:23:43.862889Z","shell.execute_reply":"2024-09-29T20:23:44.129006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model_without_mixed_precision(model, dataloaders, criterion, optimizer, scheduler, device, num_epochs=25):\n    best_model_wts = model.state_dict()\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print(f'Епоха {epoch+1}/{num_epochs}')\n        print('-' * 10)\n\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Тренувальний режим\n            else:\n                model.eval()   # Валідаційний режим\n\n            running_loss = 0.0\n            running_corrects = 0\n\n            for inputs, labels in tqdm(dataloaders[phase], desc=f\"{phase.capitalize()} Phase\"):\n                inputs = inputs.to(device, non_blocking=True)\n                labels = labels.to(device, non_blocking=True)\n\n                optimizer.zero_grad()\n\n                outputs = model(inputs)\n                loss = criterion(outputs, labels)\n                _, preds = torch.max(outputs, 1)\n\n                if phase == 'train':\n                    loss.backward()\n                    optimizer.step()\n                    scheduler.step()\n\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n\n            epoch_loss = running_loss / len(dataloaders[phase].dataset)\n            epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)\n\n            print(f'{phase.capitalize()} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = model.state_dict()\n\n        # Моніторинг GPU після кожної епохи\n        print_gpu_status()\n\n    print(f'Найкраща валідаційна точність: {best_acc:.4f}')\n\n    model.load_state_dict(best_model_wts)\n    return model\n","metadata":{"_uuid":"ae6cccb7-34f3-4461-be17-16dece652d6c","_cell_guid":"136b442f-ef89-42ed-b2dd-0624ae10825e","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:44.131100Z","iopub.execute_input":"2024-09-29T20:23:44.131402Z","iopub.status.idle":"2024-09-29T20:23:44.143606Z","shell.execute_reply.started":"2024-09-29T20:23:44.131371Z","shell.execute_reply":"2024-09-29T20:23:44.142430Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Параметри DataLoader і створення DataLoader\nbatch_size = 1024\nnum_workers = 16\n\nfold = 0  # Вибір фолду для валідації\ntrain_df = df_train_labels[df_train_labels['fold'] != fold].reset_index(drop=True)\nval_df = df_train_labels[df_train_labels['fold'] == fold].reset_index(drop=True)\n\n# Створення датасетів для тренування та валідації\ntrain_dataset = SpineDataset(train_df, transforms=train_transforms)\nval_dataset = SpineDataset(val_df, transforms=valid_transforms)\n\n# Створення DataLoader для тренувальних та валідаційних даних\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers, pin_memory=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=num_workers, pin_memory=True)\n\ndataloaders = {'train': train_loader, 'val': val_loader}\n\n# Модель ResNet для класифікації\nmodel = models.resnet18(pretrained=True)\nmodel.fc = nn.Linear(model.fc.in_features, len(df_train_labels['severity_encoded'].unique()))  # Враховуємо кількість класів\n\n# Переносимо модель на GPU\nmodel = model.to(device)\n\n# Оптимізатор та scheduler\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\nscheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\nscaler = GradScaler()  # Змішана точність для прискорення на GPU","metadata":{"_uuid":"cf5eddc3-5a92-40b2-bdd8-b32e680d3cf9","_cell_guid":"ce31ee75-a99e-4ccd-96bf-bda5f7bd6529","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:44.145309Z","iopub.execute_input":"2024-09-29T20:23:44.146302Z","iopub.status.idle":"2024-09-29T20:23:44.424015Z","shell.execute_reply.started":"2024-09-29T20:23:44.146245Z","shell.execute_reply":"2024-09-29T20:23:44.422993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Функція для тренування моделі без GradScaler\ndef train_model_without_mixed_precision(model, dataloaders, criterion, optimizer, scheduler, device, num_epochs=25):\n    best_model_wts = model.state_dict()\n    best_acc = 0.0\n\n    # Перевірка пристрою моделі перед тренуванням\n    print(f\"Модель працює на {next(model.parameters()).device}\")\n\n    for epoch in range(num_epochs):\n        print(f'Епоха {epoch+1}/{num_epochs}')\n        print('-' * 10)\n\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Тренувальний режим\n            else:\n                model.eval()   # Валідаційний режим\n\n            running_loss = 0.0\n            running_corrects = 0\n\n            # Проходження через батчі\n            for inputs, labels in tqdm(dataloaders[phase], desc=f\"{phase.capitalize()} Phase\"):\n                # Переносимо дані на GPU\n                inputs = inputs.to(device, non_blocking=True)\n                labels = labels.to(device, non_blocking=True)\n\n                # Обнулення градієнтів\n                optimizer.zero_grad()\n\n                # Прямий прохід і обчислення втрат\n                outputs = model(inputs)\n                loss = criterion(outputs, labels)\n                _, preds = torch.max(outputs, 1)\n\n                # Зворотне поширення та оптимізація в тренувальній фазі\n                if phase == 'train':\n                    loss.backward()\n                    optimizer.step()\n                    scheduler.step()\n\n                # Статистика\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n\n            epoch_loss = running_loss / len(dataloaders[phase].dataset)\n            epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)\n\n            print(f'{phase.capitalize()} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n\n            # Збереження найкращої моделі\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = model.state_dict()\n\n        # Моніторинг GPU після кожної епохи\n        print_gpu_status()\n\n        # Очищення кешу GPU після кожної епохи\n        torch.cuda.empty_cache()\n\n    print(f'Найкраща валідаційна точність: {best_acc:.4f}')\n\n    # Завантажуємо найкращі ваги моделі\n    model.load_state_dict(best_model_wts)\n    return model\n","metadata":{"_uuid":"cafe98cb-f755-4d4d-8011-5cc23f98753f","_cell_guid":"9c4bde82-4963-498a-b9df-05aec3ecb758","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:44.425267Z","iopub.execute_input":"2024-09-29T20:23:44.425575Z","iopub.status.idle":"2024-09-29T20:23:44.439543Z","shell.execute_reply.started":"2024-09-29T20:23:44.425543Z","shell.execute_reply":"2024-09-29T20:23:44.438621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Визначаємо функцію втрат і кількість епох\ncriterion = nn.CrossEntropyLoss()\nnum_epochs = 10\n\n# Тренуємо модель без змішаної точності\nbest_model = train_model_without_mixed_precision(\n    model=model,\n    dataloaders=dataloaders,\n    criterion=criterion,\n    optimizer=optimizer,\n    scheduler=scheduler,\n    device=device,\n    num_epochs=num_epochs\n)","metadata":{"_uuid":"7ec5a7ba-2409-405a-bb62-9d5d3a6c7975","_cell_guid":"935955c0-be86-4323-b48f-164c9358742b","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:23:44.440958Z","iopub.execute_input":"2024-09-29T20:23:44.441324Z","iopub.status.idle":"2024-09-29T20:28:51.519355Z","shell.execute_reply.started":"2024-09-29T20:23:44.441283Z","shell.execute_reply":"2024-09-29T20:28:51.517752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Оцінка моделі на валідаційних даних\ndef evaluate_model(model, dataloader, criterion, device):\n    model.eval()\n    running_loss = 0.0\n    running_corrects = 0\n\n    for inputs, labels in tqdm(dataloader, desc=\"Evaluation Phase\"):\n        inputs = inputs.to(device, non_blocking=True)\n        labels = labels.to(device, non_blocking=True)\n\n        with torch.no_grad():\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            _, preds = torch.max(outputs, 1)\n\n        running_loss += loss.item() * inputs.size(0)\n        running_corrects += torch.sum(preds == labels.data)\n\n    total_loss = running_loss / len(dataloader.dataset)\n    total_acc = running_corrects.double() / len(dataloader.dataset)\n    \n    print(f'Loss: {total_loss:.4f} Acc: {total_acc:.4f}')\n\n# Оцінюємо модель на валідаційній вибірці\nevaluate_model(best_model, val_loader, criterion, device)","metadata":{"_uuid":"5dfd1d46-8632-4668-b24d-2c19fef4a1d1","_cell_guid":"7cdfd2b2-a8c4-46ce-84a6-2096ac54b4ee","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:28:51.520795Z","iopub.status.idle":"2024-09-29T20:28:51.521319Z","shell.execute_reply.started":"2024-09-29T20:28:51.521050Z","shell.execute_reply":"2024-09-29T20:28:51.521077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Функція для збереження моделі\ndef save_model(model, model_path=\"best_model.pth\"):\n    torch.save(model.state_dict(), model_path)\n    print(f\"Модель збережено за адресою: {model_path}\")\n\n# Збереження найкращої моделі\nsave_model(best_model)","metadata":{"_uuid":"58bf90c6-4d43-45f3-bf37-a30261ac257c","_cell_guid":"fd6b5ac2-dcd7-4ab3-add5-d1c6df454d00","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:28:51.523558Z","iopub.status.idle":"2024-09-29T20:28:51.524353Z","shell.execute_reply.started":"2024-09-29T20:28:51.524095Z","shell.execute_reply":"2024-09-29T20:28:51.524120Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Функція для завантаження збереженої моделі\ndef load_model(model, model_path=\"best_model.pth\"):\n    model.load_state_dict(torch.load(model_path))\n    model.eval()  # Переключаємо модель у режим оцінки\n    print(f\"Модель завантажена з: {model_path}\")\n    return model\n\n# Завантаження моделі\nloaded_model = load_model(model, \"best_model.pth\")","metadata":{"_uuid":"ce8b2529-53a1-4fbf-bf1a-2df1a89f41d5","_cell_guid":"9140a12b-b082-4331-8fb8-bedf03e5007f","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:28:51.525799Z","iopub.status.idle":"2024-09-29T20:28:51.526570Z","shell.execute_reply.started":"2024-09-29T20:28:51.526313Z","shell.execute_reply":"2024-09-29T20:28:51.526339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Оцінка збереженої моделі на валідаційних даних\nevaluate_model(loaded_model, val_loader, criterion, device)","metadata":{"_uuid":"7204cde3-b4d5-4f4e-8e0d-0f552be535fe","_cell_guid":"eaf10270-e134-4b0b-a4c2-dca10e1ed877","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:28:51.528033Z","iopub.status.idle":"2024-09-29T20:28:51.528834Z","shell.execute_reply.started":"2024-09-29T20:28:51.528542Z","shell.execute_reply":"2024-09-29T20:28:51.528569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Інференс на нових даних\ndef inference(model, dataloader, device):\n    model.eval()\n    predictions = []\n\n    for inputs in tqdm(dataloader, desc=\"Inference Phase\"):\n        inputs = inputs.to(device, non_blocking=True)\n        \n        with torch.no_grad():\n            outputs = model(inputs)\n            _, preds = torch.max(outputs, 1)\n            predictions.append(preds.cpu().numpy())\n    \n    return np.concatenate(predictions)\n\n# Створюємо DataLoader для нових даних (припустимо, що нові дані мають той самий формат, що і валідаційні)\n# inference_loader = DataLoader(new_dataset, batch_size=batch_size, shuffle=False, num_workers=num_workers, pin_memory=True)\n\n# Отримання прогнозів\n# predictions = inference(loaded_model, inference_loader, device)","metadata":{"_uuid":"49555237-224d-410b-b4b4-eecf2e1d83c8","_cell_guid":"0d8af2ee-9ab7-4417-9709-f50ec6f42b4a","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:28:51.530298Z","iopub.status.idle":"2024-09-29T20:28:51.531088Z","shell.execute_reply.started":"2024-09-29T20:28:51.530829Z","shell.execute_reply":"2024-09-29T20:28:51.530855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Функція для перетворення прогнозів у зручний для подання формат\ndef create_submission(predictions, sample_submission):\n    sample_submission['severity_encoded'] = predictions\n    sample_submission.to_csv('submission.csv', index=False)\n    print(f\"Файл з результатами збережено як: submission.csv\")\n\n# Створюємо файл для подання\n# create_submission(predictions, df_sample_submission)","metadata":{"_uuid":"17aa524a-38c2-4053-9843-60e5f872bdcf","_cell_guid":"e1dfe1c7-9ce4-4c2e-9be0-1dcea6633de5","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-09-29T20:28:51.532528Z","iopub.status.idle":"2024-09-29T20:28:51.533360Z","shell.execute_reply.started":"2024-09-29T20:28:51.533081Z","shell.execute_reply":"2024-09-29T20:28:51.533109Z"},"trusted":true},"execution_count":null,"outputs":[]}]}