# Model update with "share\_memory" need lock protection

**URL:** <https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857>\
**Category:** reinforcement-learning\
**Created:** [March 11, 2020, 10:24am UTC](https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857 "2020-03-11T10:24:31Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![S\_Q](https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/s_q/32/15892_2.png) [@S\_Q](https://discuss.pytorch.org/u/S_Q)\
**Post date:** [March 11, 2020, 10:24am UTC](https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857/1 "2020-03-11T10:24:32Z")

</div>

TL;DR.  
Maybe a lock is needed for `optimizer.step()` while using multiprocessing.

* * *

The example provided in [MULTIPROCESSING BEST PRACTICES] ([https://pytorch.org/docs/stable/notes/multiprocessing.html](https://pytorch.org/docs/stable/notes/multiprocessing.html)) is to update parameters without lock protection.

```auto
import torch.multiprocessing as mp
from model import MyModel

def train(model):
    # Construct data_loader, optimizer, etc.
    for data, labels in data_loader:
        optimizer.zero_grad()
        loss_fn(model(data), labels).backward()
        optimizer.step() # This will update the shared parameters

if __name__ == ' __main__':
    num_processes = 4
    model = MyModel()
    # NOTE: this is required for the ``fork`` method to work
    model.share_memory()
    processes = []
    for rank in range(num_processes):
        p = mp.Process(target=train, args=(model,))
        p.start()
        processes.append(p)
    for p in processes:
        p.join()

```

And I checked some A3C code from github, and they do it in the similar way.

To double check whether it’s safe to do that, I created a test case:

- The global network is init with 0
- one worker will add it 1 for 1000 times
- another worker will less it 1 for 1000 times
- if it is safe, the final network’s weight shall be 0
- repeat 100 times to check whether it is safe

Test results:

- With lock protection, it’s safe
- Without lock protection (comment the lock, and unindent the `optimizer.step()`), from time to time, the weight can not come back to 0, which means: not safe

```auto
import torch
import torch.nn as nn
import torch.multiprocessing as mp
import torch.optim as optim
from torch.autograd import Variable
import os

class Net(nn.Module):
    def __init__ (self):
        super(Net, self). __init__ ()
        self.fc1 = nn.Linear(1, 1)
        self.fc1.weight.data.fill_(0.0)
        self.fc1.bias.data.fill_(0.0)

    def forward(self):
        return 0

def worker1(net, grad, lock):
    optimizer = optim.SGD(net.parameters(), lr=1)
    for _ in range(1000):
        optimizer.zero_grad()
        for param in net.parameters():
            param._grad = Variable(torch.ones_like(param))
        with lock:
            optimizer.step()
        # print(f'in process {os.getpid()}, the grad of weight is: {net.fc1.weight.grad.item()}, weight is {net.fc1.weight.item()}')

def worker2(net, grad, lock):
    optimizer = optim.SGD(net.parameters(), lr=1)
    for _ in range(1000):
        optimizer.zero_grad()
        for param in net.parameters():
            param._grad = -Variable(torch.ones_like(param))
        with lock:
            optimizer.step()
        # print(f'in process {os.getpid()}, the grad of weight is: {net.fc1.weight.grad.item()}, weight is {net.fc1.weight.item()}')

if __name__ == ' __main__':
    n = Net()
    n.share_memory()

    lock = mp.Lock()

    for idx in range(100):
        # print(idx)
        # print(f'in main {os.getpid()}, weight is {n.fc1.weight.item()}')

        p1 = mp.Process(target = worker1, args=(n, 1.0, lock))
        p2 = mp.Process(target = worker2, args=(n, 1.0, lock))

        p1.start()
        p2.start()

        p1.join()
        p2.join()

        # print(f'in main {os.getpid()}, weight is {n.fc1.weight.item()}')

        if n.fc1.weight.item() != 0:
            print(f'{idx} in main {os.getpid()}, weight is {n.fc1.weight.item()}')
            break
    
    print('finished')

```

My pytorch version is 1.4.0+cpu

However, as I find it works without lock in the official “Hogwild” example and other examples, maybe the safe issue is not that important…

---

<div class="post-metadata">

**Author:** ![iffiX](https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/iffix/32/24443_2.png) [@iffiX](https://discuss.pytorch.org/u/iffiX)\
**Post date:** [June 4, 2020, 5:24pm UTC](https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857/2 "2020-06-04T17:24:46Z")

</div>

thread safety is not important, the hogwild essay basically spent pages trying to explain that the update is sparse and you can update in **whatever** way(sequence). It’s magic, so forget about the safety. 🤣

---

<div class="post-metadata">

**Author:** ![Brando\_Miranda](https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/brando_miranda/32/14355_2.png) [@Brando\_Miranda](https://discuss.pytorch.org/u/Brando_Miranda)\
**Post date:** [February 15, 2021, 12:52am UTC](https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857/3 "2021-02-15T00:52:54Z")

</div>

> [@iffiX](#):
>
> you can update in **whatever** way(sequence)

Can you clarify what you mean by “it’s magic”?

---

<div class="post-metadata">

**Author:** ![S\_Q](https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/s_q/32/15892_2.png) [@S\_Q](https://discuss.pytorch.org/u/S_Q)\
**Post date:** [February 17, 2021, 10:20am UTC](https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857/4 "2021-02-17T10:20:08Z")

</div>

Hi, does “whatever way” include update with data race? 👻

---

<div class="post-metadata">

**Author:** ![OrNot](https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/ornot/32/12839_2.png) [@OrNot](https://discuss.pytorch.org/u/OrNot)\
**Post date:** [May 12, 2021, 12:20am UTC](https://discuss.pytorch.org/t/model-update-with-share-memory-need-lock-protection/72857/5 "2021-05-12T00:20:26Z")

</div>

Any clue on this? I have the same question.
