forge/trinity/sword.py (67 lines of code) (raw):

from pdb import set_trace as T from collections import defaultdict import numpy as np from forge import trinity from forge.ethyr.torch.param import setParameters, zeroGrads from forge.ethyr.torch import optim from forge.ethyr.rollouts import Rollout class Sword: def __init__(self, config, args): self.config, self.args = config, args self.nANN, self.h = config.NPOP, config.HIDDEN self.anns = [trinity.ANN(config) for i in range(self.nANN)] self.init, self.nRollouts = True, 32 self.networksUsed = set() self.updates, self.rollouts = defaultdict(Rollout), {} self.ents, self.rewards, self.grads = {}, [], None self.nGrads = 0 def backward(self): ents = self.rollouts.keys() anns = [self.anns[idx] for idx in self.networksUsed] reward, val, grads, pg, valLoss, entropy = optim.backward( self.rollouts, anns, valWeight=0.25, entWeight=self.config.ENTROPY) self.grads = dict((idx, grad) for idx, grad in zip(self.networksUsed, grads)) self.blobs = [r.feather.blob for r in self.rollouts.values()] self.rollouts = {} self.nGrads = 0 self.networksUsed = set() def sendGradUpdate(self): grads = self.grads self.grads = None return grads def sendLogUpdate(self): blobs = self.blobs self.blobs = [] return blobs def sendUpdate(self): if self.grads is None: return None, None return self.sendGradUpdate(), self.sendLogUpdate() def recvUpdate(self, update): for idx, paramVec in enumerate(update): setParameters(self.anns[idx], paramVec) zeroGrads(self.anns[idx]) def collectStep(self, entID, atnArgs, val, reward): if self.config.TEST: return self.updates[entID].step(atnArgs, val, reward) def collectRollout(self, entID, ent): assert entID not in self.rollouts rollout = self.updates[entID] rollout.finish() self.nGrads += rollout.lifespan self.rollouts[entID] = rollout del self.updates[entID] # assert ent.annID == (hash(entID) % self.nANN) self.networksUsed.add(ent.annID) #Two options: fixed number of gradients or rollouts #if len(self.rollouts) >= self.nRollouts: if self.nGrads >= 100*32: self.backward() def decide(self, ent, stim): reward, entID, annID = 0, ent.entID, ent.annID action, arguments, atnArgs, val = self.anns[annID](ent, stim) self.collectStep(entID, atnArgs, val, reward) self.updates[entID].feather.scrawl( stim, ent, val, reward) return action, arguments, float(val)