|
| 1 | +from .diffusion import LearnedVarianceGaussianDiffusion |
| 2 | + |
| 3 | +### Start OpenAI Code |
| 4 | +def space_timesteps(num_timesteps, section_counts): |
| 5 | + """ |
| 6 | + Create a list of timesteps to use from an original diffusion process, |
| 7 | + given the number of timesteps we want to take from equally-sized portions |
| 8 | + of the original process. |
| 9 | + For example, if there's 300 timesteps and the section counts are [10,15,20] |
| 10 | + then the first 100 timesteps are strided to be 10 timesteps, the second 100 |
| 11 | + are strided to be 15 timesteps, and the final 100 are strided to be 20. |
| 12 | + If the stride is a string starting with "ddim", then the fixed striding |
| 13 | + from the DDIM paper is used, and only one section is allowed. |
| 14 | + :param num_timesteps: the number of diffusion steps in the original |
| 15 | + process to divide up. |
| 16 | + :param section_counts: either a list of numbers, or a string containing |
| 17 | + comma-separated numbers, indicating the step count |
| 18 | + per section. As a special case, use "ddimN" where N |
| 19 | + is a number of steps to use the striding from the |
| 20 | + DDIM paper. |
| 21 | + :return: a set of diffusion steps from the original process to use. |
| 22 | + """ |
| 23 | + if isinstance(section_counts, str): |
| 24 | + if section_counts.startswith("ddim"): |
| 25 | + desired_count = int(section_counts[len("ddim") :]) |
| 26 | + for i in range(1, num_timesteps): |
| 27 | + if len(range(0, num_timesteps, i)) == desired_count: |
| 28 | + return set(range(0, num_timesteps, i)) |
| 29 | + raise ValueError( |
| 30 | + f"cannot create exactly {num_timesteps} steps with an integer stride" |
| 31 | + ) |
| 32 | + section_counts = [int(x) for x in section_counts.split(",")] |
| 33 | + size_per = num_timesteps // len(section_counts) |
| 34 | + extra = num_timesteps % len(section_counts) |
| 35 | + start_idx = 0 |
| 36 | + all_steps = [] |
| 37 | + for i, section_count in enumerate(section_counts): |
| 38 | + size = size_per + (1 if i < extra else 0) |
| 39 | + if size < section_count: |
| 40 | + raise ValueError( |
| 41 | + f"cannot divide section of {size} steps into {section_count}" |
| 42 | + ) |
| 43 | + if section_count <= 1: |
| 44 | + frac_stride = 1 |
| 45 | + else: |
| 46 | + frac_stride = (size - 1) / (section_count - 1) |
| 47 | + cur_idx = 0.0 |
| 48 | + taken_steps = [] |
| 49 | + for _ in range(section_count): |
| 50 | + taken_steps.append(start_idx + round(cur_idx)) |
| 51 | + cur_idx += frac_stride |
| 52 | + all_steps += taken_steps |
| 53 | + start_idx += size |
| 54 | + return set(all_steps) |
| 55 | + |
| 56 | + |
| 57 | +### End OpenAI Code |
| 58 | + |
| 59 | + |
| 60 | +def create_map_and_betas(betas, use_timesteps): |
| 61 | + use_timesteps = set(use_timesteps) |
| 62 | + |
| 63 | + # Doesn't matter what diffusion we use since the constructor |
| 64 | + # is defined in the base class |
| 65 | + base_diffusion = LearnedVarianceGaussianDiffusion(betas) |
| 66 | + as_t_m_1 = 1 |
| 67 | + |
| 68 | + map_generation_step_to_timestep = [] |
| 69 | + |
| 70 | + new_betas = [] |
| 71 | + for i, as_t in enumerate(base_diffusion.alphas_cumprod): |
| 72 | + if i in use_timesteps: |
| 73 | + new_betas.append(1 - (as_t / as_t_m_1)) |
| 74 | + as_t_m_1 = as_t |
| 75 | + map_generation_step_to_timestep.append(i) |
| 76 | + |
| 77 | + assert len(new_betas) == len(map_generation_step_to_timestep) |
| 78 | + return map_generation_step_to_timestep, new_betas |
0 commit comments