Pytorch: problème load_state_dict() de l'optimiseur ?

Créé le 22 sept. 2017  ·  23Commentaires  ·  Source: pytorch/pytorch

Bonjour, j'ai rencontré ce bug :

    optimizer.step()
    exp_avg.mul_(beta1).add_(1 - beta1, grad)

TypeError: add_ received an invalid combination of arguments - got (float, torch.cuda.FloatTensor), but expected one of:
 * (float value)
 * (torch.FloatTensor other)
 * (torch.SparseFloatTensor other)
 * (float value, torch.FloatTensor other)
      didn't match because some of the arguments have invalid types: (float, torch.cuda.FloatTensor)
 * (float value, torch.SparseFloatTensor other)
      didn't match because some of the arguments have invalid types: (float, torch.cuda.FloatTensor)

Le squelette de code est comme :

model = Model()
model.load_state_dict(checkpoint['model'])
model.cuda()

optimizer = optim.Adam()
optimizer.load_state_dict(checkpoint['optimizer'])

...
#  In train loop
for epoch in range(...):
  ...
  optimizer.step()
     -> BUG <-

Il semble que les param_groups chargés soient torch.cuda.FloatTensor , et j'ai essayé une solution de contournement pour
déplacez optmizer.param_groups vers cpu , mais il a toujours le même bogue.

awaiting response (this tag is deprecated) needs reproduction

Commentaire le plus utile

@apaszke Ah, mon mauvais. J'ai oublié de mettre à jour la ligne où l'optimiseur est recréé. Mais sinon, ce qui suit devrait faire l'affaire, n'est-ce pas ?

model = Model()
model.load_state_dict(checkpoint['model'])
model.cuda()
optimizer = optim.Adam(model.parameters())
optimizer.load_state_dict(checkpoint['optimizer'])
for state in optimizer.state.values():
    for k, v in state.items():
        if isinstance(v, torch.Tensor):
            state[k] = v.cuda()

Tous les 23 commentaires

Pourriez-vous fournir un script complet pour reproduire le problème ?

peut-être que tu peux essayer comme ça,
optimiseur.step()
exp_avg.mul_(beta1).add_(1 - beta1, grad.cpu())

Désolé, j'ai raté l'e-mail de réponse.

Je crains de ne pas être en mesure de fournir un reproducteur maintenant. C'est un travail que je fais pour le projet OpenNMT-py : https://github.com/OpenNMT/OpenNMT-py, en essayant d'utiliser lr_scheduler pour faire la mise à jour lr. Et j'ai rencontré ce problème lors du test du cas resume a suspended training . J'ai donc factorisé le squelette de code concernant ce problème ci-dessus.

J'ai essayé plusieurs méthodes, y compris des astuces comme celle suggérée par @hefeicyp , mais cela arrive toujours.

D'après mon analyse, c'est parce que la formation précédente a été effectuée sur GPU, donc lors de l'enregistrement du optimizer.state_dict , les états (tenseurs) stockés sont de la version cuda . Lors de la reprise, lorsque nous chargeons l'optimiseur enregistré, load_state_dict() charge cette version cuda sur cpu(le modèle( nn.Module ) peut être déplacé facilement vers gpu, mais torch.optimizer semble manquer de cette capacité ?) , donc ce problème émerge.

Essayez de déplacer manuellement l'état de l'optimiseur vers la mémoire GPU après l'avoir chargé à partir du point de contrôle.

optimizer = optim.Adam()
optimizer.load_state_dict(checkpoint['optimizer'])
for state in optimizer.state.values():
    for k, v in state.items():
        if isinstance(v, torch.Tensor):
            state[k] = v.cuda()

Je suis d'accord qu'avoir une méthode optimizer.cuda() pour cette opération serait bien.

@dogancan , merci. Mon travail a été suspendu en raison d'autres problèmes, une fois repris, j'essayerai votre méthode.

J'ai peur que la solution de load_state_dict pour restaurer l'état d'une copie précédente. Cela ne fonctionne pas actuellement, mais nous devrions le corriger (en copiant les données du dict d'état, au lieu d'utiliser les tenseurs directement - cela permet des mises à jour inter-appareils ou inter-types).

@apaszke ,

@apaszke Ah, mon mauvais. J'ai oublié de mettre à jour la ligne où l'optimiseur est recréé. Mais sinon, ce qui suit devrait faire l'affaire, n'est-ce pas ?

model = Model()
model.load_state_dict(checkpoint['model'])
model.cuda()
optimizer = optim.Adam(model.parameters())
optimizer.load_state_dict(checkpoint['optimizer'])
for state in optimizer.state.values():
    for k, v in state.items():
        if isinstance(v, torch.Tensor):
            state[k] = v.cuda()

euh, d'accord. ça devrait marcher

Sauf que vous devriez utiliser torch.is_tensor(v) au lieu de isinstance(v, torch.Tensor)

J'avais un problème similaire. Lorsque j'enregistre l'état de l'optimiseur à partir d'un GPU autre que le GPU 0, puis que je charge l'état, il charge toujours tout sur le GPU 0. La spécification de map_location dans torch.load() n'a pas fonctionné non plus. La solution de @dogancan résout ce problème.

Salut les gars, j'ai un problème très similaire à celui de ce fil, voici mon code:

model = inceptionresnetv2(num_classes=config['tr_classes'])
model = torch.nn.DataParallel(model).cuda()
model.load_state_dict(checkpoint['md_state_dict'])
optimizer = torch.optim.Adam(model.parameters(), lr=config['tr_lr'], weight_decay=config['tr_weightdecay'])
optimizer.load_state_dict(checkpoint['md_optimizer'])
for state in optimizer.state.values():
    for k, v in state.items():
        if torch.is_tensor(v):
            state[k] = v.cuda()

Et puis une fois que je reprends, j'ai des KeyErrors sur mon optimiseur :

---> 40         optimizer.step()
     41 
     42         config['am_batch_time'].update(time.time() - end)
~/.conda/envs/env_pytorch/lib/python3.5/site-packages/torch/optim/adam.py in step(self, closure)
     44                     continue
     45                 grad = p.grad.data
---> 46                 state = self.state[p]
     47 
     48                 # State initialization
KeyError: Parameter containing:
(0 ,0 ,.,.) = 
 -1.6336e-01 -5.6482e-01 -4.2228e-02
...
[torch.cuda.FloatTensor of size 32x3x3x3 (GPU 0)]

Savez-vous les gars comment résoudre ce problème? BTW, j'ai utilisé 8 GPU , je suppose que ce problème est dû à cela?

@CodArs-van avez-vous pu résoudre votre problème avec plusieurs GPU ?

@rafaelvalle Merci d'avoir demandé. Oui, je suis capable de le faire, il s'avère que le problème est dû au fait que j'ai utilisé une première version de PyTorch, après avoir mis à jour la version, cela fonctionne à merveille !

Juste un commentaire, ce problème est causé par

    def load_state_dict(self, state_dict):
        ...
        # deepcopy, to be consistent with module API
        state_dict = deepcopy(state_dict)
       ...  

deepcopy fait que tous les tenseurs d'état sont déplacés dans GPU0 ,
ainsi, en déplaçant l'état d'un optimiseur vers un GPU spécifique, cela résoudra ce problème.

Salut @lzcn , comment connaître à l'avance l'emplacement spécifique du GPU des différents tenseurs ?

Une fonctionnalité où tous les appels torch.save() utilisent toujours une version CPU générée automatiquement serait-elle faisable ?
Et puis, à la reprise, torch.load() utiliserait le périphérique "actuel" utilisé (ou toute meilleure stratégie).
Pour le moment, il semble que nous ayons besoin de beaucoup de code passe-partout pour garantir que la sauvegarde et le chargement sont cohérents sur tous les appareils pour les modèles/optimiseur/planificateur/etc.

J'ai rencontré un problème similaire, j'ai recréé l'optimiseur Adam sans Optimizer.cuda() après avoir rechargé model, model.cuda() et DataParallel(model) selon la solution de @dogancan .

merci, ça marche !

@apaszke Ah, mon mauvais. J'ai oublié de mettre à jour la ligne où l'optimiseur est recréé. Mais sinon, ce qui suit devrait faire l'affaire, n'est-ce pas ?

model = Model()
model.load_state_dict(checkpoint['model'])
model.cuda()
optimizer = optim.Adam(model.parameters())
optimizer.load_state_dict(checkpoint['optimizer'])
for state in optimizer.state.values():
    for k, v in state.items():
        if isinstance(v, torch.Tensor):
            state[k] = v.cuda()

@apaszke
Bonjour, comme vous le dites : à chaque déplacement du modèle vers un autre appareil, nous devons construire l'optimiseur, mais, si nous déplaçons le modèle vers un autre appareil et reculons, devrions-nous reconstruire l'optimiseur ?
voici un exemple de code :

model = Model()
model.cuda()
optimizer = optim.Adam(model.parameters())

for d, gt in trn_dataloader:
    # train
    ... 
    optimizer.step()
    model.cpu() # move to cpu
    # eval or do other things
    ...
    model.cuda()  # but finnally, move back

l'optimiseur s'exécute-t-il comme prévu ?

aussi, si nous faisons model.to(model.device) , devrions-nous reconstruire l'optimiseur ?

@apaszke Ah, mon mauvais. J'ai oublié de mettre à jour la ligne où l'optimiseur est recréé. Mais sinon, ce qui suit devrait faire l'affaire, n'est-ce pas ?

model = Model()
model.load_state_dict(checkpoint['model'])
model.cuda()
optimizer = optim.Adam(model.parameters())
optimizer.load_state_dict(checkpoint['optimizer'])
for state in optimizer.state.values():
    for k, v in state.items():
        if isinstance(v, torch.Tensor):
            state[k] = v.cuda()

@apaszke Y a-t-il un problème si vous passez la commande à quelque chose comme ça ?

```python
modèle = Modèle()
model.to('cuda')
optimiseur = optim.Adam(model.parameters())
optimiseur.load_state_dict(checkpoint['optimizer'])
pour l'état dans Optimizer.state.values() :
pour k, v dans state.items() :
if isinstance(v, torch.Tensor):
état[k] = v.cuda()
model.load_state_dict(checkpoint['model'])

Cela signifie déplacer le modèle vers « cuda » mais ne charger son dict d'état qu'à partir du point de contrôle après avoir d'abord chargé le dict d'état de l'optimiseur ?

Le problème peut être conclu que l'état de l'optimiseur sera chargé sur l'appareil de la même manière que le modèle. Vous devez d'abord charger le modèle sur le GPU, puis charger l'état de l'optimiseur. Pour que le modèle et l'état de l'optimiseur soient chargés dans le GPU.

Au lieu de déplacer l'optimiseur vers cuda après l'avoir chargé dans le processeur, vous pouvez charger le point de contrôle directement dans cuda :

model.to(device)

ckpt = torch.load(<model_path>, map_location=device)

model.load_state_dict(ckpt['state_dict'])
optimizer.load_state_dict(ckpt['optimizer'])
scheduler.load_state_dict(ckpt['scheduler'])

del ckpt
Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

ikostrikov picture ikostrikov  ·  3Commentaires

bartolsthoorn picture bartolsthoorn  ·  3Commentaires

miguelvr picture miguelvr  ·  3Commentaires

soumith picture soumith  ·  3Commentaires

szagoruyko picture szagoruyko  ·  3Commentaires