{"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"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import json\nimport glob\nimport random\nimport collections\n\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\n\nimport numpy as np\nimport pandas as pd\n\nimport os\nimport plotly.express as px\n\nimport matplotlib\nimport matplotlib.pyplot as plt\n%matplotlib inline\nimport seaborn as sns\nimport cv2\n\n#Text Color\nfrom termcolor import colored\n\npackage_path = \"../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master/\"\nimport sys \nsys.path.append(package_path)\n\nimport time\n\nimport torch\nfrom torch import nn\nfrom torch.utils import data as torch_data\nfrom sklearn import model_selection as sk_model_selection\nfrom torch.nn import functional as torch_functional\nimport efficientnet_pytorch\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom kaggle_secrets import UserSecretsClient\nuser_secrets = UserSecretsClient()\nsecret_value_0 = user_secrets.get_secret(\"wandb_key\")\n# W&B for experiment tracking\nimport wandb\nwandb.login(key = secret_value_0)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:37.33534Z","iopub.execute_input":"2021-08-14T19:35:37.335729Z","iopub.status.idle":"2021-08-14T19:35:51.930322Z","shell.execute_reply.started":"2021-08-14T19:35:37.335642Z","shell.execute_reply":"2021-08-14T19:35:51.929383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class config:\n    DIRECTORY_PATH = \"../input/rsna-miccai-brain-tumor-radiogenomic-classification\"\n    TRAIN_LABELS_PATH = DIRECTORY_PATH + \"/train_labels.csv\"\n    \n# wandb config\nWANDB_CONFIG = {\n    'competition': 'rsna-miccai-brain', \n}","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:55.372903Z","iopub.execute_input":"2021-08-14T19:35:55.373245Z","iopub.status.idle":"2021-08-14T19:35:55.377976Z","shell.execute_reply.started":"2021-08-14T19:35:55.373207Z","shell.execute_reply":"2021-08-14T19:35:55.376816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    if torch.cuda.is_available():\n        torch.cuda.manual_seed_all(seed)\n        torch.backends.cudnn.deterministic = True\n\n\nset_seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:55.649689Z","iopub.execute_input":"2021-08-14T19:35:55.650011Z","iopub.status.idle":"2021-08-14T19:35:55.699694Z","shell.execute_reply.started":"2021-08-14T19:35:55.649981Z","shell.execute_reply":"2021-08-14T19:35:55.698757Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv(config.TRAIN_LABELS_PATH)\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:56.734028Z","iopub.execute_input":"2021-08-14T19:35:56.734439Z","iopub.status.idle":"2021-08-14T19:35:56.765035Z","shell.execute_reply.started":"2021-08-14T19:35:56.734406Z","shell.execute_reply":"2021-08-14T19:35:56.764226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Function to print stylized text\ndef style_text(text, text_color = 'yellow', attributes = ['bold'], data = False):\n    \"\"\"\n    Function to stylize print Text using Colored by Termcolor\n    \n    parameters: text(str) - Input Text to be Stylized\n                text_color(str) - Color of text\n                attributes(list of strings) - Attributes to be applied on text\n                data - To be printed with text \n    \"\"\"\n    if data:\n        print(colored(text, text_color, attrs = attributes), data)\n        \n    else:\n        print(colored(text, text_color, attrs = attributes))","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:58.285119Z","iopub.execute_input":"2021-08-14T19:35:58.285504Z","iopub.status.idle":"2021-08-14T19:35:58.291128Z","shell.execute_reply.started":"2021-08-14T19:35:58.28547Z","shell.execute_reply":"2021-08-14T19:35:58.290223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Data shape\nstyle_text(\"No. of Rows in train_df: \", data = train_df.shape[0])\nstyle_text(\"No. of Columns in train_df: \", data = train_df.shape[1])","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:58.655433Z","iopub.execute_input":"2021-08-14T19:35:58.65577Z","iopub.status.idle":"2021-08-14T19:35:58.661168Z","shell.execute_reply.started":"2021-08-14T19:35:58.655735Z","shell.execute_reply":"2021-08-14T19:35:58.659963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Missing Values\nstyle_text(\"Missing Values in train_df:\")\nprint(train_df.isnull().sum())","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:59.003793Z","iopub.execute_input":"2021-08-14T19:35:59.004107Z","iopub.status.idle":"2021-08-14T19:35:59.010649Z","shell.execute_reply.started":"2021-08-14T19:35:59.004078Z","shell.execute_reply":"2021-08-14T19:35:59.009624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Thus, there are no missing values in the `train_df` dataset.","metadata":{}},{"cell_type":"code","source":"#Dataset Info\nstyle_text(\"Info about train_df:\")\ntrain_df.info()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:35:59.814073Z","iopub.execute_input":"2021-08-14T19:35:59.814424Z","iopub.status.idle":"2021-08-14T19:35:59.831559Z","shell.execute_reply.started":"2021-08-14T19:35:59.814392Z","shell.execute_reply":"2021-08-14T19:35:59.830425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## CountPlot for MGMT Value","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(5, 5))\nsns.countplot(data=train_df, x=\"MGMT_value\");","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:00.605866Z","iopub.execute_input":"2021-08-14T19:36:00.606186Z","iopub.status.idle":"2021-08-14T19:36:00.750143Z","shell.execute_reply.started":"2021-08-14T19:36:00.606156Z","shell.execute_reply":"2021-08-14T19:36:00.749193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wandb.init(project='brain-tumor-video', config=WANDB_CONFIG)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:02.614877Z","iopub.execute_input":"2021-08-14T19:36:02.615204Z","iopub.status.idle":"2021-08-14T19:36:08.890814Z","shell.execute_reply.started":"2021-08-14T19:36:02.615172Z","shell.execute_reply":"2021-08-14T19:36:08.889995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dicom(path):\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\n    data = data - np.min(data)\n    if np.max(data) != 0:\n        data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return data","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:08.893675Z","iopub.execute_input":"2021-08-14T19:36:08.893938Z","iopub.status.idle":"2021-08-14T19:36:08.900199Z","shell.execute_reply.started":"2021-08-14T19:36:08.893907Z","shell.execute_reply":"2021-08-14T19:36:08.899357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv\")\ndf_train, df_valid = sk_model_selection.train_test_split(\n    df, \n    test_size=0.2, \n    random_state=42, \n    stratify=train_df[\"MGMT_value\"],\n)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:08.902388Z","iopub.execute_input":"2021-08-14T19:36:08.90296Z","iopub.status.idle":"2021-08-14T19:36:08.917969Z","shell.execute_reply.started":"2021-08-14T19:36:08.902899Z","shell.execute_reply":"2021-08-14T19:36:08.917142Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataRetriever(torch_data.Dataset):\n    def __init__(self, paths, targets):\n        self.paths = paths\n        self.targets = targets\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):\n        _id = self.paths[index]\n        patient_path = f\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/{str(_id).zfill(5)}/\"\n        channels = []\n        for t in (\"FLAIR\", \"T1w\", \"T1wCE\"): # \"T2w\"\n            t_paths = sorted(\n                glob.glob(os.path.join(patient_path, t, \"*\")), \n                key=lambda x: int(x[:-4].split(\"-\")[-1]),\n            )\n            # start, end = int(len(t_paths) * 0.475), int(len(t_paths) * 0.525)\n            x = len(t_paths)\n            if x < 10:\n                r = range(x)\n            else:\n                d = x // 10\n                r = range(d, x - d, d)\n                \n            channel = []\n            # for i in range(start, end + 1):\n            for i in r:\n                channel.append(cv2.resize(load_dicom(t_paths[i]), (256, 256)) / 255)\n            channel = np.mean(channel, axis=0)\n            channels.append(channel)\n            \n        y = torch.tensor(self.targets[index], dtype=torch.float)\n        \n        return {\"X\": torch.tensor(channels).float(), \"y\": y}","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:08.919595Z","iopub.execute_input":"2021-08-14T19:36:08.919894Z","iopub.status.idle":"2021-08-14T19:36:08.930924Z","shell.execute_reply.started":"2021-08-14T19:36:08.919867Z","shell.execute_reply":"2021-08-14T19:36:08.929971Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_retriever = DataRetriever(\n    df_train[\"BraTS21ID\"].values, \n    df_train[\"MGMT_value\"].values, \n)\n\nvalid_data_retriever = DataRetriever(\n    df_valid[\"BraTS21ID\"].values, \n    df_valid[\"MGMT_value\"].values,\n)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:08.932389Z","iopub.execute_input":"2021-08-14T19:36:08.933016Z","iopub.status.idle":"2021-08-14T19:36:08.943936Z","shell.execute_reply.started":"2021-08-14T19:36:08.932976Z","shell.execute_reply":"2021-08-14T19:36:08.94305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(16, 6))\nfor i in range(3):\n    plt.subplot(1, 3, i + 1)\n    plt.imshow(train_data_retriever[100][\"X\"].numpy()[i], cmap=\"gray\")","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:08.945413Z","iopub.execute_input":"2021-08-14T19:36:08.946169Z","iopub.status.idle":"2021-08-14T19:36:09.996058Z","shell.execute_reply.started":"2021-08-14T19:36:08.946125Z","shell.execute_reply":"2021-08-14T19:36:09.995205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Model(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.net = efficientnet_pytorch.EfficientNet.from_name(\"efficientnet-b0\")\n        checkpoint = torch.load(\"../input/efficientnet-pytorch/efficientnet-b0-08094119.pth\")\n        self.net.load_state_dict(checkpoint)\n        n_features = self.net._fc.in_features\n        self.net._fc = nn.Linear(in_features=n_features, out_features=1, bias=True)\n    \n    def forward(self, x):\n        out = self.net(x)\n        return out","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:09.997212Z","iopub.execute_input":"2021-08-14T19:36:09.997755Z","iopub.status.idle":"2021-08-14T19:36:10.005168Z","shell.execute_reply.started":"2021-08-14T19:36:09.997712Z","shell.execute_reply":"2021-08-14T19:36:10.004205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class LossMeter:\n    def __init__(self):\n        self.avg = 0\n        self.n = 0\n\n    def update(self, val):\n        self.n += 1\n        # incremental update\n        self.avg = val / self.n + (self.n - 1) / self.n * self.avg\n\n        \nclass AccMeter:\n    def __init__(self):\n        self.avg = 0\n        self.n = 0\n        \n    def update(self, y_true, y_pred):\n        y_true = y_true.cpu().numpy().astype(int)\n        y_pred = y_pred.cpu().numpy() >= 0\n        last_n = self.n\n        self.n += len(y_true)\n        true_count = np.sum(y_true == y_pred)\n        # incremental update\n        self.avg = true_count / self.n + last_n / self.n * self.avg","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:10.007433Z","iopub.execute_input":"2021-08-14T19:36:10.007938Z","iopub.status.idle":"2021-08-14T19:36:10.018924Z","shell.execute_reply.started":"2021-08-14T19:36:10.0079Z","shell.execute_reply":"2021-08-14T19:36:10.018019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Wandb Step 2:** In this example we are going to log the Training and Validation losses. To do this we need to instruct wandb to `watch` the `model`","metadata":{}},{"cell_type":"code","source":"class Trainer:\n    def __init__(\n        self, \n        model, \n        device, \n        optimizer, \n        criterion, \n        loss_meter, \n        score_meter\n    ):\n        self.model = model\n        self.device = device\n        self.optimizer = optimizer\n        self.criterion = criterion\n        self.loss_meter = loss_meter\n        self.score_meter = score_meter\n        \n        self.best_valid_score = -np.inf\n        self.n_patience = 0\n        \n        self.messages = {\n            \"epoch\": \"[Epoch {}: {}] loss: {:.5f}, score: {:.5f}, time: {} s\",\n            \"checkpoint\": \"The score improved from {:.5f} to {:.5f}. Save model to '{}'\",\n            \"patience\": \"\\nValid score didn't improve last {} epochs.\"\n        }\n    \n    def fit(self, epochs, train_loader, valid_loader, save_path, patience):        \n        for n_epoch in range(1, epochs + 1):\n            self.info_message(\"EPOCH: {}\", n_epoch)\n            \n            train_loss, train_score, train_time = self.train_epoch(train_loader)\n            valid_loss, valid_score, valid_time = self.valid_epoch(valid_loader)\n            \n            self.info_message(\n                self.messages[\"epoch\"], \"Train\", n_epoch, train_loss, train_score, train_time\n            )\n            \n            self.info_message(\n                self.messages[\"epoch\"], \"Valid\", n_epoch, valid_loss, valid_score, valid_time\n            )\n\n            if True:\n#             if self.best_valid_score < valid_score:\n                self.info_message(\n                    self.messages[\"checkpoint\"], self.best_valid_score, valid_score, save_path\n                )\n                self.best_valid_score = valid_score\n                self.save_model(n_epoch, save_path)\n                self.n_patience = 0\n            else:\n                self.n_patience += 1\n            \n            if self.n_patience >= patience:\n                self.info_message(self.messages[\"patience\"], patience)\n                break\n            \n    def train_epoch(self, train_loader):\n        \n        wandb.watch(model,log_freq=100)    # Use wandb.watch() to provide the model to be logged upon\n\n        self.model.train()\n        t = time.time()\n        train_loss = self.loss_meter()\n        train_score = self.score_meter()\n                \n        for step, batch in enumerate(train_loader, 1):\n            X = batch[\"X\"].to(self.device)\n            targets = batch[\"y\"].to(self.device)\n            self.optimizer.zero_grad()\n            outputs = self.model(X).squeeze(1)\n            \n            loss = self.criterion(outputs, targets)\n            wandb.log({\"train_loss\": loss})    # Use wandb.log() to log desired metrics \n            \n            loss.backward()\n\n            train_loss.update(loss.detach().item())\n            train_score.update(targets, outputs.detach())\n\n            self.optimizer.step()\n            \n            _loss, _score = train_loss.avg, train_score.avg\n            message = 'Train Step {}/{}, train_loss: {:.5f}, train_score: {:.5f}'\n            self.info_message(message, step, len(train_loader), _loss, _score, end=\"\\r\")\n        \n        return train_loss.avg, train_score.avg, int(time.time() - t)\n    \n    def valid_epoch(self, valid_loader):\n        self.model.eval()\n        t = time.time()\n        valid_loss = self.loss_meter()\n        valid_score = self.score_meter()\n        \n        for step, batch in enumerate(valid_loader, 1):\n            with torch.no_grad():\n                X = batch[\"X\"].to(self.device)\n                targets = batch[\"y\"].to(self.device)\n\n                outputs = self.model(X).squeeze(1)\n                loss = self.criterion(outputs, targets)\n                wandb.log({\"valid_loss\": loss})    # Use wandb.log() to log desired metrics \n\n                valid_loss.update(loss.detach().item())\n                valid_score.update(targets, outputs)\n                \n            _loss, _score = valid_loss.avg, valid_score.avg\n            message = 'Valid Step {}/{}, valid_loss: {:.5f}, valid_score: {:.5f}'\n            self.info_message(message, step, len(valid_loader), _loss, _score, end=\"\\r\")\n        \n        return valid_loss.avg, valid_score.avg, int(time.time() - t)\n    \n    def save_model(self, n_epoch, save_path):\n        torch.save(\n            {\n                \"model_state_dict\": self.model.state_dict(),\n                \"optimizer_state_dict\": self.optimizer.state_dict(),\n                \"best_valid_score\": self.best_valid_score,\n                \"n_epoch\": n_epoch,\n            },\n            save_path,\n        )\n    \n    @staticmethod\n    def info_message(message, *args, end=\"\\n\"):\n        print(message.format(*args), end=end)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:10.020575Z","iopub.execute_input":"2021-08-14T19:36:10.020953Z","iopub.status.idle":"2021-08-14T19:36:10.043719Z","shell.execute_reply.started":"2021-08-14T19:36:10.020915Z","shell.execute_reply":"2021-08-14T19:36:10.042902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ntrain_data_retriever = DataRetriever(\n    df_train[\"BraTS21ID\"].values, \n    df_train[\"MGMT_value\"].values, \n)\n\nvalid_data_retriever = DataRetriever(\n    df_valid[\"BraTS21ID\"].values, \n    df_valid[\"MGMT_value\"].values,\n)\n\ntrain_loader = torch_data.DataLoader(\n    train_data_retriever,\n    batch_size=8,\n    shuffle=True,\n    num_workers=8,\n)\n\nvalid_loader = torch_data.DataLoader(\n    valid_data_retriever, \n    batch_size=8,\n    shuffle=False,\n    num_workers=8,\n)\n\nmodel = Model()\nmodel.to(device)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\ncriterion = torch_functional.binary_cross_entropy_with_logits\n\ntrainer = Trainer(\n    model, \n    device, \n    optimizer, \n    criterion, \n    LossMeter, \n    AccMeter\n)\n\nhistory = trainer.fit(\n    1, \n    train_loader, \n    valid_loader, \n    f\"best-model-0.pth\", \n    100,\n)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:36:10.045046Z","iopub.execute_input":"2021-08-14T19:36:10.045397Z","iopub.status.idle":"2021-08-14T19:37:27.434973Z","shell.execute_reply.started":"2021-08-14T19:36:10.045363Z","shell.execute_reply":"2021-08-14T19:37:27.43403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"And that's it, with just 2 Steps you have successfully integrated wandb to your project. Now you can go to your dashboard and check the logged metrics. You can even follow the same method to log the hyperparameters.","metadata":{}},{"cell_type":"code","source":"models = []\nfor i in range(1):\n    model = Model()\n    model.to(device)\n    \n    checkpoint = torch.load(f\"best-model-{i}.pth\")\n    model.load_state_dict(checkpoint[\"model_state_dict\"])\n    model.eval()\n    \n    models.append(model)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T19:37:27.436916Z","iopub.execute_input":"2021-08-14T19:37:27.437307Z","iopub.status.idle":"2021-08-14T19:37:27.73051Z","shell.execute_reply.started":"2021-08-14T19:37:27.437219Z","shell.execute_reply":"2021-08-14T19:37:27.729656Z"},"trusted":true},"execution_count":null,"outputs":[]}]}