从第一行代码学Python:理解from..import

本文详细介绍了Python中的模块导入机制,包括import和from...import...的使用及逻辑。从模块、函数和包的概念出发,阐述了导入模块的搜索路径,探讨了PEP8推荐的绝对引用与相对引用的优缺点。通过实例解析了不同导入方式的适用场景,帮助读者理解Python导入系统的底层工作原理。

0. 前言

在几乎所有实践中,Python不可避免的需要导入其他模块,例如,当我们实践机器学习项目时,难免会在开头写到:

import numpy as np

在大多数时候,我们并不会仔细去思考他的运作方式,在许多教学视频或者书籍中,也不会仔细介绍import的逻辑。在代码量增大,或者是要发布/魔改package的时候,往往会出问题。下面就将总结import的几点机制,留作笔记之用。

1. Functions, Modules and Packages

Python是一门面向对象的编程语言,“模块化”贯穿了整个Pythonic思想,而函数、模块和包在Python之中起着举足轻重的作用。

简单地讲:
一段能够执行某个功能的代码皆可以称之为函数;
模块是函数的集合;
包是模块的集合。

特此说明,这样说并不严谨,例如模块甚至可以是Cython或纯粹C语言所写;包也可以包含子包。

2. Import速览

import_stmt     ::=  "import" module ["as" identifier] ("," module ["as" identifier])*
                     | "from" relative_module "import" identifier ["as" identifier]
                     ("," identifier ["as" identifier])*
                     | "from" relative_module "import" "(" identifier ["as" identifier]
                     ("," identifier ["as" identifier])* [","] ")"
                     | "from" relative_module "import" "*"
module          ::=  (identifier ".")* identifier
relative_module ::=  "."* module | "."+

以上摘自官方文档

简单来说,可以不严谨的描述为
[from] [packge|module] import module [as] [alias]
[ ]中为可选项
examples:
均以使用zeros函数为例

import numpy #numpy.zeros()
import numpy as np #np.zeros()
from numpy import zeros,eye #zeros(),逗号可以Import多个
from numpy import * #zeros()

03. Import逻辑探析

02章节中介绍的是基本用法,但在深层次的应用上往往会有更细节的情况。
例如,偶尔会有人问到:from …module import xxx是什么意思?Python中from 省略号/点点 Import …是什么意思?

from ..utils import Padding
from myutils.utils import Padding

首先是import的逻辑:

  1. 为了减少开销,Import会首先搜索模块缓存。
  2. 然后会搜索内置模块列表
  3. 最后会搜索sys.path
    sys.path:

A list of strings that specifies the search path for modules. Initialized from the environment variable PYTHONPATH, plus an installation-dependent default.

  1. 找不到时抛出错误。

from的逻辑:
from的逻辑与Import类似,只是多一个搜索绑定的过程。
值得一提的是,PEP8推荐的是绝对引用,虽然绝对引用可能对开销来说更加友好,但也许会对我们人类自己造成一些困难。例如:

from transfomer.tokenlizer.wordpiece.unigram import is_sp_token

这样的代码段太冗长了,并且,我个人在阅读部分知名开源库的时候,发现更常用的往往是相对引用。

例如前文所述的

from ..utils import Padding

这里的".",并不是省略号,而是“点”(dot),是上古先贤们传下来的文化传统。

对于当前位置而言,
一个点代表处于同级目录,
两个点代表处于父目录,
三个点代表处于祖父目录…

04. 小结

虽然很多实践还是相对引用得多,
但代码看多了还是觉得绝对引用比较好,
毕竟是PEP8
在这里插入图片描述

<think>好的,用户现在想知道如何在他们现有的代码中修改以适配PiPPy,特别是替换旧的管道并行实现。之前的对话中,我已经给出了替换导入语句的建议,但用户可能还不清楚具体在哪个文件中进行修改,或者如何操作。 首先,我需要确认用户的问题。用户提供的错误信息显示他们的代码中使用了`from torch.distributed.pipeline.sync import Pipe`,而这是已被弃用的模块。现在需要替换为PiPPy的`from pippy.IR import Pipe`。用户的问题是,这几行修改应该在他们代码的哪个部分进行。 我需要回忆用户之前提供的错误追踪路径:他们的训练脚本是`E:\ultralytics\yolov8_train.py`,错误发生在该文件的第1行,尝试从旧的路径导入模块。因此,用户需要修改的是他们自己的训练脚本`yolov8_train.py`中的导入语句。 接下来,我需要考虑用户可能对代码结构不熟悉,特别是如果他们使用的是YOLOv8官方代码还是自定义的脚本。用户提到使用的是`yolov8_train.py`,这可能是一个自定义的训练脚本,因为Ultralytics的YOLOv8通常通过`model.train()`方式启动,而不需要直接编写训练循环。因此,用户可能修改了官方代码或自己编写了训练脚本,导致导入了旧的模块。 用户可能需要指导如何找到需要修改的具体代码行。例如,在他们的`yolov8_train.py`中,是否存在直接导入`Pipe`类的语句?根据错误信息,第1行是`from torch.distributed.pipeline.sync.worker import worker`,但用户示例中提到的旧代码是`from torch.distributed.pipeline.sync import Pipe`,这可能意味着他们在脚本中多个地方使用了旧的管道并行代码。 需要明确告诉用户在哪里修改导入语句。例如,在`yolov8_train.py`中查找所有从`torch.distributed.pipeline.sync`导入的语句,并将它们替换为PiPPy对应的导入。同时,可能需要调整使用`Pipe`类的方式,因为PiPPy的API可能与旧版不同。 还需要提醒用户,除了替换导入语句之外,可能还需要修改Pipe的初始化参数或使用方式,因为PiPPy的接口可能有所变化。例如,旧版Pipe可能需要不同的参数,或者PiPPy的Pipe需要额外的配置步骤,比如使用`pippy.PipelineDriver`来包装模型。 此外,用户可能需要安装PiPPy库,如果之前没有安装的话,所以需要再次强调安装步骤,确保他们执行了`pip install torchpippy`。同时,检查PyTorch版本是否兼容PiPPy,避免版本冲突。 用户可能遇到的另一个问题是,替换导入后仍然出现其他错误,比如缺少其他模块或参数错误。这时候需要建议用户查阅PiPPy的官方文档或示例,确保他们的管道并行实现符合新的API规范。 最后,需要以清晰的结构逐步引导用户完成修改,确保他们理解每一步的操作,并验证修改后的代码是否解决了导入错误,同时处理可能出现的后续问题。</think>要在代码中修改适配PiPPy的管道并行实现,需按以下步骤操作: --- ### **步骤详解:代码修改位置** #### **1. 定位旧版Pipe的调用** 在你的训练脚本`yolov8_train.py`中搜索以下代码段: ```python from torch.distributed.pipeline.sync import Pipe ``` 或类似导入语句(例如`from torch.distributed.pipeline.sync.worker import worker`)。 #### **2. 直接替换导入路径** 将旧版Pipe导入语句: ```python from torch.distributed.pipeline.sync import Pipe ``` 替换为PiPPy的新导入方式: ```python from pippy.IR import Pipe ``` #### **3. 修改Pipe的初始化参数(关键差异)** 旧版Pipe的调用可能形如: ```python model = Pipe(model, chunks=4, checkpoint="always") ``` PiPPy的`Pipe`需要**设备映射**和**更明确的切分策略**,典型修改后代码: ```python from pippy.IR import annotate_split_points, PipeSplitWrapper # 定义模型切分点(示例) annotate_split_points(model, {"layer1": PipeSplitWrapper}) # 根据实际模型结构定义切分点 # 创建Pipe实例 model = Pipe( model, chunks=4, checkpoint="always", # 需指定设备映射(根据实际GPU数量调整) device_mapping=["cuda:0", "cuda:1"] ) ``` --- ### **具体修改文件** 根据你提供的错误追踪路径: ``` File "E:\ultralytics\yolov8_train.py", line 1, in <module> from torch.distributed.pipeline.sync.worker import worker ``` 需修改`yolov8_train.py`文件中的以下内容: #### **原始代码(旧版)** ```python # 旧版导入(需删除) from torch.distributed.pipeline.sync import Pipe from torch.distributed.pipeline.sync.worker import worker # 第1行报错位置 ``` #### **修改后代码(PiPPy适配)** ```python # 新版导入(替换为PiPPy) from pippy.IR import Pipe, PipeSplitWrapper, annotate_split_points from pippy.PipelineDriver import PipelineDriverFillDrain # 可能需要新增的驱动类 # 删除旧版worker导入(PiPPy内部已处理) ``` --- ### **验证修改有效性** 1. **安装PiPPy**(如未执行): ```bash pip install torchpippy ``` 2. **运行最小测试**: ```python # 测试PiPPy Pipe是否能正确初始化 import torch from pippy.IR import Pipe model = torch.nn.Linear(10, 10) pipe_model = Pipe(model, chunks=2, device_mapping=["cuda:0"]) print(pipe_model) ``` 3. **检查分布式初始化**: PiPPy通常需要结合`torch.distributed.rpc`初始化: ```python import torch.distributed.rpc as rpc rpc.init_rpc("worker", rank=0, world_size=1) # 根据实际分布式配置调整 ``` --- ### **常见问题补充** 1. **错误`No module named 'pippy'`**: - 未正确安装PiPPy库 → 执行`pip install torchpippy` 2. **设备映射不匹配**: - 检查`device_mapping`参数是否与可用GPU数量一致 3. **模型切分点定义错误**: - 使用`annotate_split_points`明确标注模型切分位置,需与模型结构对应 --- ### **替代方案建议** 如果修改复杂度较高,可改用**官方推荐的DDP(分布式数据并行)**: ```python # 在yolov8_train.py中直接使用 import torch from torch.nn.parallel import DistributedDataParallel as DDP # 初始化进程组 torch.distributed.init_process_group(backend="nccl") model = DDP(model, device_ids=[local_rank]) ``` 需要配合命令行启动: ```bash python -m torch.distributed.run --nproc_per_node 4 yolov8_train.py ``` --- 通过以上修改,你的代码将适配PiPPy实现管道并行。如果仍有问题,请提供`Pipe`调用的完整代码段以便进一步分析。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值