BonanDing commited on
Commit
44f5956
·
1 Parent(s): e8059ff

Slice DeMemWM diffusion updates to target frames

Browse files
algorithms/dememwm/models/diffusion.py CHANGED
@@ -188,7 +188,13 @@ class Diffusion(nn.Module):
188
  model_output = self.model(x, t, action_cond, **model_kwargs)
189
  model_output = model_output.permute(1,0,2,3,4)
190
  x = x.permute(1,0,2,3,4)
191
- t = t.permute(1,0)
 
 
 
 
 
 
192
 
193
  if self.objective == "pred_noise":
194
  pred_noise = torch.clamp(model_output, -self.clip_noise, self.clip_noise)
@@ -262,6 +268,10 @@ class Diffusion(nn.Module):
262
  frame_memory_masks=frame_memory_masks,
263
  frame_memory_pose=frame_memory_pose, image_hw=image_hw)
264
  x_start = model_pred.pred_x_start
 
 
 
 
265
  return self.q_posterior(x_start=x_start, x_t=x, t=t)
266
 
267
  def compute_loss_weights(self, noise_levels: torch.Tensor):
@@ -328,19 +338,27 @@ class Diffusion(nn.Module):
328
 
329
  pred = model_pred.model_out
330
  x_pred = model_pred.pred_x_start
 
 
 
 
 
 
 
 
331
 
332
  if self.objective == "pred_noise":
333
- target = noise
334
  elif self.objective == "pred_x0":
335
- target = x
336
  elif self.objective == "pred_v":
337
- target = self.predict_v(x, noise_levels, noise)
338
  else:
339
  raise ValueError(f"unknown objective {self.objective}")
340
 
341
  # 训练的时候每个frame随便给噪声
342
  loss = F.mse_loss(pred, target.detach(), reduction="none")
343
- loss_weight = self.compute_loss_weights(noise_levels)
344
 
345
  loss_weight = loss_weight.view(*loss_weight.shape, *((1,) * (loss.ndim - 2)))
346
 
@@ -458,16 +476,25 @@ class Diffusion(nn.Module):
458
  image_hw=image_hw
459
  )
460
 
 
 
 
 
 
 
 
 
 
461
  noise = torch.where(
462
- self.add_shape_channels(clipped_curr_noise_level > 0),
463
- torch.randn_like(x),
464
  0,
465
  )
466
  noise = torch.clamp(noise, -self.clip_noise, self.clip_noise)
467
  x_pred = model_mean + torch.exp(0.5 * model_log_variance) * noise
468
 
469
  # only update frames where the noise level decreases
470
- return torch.where(self.add_shape_channels(curr_noise_level == -1), orig_x, x_pred)
471
 
472
  def ddim_sample_step(
473
  self,
@@ -502,15 +529,26 @@ class Diffusion(nn.Module):
502
  )
503
  x = torch.where(self.add_shape_channels(curr_noise_level < 0), scaled_context, orig_x)
504
 
505
- alpha = self.alphas_cumprod[clipped_curr_noise_level]
 
 
 
 
 
 
 
 
 
 
 
506
  alpha_next = torch.where(
507
- next_noise_level < 0,
508
- torch.ones_like(next_noise_level),
509
- self.alphas_cumprod[next_noise_level],
510
  )
511
  sigma = torch.where(
512
- next_noise_level < 0,
513
- torch.zeros_like(next_noise_level),
514
  self.ddim_sampling_eta * ((1 - alpha / alpha_next) * (1 - alpha_next) / (1 - alpha)).sqrt(),
515
  )
516
  c = (1 - alpha_next - sigma**2).sqrt()
@@ -522,6 +560,9 @@ class Diffusion(nn.Module):
522
  if guidance_fn is not None:
523
  with torch.enable_grad():
524
  x = x.detach().requires_grad_()
 
 
 
525
 
526
  model_pred = self.model_predictions(
527
  x=x,
@@ -543,9 +584,11 @@ class Diffusion(nn.Module):
543
  guidance_loss,
544
  x,
545
  )[0]
 
 
546
 
547
  pred_noise = model_pred.pred_noise + (1 - alpha_next).sqrt() * grad
548
- x_start = self.predict_start_from_noise(x, clipped_curr_noise_level, pred_noise)
549
 
550
  else:
551
  # print(clipped_curr_noise_level)
@@ -565,17 +608,20 @@ class Diffusion(nn.Module):
565
  )
566
  x_start = model_pred.pred_x_start
567
  pred_noise = model_pred.pred_noise
 
 
 
568
 
569
- noise = torch.randn_like(x)
570
  noise = torch.clamp(noise, -self.clip_noise, self.clip_noise)
571
 
572
  x_pred = x_start * alpha_next.sqrt() + pred_noise * c + sigma * noise
573
 
574
  # only update frames where the noise level decreases
575
- mask = curr_noise_level == next_noise_level
576
  x_pred = torch.where(
577
  self.add_shape_channels(mask),
578
- orig_x,
579
  x_pred,
580
  )
581
 
 
188
  model_output = self.model(x, t, action_cond, **model_kwargs)
189
  model_output = model_output.permute(1,0,2,3,4)
190
  x = x.permute(1,0,2,3,4)
191
+ t = t.permute(1,0)
192
+
193
+ target_frames = self._target_frames(x, frame_memory_segments)
194
+ if frame_memory_segments is not None:
195
+ model_output = model_output[:target_frames]
196
+ x = x[:target_frames]
197
+ t = t[:target_frames]
198
 
199
  if self.objective == "pred_noise":
200
  pred_noise = torch.clamp(model_output, -self.clip_noise, self.clip_noise)
 
268
  frame_memory_masks=frame_memory_masks,
269
  frame_memory_pose=frame_memory_pose, image_hw=image_hw)
270
  x_start = model_pred.pred_x_start
271
+ target_frames = self._target_frames(x, frame_memory_segments)
272
+ if frame_memory_segments is not None:
273
+ x = x[:target_frames]
274
+ t = t[:target_frames]
275
  return self.q_posterior(x_start=x_start, x_t=x, t=t)
276
 
277
  def compute_loss_weights(self, noise_levels: torch.Tensor):
 
338
 
339
  pred = model_pred.model_out
340
  x_pred = model_pred.pred_x_start
341
+ target_frames = self._target_frames(x, frame_memory_segments)
342
+ target_x = x
343
+ target_noise = noise
344
+ target_noise_levels = noise_levels
345
+ if frame_memory_segments is not None:
346
+ target_x = x[:target_frames]
347
+ target_noise = noise[:target_frames]
348
+ target_noise_levels = noise_levels[:target_frames]
349
 
350
  if self.objective == "pred_noise":
351
+ target = target_noise
352
  elif self.objective == "pred_x0":
353
+ target = target_x
354
  elif self.objective == "pred_v":
355
+ target = self.predict_v(target_x, target_noise_levels, target_noise)
356
  else:
357
  raise ValueError(f"unknown objective {self.objective}")
358
 
359
  # 训练的时候每个frame随便给噪声
360
  loss = F.mse_loss(pred, target.detach(), reduction="none")
361
+ loss_weight = self.compute_loss_weights(target_noise_levels)
362
 
363
  loss_weight = loss_weight.view(*loss_weight.shape, *((1,) * (loss.ndim - 2)))
364
 
 
476
  image_hw=image_hw
477
  )
478
 
479
+ target_frames = self._target_frames(x, frame_memory_segments)
480
+ update_curr_noise_level = curr_noise_level
481
+ update_clipped_curr_noise_level = clipped_curr_noise_level
482
+ update_orig_x = orig_x
483
+ if frame_memory_segments is not None:
484
+ update_curr_noise_level = curr_noise_level[:target_frames]
485
+ update_clipped_curr_noise_level = clipped_curr_noise_level[:target_frames]
486
+ update_orig_x = orig_x[:target_frames]
487
+
488
  noise = torch.where(
489
+ self.add_shape_channels(update_clipped_curr_noise_level > 0),
490
+ torch.randn_like(model_mean),
491
  0,
492
  )
493
  noise = torch.clamp(noise, -self.clip_noise, self.clip_noise)
494
  x_pred = model_mean + torch.exp(0.5 * model_log_variance) * noise
495
 
496
  # only update frames where the noise level decreases
497
+ return torch.where(self.add_shape_channels(update_curr_noise_level == -1), update_orig_x, x_pred)
498
 
499
  def ddim_sample_step(
500
  self,
 
529
  )
530
  x = torch.where(self.add_shape_channels(curr_noise_level < 0), scaled_context, orig_x)
531
 
532
+ target_frames = self._target_frames(x, frame_memory_segments)
533
+ update_curr_noise_level = curr_noise_level
534
+ update_clipped_curr_noise_level = clipped_curr_noise_level
535
+ update_next_noise_level = next_noise_level
536
+ update_orig_x = orig_x
537
+ if frame_memory_segments is not None:
538
+ update_curr_noise_level = curr_noise_level[:target_frames]
539
+ update_clipped_curr_noise_level = clipped_curr_noise_level[:target_frames]
540
+ update_next_noise_level = next_noise_level[:target_frames]
541
+ update_orig_x = orig_x[:target_frames]
542
+
543
+ alpha = self.alphas_cumprod[update_clipped_curr_noise_level]
544
  alpha_next = torch.where(
545
+ update_next_noise_level < 0,
546
+ torch.ones_like(update_next_noise_level),
547
+ self.alphas_cumprod[update_next_noise_level],
548
  )
549
  sigma = torch.where(
550
+ update_next_noise_level < 0,
551
+ torch.zeros_like(update_next_noise_level),
552
  self.ddim_sampling_eta * ((1 - alpha / alpha_next) * (1 - alpha_next) / (1 - alpha)).sqrt(),
553
  )
554
  c = (1 - alpha_next - sigma**2).sqrt()
 
560
  if guidance_fn is not None:
561
  with torch.enable_grad():
562
  x = x.detach().requires_grad_()
563
+ update_x = x
564
+ if frame_memory_segments is not None:
565
+ update_x = x[:target_frames]
566
 
567
  model_pred = self.model_predictions(
568
  x=x,
 
584
  guidance_loss,
585
  x,
586
  )[0]
587
+ if frame_memory_segments is not None:
588
+ grad = grad[:target_frames]
589
 
590
  pred_noise = model_pred.pred_noise + (1 - alpha_next).sqrt() * grad
591
+ x_start = self.predict_start_from_noise(update_x, update_clipped_curr_noise_level, pred_noise)
592
 
593
  else:
594
  # print(clipped_curr_noise_level)
 
608
  )
609
  x_start = model_pred.pred_x_start
610
  pred_noise = model_pred.pred_noise
611
+ update_x = x
612
+ if frame_memory_segments is not None:
613
+ update_x = x[:target_frames]
614
 
615
+ noise = torch.randn_like(update_x)
616
  noise = torch.clamp(noise, -self.clip_noise, self.clip_noise)
617
 
618
  x_pred = x_start * alpha_next.sqrt() + pred_noise * c + sigma * noise
619
 
620
  # only update frames where the noise level decreases
621
+ mask = update_curr_noise_level == update_next_noise_level
622
  x_pred = torch.where(
623
  self.add_shape_channels(mask),
624
+ update_orig_x,
625
  x_pred,
626
  )
627
 
tests/test_dememwm_diffusion.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+
3
+ import torch
4
+ from torch import nn
5
+
6
+ from algorithms.dememwm.models.diffusion import Diffusion
7
+
8
+
9
+ class FakeDenoiser(nn.Module):
10
+ def __init__(self, output_frames=None):
11
+ super().__init__()
12
+ self.output_frames = output_frames
13
+ self.calls = []
14
+
15
+ def forward(self, x, t, action_cond, **kwargs):
16
+ self.calls.append({
17
+ "x_shape": tuple(x.shape),
18
+ "t_shape": tuple(t.shape),
19
+ "kwargs": kwargs,
20
+ })
21
+ frames = self.output_frames if self.output_frames is not None else x.shape[1]
22
+ return torch.zeros((x.shape[0], frames, *x.shape[2:]), device=x.device, dtype=x.dtype)
23
+
24
+
25
+ def _make_diffusion(output_frames=None):
26
+ diffusion = Diffusion.__new__(Diffusion)
27
+ nn.Module.__init__(diffusion)
28
+ diffusion.x_shape = torch.Size((1, 1, 1))
29
+ diffusion.timesteps = 4
30
+ diffusion.sampling_timesteps = 4
31
+ diffusion.is_ddim_sampling = False
32
+ diffusion.objective = "pred_noise"
33
+ diffusion.use_fused_snr = False
34
+ diffusion.snr_clip = 5.0
35
+ diffusion.cum_snr_decay = 0.9
36
+ diffusion.ddim_sampling_eta = 0.0
37
+ diffusion.clip_noise = 10.0
38
+ diffusion.stabilization_level = 1
39
+ diffusion.model = FakeDenoiser(output_frames=output_frames)
40
+
41
+ betas = torch.tensor([0.05, 0.10, 0.15, 0.20], dtype=torch.float32)
42
+ alphas = 1.0 - betas
43
+ alphas_cumprod = torch.cumprod(alphas, dim=0)
44
+ alphas_cumprod_prev = torch.nn.functional.pad(alphas_cumprod[:-1], (1, 0), value=1.0)
45
+ posterior_variance = betas * (1.0 - alphas_cumprod_prev) / (1.0 - alphas_cumprod)
46
+ snr = alphas_cumprod / (1.0 - alphas_cumprod)
47
+
48
+ diffusion.register_buffer("betas", betas)
49
+ diffusion.register_buffer("alphas_cumprod", alphas_cumprod)
50
+ diffusion.register_buffer("alphas_cumprod_prev", alphas_cumprod_prev)
51
+ diffusion.register_buffer("sqrt_alphas_cumprod", torch.sqrt(alphas_cumprod))
52
+ diffusion.register_buffer("sqrt_one_minus_alphas_cumprod", torch.sqrt(1.0 - alphas_cumprod))
53
+ diffusion.register_buffer("log_one_minus_alphas_cumprod", torch.log(1.0 - alphas_cumprod))
54
+ diffusion.register_buffer("sqrt_recip_alphas_cumprod", torch.sqrt(1.0 / alphas_cumprod))
55
+ diffusion.register_buffer("sqrt_recipm1_alphas_cumprod", torch.sqrt(1.0 / alphas_cumprod - 1.0))
56
+ diffusion.register_buffer("posterior_variance", posterior_variance)
57
+ diffusion.register_buffer("posterior_log_variance_clipped", torch.log(posterior_variance.clamp(min=1e-20)))
58
+ diffusion.register_buffer("posterior_mean_coef1", betas * torch.sqrt(alphas_cumprod_prev) / (1.0 - alphas_cumprod))
59
+ diffusion.register_buffer("posterior_mean_coef2", (1.0 - alphas_cumprod_prev) * torch.sqrt(alphas) / (1.0 - alphas_cumprod))
60
+ diffusion.register_buffer("snr", snr)
61
+ diffusion.register_buffer("clipped_snr", snr.clamp(max=diffusion.snr_clip))
62
+ return diffusion
63
+
64
+
65
+ def _packed_inputs():
66
+ x = torch.arange(5, dtype=torch.float32).view(5, 1, 1, 1, 1)
67
+ action_cond = torch.zeros((5, 1, 3), dtype=torch.float32)
68
+ noise_levels = torch.tensor([[1], [2], [0], [0], [0]], dtype=torch.long)
69
+ segments = {"target": 2, "anchor": 1, "dynamic": 1, "revisit": 1}
70
+ return x, action_cond, noise_levels, segments
71
+
72
+
73
+ class DeMemWMDiffusionTargetOnlyTests(unittest.TestCase):
74
+ def test_forward_noises_packed_input_but_returns_target_loss(self):
75
+ torch.manual_seed(0)
76
+ diffusion = _make_diffusion(output_frames=2)
77
+ x, action_cond, noise_levels, segments = _packed_inputs()
78
+
79
+ x_pred, loss = diffusion(
80
+ x,
81
+ action_cond,
82
+ None,
83
+ noise_levels=noise_levels,
84
+ reference_length=0,
85
+ frame_memory_segments=segments,
86
+ )
87
+
88
+ self.assertEqual(diffusion.model.calls[0]["x_shape"], (1, 5, 1, 1, 1))
89
+ self.assertEqual(tuple(x_pred.shape), (2, 1, 1, 1, 1))
90
+ self.assertEqual(tuple(loss.shape), (2, 1, 1, 1, 1))
91
+
92
+ def test_forward_without_frame_memory_keeps_full_length(self):
93
+ torch.manual_seed(0)
94
+ diffusion = _make_diffusion()
95
+ x, action_cond, noise_levels, _ = _packed_inputs()
96
+
97
+ x_pred, loss = diffusion(
98
+ x,
99
+ action_cond,
100
+ None,
101
+ noise_levels=noise_levels,
102
+ reference_length=0,
103
+ )
104
+
105
+ self.assertEqual(diffusion.model.calls[0]["x_shape"], (1, 5, 1, 1, 1))
106
+ self.assertEqual(tuple(x_pred.shape), tuple(x.shape))
107
+ self.assertEqual(tuple(loss.shape), tuple(x.shape))
108
+
109
+ def test_posterior_and_sample_steps_return_target_frames_for_frame_memory(self):
110
+ torch.manual_seed(0)
111
+ x, action_cond, _, segments = _packed_inputs()
112
+ curr = torch.tensor([[2], [1], [-1], [-1], [-1]], dtype=torch.long)
113
+ next_level = torch.tensor([[1], [0], [-1], [-1], [-1]], dtype=torch.long)
114
+
115
+ diffusion = _make_diffusion(output_frames=2)
116
+ mean, variance, log_variance = diffusion.p_mean_variance(
117
+ x,
118
+ curr,
119
+ action_cond=action_cond,
120
+ pose_cond=None,
121
+ reference_length=0,
122
+ frame_memory_segments=segments,
123
+ )
124
+ self.assertEqual(tuple(mean.shape), (2, 1, 1, 1, 1))
125
+ self.assertEqual(tuple(variance.shape), (2, 1, 1, 1, 1))
126
+ self.assertEqual(tuple(log_variance.shape), (2, 1, 1, 1, 1))
127
+
128
+ diffusion = _make_diffusion(output_frames=2)
129
+ ddpm = diffusion.ddpm_sample_step(
130
+ x,
131
+ action_cond,
132
+ None,
133
+ curr_noise_level=curr,
134
+ reference_length=0,
135
+ frame_memory_segments=segments,
136
+ )
137
+ self.assertEqual(diffusion.model.calls[0]["x_shape"], (1, 5, 1, 1, 1))
138
+ self.assertEqual(tuple(ddpm.shape), (2, 1, 1, 1, 1))
139
+
140
+ diffusion = _make_diffusion(output_frames=2)
141
+ ddim = diffusion.ddim_sample_step(
142
+ x,
143
+ action_cond,
144
+ None,
145
+ curr_noise_level=curr,
146
+ next_noise_level=next_level,
147
+ reference_length=0,
148
+ frame_memory_segments=segments,
149
+ )
150
+ self.assertEqual(diffusion.model.calls[0]["x_shape"], (1, 5, 1, 1, 1))
151
+ self.assertEqual(tuple(ddim.shape), (2, 1, 1, 1, 1))
152
+
153
+
154
+ if __name__ == "__main__":
155
+ unittest.main()