Conditional Generator

Generate a feasible design from an array of latent weights
my_brush = circular_brush(7)
my_brush = notched_square_brush(5, 1)
show_mask(my_brush)
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)

Latent Design

It’s not very well explained in the paper what the latent design actually is. In this case we’ll just assume it’s an array of the same shape as the design, but with continuous values between 0 and 1.


source

new_latent_design

 new_latent_design (shape, bias=0, r=None, r_scale=1)
seed=42
m,n = 30, 30
latent = new_latent_design((m,n), r=seed)
print(latent[:3, :3])
plt.imshow(latent, vmin=-3, vmax=3, cmap="Greys")
plt.colorbar()
plt.show()
[[ 0.49671414 -0.1382643   0.64768857]
 [-0.6017066   1.8522782  -0.01349723]
 [-0.47917423 -0.18565898 -1.1063349 ]]

#with open(f"latent{seed}_{m}x{n}.bin", "wb") as file:
#    file.write(latent.tobytes())

Transform

The transform removes some of the noise from the latent design.


source

transform

 transform (latent, brush, beta=5.0)
latent_t = transform(latent, my_brush)
print(latent_t[:3, :3])
plt.imshow(latent_t, cmap="Greys", vmin=-1, vmax=1)
plt.colorbar()
plt.show()
[[ 0.3590585   0.21954855  0.19020812]
 [ 0.35060647  0.0249535   0.25184518]
 [ 0.01658658 -0.10942358 -0.0914182 ]]

Conditional Generator


source

conditional_algirithm_step

 conditional_algirithm_step (latent_t, design, brush, verbose=False)

source

conditional_generator

 conditional_generator (latent_t, brush, verbose=False)

source

generate_feasible_design

 generate_feasible_design (latent_t, brush, verbose=False, backend='auto')
Type Default Details
latent_t
brush
verbose bool False
backend str auto backend: ‘auto’, ‘rust’, ‘python’
my_design
CPU times: user 11.1 ms, sys: 4.54 ms, total: 15.6 ms
Wall time: 16.4 ms

latent_t = transform(latent, my_brush)
plt.imshow(latent_t, cmap="Greys", vmin=-1, vmax=1)
plt.colorbar()
plt.show()

In practice however, it’s probably more useful to generate a design mask straight away (+1.0 for solid, -1.0 for void):


source

generate_feasible_design_mask_

 generate_feasible_design_mask_ (latent_t, brush, backend='auto')
my_design_mask = generate_feasible_design_mask_(latent_t, my_brush)
my_design_mask.shape
(30, 30)
plt.imshow(my_design_mask, cmap="Greys", vmin=-1, vmax=1)
plt.colorbar()
plt.show()

Straight Through Estimator

We cannot just call jax.grad on our feasible design mask generator. All gradients will be zero as our mask generator is not differentiable…

def my_test_loss_function_(latent_t, brush):
    return generate_feasible_design_mask_(latent_t, brush, backend='python').mean()
g = jax.grad(my_test_loss_function_)
assert (g(latent_t, my_brush) == 0).all()

Moreover, if we would have chosen the Rust-based backend, the above cell would have errored out…

In stead, we use a straight-through estimator (a.k.a. identity function) for our feasible design:


source

generate_feasible_design_mask

 generate_feasible_design_mask (latent_t, brush)

source

generate_feasible_design_mask_jvp

 generate_feasible_design_mask_jvp (primals, tangents)
def my_test_loss_function(latent_t, brush):
    return generate_feasible_design_mask(latent_t, brush).mean()
g = jax.grad(my_test_loss_function)
assert (g(latent_t, my_brush) != 0).any()