{"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"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91249,"databundleVersionId":11294684,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!git clone https://github.com/ultralytics/ultralytics","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"see ultralytics in local","metadata":{}},{"cell_type":"markdown","source":"content(lines mentioned are differnet due to the code change)","metadata":{}},{"cell_type":"code","source":"# It starts from ultralytics.models.yolo.detect.train.py\n\n    def get_model(self, cfg=None, weights=None, verbose=True):\n        \"\"\"\n        Return a YOLO detection model.\n\n        Args:\n            cfg (str, optional): Path to model configuration file.\n            weights (str, optional): Path to model weights.\n            verbose (bool): Whether to display model information.\n\n        Returns:\n            (DetectionModel): YOLO detection model.\n        \"\"\"\n        model = DetectionModel(cfg, nc=self.data[\"nc\"], ch=self.data[\"channels\"], verbose=verbose and RANK == -1)\n        if weights:\n            model.load(weights)\n        return model\n\n# Since model = DetectionModel(cfg, nc, ch, verbose), we move to DetectionModel\n\n# DetectionModel is imported at the top: from ultralytics.nn.tasks import DetectionModel\n# So go to ultralytics/nn/tasks.py\n\n# In class DetectionModel(BaseModel), the __init__ shows:\n# cfg = \"yolo11n.yaml\" is the default, though it would vary depending on the weights\n-> line 311\n\nself.yaml = cfg or yaml_model_load(cfg)\n-> line 322\n\nself.model, self.save = parse_model(deepcopy(self.yaml), ch=ch, verbose=verbose)\n-> line 335\n\n# So we now need to check cfg and parse_model\n\n# parse_model is defined in the same file, ultralytics/nn/tasks.py, line 1330\n\n# The first argument `d` is model_dict\n\n# At line 1347, we see:\nnc, act, scales = (d.get(x) for x in (\"nc\", \"activation\", \"scales\"))\n# This shows that d is something like:\nd = {\n    \"nc\": 80,\n    \"activation\": \"ReLU\",\n    \"scales\": [0.33, 0.25, 1024],\n    \"depth_multiple\": [...],\n    \"width_multiple\": [],\n    \"kpt_shape\": [],\n    ...\n}\n\n# parse_model returns torch.nn.Sequential(*layers), sorted(save) -> line 1505\n# It is constructed from base_modules (line 1365) and repeat_modules (line 1403)\n\n>> Therefore, if you want to inject a custom backbone, you can hook it into the output of parse_model. <<\n\n# Since self.model = torch.nn.Sequential(*layers), you can modify self.model to insert your custom backbone.\n\n# Now, for cfg,\n# We look into ultralytics/cfg/models/v8 because we are using YOLOv8\n\n# In yolov8.yaml line 20, the first layer in backbone is Conv\n# Conv is defined in ultralytics/nn/modules/conv.py\n\n# The Conv class is defined at line 37.\n# At line 79, return value shows that this class is a conv + batchnorm + activation block\n\n# Then at line 94, there is Conv2 which inherits from Conv\n# Conv2 sets kernel size to 3\n\n# In Conv2's return (line 144): self.act(self.bn(self.conv(x)))\n\n# Important note: in Conv (line 50), only c1, c2 are required positional arguments\n\n# However, in yolov8.yaml line 20, the args are [64, 3, 2] — these are likely output_channel, kernel_size, stride\n# There's no input_channel here.\n\n-> But input_channel is passed as `ch` = 3 in DetectionModel (line 311)\n\n# Back in yolov8.yaml, line 18 defines the 'backbone'\n# The first line in backbone is: [-1, 1, Conv, [64, 3, 2]]\n# But this Conv is not inserted blindly\n\n# We have to look again at DetectionModel in ultralytics/nn/tasks.py\n\n# At line 335: parse_model(deepcopy(self.yaml), ch=ch, verbose=verbose)\n\n# Then at line 1330: def parse_model(d, ch, verbose=True):\n\n# So d = self.yaml and ch = 3 from DetectionModel\n\n# Now looking at parse_model:\n# At line 1436: if the module is in base_modules (defined at line 1365),\n# then c1, c2 = input_channel, output_channel\n\n# At line 1438: make_divisible is used\n# It comes from ultralytics.utils.ops (line 82 import)\n\n# At line 130 in ops.py:\ndef make_divisible(x, a): returns the nearest value >= x that is divisible by a\n\n# Back to tasks.py:\n# From lines 1422 to 1504, each line in YAML is processed to determine input/output channels\n# Then modules are stacked and returned as a model\n\n\"\"\"\nSo, if you want to replace the **first block in the backbone**, you need to:\n\n1) Edit the first line in your YAML file\n2) Register your custom module where Conv is handled\n3) In lines 1502–1503, when i == 0 (first block), ch is assigned c2.\n   - You can add an `elif` statement, or\n   - Add your custom module to base_modules list so it's handled automatically\n   - If your module already exists, it might be already handled\n4) ...\n\nIn ultralytics/nn/modules/conv.py, add your custom class name to the `__all__` list (line 10)\n→ So it can be imported and used elsewhere.\n\"\"\"\n\n# Even if you do:\nmodel.model[0] = CustomClass(...)\n# It may not take effect during training because of default config overrides.\n\n# The reason is likely at line 263 in ultralytics/engine/model.py:\nself.model.args = {**DEFAULT_CFG_DICT, **self.overrides}\n\n# At line 14:\nfrom ultralytics.utils import DEFAULT_CFG_DICT\n\n# DEFAULT_CFG_DICT is defined at line 546 in:\nultralytics/utils/__init__.py\n\n-> DEFAULT_CFG_DICT = yaml_load(DEFAULT_CFG_PATH)\n\n# At line 41:\nDEFAULT_CFG_PATH = ROOT / \"cfg/default.yaml\"\n\n# If you open ultralytics/cfg/default.yaml, you'll see default config values are hardcoded there.","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"compress modified ultralytics into .7z","metadata":{}},{"cell_type":"markdown","source":"use upload to upload ultralytics.7z from local folder(.zip makes error in my case, so use 7z","metadata":{}},{"cell_type":"code","source":"!cp -r /path_to_ultralytics.7z/ ./ultralytics","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install ipywidgets\n%cd ultralytics\n\n!pip install -e .","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}