Training fails mid-run when code is changed for distributed training

numpee: <p>Hi,</p>
<p>I had a few models training with distributed pytorch (DistributedSampler + DistributedDataParallel + multiprocessing). While the models were training for a few days, I changed a part of the data transformation code, where I renamed a file and changed all the necessary imports.</p>
<p>After I changed this part of the code, the models that were training all suddenly crashed when initializing the next epoch. They all crashed with error messages along the lines of “No module named __”.</p>
<p>What’s weird is that this module is only loaded when initializing each process, and the training loop is confined within each spawned process. Thus, I’m not sure why changing the name of this module caused my code to crash mid-training. Is this a common issue in multiprocessing? Am I misunderstanding something here?</p>
<p>PS. In case it helps to know which module it was…<br>
The module I changed was a file named <code>transformations.transforms</code>. I changed it to <code>transformations.single_transforms</code> since it seemed to be interfering with <code>torchvision.transforms</code>. As usual, loading transformations only occurs once in the code just before loading the dataset.<br>
Also, it wasn’t like the training crashed as soon as I made this change - it crashed after finishing 1 epoch of training which is also weird…</p>
<p>Thanks in advance!</p>

osalpekar: <p>Do you have some code that we can examine? I put together a very simple program with multiprocessing and tried changing one of the module names during execution, but there was no crash. Are you potentially loading the module within the <code>Dataset</code> or <code>Dataloader</code> classes? Given that the program code is compiled into Python bytecode, and only then interpreted, I’m not sure why changing the Python code mid-execution will affect the program since it’s just the bytcode being interpreted. In fact, even deleting the bytecode during execution shouldn’t make a difference since the program has been loaded into memory. Any thoughts on what could cause this behavior <a class="mention" href="/u/mrshenli">@mrshenli</a>?</p>
<p>As an aside, I would recommend checkpointing (and potentially torchelastic) so you don’t lose training progress for long-running jobs.</p>

numpee: <p>So my entire code base is actually quite large, but here are some necessary details.</p>
<p>As I said, the module import error occurred after changing <code>transformations.transforms</code> to <code>transformations.single_transforms</code>. This module is only directly imported in <code>transformations.__init__</code> where my <code>transform_factory</code> code resides.</p>
<p>The multiprocessing code is structured as follows. As usual, I have some relevant setup in the <code>main</code> function, where I spawn the <code>main_process</code> function.</p>
<p>In the <code>main_process</code> function, the code is structured as:</p>
<ol>
<li>Init process group</li>
<li>Obtain transformations (through <code>transform_factory</code> - probably the module in question)</li>
<li>Create Datasets, Distributed samplers, and Dataloaders</li>
<li>Create distributed model, loss fns, optimizers, etc.</li>
<li>Initialize the trainer class</li>
<li>Run training</li>
</ol>
<p>The last step - <em>run training</em> - is basically just a nested for loop where I run one round of training followed by one round of evaluation. Simplified example:</p>
<pre><code class="lang-auto">    def run(self):
        self.model.train()
        for epoch in range(0, self.num_epochs):
            if self.train_sampler is not None:
                self.train_sampler.set_epoch(epoch)
            for phase in ['train', 'val']:
                if phase == 'train':
                    self.model.train()
                    train_results = self.train_one_epoch(epoch)
                    print(train_results)
                else:
                    self.model.eval()
                    val_results = self.validate(epoch)
                    print(val_results)
</code></pre>
<p>In no part of the training do I reference or try to import from <code>transformations.single_transforms</code>. And as you said, even if I did, <strong>it shouldn’t matter because of the  python Bytecode</strong>.</p>
<p>Some other details that may help…</p>
<ol>
<li>I’ve been using PyTorch for around 3 years now, mostly using <code>DataParallel</code>, and I’ve never encountered this issue before. I only switched to Distributed training a few weeks ago, and it’s my first time seeing this problem.</li>
<li>The training doesn’t bug out as soon as the change is made. In fact, it will finish its current phase of training (until the dataloader is finished iterating), then die during the transition from <code>train</code> --&gt; <code>evaluation</code> or vice versa.</li>
</ol>
<p>Finally, thanks for the suggestion. I do in fact checkpoint every epoch, so I can resume training. I just wanted to get to the bottom of this because I just can’t understand why the code would crash mid-training. I talked to one of my colleagues about this, and he said that he’s experienced something similar in distributed training. He also noted that changing the model structure will also cause the code to crash, but I haven’t checked this for myself.</p>

Neabfi: <p>This is when num_workers &gt; 0. Every new worker will run the files.</p>

numpee: <p>Well I use DDP to speed up my training, so I’m not sure if reducing the num_workers to 0 - and thus, slowing down the code -  would be a solution <img src="https://discuss.pytorch.org/images/emoji/apple/frowning.png?v=9" title=":frowning:" class="emoji" alt=":frowning:"></p>

zoujx96: <p>This happens when <strong>persistent_workers</strong> == <strong>False</strong> and <strong>num_workers</strong> &gt; 0. In that case the data loader will shut down after every epoch and read from data loading script again. Make sure to set it to <strong>True</strong>.</p>