{
  "id": 280107,
  "title": "691nd place solution. (Code)",
  "url": "/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/discussion/280107",
  "author_name": "Innat",
  "post_date": "2021-10-20T13:36:29.509000",
  "votes": 9,
  "comment_count": 0,
  "views": 0,
  "content": "<p>Big congrats to all the winners. Though we couldn't survive the shake-up and were way too behind, we thought it might be useful for some readers. From the beginning, we've mainly aimed to hands-on the 3D data set and 3D modeling approach first time with <code>TensorFlow.Keras</code> and 3D augmentation for that as well.</p>\n<p><strong>3D modeling</strong>:  We only use <a href=\"https://github.com/ZFTurbo/efficientnet_3D\" target=\"_blank\"><code>3D-EfficientNet-BO</code> </a> for most of the cases due to limited resources. We trained the model with 5 fold stratified dataset, considering all modalities. In most of the folds training, we used <a href=\"https://github.com/ZFTurbo/volumentations\" target=\"_blank\">volumentations</a> for augmenting the dataset. Basically, the most training part was taken from my <a href=\"https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification\" target=\"_blank\">public notebook</a>. Each of the 5 folds was trained with the same configuration (same seed, lr, etc), the local cv for each fold varies between 0.49~0.61. Next, we've used the Bayesian Optimization technique to get the optimal linear weights, using my other <a href=\"https://www.kaggle.com/ipythonx/optimizing-metrics-out-of-fold-weights-ensemble/notebook\" target=\"_blank\">notebook here</a>. </p>\n<table>\n<thead>\n<tr>\n<th>-</th>\n<th>3D-EfficientNet-BO</th>\n<th>SimpleAvg</th>\n<th>BaysianOpt</th>\n<th>TTA (Volumentation: Step 5)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CV</td>\n<td>(0.49~0.62)</td>\n<td>0.55</td>\n<td>0.57</td>\n<td>0.601</td>\n</tr>\n<tr>\n<td>Public LB</td>\n<td>--</td>\n<td>0.54</td>\n<td>0.59</td>\n<td>0.635</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<p><strong>2D Ensemble Modeling</strong>.  We've built a giant model for end-to-end training consisting of 4 models i.e. <code>EfficientNetB2</code>, <code>DenseNet121</code>, <code>ResNet18</code> and <code>SeResNeXt50</code> - where each modality passed as in input for each models but <strong>randomly</strong>.  </p>\n<pre><code>def build_model(base_net):\n\n    if base_net == 'a':\n        base_Mchannel = model.EfficientNetB2\n        x = layers.Dropout\n        return Model(inputs=base_Mchannel.input, \n                              outputs=x, name='flair')\n    elif base_net == 'b':\n        base_Mchannel = model.DenseNet121\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1')\n    elif base_net == 'c':\n        get_model, _ = Classifiers.get('resnet18')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1w')\n    elif base_net == 'd':\n        get_model, _ = Classifiers.get('seresnext50')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D) \n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t2')\n\n# detect and init the TPU\nmodel_a = build_model('a') # for flair\nmodel_b = build_model('b') # for t1\nmodel_c = build_model('c') # for t1w\nmodel_d = build_model('d') # for t2\n\nx_a = layers.Dense(764, activation='relu')(model_a.output)\nx_b = layers.Dense(764, activation='relu')(model_b.output)\nx_c = layers.Dense(764, activation='relu')(model_c.output)\nx_d = layers.Dense(764, activation='relu')(model_d.output)\noutput = layers.average([x_a, x_b, x_c, x_d])\n\nhead_layer = layers.Dense(512, activation='relu')(output)\nhead_layer = layers.Dropout(0.5)(head_layer)\nfindal_output = layers.Dense(1, activation='sigmoid')(head_layer)\nmodel = Model(\n    inputs  = [model_a.input, model_b.input, \n                     model_c.input, model_d.input],\n    outputs = [findal_output]\n)\n</code></pre>\n<p>We have also the <code>Swin-Transformer</code> one of the four models but it didn't perform well (or we were too impatient). Additionally, during the training time, we randomly switch the modality from the dataloader. It's done on the assumption that each of the four models may have the knowledge of modalities. </p>\n<pre><code>      if self.split == 'train':\n            if np.random.rand() &lt; 0.2:\n                flair_x, t1_x = t1_x, flair_x\n            elif np.random.rand() &lt; 0.4:\n                t1w_x,  t2_x = t2_x, t1w_x\n            elif np.random.rand() &lt; 0.6:\n                t2_x, flair_x = flair_x, t2_x\n            else:\n                pass \n\n      # dictionary mapping for corresponding models \n      return {\n            'flair' : flair_x, \n            't1'    : t1_x, \n            't1w'   : t1w_x, \n            't2'    : t2_x \n        }\n</code></pre>\n<p>For 2D modeling, we've used built-in <a href=\"https://keras.io/api/layers/preprocessing_layers/image_augmentation/\" target=\"_blank\"><code>keras augmentation</code></a></p>\n<table>\n<thead>\n<tr>\n<th>-</th>\n<th>SimpleAvg</th>\n<th>TTA (Keras: Step 5)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CV</td>\n<td>0.59</td>\n<td>0.61</td>\n</tr>\n<tr>\n<td>Public LB</td>\n<td>0.57</td>\n<td>0.621</td>\n</tr>\n</tbody>\n</table>\n<p>Final Ensemble </p>\n<table>\n<thead>\n<tr>\n<th>-</th>\n<th>3D</th>\n<th>2D</th>\n<th>Public LB</th>\n<th>Private LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td></td>\n<td>0.635</td>\n<td>0.621</td>\n<td>0.68340</td>\n<td>0.52730</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<p><strong>Final Note</strong></p>\n<p>It's not that robust model with many issues and we'll be continuing working on such problems. We've made all the code publicly accessible <a href=\"https://github.com/innat/BraTS-MGMT-Classification\" target=\"_blank\">BraTS-MGMT-Classification</a> with the structural format and actively updating. And here is the minimum <a href=\"https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification\" target=\"_blank\">notebook view</a>.</p>\n<h2>Code: <a href=\"https://github.com/innat/BraTS-MGMT-Classification\" target=\"_blank\">BraTS-MGMT-Classification</a></h2>",
  "messages": [
    {
      "id": 1551288,
      "postDate": "2021-10-20T13:36:29.510Z",
      "content": "<p>Big congrats to all the winners. Though we couldn't survive the shake-up and were way too behind, we thought it might be useful for some readers. From the beginning, we've mainly aimed to hands-on the 3D data set and 3D modeling approach first time with <code>TensorFlow.Keras</code> and 3D augmentation for that as well.</p>\n<p><strong>3D modeling</strong>:  We only use <a href=\"https://github.com/ZFTurbo/efficientnet_3D\" target=\"_blank\"><code>3D-EfficientNet-BO</code> </a> for most of the cases due to limited resources. We trained the model with 5 fold stratified dataset, considering all modalities. In most of the folds training, we used <a href=\"https://github.com/ZFTurbo/volumentations\" target=\"_blank\">volumentations</a> for augmenting the dataset. Basically, the most training part was taken from my <a href=\"https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification\" target=\"_blank\">public notebook</a>. Each of the 5 folds was trained with the same configuration (same seed, lr, etc), the local cv for each fold varies between 0.49~0.61. Next, we've used the Bayesian Optimization technique to get the optimal linear weights, using my other <a href=\"https://www.kaggle.com/ipythonx/optimizing-metrics-out-of-fold-weights-ensemble/notebook\" target=\"_blank\">notebook here</a>. </p>\n<table>\n<thead>\n<tr>\n<th>-</th>\n<th>3D-EfficientNet-BO</th>\n<th>SimpleAvg</th>\n<th>BaysianOpt</th>\n<th>TTA (Volumentation: Step 5)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CV</td>\n<td>(0.49~0.62)</td>\n<td>0.55</td>\n<td>0.57</td>\n<td>0.601</td>\n</tr>\n<tr>\n<td>Public LB</td>\n<td>--</td>\n<td>0.54</td>\n<td>0.59</td>\n<td>0.635</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<p><strong>2D Ensemble Modeling</strong>.  We've built a giant model for end-to-end training consisting of 4 models i.e. <code>EfficientNetB2</code>, <code>DenseNet121</code>, <code>ResNet18</code> and <code>SeResNeXt50</code> - where each modality passed as in input for each models but <strong>randomly</strong>.  </p>\n<pre><code>def build_model(base_net):\n\n    if base_net == 'a':\n        base_Mchannel = model.EfficientNetB2\n        x = layers.Dropout\n        return Model(inputs=base_Mchannel.input, \n                              outputs=x, name='flair')\n    elif base_net == 'b':\n        base_Mchannel = model.DenseNet121\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1')\n    elif base_net == 'c':\n        get_model, _ = Classifiers.get('resnet18')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1w')\n    elif base_net == 'd':\n        get_model, _ = Classifiers.get('seresnext50')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D) \n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t2')\n\n# detect and init the TPU\nmodel_a = build_model('a') # for flair\nmodel_b = build_model('b') # for t1\nmodel_c = build_model('c') # for t1w\nmodel_d = build_model('d') # for t2\n\nx_a = layers.Dense(764, activation='relu')(model_a.output)\nx_b = layers.Dense(764, activation='relu')(model_b.output)\nx_c = layers.Dense(764, activation='relu')(model_c.output)\nx_d = layers.Dense(764, activation='relu')(model_d.output)\noutput = layers.average([x_a, x_b, x_c, x_d])\n\nhead_layer = layers.Dense(512, activation='relu')(output)\nhead_layer = layers.Dropout(0.5)(head_layer)\nfindal_output = layers.Dense(1, activation='sigmoid')(head_layer)\nmodel = Model(\n    inputs  = [model_a.input, model_b.input, \n                     model_c.input, model_d.input],\n    outputs = [findal_output]\n)\n</code></pre>\n<p>We have also the <code>Swin-Transformer</code> one of the four models but it didn't perform well (or we were too impatient). Additionally, during the training time, we randomly switch the modality from the dataloader. It's done on the assumption that each of the four models may have the knowledge of modalities. </p>\n<pre><code>      if self.split == 'train':\n            if np.random.rand() &lt; 0.2:\n                flair_x, t1_x = t1_x, flair_x\n            elif np.random.rand() &lt; 0.4:\n                t1w_x,  t2_x = t2_x, t1w_x\n            elif np.random.rand() &lt; 0.6:\n                t2_x, flair_x = flair_x, t2_x\n            else:\n                pass \n\n      # dictionary mapping for corresponding models \n      return {\n            'flair' : flair_x, \n            't1'    : t1_x, \n            't1w'   : t1w_x, \n            't2'    : t2_x \n        }\n</code></pre>\n<p>For 2D modeling, we've used built-in <a href=\"https://keras.io/api/layers/preprocessing_layers/image_augmentation/\" target=\"_blank\"><code>keras augmentation</code></a></p>\n<table>\n<thead>\n<tr>\n<th>-</th>\n<th>SimpleAvg</th>\n<th>TTA (Keras: Step 5)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CV</td>\n<td>0.59</td>\n<td>0.61</td>\n</tr>\n<tr>\n<td>Public LB</td>\n<td>0.57</td>\n<td>0.621</td>\n</tr>\n</tbody>\n</table>\n<p>Final Ensemble </p>\n<table>\n<thead>\n<tr>\n<th>-</th>\n<th>3D</th>\n<th>2D</th>\n<th>Public LB</th>\n<th>Private LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td></td>\n<td>0.635</td>\n<td>0.621</td>\n<td>0.68340</td>\n<td>0.52730</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<p><strong>Final Note</strong></p>\n<p>It's not that robust model with many issues and we'll be continuing working on such problems. We've made all the code publicly accessible <a href=\"https://github.com/innat/BraTS-MGMT-Classification\" target=\"_blank\">BraTS-MGMT-Classification</a> with the structural format and actively updating. And here is the minimum <a href=\"https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification\" target=\"_blank\">notebook view</a>.</p>\n<h2>Code: <a href=\"https://github.com/innat/BraTS-MGMT-Classification\" target=\"_blank\">BraTS-MGMT-Classification</a></h2>",
      "rawMarkdown": "Big congrats to all the winners. Though we couldn't survive the shake-up and were way too behind, we thought it might be useful for some readers. From the beginning, we've mainly aimed to hands-on the 3D data set and 3D modeling approach first time with `TensorFlow.Keras` and 3D augmentation for that as well.\n\n**3D modeling**:  We only use [`3D-EfficientNet-BO` ](https://github.com/ZFTurbo/efficientnet_3D) for most of the cases due to limited resources. We trained the model with 5 fold stratified dataset, considering all modalities. In most of the folds training, we used [volumentations](https://github.com/ZFTurbo/volumentations) for augmenting the dataset. Basically, the most training part was taken from my [public notebook](https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification). Each of the 5 folds was trained with the same configuration (same seed, lr, etc), the local cv for each fold varies between 0.49~0.61. Next, we've used the Bayesian Optimization technique to get the optimal linear weights, using my other [notebook here](https://www.kaggle.com/ipythonx/optimizing-metrics-out-of-fold-weights-ensemble/notebook). \n\n|-| 3D-EfficientNet-BO | SimpleAvg | BaysianOpt   | TTA (Volumentation: Step 5) | \n|---|---|---|---|---|\n|CV |  (0.49~0.62) |0.55 | 0.57| 0.601 |\n|Public LB |  -- |0.54 | 0.59 | 0.635 |  |\n\n---\n\n**2D Ensemble Modeling**.  We've built a giant model for end-to-end training consisting of 4 models i.e. `EfficientNetB2`, `DenseNet121`, `ResNet18` and `SeResNeXt50` - where each modality passed as in input for each models but **randomly**.  \n\n```\ndef build_model(base_net):\n   \n    if base_net == 'a':\n        base_Mchannel = model.EfficientNetB2\n        x = layers.Dropout\n        return Model(inputs=base_Mchannel.input, \n                              outputs=x, name='flair')\n    elif base_net == 'b':\n        base_Mchannel = model.DenseNet121\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1')\n    elif base_net == 'c':\n        get_model, _ = Classifiers.get('resnet18')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1w')\n    elif base_net == 'd':\n        get_model, _ = Classifiers.get('seresnext50')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D) \n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t2')\n\n# detect and init the TPU\nmodel_a = build_model('a') # for flair\nmodel_b = build_model('b') # for t1\nmodel_c = build_model('c') # for t1w\nmodel_d = build_model('d') # for t2\n\nx_a = layers.Dense(764, activation='relu')(model_a.output)\nx_b = layers.Dense(764, activation='relu')(model_b.output)\nx_c = layers.Dense(764, activation='relu')(model_c.output)\nx_d = layers.Dense(764, activation='relu')(model_d.output)\noutput = layers.average([x_a, x_b, x_c, x_d])\n\nhead_layer = layers.Dense(512, activation='relu')(output)\nhead_layer = layers.Dropout(0.5)(head_layer)\nfindal_output = layers.Dense(1, activation='sigmoid')(head_layer)\nmodel = Model(\n    inputs  = [model_a.input, model_b.input, \n                     model_c.input, model_d.input],\n    outputs = [findal_output]\n)\n```\n\nWe have also the `Swin-Transformer` one of the four models but it didn't perform well (or we were too impatient). Additionally, during the training time, we randomly switch the modality from the dataloader. It's done on the assumption that each of the four models may have the knowledge of modalities. \n\n```\n      if self.split == 'train':\n            if np.random.rand() < 0.2:\n                flair_x, t1_x = t1_x, flair_x\n            elif np.random.rand() < 0.4:\n                t1w_x,  t2_x = t2_x, t1w_x\n            elif np.random.rand() < 0.6:\n                t2_x, flair_x = flair_x, t2_x\n            else:\n                pass \n\n      # dictionary mapping for corresponding models \n      return {\n            'flair' : flair_x, \n            't1'    : t1_x, \n            't1w'   : t1w_x, \n            't2'    : t2_x \n        }\n```\n\nFor 2D modeling, we've used built-in [`keras augmentation`](https://keras.io/api/layers/preprocessing_layers/image_augmentation/)\n\n|-  | SimpleAvg | TTA (Keras: Step 5) | \n|---|---|---|\n|CV |  0.59 | 0.61 |\n|Public LB| 0.57 | 0.621 | \n\nFinal Ensemble \n\n|-| 3D  | 2D | Public LB | Private LB | \n|---|---|---|---|---|\n| | 0.635 | 0.621 | 0.68340 | 0.52730 |\n\n\n---\n\n**Final Note**\n\nIt's not that robust model with many issues and we'll be continuing working on such problems. We've made all the code publicly accessible [BraTS-MGMT-Classification](https://github.com/innat/BraTS-MGMT-Classification) with the structural format and actively updating. And here is the minimum [notebook view](https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification).\n\n## Code: [BraTS-MGMT-Classification](https://github.com/innat/BraTS-MGMT-Classification)\n",
      "votes": 9
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "1551288": "Big congrats to all the winners. Though we couldn't survive the shake-up and were way too behind, we thought it might be useful for some readers. From the beginning, we've mainly aimed to hands-on the 3D data set and 3D modeling approach first time with `TensorFlow.Keras` and 3D augmentation for that as well.\n\n**3D modeling**:  We only use [`3D-EfficientNet-BO` ](https://github.com/ZFTurbo/efficientnet_3D) for most of the cases due to limited resources. We trained the model with 5 fold stratified dataset, considering all modalities. In most of the folds training, we used [volumentations](https://github.com/ZFTurbo/volumentations) for augmenting the dataset. Basically, the most training part was taken from my [public notebook](https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification). Each of the 5 folds was trained with the same configuration (same seed, lr, etc), the local cv for each fold varies between 0.49~0.61. Next, we've used the Bayesian Optimization technique to get the optimal linear weights, using my other [notebook here](https://www.kaggle.com/ipythonx/optimizing-metrics-out-of-fold-weights-ensemble/notebook). \n\n|-| 3D-EfficientNet-BO | SimpleAvg | BaysianOpt   | TTA (Volumentation: Step 5) | \n|---|---|---|---|---|\n|CV |  (0.49~0.62) |0.55 | 0.57| 0.601 |\n|Public LB |  -- |0.54 | 0.59 | 0.635 |  |\n\n---\n\n**2D Ensemble Modeling**.  We've built a giant model for end-to-end training consisting of 4 models i.e. `EfficientNetB2`, `DenseNet121`, `ResNet18` and `SeResNeXt50` - where each modality passed as in input for each models but **randomly**.  \n\n```\ndef build_model(base_net):\n   \n    if base_net == 'a':\n        base_Mchannel = model.EfficientNetB2\n        x = layers.Dropout\n        return Model(inputs=base_Mchannel.input, \n                              outputs=x, name='flair')\n    elif base_net == 'b':\n        base_Mchannel = model.DenseNet121\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1')\n    elif base_net == 'c':\n        get_model, _ = Classifiers.get('resnet18')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D\n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t1w')\n    elif base_net == 'd':\n        get_model, _ = Classifiers.get('seresnext50')\n        base_Mchannel = get_model\n        x = layers.GlobalAveragePooling2D) \n        return Model(inputs=base_Mchannel.input, \n                               outputs=x, name='t2')\n\n# detect and init the TPU\nmodel_a = build_model('a') # for flair\nmodel_b = build_model('b') # for t1\nmodel_c = build_model('c') # for t1w\nmodel_d = build_model('d') # for t2\n\nx_a = layers.Dense(764, activation='relu')(model_a.output)\nx_b = layers.Dense(764, activation='relu')(model_b.output)\nx_c = layers.Dense(764, activation='relu')(model_c.output)\nx_d = layers.Dense(764, activation='relu')(model_d.output)\noutput = layers.average([x_a, x_b, x_c, x_d])\n\nhead_layer = layers.Dense(512, activation='relu')(output)\nhead_layer = layers.Dropout(0.5)(head_layer)\nfindal_output = layers.Dense(1, activation='sigmoid')(head_layer)\nmodel = Model(\n    inputs  = [model_a.input, model_b.input, \n                     model_c.input, model_d.input],\n    outputs = [findal_output]\n)\n```\n\nWe have also the `Swin-Transformer` one of the four models but it didn't perform well (or we were too impatient). Additionally, during the training time, we randomly switch the modality from the dataloader. It's done on the assumption that each of the four models may have the knowledge of modalities. \n\n```\n      if self.split == 'train':\n            if np.random.rand() < 0.2:\n                flair_x, t1_x = t1_x, flair_x\n            elif np.random.rand() < 0.4:\n                t1w_x,  t2_x = t2_x, t1w_x\n            elif np.random.rand() < 0.6:\n                t2_x, flair_x = flair_x, t2_x\n            else:\n                pass \n\n      # dictionary mapping for corresponding models \n      return {\n            'flair' : flair_x, \n            't1'    : t1_x, \n            't1w'   : t1w_x, \n            't2'    : t2_x \n        }\n```\n\nFor 2D modeling, we've used built-in [`keras augmentation`](https://keras.io/api/layers/preprocessing_layers/image_augmentation/)\n\n|-  | SimpleAvg | TTA (Keras: Step 5) | \n|---|---|---|\n|CV |  0.59 | 0.61 |\n|Public LB| 0.57 | 0.621 | \n\nFinal Ensemble \n\n|-| 3D  | 2D | Public LB | Private LB | \n|---|---|---|---|---|\n| | 0.635 | 0.621 | 0.68340 | 0.52730 |\n\n\n---\n\n**Final Note**\n\nIt's not that robust model with many issues and we'll be continuing working on such problems. We've made all the code publicly accessible [BraTS-MGMT-Classification](https://github.com/innat/BraTS-MGMT-Classification) with the structural format and actively updating. And here is the minimum [notebook view](https://www.kaggle.com/ipythonx/tf-3d-2d-model-for-brain-tumor-classification).\n\n## Code: [BraTS-MGMT-Classification](https://github.com/innat/BraTS-MGMT-Classification)\n"
  }
}