Difference between pipeline parallelism and multiprocessing?

Nick_Lin: <p>I’m trying to train a model contains two sub models with two GPUs simultaneously, and I’m looking to parallelism and multiprocessing.</p>
<p>As I know, parallelism contains data parallelism and model parallelism, in my case is more likely to use <strong>model parallelism</strong>, and we usually use <strong>pipeline</strong> together to reduce the waste of transfering data between different model. This can be implemented by using <strong>torch.distributed.pipeline.sync</strong> package.</p>
<p>On the other hand, due to GIL in python, if we really want to execute multiple threads (in my case, training two models) at the same time, one way is using <strong>torch.multiprocessing</strong> based on python’s multiprocessing package, which will spawn new intepreter to solve the limitation of GIL.</p>
<p>What I question about are below:</p>
<ol>
<li>What is difference between parallelism and multiprocessing?</li>
<li>In my case which one (or which package) should I use?</li>
<li>I found two pytorch’s document related to parallelism:</li>
</ol>
<p><a href="https://pytorch.org/tutorials/intermediate/model_parallel_tutorial.html" rel="noopener nofollow ugc">SINGLE-MACHINE MODEL PARALLEL BEST PRACTICES</a></p>
<p><a href="https://pytorch.org/tutorials/intermediate/pipeline_tutorial.html#training-transformer-models-using-pipeline-parallelism" rel="noopener nofollow ugc">TRAINING TRANSFORMER MODELS USING PIPELINE PARALLELISM</a></p>
<p>But I wonder the former one really does “parallelism”? Doesn’t it just split the model and only one model in calculation in one time?</p>
<p>Thanks for anyone who takes a look of my question.</p>

cbalioglu: <p><code>torch.multiprocessing</code> is nothing more than a glorified version of Python’s standard <code>multiprocessing</code> package. It has no inherent knowledge of models or any sort of parallelism. When using <code>torch.multiprocessing</code> you are responsible for implementing all such concepts such as model parallelism, which can be quite an undertaking.</p>
<p>Regarding your question about the two docs you referred to. Please note that the first doc’s last section “Speed up by Pipelining Inputs” is actually where the “magic” happens.</p>
<p><a href="https://pytorch.org/tutorials/intermediate/model_parallel_tutorial.html#speed-up-by-pipelining-inputs" class="onebox" target="_blank" rel="noopener nofollow ugc">https://pytorch.org/tutorials/intermediate/model_parallel_tutorial.html#speed-up-by-pipelining-inputs</a></p>

Nick_Lin: <p><a class="mention" href="/u/cbalioglu">@cbalioglu</a> Thanks for your reply <img src="https://discuss.pytorch.org/images/emoji/apple/heart_eyes.png?v=12" title=":heart_eyes:" class="emoji" alt=":heart_eyes:" loading="lazy" width="20" height="20"> I have this question because I think no matter which way I use, I should implement model parallelism myself (in other words, set model and input/output into correct device), but I found some dicussion said that multiprocessing is not actually capable with CUDA and it might cause the GPU not doing what “multiprocessing” you think.</p>
<p>On the other hand, I also found the difference between this tow docs. The latter one use rpc, which is mainly for multiple machine’s training, but I still have questions:</p>
<ol>
<li>In first doc’s, I found I got more training time when I do the following code (same as tutorial):</li>
</ol>
<pre><code class="lang-auto"># With model parallelism only
model = Classification_model_parel()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)

model.train()
x, y = batchloader(X_train, y_train, batch_size)

start = time.time()

for i in range(epoch):
    
    for x_batch, y_batch in zip(x,y):
        out = model(x_batch.to(torch.float32))        
        loss = F.cross_entropy(out, y_batch.to('cuda:1'))
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

end = time.time()

model.eval()
pred = model(X_test)

correct = (pred.argmax(dim = 1) == y_test.to('cuda:1')).sum()
auc = correct / len(y_test)
print(f'Auc:{auc:.4f}, trainning time = {end - start}')
</code></pre>
<pre><code class="lang-auto"># With pipeline and model parallelism
split_test = [4,8,12,24,48,96,128,256]
record = []
for splitset in split_test:
    model = Classification_model_parel_pipe(splitset)
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)

    model.train()
    x, y = batchloader(X_train.to(torch.float32), y_train, batch_size)

    start = time.time()
    for i in range(epoch):
        for x_batch, y_batch in zip(x,y):
            out = model(x_batch.to('cuda:0'))
            loss = F.cross_entropy(out, y_batch.to('cuda:1'))
            loss.backward()    
            optimizer.step()
            optimizer.zero_grad()

    end = time.time()

    model.eval()
    pred = model(X_test.to('cuda:0'))

    correct = (pred.argmax(dim = 1) == y_test.to('cuda:1')).sum()
    auc = correct / len(y_test)
    print(f'Set {splitset}, Auc:{auc:.4f}, trainning time = {end - start}')
    record.append(end - start)
</code></pre>
<p>The training time with pipeline in all splt_size are more than the training time without pipeline. Only when I set the split size as original batch_size and batch_size as 2*batch_size, the training time with pipeline will faster than the training time without pipeline. Is this correct?</p>
<ol start="2">
<li>Although rpc is use in multiple machines, if I init rpc with only one worker and use Pipe in torch.distributed package according to the second docs,  I think this is doing the same thing as the first docs. But the result comes out that using rpc and Pipe will training much time than the first doc’s way, is my concept wrong?</li>
</ol>