Grow a Target From One Seed
Cellular Automata From First Principles 39: Grow a Target From One Seed
Now we can pose the central morphogenesis problem:
Start from one cell and learn local rules that construct a target pattern.
Prepare a target
Assume an RGBA image has been loaded into a tensor:
# shape: [1, 4, H, W], values in [0, 1]
target = load_target("target.png").to(DEVICE)
The NCA state contains more channels than the image, so only the visible channels are compared:
def target_loss(x, target):
return F.mse_loss(x[:, :4], target)
Randomize rollout length
Training at one exact step count encourages brittle timing tricks.
Instead sample a horizon:
steps = torch.randint(64, 97, ()).item()
x = make_seed(size=target.shape[-1], channels=16)
for _ in range(steps):
x = model(x)
Now the model must approach a useful region of state space across a range of times.
Train the local rule
optimizer = torch.optim.Adam(model.parameters(), lr=2e-3)
for iteration in range(8000):
x = make_seed(size=target.shape[-1], channels=16)
steps = torch.randint(64, 97, ()).item()
for _ in range(steps):
x = model(x)
loss = target_loss(x, target)
optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
Why growth from one seed is difficult
Every cell executes the same local rule, yet different regions must eventually play different roles.
The system has to create its own positional information through local interactions.
That is the real problem:
identical rule
+ local communication
+ recurrent hidden state
↓
spatial differentiation
Do not judge only the final frame
Record the entire trajectory:
frames = []
x = make_seed()
for step in range(128):
x = model(x)
if step % 4 == 0:
frames.append(x[:, :4].detach().cpu())
Later, the visual pass for this book should turn this trajectory into an animation. The process of becoming is more informative than the final image.
A low final loss can still hide a bad dynamical system
Check what happens after the training horizon:
for _ in range(500):
x = model(x)
Does the organism:
persist?
explode?
decay?
drift?
keep growing?
A model that reaches the target and then destroys it has learned growth, not homeostasis.
Separate growth from persistence
This distinction gives us three different capabilities:
growing = reach the target
persistent = remain near the target
regenerating = return after damage
They should be tested separately.
Further reading: Growing Neural Cellular Automata.
Before training persistence and regeneration, however, we need to remove another unrealistic assumption: that every cell updates at exactly the same instant.
In the next chapter we randomize the update schedule.