Skip to content

Commit b80790f

Browse files
offchan42patrickvonplaten
authored andcommitted
Fix typo and format BasicTransformerBlock attributes (huggingface#2953)
* ⚙️chore(train_controlnet) fix typo in logger message * ⚙️chore(models) refactor modules order; make them the same as calling order When printing the BasicTransformerBlock to stdout, I think it's crucial that the attributes order are shown in proper order. And also previously the "3. Feed Forward" comment was not making sense. It should have been close to self.ff but it's instead next to self.norm3 * correct many tests * remove bogus file * make style * correct more tests * finish tests * fix one more * make style * make unclip deterministic * ⚙️chore(models/attention) reorganize comments in BasicTransformerBlock class --------- Co-authored-by: Patrick von Platen <[email protected]>
1 parent 0c8fd45 commit b80790f

25 files changed

+87
-154
lines changed

examples/controlnet/train_controlnet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ def make_train_dataset(args, tokenizer, accelerator):
577577

578578
if args.conditioning_image_column is None:
579579
conditioning_image_column = column_names[2]
580-
logger.info(f"conditioning image column defaulting to {caption_column}")
580+
logger.info(f"conditioning image column defaulting to {conditioning_image_column}")
581581
else:
582582
conditioning_image_column = args.conditioning_image_column
583583
if conditioning_image_column not in column_names:

src/diffusers/models/attention.py

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,14 @@ def __init__(
224224
f" define `num_embeds_ada_norm` if setting `norm_type` to {norm_type}."
225225
)
226226

227+
# Define 3 blocks. Each block has its own normalization layer.
227228
# 1. Self-Attn
229+
if self.use_ada_layer_norm:
230+
self.norm1 = AdaLayerNorm(dim, num_embeds_ada_norm)
231+
elif self.use_ada_layer_norm_zero:
232+
self.norm1 = AdaLayerNormZero(dim, num_embeds_ada_norm)
233+
else:
234+
self.norm1 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
228235
self.attn1 = Attention(
229236
query_dim=dim,
230237
heads=num_attention_heads,
@@ -235,10 +242,16 @@ def __init__(
235242
upcast_attention=upcast_attention,
236243
)
237244

238-
self.ff = FeedForward(dim, dropout=dropout, activation_fn=activation_fn, final_dropout=final_dropout)
239-
240245
# 2. Cross-Attn
241246
if cross_attention_dim is not None or double_self_attention:
247+
# We currently only use AdaLayerNormZero for self attention where there will only be one attention block.
248+
# I.e. the number of returned modulation chunks from AdaLayerZero would not make sense if returned during
249+
# the second cross attention block.
250+
self.norm2 = (
251+
AdaLayerNorm(dim, num_embeds_ada_norm)
252+
if self.use_ada_layer_norm
253+
else nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
254+
)
242255
self.attn2 = Attention(
243256
query_dim=dim,
244257
cross_attention_dim=cross_attention_dim if not double_self_attention else None,
@@ -248,30 +261,13 @@ def __init__(
248261
bias=attention_bias,
249262
upcast_attention=upcast_attention,
250263
) # is self-attn if encoder_hidden_states is none
251-
else:
252-
self.attn2 = None
253-
254-
if self.use_ada_layer_norm:
255-
self.norm1 = AdaLayerNorm(dim, num_embeds_ada_norm)
256-
elif self.use_ada_layer_norm_zero:
257-
self.norm1 = AdaLayerNormZero(dim, num_embeds_ada_norm)
258-
else:
259-
self.norm1 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
260-
261-
if cross_attention_dim is not None or double_self_attention:
262-
# We currently only use AdaLayerNormZero for self attention where there will only be one attention block.
263-
# I.e. the number of returned modulation chunks from AdaLayerZero would not make sense if returned during
264-
# the second cross attention block.
265-
self.norm2 = (
266-
AdaLayerNorm(dim, num_embeds_ada_norm)
267-
if self.use_ada_layer_norm
268-
else nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
269-
)
270264
else:
271265
self.norm2 = None
266+
self.attn2 = None
272267

273268
# 3. Feed-forward
274269
self.norm3 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
270+
self.ff = FeedForward(dim, dropout=dropout, activation_fn=activation_fn, final_dropout=final_dropout)
275271

276272
def forward(
277273
self,
@@ -283,6 +279,8 @@ def forward(
283279
cross_attention_kwargs=None,
284280
class_labels=None,
285281
):
282+
# Notice that normalization is always applied before the real computation in the following blocks.
283+
# 1. Self-Attention
286284
if self.use_ada_layer_norm:
287285
norm_hidden_states = self.norm1(hidden_states, timestep)
288286
elif self.use_ada_layer_norm_zero:
@@ -292,7 +290,6 @@ def forward(
292290
else:
293291
norm_hidden_states = self.norm1(hidden_states)
294292

295-
# 1. Self-Attention
296293
cross_attention_kwargs = cross_attention_kwargs if cross_attention_kwargs is not None else {}
297294
attn_output = self.attn1(
298295
norm_hidden_states,
@@ -304,14 +301,14 @@ def forward(
304301
attn_output = gate_msa.unsqueeze(1) * attn_output
305302
hidden_states = attn_output + hidden_states
306303

304+
# 2. Cross-Attention
307305
if self.attn2 is not None:
308306
norm_hidden_states = (
309307
self.norm2(hidden_states, timestep) if self.use_ada_layer_norm else self.norm2(hidden_states)
310308
)
311309
# TODO (Birch-San): Here we should prepare the encoder_attention mask correctly
312310
# prepare attention mask here
313311

314-
# 2. Cross-Attention
315312
attn_output = self.attn2(
316313
norm_hidden_states,
317314
encoder_hidden_states=encoder_hidden_states,

tests/pipelines/altdiffusion/test_alt_diffusion_img2img.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def test_stable_diffusion_img2img_default_case(self):
166166
image_from_tuple_slice = image_from_tuple[0, -3:, -3:, -1]
167167

168168
assert image.shape == (1, 32, 32, 3)
169-
expected_slice = np.array([0.4115, 0.3870, 0.4089, 0.4807, 0.4668, 0.4144, 0.4151, 0.4721, 0.4569])
169+
expected_slice = np.array([0.4427, 0.3731, 0.4249, 0.4941, 0.4546, 0.4148, 0.4193, 0.4666, 0.4499])
170170

171171
assert np.abs(image_slice.flatten() - expected_slice).max() < 5e-3
172172
assert np.abs(image_from_tuple_slice.flatten() - expected_slice).max() < 5e-3

tests/pipelines/dit/test_dit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def test_inference(self):
9292
image_slice = image[0, -3:, -3:, -1]
9393

9494
self.assertEqual(image.shape, (1, 16, 16, 3))
95-
expected_slice = np.array([0.4380, 0.4141, 0.5159, 0.0000, 0.4282, 0.6680, 0.5485, 0.2545, 0.6719])
95+
expected_slice = np.array([0.2946, 0.6601, 0.4329, 0.3296, 0.4144, 0.5319, 0.7273, 0.5013, 0.4457])
9696
max_diff = np.abs(image_slice.flatten() - expected_slice).max()
9797
self.assertLessEqual(max_diff, 1e-3)
9898

tests/pipelines/latent_diffusion/test_latent_diffusion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def test_inference_text2img(self):
125125
image_slice = image[0, -3:, -3:, -1]
126126

127127
assert image.shape == (1, 16, 16, 3)
128-
expected_slice = np.array([0.59450, 0.64078, 0.55509, 0.51229, 0.69640, 0.36960, 0.59296, 0.60801, 0.49332])
128+
expected_slice = np.array([0.6101, 0.6156, 0.5622, 0.4895, 0.6661, 0.3804, 0.5748, 0.6136, 0.5014])
129129

130130
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
131131

tests/pipelines/paint_by_example/test_paint_by_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_paint_by_example_inpaint(self):
129129
image_slice = image[0, -3:, -3:, -1]
130130

131131
assert image.shape == (1, 64, 64, 3)
132-
expected_slice = np.array([0.4701, 0.5555, 0.3994, 0.5107, 0.5691, 0.4517, 0.5125, 0.4769, 0.4539])
132+
expected_slice = np.array([0.4686, 0.5687, 0.4007, 0.5218, 0.5741, 0.4482, 0.4940, 0.4629, 0.4503])
133133

134134
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
135135

tests/pipelines/semantic_stable_diffusion/test_semantic_diffusion.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def test_semantic_diffusion_ddim(self):
154154
image_from_tuple_slice = image_from_tuple[0, -3:, -3:, -1]
155155

156156
assert image.shape == (1, 64, 64, 3)
157-
expected_slice = np.array([0.5644, 0.6018, 0.4799, 0.5267, 0.5585, 0.4641, 0.516, 0.4964, 0.4792])
157+
expected_slice = np.array([0.5753, 0.6114, 0.5001, 0.5034, 0.5470, 0.4729, 0.4971, 0.4867, 0.4867])
158158

159159
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
160160
assert np.abs(image_from_tuple_slice.flatten() - expected_slice).max() < 1e-2
@@ -200,7 +200,7 @@ def test_semantic_diffusion_pndm(self):
200200
image_from_tuple_slice = image_from_tuple[0, -3:, -3:, -1]
201201

202202
assert image.shape == (1, 64, 64, 3)
203-
expected_slice = np.array([0.5095, 0.5674, 0.4668, 0.5126, 0.5697, 0.4675, 0.5278, 0.4964, 0.4945])
203+
expected_slice = np.array([0.5122, 0.5712, 0.4825, 0.5053, 0.5646, 0.4769, 0.5179, 0.4894, 0.4994])
204204

205205
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
206206
assert np.abs(image_from_tuple_slice.flatten() - expected_slice).max() < 1e-2

tests/pipelines/stable_diffusion/test_stable_diffusion.py

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def test_stable_diffusion_ddim(self):
135135
image_slice = image[0, -3:, -3:, -1]
136136

137137
assert image.shape == (1, 64, 64, 3)
138-
expected_slice = np.array([0.5643, 0.6017, 0.4799, 0.5267, 0.5584, 0.4641, 0.5159, 0.4963, 0.4791])
138+
expected_slice = np.array([0.5756, 0.6118, 0.5005, 0.5041, 0.5471, 0.4726, 0.4976, 0.4865, 0.4864])
139139

140140
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
141141

@@ -282,7 +282,7 @@ def test_stable_diffusion_pndm(self):
282282
image_slice = image[0, -3:, -3:, -1]
283283

284284
assert image.shape == (1, 64, 64, 3)
285-
expected_slice = np.array([0.5094, 0.5674, 0.4667, 0.5125, 0.5696, 0.4674, 0.5277, 0.4964, 0.4945])
285+
expected_slice = np.array([0.5122, 0.5712, 0.4825, 0.5053, 0.5646, 0.4769, 0.5179, 0.4894, 0.4994])
286286

287287
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
288288

@@ -322,19 +322,7 @@ def test_stable_diffusion_k_lms(self):
322322
image_slice = image[0, -3:, -3:, -1]
323323

324324
assert image.shape == (1, 64, 64, 3)
325-
expected_slice = np.array(
326-
[
327-
0.47082293033599854,
328-
0.5371589064598083,
329-
0.4562119245529175,
330-
0.5220914483070374,
331-
0.5733777284622192,
332-
0.4795039892196655,
333-
0.5465868711471558,
334-
0.5074326395988464,
335-
0.5042197108268738,
336-
]
337-
)
325+
expected_slice = np.array([0.4873, 0.5443, 0.4845, 0.5004, 0.5549, 0.4850, 0.5191, 0.4941, 0.5065])
338326

339327
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
340328

@@ -353,19 +341,7 @@ def test_stable_diffusion_k_euler_ancestral(self):
353341
image_slice = image[0, -3:, -3:, -1]
354342

355343
assert image.shape == (1, 64, 64, 3)
356-
expected_slice = np.array(
357-
[
358-
0.4707113206386566,
359-
0.5372191071510315,
360-
0.4563021957874298,
361-
0.5220003724098206,
362-
0.5734264850616455,
363-
0.4794946610927582,
364-
0.5463782548904419,
365-
0.5074145197868347,
366-
0.504422664642334,
367-
]
368-
)
344+
expected_slice = np.array([0.4872, 0.5444, 0.4846, 0.5003, 0.5549, 0.4850, 0.5189, 0.4941, 0.5067])
369345

370346
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
371347

@@ -384,19 +360,7 @@ def test_stable_diffusion_k_euler(self):
384360
image_slice = image[0, -3:, -3:, -1]
385361

386362
assert image.shape == (1, 64, 64, 3)
387-
expected_slice = np.array(
388-
[
389-
0.47082313895225525,
390-
0.5371587872505188,
391-
0.4562119245529175,
392-
0.5220913887023926,
393-
0.5733776688575745,
394-
0.47950395941734314,
395-
0.546586811542511,
396-
0.5074326992034912,
397-
0.5042197108268738,
398-
]
399-
)
363+
expected_slice = np.array([0.4873, 0.5443, 0.4845, 0.5004, 0.5549, 0.4850, 0.5191, 0.4941, 0.5065])
400364

401365
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
402366

@@ -468,19 +432,7 @@ def test_stable_diffusion_negative_prompt(self):
468432
image_slice = image[0, -3:, -3:, -1]
469433

470434
assert image.shape == (1, 64, 64, 3)
471-
expected_slice = np.array(
472-
[
473-
0.5108221173286438,
474-
0.5688379406929016,
475-
0.4685141146183014,
476-
0.5098261833190918,
477-
0.5657756328582764,
478-
0.4631010890007019,
479-
0.5226285457611084,
480-
0.49129390716552734,
481-
0.4899061322212219,
482-
]
483-
)
435+
expected_slice = np.array([0.5114, 0.5706, 0.4772, 0.5028, 0.5637, 0.4732, 0.5169, 0.4881, 0.4977])
484436

485437
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
486438

tests/pipelines/stable_diffusion/test_stable_diffusion_image_variation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def test_stable_diffusion_img_variation_default_case(self):
119119
image_slice = image[0, -3:, -3:, -1]
120120

121121
assert image.shape == (1, 64, 64, 3)
122-
expected_slice = np.array([0.5167, 0.5746, 0.4835, 0.4914, 0.5605, 0.4691, 0.5201, 0.4898, 0.4958])
122+
expected_slice = np.array([0.5239, 0.5723, 0.4796, 0.5049, 0.5550, 0.4685, 0.5329, 0.4891, 0.4921])
123123

124124
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
125125

@@ -139,7 +139,7 @@ def test_stable_diffusion_img_variation_multiple_images(self):
139139
image_slice = image[-1, -3:, -3:, -1]
140140

141141
assert image.shape == (2, 64, 64, 3)
142-
expected_slice = np.array([0.6568, 0.5470, 0.5684, 0.5444, 0.5945, 0.6221, 0.5508, 0.5531, 0.5263])
142+
expected_slice = np.array([0.6892, 0.5637, 0.5836, 0.5771, 0.6254, 0.6409, 0.5580, 0.5569, 0.5289])
143143

144144
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
145145

tests/pipelines/stable_diffusion/test_stable_diffusion_img2img.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def test_stable_diffusion_img2img_default_case(self):
138138
image_slice = image[0, -3:, -3:, -1]
139139

140140
assert image.shape == (1, 32, 32, 3)
141-
expected_slice = np.array([0.4492, 0.3865, 0.4222, 0.5854, 0.5139, 0.4379, 0.4193, 0.48, 0.4218])
141+
expected_slice = np.array([0.4555, 0.3216, 0.4049, 0.4620, 0.4618, 0.4126, 0.4122, 0.4629, 0.4579])
142142

143143
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
144144

@@ -157,7 +157,7 @@ def test_stable_diffusion_img2img_negative_prompt(self):
157157
image_slice = image[0, -3:, -3:, -1]
158158

159159
assert image.shape == (1, 32, 32, 3)
160-
expected_slice = np.array([0.4065, 0.3783, 0.4050, 0.5266, 0.4781, 0.4252, 0.4203, 0.4692, 0.4365])
160+
expected_slice = np.array([0.4593, 0.3408, 0.4232, 0.4749, 0.4476, 0.4115, 0.4357, 0.4733, 0.4663])
161161

162162
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
163163

@@ -176,7 +176,7 @@ def test_stable_diffusion_img2img_multiple_init_images(self):
176176
image_slice = image[-1, -3:, -3:, -1]
177177

178178
assert image.shape == (2, 32, 32, 3)
179-
expected_slice = np.array([0.5144, 0.4447, 0.4735, 0.6676, 0.5526, 0.5454, 0.645, 0.5149, 0.4689])
179+
expected_slice = np.array([0.4241, 0.5576, 0.5711, 0.4792, 0.4311, 0.5952, 0.5827, 0.5138, 0.5109])
180180

181181
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
182182

@@ -196,7 +196,7 @@ def test_stable_diffusion_img2img_k_lms(self):
196196
image_slice = image[0, -3:, -3:, -1]
197197

198198
assert image.shape == (1, 32, 32, 3)
199-
expected_slice = np.array([0.4367, 0.4986, 0.4372, 0.6706, 0.5665, 0.444, 0.5864, 0.6019, 0.5203])
199+
expected_slice = np.array([0.4398, 0.4949, 0.4337, 0.6580, 0.5555, 0.4338, 0.5769, 0.5955, 0.5175])
200200

201201
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
202202

tests/pipelines/stable_diffusion/test_stable_diffusion_instruction_pix2pix.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def test_stable_diffusion_pix2pix_default_case(self):
124124
image = sd_pipe(**inputs).images
125125
image_slice = image[0, -3:, -3:, -1]
126126
assert image.shape == (1, 32, 32, 3)
127-
expected_slice = np.array([0.7318, 0.3723, 0.4662, 0.623, 0.5770, 0.5014, 0.4281, 0.5550, 0.4813])
127+
expected_slice = np.array([0.7526, 0.3750, 0.4547, 0.6117, 0.5866, 0.5016, 0.4327, 0.5642, 0.4815])
128128

129129
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
130130

@@ -142,7 +142,7 @@ def test_stable_diffusion_pix2pix_negative_prompt(self):
142142
image_slice = image[0, -3:, -3:, -1]
143143

144144
assert image.shape == (1, 32, 32, 3)
145-
expected_slice = np.array([0.7323, 0.3688, 0.4611, 0.6255, 0.5746, 0.5017, 0.433, 0.5553, 0.4827])
145+
expected_slice = np.array([0.7511, 0.3642, 0.4553, 0.6236, 0.5797, 0.5013, 0.4343, 0.5611, 0.4831])
146146

147147
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
148148

@@ -165,7 +165,7 @@ def test_stable_diffusion_pix2pix_multiple_init_images(self):
165165
image_slice = image[-1, -3:, -3:, -1]
166166

167167
assert image.shape == (2, 32, 32, 3)
168-
expected_slice = np.array([0.606, 0.5712, 0.5099, 0.598, 0.5805, 0.7205, 0.6793, 0.554, 0.5607])
168+
expected_slice = np.array([0.5812, 0.5748, 0.5222, 0.5908, 0.5695, 0.7174, 0.6804, 0.5523, 0.5579])
169169

170170
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
171171

@@ -187,7 +187,7 @@ def test_stable_diffusion_pix2pix_euler(self):
187187
print(",".join([str(x) for x in slice]))
188188

189189
assert image.shape == (1, 32, 32, 3)
190-
expected_slice = np.array([0.726, 0.3902, 0.4868, 0.585, 0.5672, 0.511, 0.3906, 0.551, 0.4846])
190+
expected_slice = np.array([0.7417, 0.3842, 0.4732, 0.5776, 0.5891, 0.5139, 0.4052, 0.5673, 0.4986])
191191

192192
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-3
193193

tests/pipelines/stable_diffusion/test_stable_diffusion_model_editing.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,7 @@ def test_stable_diffusion_model_editing_default_case(self):
118118
image_slice = image[0, -3:, -3:, -1]
119119
assert image.shape == (1, 64, 64, 3)
120120

121-
expected_slice = np.array(
122-
[0.5217179, 0.50658035, 0.5003239, 0.41109088, 0.3595158, 0.46607107, 0.5323504, 0.5335255, 0.49187922]
123-
)
121+
expected_slice = np.array([0.4755, 0.5132, 0.4976, 0.3904, 0.3554, 0.4765, 0.5139, 0.5158, 0.4889])
124122

125123
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
126124

@@ -139,9 +137,7 @@ def test_stable_diffusion_model_editing_negative_prompt(self):
139137

140138
assert image.shape == (1, 64, 64, 3)
141139

142-
expected_slice = np.array(
143-
[0.546259, 0.5108156, 0.50897664, 0.41931948, 0.3748669, 0.4669299, 0.5427151, 0.54561913, 0.49353]
144-
)
140+
expected_slice = np.array([0.4992, 0.5101, 0.5004, 0.3949, 0.3604, 0.4735, 0.5216, 0.5204, 0.4913])
145141

146142
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
147143

@@ -161,9 +157,7 @@ def test_stable_diffusion_model_editing_euler(self):
161157

162158
assert image.shape == (1, 64, 64, 3)
163159

164-
expected_slice = np.array(
165-
[0.47106352, 0.53579676, 0.45798016, 0.514294, 0.56856745, 0.4788605, 0.54380214, 0.5046455, 0.50404465]
166-
)
160+
expected_slice = np.array([0.4747, 0.5372, 0.4779, 0.4982, 0.5543, 0.4816, 0.5238, 0.4904, 0.5027])
167161

168162
assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2
169163

0 commit comments

Comments
 (0)