def _state_dict(self) -> Dict[str, Any]: state_dict = dict() # need to store model arch because of randomness of random layers state_dict['model_arch'] = self.model state_dict['model'] = self.model.state_dict() state_dict['optimizer'] = self.optimizer.state_dict() state_dict['scheduler'] = self.scheduler.state_dict() if getattr(self.model, 'sample_arch', None) is not None: state_dict['sample_arch'] = self.model.sample_arch try: state_dict['q_layer_op_list'] = build_module_op_list( self.model.q_layer) state_dict['encoder_func_list'] = self.model.encoder.func_list except AttributeError: logger.warning(f"No q_layer_op_list or encoder_func_list found, " f"will not save them") if self.solution is not None: state_dict['solution'] = self.solution state_dict['score'] = self.score try: state_dict['v_c_reg_mapping'] = self.model.measure.v_c_reg_mapping except AttributeError: logger.warning(f"No v_c_reg_mapping found, will not save it.") return state_dict
def _trigger(self): if self.scalar not in self.trainer.summary: logger.warning( f'`{self.scalar}` has not been added to `trainer.summary`.') return step, value = self.trainer.summary[self.scalar][-1] if self.step is not None and step <= self.step: logger.warning( f'`{self.scalar}` has not been updated since last trigger.') return self.step = step if (self.best is None or (self.extreme == 'min' and value < self.best[1]) or (self.extreme == 'max' and value > self.best[1])): self.best = (step, value) save_path = os.path.join(self.save_dir, self.name + '.pt') try: io.save(save_path, self.trainer.state_dict()) except OSError: logger.exception( f'Error occurred when saving checkpoint "{save_path}".') else: logger.info(f'Checkpoint saved: "{save_path}" ({value:.5g}).') if self.best is not None: self.trainer.summary.add_scalar(self.scalar + '/' + self.extreme, self.best[1])
def init( backend: str = 'nccl', timeout: timedelta = default_pg_timeout, ) -> None: from mpi4py import MPI world_comm = MPI.COMM_WORLD local_comm = MPI.COMM_WORLD.Split_type(MPI.COMM_TYPE_SHARED) global _world_size, _world_rank, _local_size, _local_rank _world_size, _world_rank = world_comm.Get_size(), world_comm.Get_rank() _local_size, _local_rank = local_comm.Get_size(), local_comm.Get_rank() if 'MASTER_HOST' in os.environ: master_host = 'tcp://' + os.environ['MASTER_HOST'] else: master_host = f'tcp://localhost:{get_free_tcp_port()}' logger.warning( 'Distributed environment not detected, fall back to default') torch.distributed.init_process_group( backend=backend, init_method=master_host, timeout=timeout, world_size=_world_size, rank=_world_rank, )
def __init__(self, has_params: bool = False, trainable: bool = False, init_params=None, n_wires=None, wires=None): super().__init__() self.params = None # number of wires of the operator # n_wires is used in gates that can be applied to arbitrary number # of qubits such as MultiRZ self.n_wires = n_wires # wires that the operator applies to self.wires = wires self._name = self.__class__.__name__ # for static mode self.static_matrix = None self.inverse = False try: assert not (trainable and not has_params) except AssertionError: has_params = True logger.warning(f"Module must have parameters to be trainable; " f"Switched 'has_params' to True.") self.has_params = has_params self.trainable = trainable if self.has_params: self.params = self.build_params(trainable=self.trainable) self.reset_params(init_params)
def build_module_from_op_list(op_list: List[Dict], remove_ops=False, thres=None) -> tq.QuantumModule: logger.info(f"Building module from op_list...") thres = 1e-5 if thres is None else thres n_removed_ops = 0 ops = [] for info in op_list: params = info['params'] if remove_ops: if params is not None: params = np.array(params) if isinstance(params, Iterable) \ else np.array([params]) params = params % (2 * np.pi) params[params > np.pi] -= 2 * np.pi if all(abs(params) < thres): n_removed_ops += 1 continue op = tq.op_name_dict[info['name']]( has_params=info['has_params'], trainable=info['trainable'], wires=info['wires'], n_wires=info['n_wires'], init_params=info['params'], ) ops.append(op) if n_removed_ops > 0: logger.warning(f"Remove in total {n_removed_ops} pruned operations.") else: logger.info(f"Do not remove any operations.") return tq.QuantumModuleFromOps(ops)
def get_n_ops_per_chunk(self): """separate the space to several subspace""" n_chunks = self.strategy['n_chunks'] if self.strategy['chunk_mode'] == 'same_interval': logger.warning(f"same_interval chunking may cause extra long " f"time to sample a sub network because of the " f"Central Limit Theorem of n_ops in a subnet") self.n_ops_per_chunk = list(np.linspace(self.n_ops_smallest, self.n_ops_largest, n_chunks + 1).astype(int)) elif self.strategy['chunk_mode'] == 'same_n_samples': logger.info("estimating the chunks...") n_ops_all = [] n_chunk_est_samples = self.strategy['n_chunk_est_samples'] for k in range(n_chunk_est_samples): sample_arch = self.get_random_sample_arch() n_ops_all.append(self.get_sample_stats(sample_arch)) n_ops_all.sort() idx_all = np.linspace(0, n_chunk_est_samples - 1, n_chunks + 1).astype(int) self.n_ops_per_chunk = [n_ops_all[idx] for idx in idx_all] self.n_ops_per_chunk[0] = self.n_ops_smallest self.n_ops_per_chunk[-1] = self.n_ops_largest else: raise NotImplementedError( f"chunk mode {self.strategy['chunk_mode']} not supported.")
def build_flat_module_list(self, module_list=None): if module_list is None: module_list = self.module_list for module in module_list: if len(module.graph.module_list) == 0 and not \ isinstance(module, tq.Operator): logger.warning(f"Module with no operations exists!") if len(module.graph.module_list) == 0 and isinstance( module, tq.Operator): # leaf node self.flat_module_list.append(module) else: self.build_flat_module_list(module.graph.module_list)
def __init__(self, population_size, parent_size, mutation_size, mutation_prob, crossover_size, n_wires, n_available_wires, arch_space, gene_mask=None, enumerate_layout=False, random_search=False ): self.population_size = population_size self.parent_size = parent_size self.mutation_size = mutation_size self.mutation_prob = mutation_prob self.crossover_size = crossover_size assert self.population_size == self.parent_size + self.mutation_size \ + self.crossover_size self.n_wires = n_wires self.n_available_wires = n_available_wires self.arch_space = arch_space self.converter = Converter( self.n_wires, self.n_available_wires, self.arch_space ) self.gene_choice = self.converter.get_gene_choice() self.gene_len = len(self.gene_choice) self.best_solution = None self.best_score = None self.random_search = random_search # to constraint the design space in a fine-grained manner self.gene_mask = gene_mask if gene_mask is not None and \ all(np.array(gene_mask[:n_wires]) == -1) and \ all(np.array(gene_mask[n_wires:]) > -1) and enumerate_layout: # enumerate all possible layouts and only need run 1 iteration logger.warning(f"Shift to exhaustive search for best layout, " f"surpass all evolution configs!") self.population = self.enumerate_layout() else: # initialize with random samples self.population = self.random_sample(self.population_size)
def _state_dict(self) -> Dict[str, Any]: state_dict = dict() # need to store model arch because of randomness of random layers state_dict['model_arch'] = self.model state_dict['model'] = self.model.state_dict() state_dict['optimizer'] = self.optimizer.state_dict() state_dict['scheduler'] = self.scheduler.state_dict() if getattr(self.model, 'sample_arch', None) is not None: state_dict['sample_arch'] = self.model.sample_arch try: state_dict['v_c_reg_mapping'] = self.model.measure.v_c_reg_mapping except AttributeError: logger.warning(f"No v_c_reg_mapping found, will not save it.") return state_dict
def _before_train(self) -> None: checkpoints = glob.glob(os.path.join(self.load_dir, 'step-*.pt')) if not checkpoints: logger.warning(f'No checkpoints found: "{self.load_dir}".') return load_path = max(checkpoints, key=os.path.getmtime) try: state_dict = io.load(load_path, map_location='cpu') self.trainer.load_state_dict(state_dict) except OSError: logger.exception( f'Error occurred when loading checkpoint "{load_path}".') else: logger.info(f'Checkpoint loaded: "{load_path}".')
def _state_dict(self) -> Dict[str, Any]: state_dict = dict() # need to store model arch because of randomness of random layers state_dict['model_arch'] = self.model state_dict['model'] = self.model.state_dict() state_dict['optimizer'] = self.optimizer.state_dict() state_dict['scheduler'] = self.scheduler.state_dict() if getattr(self.model, 'sample_arch', None) is not None: state_dict['sample_arch'] = self.model.sample_arch if self.solution is not None: state_dict['solution'] = self.solution state_dict['score'] = self.score if getattr(self.model, 'encoder', None) is not None: if getattr(self.model.encoder, 'func_list', None) is not None: state_dict['encoder_func_list'] = self.model.encoder.func_list if getattr(self.model, 'q_layer', None) is not None: state_dict['q_layer_op_list'] = build_module_op_list( self.model.q_layer) if getattr(self.model, 'measure', None) is not None: if getattr(self.model.measure, 'v_c_reg_mapping', None) is not None: state_dict['v_c_reg_mapping'] = \ self.model.measure.v_c_reg_mapping if getattr(self.model, 'nodes', None) is not None: state_dict['encoder_func_list'] = [ node.encoder.func_list for node in self.model.nodes ] if configs.model.transpile_before_run: # only save op_list if transpile before run state_dict['q_layer_op_list'] = [ build_module_op_list(node.q_layer) for node in self.model.nodes ] state_dict['v_c_reg_mapping'] = [ node.measure.v_c_reg_mapping for node in self.model.nodes ] for attr in [ 'v_c_reg_mapping', 'encoder_func_list', 'q_layer_op_list' ]: if state_dict.get(attr, None) is None: logger.warning(f"No {attr} found, will not save it.") return state_dict
def __init__(self, *, devices: Optional[List[int]] = None) -> None: if devices is not None: self.devices = devices else: env = os.environ.get('CUDA_VISIBLE_DEVICES') if env: self.devices = list(map(int, env.split(','))) elif env is None: self.devices = list(range(torch.cuda.device_count())) if len(self.devices) > 1: logger.warning( 'Neither `devices` nor `CUDA_VISIBLE_DEVICES` is set! ' 'All {} visible GPUs will be monitored.'.format( len(self.devices))) else: raise RuntimeError('No GPU device is specified!')
def __init__( self, wires, n_ops=None, n_params=None, op_ratios=None, op_types=(tq.RX, tq.RY, tq.RZ, tq.CNOT), seed=None, qiskit_compatible=False, ): super().__init__() self.n_ops = n_ops self.n_params = n_params assert n_params is not None or n_ops is not None self.wires = wires if isinstance(wires, Iterable) else [wires] self.n_wires = len(wires) op_types = op_types if isinstance(op_types, Iterable) else [op_types] if op_ratios is None: op_ratios = [1] * len(op_types) else: op_ratios = op_ratios if isinstance(op_ratios, Iterable) else [op_ratios] op_types_valid = [] op_ratios_valid = [] if qiskit_compatible: for op_type, op_ratio in zip(op_types, op_ratios): if op_type().name.lower() in QISKIT_INCOMPATIBLE_FUNC_NAMES: logger.warning(f"Remove {op_type} from op_types to make " f"the layer qiskit-compatible.") else: op_types_valid.append(op_type) op_ratios_valid.append(op_ratio) else: op_types_valid = op_types op_ratios_valid = op_ratios self.op_types = op_types_valid self.op_ratios = np.array(op_ratios_valid) / sum(op_ratios_valid) self.seed = seed self.op_list = tq.QuantumModuleList() if seed is not None: np.random.seed(seed) self.build_random_layer()
def run_job_worker(data): while True: try: job = execute(**(data[0])) qiskit_verbose = data[1] if qiskit_verbose: job_monitor(job, interval=1) result = job.result() counts = result.get_counts() break except Exception as e: if "Job was cancelled" in str(e): logger.warning(f"Job is cancelled manually.") return None else: logger.warning(f"Job failed because {e}, rerun now.") return counts
def cos_adjust_noise(current_epoch, n_epochs, prob_schedule, prob_schedule_separator, orig_noise_total_prob): if prob_schedule is None: noise_total_prob = orig_noise_total_prob elif prob_schedule == 'increase': # scale the cos if current_epoch <= prob_schedule_separator: noise_total_prob = orig_noise_total_prob * ( -np.cos(current_epoch / prob_schedule_separator * np.pi) / 2 + 0.5) else: noise_total_prob = orig_noise_total_prob elif prob_schedule == 'decrease': if current_epoch >= prob_schedule_separator: noise_total_prob = orig_noise_total_prob * (np.cos( (current_epoch - prob_schedule_separator) / (n_epochs - prob_schedule_separator) * np.pi) / 2 + 0.5) else: noise_total_prob = orig_noise_total_prob elif prob_schedule == 'increase_decrease': # if current_epoch <= self.prob_schedule_separator: # self.noise_total_prob = self.orig_noise_total_prob * \ # 1 / (1 + np.exp(-(current_epoch - ( # self.prob_schedule_separator / 2)) / 10)) # else: # self.noise_total_prob = self.orig_noise_total_prob * \ # 1 / (1 + np.exp((current_epoch - ( # self.n_epochs + self.prob_schedule_separator) / 2) / # 10)) if current_epoch <= prob_schedule_separator: noise_total_prob = orig_noise_total_prob * ( -np.cos(current_epoch / prob_schedule_separator * np.pi) / 2 + 0.5) else: noise_total_prob = orig_noise_total_prob * (np.cos( (current_epoch - prob_schedule_separator) / (n_epochs - prob_schedule_separator) * np.pi) / 2 + 0.5) else: logger.warning(f"Not implemented schedule{prob_schedule}, " f"will not change prob!") noise_total_prob = orig_noise_total_prob return noise_total_prob
def get_provider(backend_name, hub=None): # mass-inst-tech-1 or MIT-1 if backend_name in ['ibmq_casablanca', 'ibmq_rome', 'ibmq_bogota']: if hub == 'mass' or hub is None: provider = IBMQ.get_provider(hub='ibm-q-research', group='mass-inst-tech-1', project='main') elif hub == 'mit': provider = IBMQ.get_provider(hub='ibm-q-research', group='MIT-1', project='main') else: raise ValueError(f"not supported backend {backend_name} in hub " f"{hub}") elif backend_name in [ 'ibmq_paris', 'ibmq_toronto', 'ibmq_manhattan', 'ibmq_guadalupe' ]: provider = IBMQ.get_provider(hub='ibm-q-ornl', group='anl', project='csc428') else: if hub == 'mass' or hub is None: try: provider = IBMQ.get_provider(hub='ibm-q-research', group='mass-inst-tech-1', project='main') except QiskitError: logger.warning(f"Cannot use MIT backend, roll back to open") provider = IBMQ.get_provider(hub='ibm-q') elif hub == 'mit': provider = IBMQ.get_provider(hub='ibm-q-research', group='MIT-1', project='main') else: provider = IBMQ.get_provider(hub='ibm-q') return provider
def _state_dict(self) -> Dict[str, Any]: # remove hook otherwise the 'model' cannot be pickled self.remove_act_quant_hook() state_dict = dict() # need to store model arch because of randomness of random layers state_dict['model_arch'] = self.model state_dict['model'] = self.model.state_dict() state_dict['optimizer'] = self.optimizer.state_dict() state_dict['scheduler'] = self.scheduler.state_dict() if getattr(self.model, 'sample_arch', None) is not None: state_dict['sample_arch'] = self.model.sample_arch if self.solution is not None: state_dict['solution'] = self.solution state_dict['score'] = self.score if getattr(self.model, 'encoder', None) is not None: if getattr(self.model.encoder, 'func_list', None) is not None: state_dict['encoder_func_list'] = self.model.encoder.func_list if getattr(self.model, 'q_layer', None) is not None: state_dict['q_layer_op_list'] = build_module_op_list( self.model.q_layer) if getattr(self.model, 'measure', None) is not None: if getattr(self.model.measure, 'v_c_reg_mapping', None) is not None: state_dict['v_c_reg_mapping'] = \ self.model.measure.v_c_reg_mapping if getattr(self.model, 'noise_model_tq', None) is not None: state_dict['noise_model_tq'] = self.model.noise_model_tq if configs.trainer.act_quant: state_dict['act_quant'] = { 'act_quant_bit': self.quantizers[0].precision, 'act_quant_level': self.quantizers[0].level, 'act_quant_ratio': self.quantizers[0].quant_ratio, 'act_quant_lower_bound': self.quantizers[0].lower_bound, 'act_quant_upper_bound': self.quantizers[0].upper_bound, } if getattr(self.model, 'nodes', None) is not None: state_dict['encoder_func_list'] = [ node.encoder.func_list for node in self.model.nodes ] if configs.model.transpile_before_run: # only save op_list if transpile before run state_dict['q_layer_op_list'] = [ build_module_op_list(node.q_layer) for node in self.model.nodes ] state_dict['v_c_reg_mapping'] = [ node.measure.v_c_reg_mapping for node in self.model.nodes ] # one node has one own noise model state_dict['noise_model_tq'] = [ node.noise_model_tq for node in self.model.nodes ] for attr in [ 'v_c_reg_mapping', 'encoder_func_list', 'q_layer_op_list', 'noise_model_tq' ]: if state_dict.get(attr, None) is None: logger.warning(f"No {attr} found, will not save it.") return state_dict
filters=lambda x: x.configuration().n_qubits >= args.n and not x. configuration().simulator and x.status().operational) candidates = [] now = datetime.now() for back in backends: backend_status = back.status() if not backend_status.operational or \ backend_status.status_msg != 'active': continue if isinstance(back, IBMQBackend): end_time = now + timedelta(minutes=args.m) try: if back.reservations(now, end_time): logger.warning( f"{back} jobs: {back.status().pending_jobs}, " f"has reservation in {args.m} minutes.") continue else: logger.info(f"{back} jobs: {back.status().pending_jobs}, " f"has no reservation in {args.m} minutes.") except Exception as err: # pylint: disable=broad-except logger.warning( "Unable to find backend reservation " "information. " "It will not be taken into consideration. %s", str(err)) candidates.append(back) if not candidates: raise ValueError('No backend matches the criteria.') least_busy_dev = min(candidates, key=lambda b: b.status().pending_jobs)
def tq2qiskit(q_device: tq.QuantumDevice, m: tq.QuantumModule, x=None, draw=False, remove_ops=False, remove_ops_thres=1e-4): # build the module list without changing the statevector of QuantumDevice original_wires_per_block = m.wires_per_block original_static_mode = m.static_mode m.static_off() m.static_on(wires_per_block=q_device.n_wires) m.is_graph_top = False # forward to register all modules and parameters if x is None: m.forward(q_device) else: m.forward(q_device, x) m.is_graph_top = True m.graph.build_flat_module_list() module_list = m.graph.flat_module_list m.static_off() if original_static_mode: m.static_on(wires_per_block=original_wires_per_block) circ = QuantumCircuit(q_device.n_wires, q_device.n_wires) for module in module_list: try: # no params in module or batch size == 1, because we will # generate only one qiskit QuantumCircuit assert (module.params is None or module.params.shape[0] == 1) except AssertionError: logger.exception(f"Cannot convert batch model tq module") n_removed_ops = 0 for module in module_list: if remove_ops: if module.name in [ 'RX', 'RY', 'RZ', 'RXX', 'RYY', 'RZZ', 'RZX', 'PhaseShift', 'CRX', 'CRY', 'CRZ', 'U1', 'CU1' ]: param = module.params[0][0].item() param = param % (2 * np.pi) param = param - 2 * np.pi if param > np.pi else param if abs(param) < remove_ops_thres: n_removed_ops += 1 continue elif module.name in ['U2', 'U3', 'CU3']: param = module.params[0].data.cpu().numpy() param = param % (2 * np.pi) param[param > np.pi] -= 2 * np.pi if all(abs(param) < remove_ops_thres): n_removed_ops += 1 continue if module.name == 'Hadamard': circ.h(*module.wires) elif module.name == 'SHadamard': circ.ry(np.pi / 4, *module.wires) elif module.name == 'PauliX': circ.x(*module.wires) elif module.name == 'PauliY': circ.y(*module.wires) elif module.name == 'PauliZ': circ.z(*module.wires) elif module.name == 'S': circ.s(*module.wires) elif module.name == 'T': circ.t(*module.wires) elif module.name == 'SX': circ.sx(*module.wires) elif module.name == 'CNOT': circ.cnot(*module.wires) elif module.name == 'CZ': circ.cz(*module.wires) elif module.name == 'CY': circ.cy(*module.wires) elif module.name == 'RX': circ.rx(module.params[0][0].item(), *module.wires) elif module.name == 'RY': circ.ry(module.params[0][0].item(), *module.wires) elif module.name == 'RZ': circ.rz(module.params[0][0].item(), *module.wires) elif module.name == 'RXX': circ.rxx(module.params[0][0].item(), *module.wires) elif module.name == 'RYY': circ.ryy(module.params[0][0].item(), *module.wires) elif module.name == 'RZZ': circ.rzz(module.params[0][0].item(), *module.wires) elif module.name == 'RZX': circ.rzx(module.params[0][0].item(), *module.wires) elif module.name == 'SWAP': circ.swap(*module.wires) elif module.name == 'SSWAP': # square root of swap from torchquantum.plugins.qiskit_unitary_gate import UnitaryGate mat = module.matrix.data.cpu().numpy() mat = switch_little_big_endian_matrix(mat) circ.append(UnitaryGate(mat), module.wires, []) elif module.name == 'CSWAP': circ.cswap(*module.wires) elif module.name == 'Toffoli': circ.ccx(*module.wires) elif module.name == 'PhaseShift': circ.p(module.params[0][0].item(), *module.wires) elif module.name == 'CRX': circ.crx(module.params[0][0].item(), *module.wires) elif module.name == 'CRY': circ.cry(module.params[0][0].item(), *module.wires) elif module.name == 'CRZ': circ.crz(module.params[0][0].item(), *module.wires) elif module.name == 'U1': circ.u1(module.params[0][0].item(), *module.wires) elif module.name == 'CU1': circ.cu1(module.params[0][0].item(), *module.wires) elif module.name == 'U2': circ.u2(*list(module.params[0].data.cpu().numpy()), *module.wires) elif module.name == 'U3': circ.u3(*list(module.params[0].data.cpu().numpy()), *module.wires) elif module.name == 'CU3': circ.cu3(*list(module.params[0].data.cpu().numpy()), *module.wires) elif module.name == 'QubitUnitary' or \ module.name == 'QubitUnitaryFast' or \ module.name == 'TrainableUnitary' or \ module.name == 'TrainableUnitaryStrict': from torchquantum.plugins.qiskit_unitary_gate import UnitaryGate mat = module.params[0].data.cpu().numpy() mat = switch_little_big_endian_matrix(mat) circ.append(UnitaryGate(mat), module.wires, []) elif module.name == 'MultiCNOT': circ.mcx(module.wires[:-1], module.wires[-1]) elif module.name == 'MultiXCNOT': controls = module.wires[:-1] target = module.wires[-1] num_ctrl_qubits = len(controls) gate = qiskit_gate.MCXGrayCode(num_ctrl_qubits, ctrl_state='0' * num_ctrl_qubits) circ.append(gate, controls + [target], []) else: logger.exception(f"{module.name} cannot be converted to Qiskit.") raise NotImplementedError(module.name) if module.inverse: data = list(circ.data[-1]) del circ.data[-1] circ.data.append(tuple([data[0].inverse()] + data[1:])) if draw: import matplotlib.pyplot as plt circ.draw() plt.show() if n_removed_ops > 0: logger.warning(f"Remove {n_removed_ops} operations with small " f"parameter magnitude.") return circ
def main() -> None: torch.backends.cudnn.benchmark = True parser = argparse.ArgumentParser() parser.add_argument('config', metavar='FILE', help='config file') parser.add_argument('--run-dir', metavar='DIR', help='run directory') parser.add_argument('--pdb', action='store_true', help='pdb') parser.add_argument('--verbose', action='store_true', help='verbose') parser.add_argument('--gpu', type=str, help='gpu ids', default=None) parser.add_argument('--print-configs', action='store_true', help='print ALL configs') parser.add_argument('--jobs', type=int, default=None, help='max parallel job on qiskit') parser.add_argument('--hub', type=str, default=None, help='IBMQ provider') args, opts = parser.parse_known_args() configs.load(os.path.join(args.run_dir, 'metainfo', 'configs.yaml')) configs.load(args.config, recursive=True) configs.update(opts) # for eval, always need load weights configs.ckpt.weight_from_scratch = False if configs.debug.pdb or args.pdb: pdb.set_trace() configs.verbose = args.verbose configs.qiskit.hub = args.hub if args.gpu is not None: os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu if args.jobs is not None: configs.qiskit.max_jobs = args.jobs if configs.run.device == 'gpu': device = torch.device('cuda') elif configs.run.device == 'cpu': device = torch.device('cpu') else: raise ValueError(configs.run.device) if args.print_configs: print_conf = configs else: print_conf = get_cared_configs(configs, 'eval') logger.info(f'Evaluation started: "{args.run_dir}".' + '\n' + f'{print_conf}') eval_config_dir = args.config.replace('/', '.').replace( 'examples.', '').replace('.yml', '').replace('configs.', '') configs.eval_config_dir = eval_config_dir configs.run_dir = args.run_dir # if configs.qiskit.use_qiskit: # IBMQ.load_account() # if configs.run.bsz == 'qiskit_max': # configs.run.bsz = IBMQ.get_provider(hub='ibm-q').get_backend( # configs.qiskit.backend_name).configuration().max_experiments dataset = builder.make_dataset() sampler = torch.utils.data.SequentialSampler( dataset[configs.dataset.split]) dataflow = torch.utils.data.DataLoader( dataset[configs.dataset.split], sampler=sampler, batch_size=configs.run.bsz, num_workers=configs.run.workers_per_gpu, pin_memory=True) state_dict = io.load(os.path.join(args.run_dir, configs.ckpt.name), map_location='cpu') model_load = state_dict['model_arch'] model = builder.make_model() for module_load, module in zip(model_load.modules(), model.modules()): if isinstance(module, tq.RandomLayer): # random layer, need to restore the architecture module.rebuild_random_layer_from_op_list( n_ops_in=module_load.n_ops, wires_in=module_load.wires, op_list_in=module_load.op_list, ) model.load_state_dict(state_dict['model'], strict=False) solution = None if 'solution' in state_dict.keys(): solution = state_dict['solution'] logger.info(f"Evaluate the solution {solution}") logger.info(f"Original score: {state_dict['score']}") model.set_sample_arch(solution['arch']) if 'v_c_reg_mapping' in state_dict.keys(): if getattr(model, 'q_layer', None) is not None: try: model.measure.set_v_c_reg_mapping( state_dict['v_c_reg_mapping']) except AttributeError: logger.warning(f"Cannot set v_c_reg_mapping.") elif getattr(model, 'nodes', None) is not None: for k, node in enumerate(model.nodes): node.measure.set_v_c_reg_mapping( state_dict['v_c_reg_mapping'][k]) if state_dict.get('q_layer_op_list', None) is not None and not \ configs.model.load_op_list: logger.warning(f"the model has op_list but is not loaded!!") if configs.model.load_op_list: assert state_dict['q_layer_op_list'] is not None logger.warning(f"Loading the op_list, will replace the q_layer in " f"the original model!") if getattr(model, 'q_layer', None) is not None: q_layer = build_module_from_op_list( op_list=state_dict['q_layer_op_list'], remove_ops=configs.prune.eval.remove_ops, thres=configs.prune.eval.remove_ops_thres) model.q_layer = q_layer elif getattr(model, 'nodes', None) is not None: for k, node in enumerate(model.nodes): q_layer = build_module_from_op_list( op_list=state_dict['q_layer_op_list'][k], remove_ops=configs.prune.eval.remove_ops, thres=configs.prune.eval.remove_ops_thres) node.q_layer = q_layer if state_dict.get('noise_model_tq', None) is not None: # the readout error is ALSO applied for eval and test so need load # noise_model_tq if getattr(model, 'q_layer', None) is not None: model.set_noise_model_tq(state_dict['noise_model_tq']) if getattr(configs, 'add_noise', False): model.noise_model_tq.mode = 'train' model.noise_model_tq.noise_total_prob = \ configs.noise_total_prob else: model.noise_model_tq.mode = 'test' elif getattr(model, 'nodes', None) is not None: for k, node in enumerate(model.nodes): node.set_noise_model_tq(state_dict['noise_model_tq'][k]) if getattr(configs, 'add_noise', False): node.noise_model_tq.mode = 'train' node.noise_model_tq.noise_total_prob = \ configs.noise_total_prob else: node.noise_model_tq.mode = 'test' if configs.model.transpile_before_run: # transpile the q_layer logger.warning(f"Transpile the q_layer to basis gate set before " f"evaluation, will replace the q_layer!") processor = builder.make_qiskit_processor() circ = tq2qiskit(model.q_device, model.q_layer) """ add measure because the transpile process may permute the wires, so we need to get the final q reg to c reg mapping """ circ.measure(list(range(model.q_device.n_wires)), list(range(model.q_device.n_wires))) if solution is not None: processor.set_layout(solution['layout']) logger.warning(f"Set layout {solution['layout']} for transpile!") logger.info("Transpiling circuit...") circ_transpiled = processor.transpile(circs=circ) q_layer = qiskit2tq(circ=circ_transpiled) model.measure.set_v_c_reg_mapping(get_v_c_reg_mapping(circ_transpiled)) model.q_layer = q_layer if configs.legalization.legalize: legalize_unitary(model) if configs.act_quant.add_in_eval: quantizers = [] assert getattr(model, 'nodes', None) is not None if getattr(configs.act_quant, 'act_quant_bit', None) is not None: # settings from config file has higher priority act_quant_bit = configs.act_quant.act_quant_bit act_quant_ratio = configs.act_quant.act_quant_ratio act_quant_level = configs.act_quant.act_quant_level act_quant_lower_bound = configs.act_quant.act_quant_lower_bound act_quant_upper_bound = configs.act_quant.act_quant_upper_bound logger.warning(f"Get act_quant setting from config file!") elif state_dict.get('act_quant', None) is not None: act_quant_bit = state_dict['act_quant']['act_quant_bit'] act_quant_ratio = state_dict['act_quant']['act_quant_ratio'] act_quant_level = state_dict['act_quant']['act_quant_level'] act_quant_lower_bound = state_dict['act_quant'][ 'act_quant_lower_bound'] act_quant_upper_bound = state_dict['act_quant'][ 'act_quant_upper_bound'] logger.warning(f"Get act_quant setting from ckpt file!") elif getattr(configs.trainer, 'act_quant_bit', None) is not None: # if the act_quant info is not stored in ckpt, use the info from # training config file act_quant_bit = configs.trainer.act_quant_bit act_quant_ratio = configs.trainer.act_quant_ratio act_quant_level = configs.trainer.act_quant_level act_quant_lower_bound = configs.trainer.act_quant_lower_bound act_quant_upper_bound = configs.trainer.act_quant_upper_bound logger.warning(f"Get act_quant setting from previous training " f"config file!") else: raise NotImplementedError('No act_quant info specified!') logger.warning(f"act_quant_bit={act_quant_bit}, " f"act_quant_ratio={act_quant_ratio}, " f"act_quant_level={act_quant_level}, " f"act_quant_lower_bound={act_quant_lower_bound}, " f"act_quant_upper_bound={act_quant_upper_bound}") for k, node in enumerate(model.nodes): if configs.trainer.act_quant_skip_last_node and k == len( model.nodes) - 1: continue quantizer = PACTActivationQuantizer( module=node, precision=act_quant_bit, level=act_quant_level, alpha=1.0, backprop_alpha=False, quant_ratio=act_quant_ratio, device=device, lower_bound=act_quant_lower_bound, upper_bound=act_quant_upper_bound, ) quantizers.append(quantizer) for quantizer in quantizers: quantizer.register_hook() if getattr(configs, 'pre_specified_mean', None) is not None and \ configs.pre_specified_std \ is not None: for k, node in enumerate(model.nodes): node.pre_specified_mean_std = { 'mean': configs.pre_specified_mean[k], 'std': configs.pre_specified_std[k], } model.to(device) model.eval() if configs.qiskit.use_qiskit: qiskit_processor = builder.make_qiskit_processor() if configs.qiskit.initial_layout is not None: layout = configs.qiskit.initial_layout logger.warning(f"Use layout {layout} from config file") elif 'solution' in state_dict.keys(): layout = state_dict['solution']['layout'] logger.warning(f"Use layout {layout} from checkpoint file") else: layout = None logger.warning(f"No specified layout") qiskit_processor.set_layout(layout) model.set_qiskit_processor(qiskit_processor) if getattr(configs.model.arch, 'sample_arch', None) is not None: sample_arch = configs.model.arch.sample_arch logger.warning(f"Setting sample arch {sample_arch} from config file!") if isinstance(sample_arch, str): # this is the name of arch sample_arch = get_named_sample_arch(model.arch_space, sample_arch) logger.warning(f"Decoded sample arch: {sample_arch}") model.set_sample_arch(sample_arch) if configs.get_n_params: n_params = model.count_sample_params() logger.info(f"Number of sampled params: {n_params}") exit(0) if configs.qiskit.est_success_rate: circ_parameterized, params = tq2qiskit_parameterized( model.q_device, model.encoder.func_list) circ_fixed = tq2qiskit(model.q_device, model.q_layer) circ = circ_parameterized + circ_fixed transpiled_circ = model.qiskit_processor.transpile(circ) success_rate = get_success_rate(model.qiskit_processor.properties, transpiled_circ) logger.info(f"Success rate: {success_rate}") logger.info(f"Size: {transpiled_circ.size()}") logger.info(f"Depth: {transpiled_circ.depth()}") logger.info(f"Width: {transpiled_circ.width()}") exit(0) total_params = sum(p.numel() for p in model.parameters()) logger.info(f'Model Size: {total_params}') if hasattr(model, 'sample_arch') and not configs.model.load_op_list: n_params = model.count_sample_params() logger.info(f"Number of sampled params: {n_params}") with torch.no_grad(): target_all = None output_all = None for feed_dict in tqdm.tqdm(dataflow): if configs.run.device == 'gpu': inputs = feed_dict[configs.dataset.input_name].cuda( non_blocking=True) targets = feed_dict[configs.dataset.target_name].cuda( non_blocking=True) else: inputs = feed_dict[configs.dataset.input_name] targets = feed_dict[configs.dataset.target_name] outputs = model(inputs, verbose=configs.verbose, use_qiskit=configs.qiskit.use_qiskit) if target_all is None: target_all = targets output_all = outputs else: target_all = torch.cat([target_all, targets], dim=0) output_all = torch.cat([output_all, outputs], dim=0) # if configs.verbose: # logger.info(f"Measured log_softmax: {outputs}") if not configs.dataset.name == 'vqe': log_acc(output_all, target_all) logger.info("Final:") if not configs.dataset.name == 'vqe': log_acc(output_all, target_all) else: logger.info(f"Eigenvalue: {output_all.detach().cpu().numpy()}")
def main() -> None: # dist.init() torch.backends.cudnn.benchmark = True # torch.cuda.set_device(dist.local_rank()) parser = argparse.ArgumentParser() parser.add_argument('config', metavar='FILE', help='config file') parser.add_argument('--ckpt-dir', metavar='DIR', help='run directory') parser.add_argument('--pdb', action='store_true', help='pdb') parser.add_argument('--gpu', type=str, help='gpu ids', default=None) parser.add_argument('--print-configs', action='store_true', help='print ALL configs') args, opts = parser.parse_known_args() configs.load(args.config, recursive=True) configs.update(opts) if configs.debug.pdb or args.pdb: pdb.set_trace() if args.gpu is not None: os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu if configs.debug.set_seed: torch.manual_seed(configs.debug.seed) np.random.seed(configs.debug.seed) if configs.run.device == 'gpu': device = torch.device('cuda') elif configs.run.device == 'cpu': device = torch.device('cpu') else: raise ValueError(configs.run.device) if isinstance(configs.optimizer.lr, str): configs.optimizer.lr = eval(configs.optimizer.lr) # set the run dir according to config file's name args.run_dir = 'runs/' + args.config.replace('/', '.').replace( 'examples.', '').replace('.yml', '').replace('configs.', '') set_run_dir(args.run_dir) logger.info(' '.join([sys.executable] + sys.argv)) if args.print_configs: print_conf = configs else: print_conf = get_cared_configs(configs, 'train') logger.info(f'Training started: "{args.run_dir}".' + '\n' + f'{print_conf}') dataset = builder.make_dataset() dataflow = dict() # for split in dataset: # sampler = torch.utils.data.distributed.DistributedSampler( # dataset[split], # num_replicas=dist.size(), # rank=dist.rank(), # shuffle=(split == 'train')) # dataflow[split] = torch.utils.data.DataLoader( # dataset[split], # batch_size=configs.run.bsz // dist.size(), # sampler=sampler, # num_workers=configs.run.workers_per_gpu, # pin_memory=True) for split in dataset: if split == 'train': sampler = torch.utils.data.RandomSampler(dataset[split]) batch_size = configs.run.bsz else: # for valid and test, use SequentialSampler to make the train.py # and eval.py results consistent sampler = torch.utils.data.SequentialSampler(dataset[split]) batch_size = getattr(configs.run, 'eval_bsz', configs.run.bsz) dataflow[split] = torch.utils.data.DataLoader( dataset[split], batch_size=batch_size, sampler=sampler, num_workers=configs.run.workers_per_gpu, pin_memory=True) model = builder.make_model() state_dict = {} solution = None score = None if configs.ckpt.load_ckpt: logger.warning('Loading checkpoint!') state_dict = io.load(os.path.join(args.ckpt_dir, configs.ckpt.name), map_location='cpu') if getattr(state_dict, 'model_arch', None) is not None: model_load = state_dict['model_arch'] for module_load, module in zip(model_load.modules(), model.modules()): if isinstance(module, tq.RandomLayer): # random layer, need to restore the architecture module.rebuild_random_layer_from_op_list( n_ops_in=module_load.n_ops, wires_in=module_load.wires, op_list_in=module_load.op_list, ) if not configs.ckpt.weight_from_scratch: model.load_state_dict(state_dict['model'], strict=False) else: logger.warning(f"DO NOT load weight, train weights from scratch!") if 'solution' in state_dict.keys(): solution = state_dict['solution'] logger.info(f"Loading the solution {solution}") logger.info(f"Original score: {state_dict['score']}") model.set_sample_arch(solution['arch']) score = state_dict['score'] if 'v_c_reg_mapping' in state_dict.keys(): try: model.measure.set_v_c_reg_mapping( state_dict['v_c_reg_mapping']) except AttributeError: logger.warning(f"Cannot set v_c_reg_mapping.") if configs.model.load_op_list: assert state_dict['q_layer_op_list'] is not None logger.warning(f"Loading the op_list, will replace the q_layer in " f"the original model!") q_layer = build_module_from_op_list(state_dict['q_layer_op_list']) model.q_layer = q_layer if configs.model.transpile_before_run: # transpile the q_layer logger.warning(f"Transpile the q_layer to basis gate set before " f"training, will replace the q_layer!") processor = builder.make_qiskit_processor() if getattr(model, 'q_layer', None) is not None: circ = tq2qiskit(model.q_device, model.q_layer) """ add measure because the transpile process may permute the wires, so we need to get the final q reg to c reg mapping """ circ.measure(list(range(model.q_device.n_wires)), list(range(model.q_device.n_wires))) logger.info("Transpiling circuit...") if solution is not None: processor.set_layout(solution['layout']) logger.warning( f"Set layout {solution['layout']} for transpile!") circ_transpiled = processor.transpile(circs=circ) q_layer = qiskit2tq(circ=circ_transpiled) model.measure.set_v_c_reg_mapping( get_v_c_reg_mapping(circ_transpiled)) model.q_layer = q_layer if configs.trainer.add_noise: # noise-aware training noise_model_tq = builder.make_noise_model_tq() noise_model_tq.is_add_noise = True noise_model_tq.v_c_reg_mapping = get_v_c_reg_mapping( circ_transpiled) noise_model_tq.p_c_reg_mapping = get_p_c_reg_mapping( circ_transpiled) noise_model_tq.p_v_reg_mapping = get_p_v_reg_mapping( circ_transpiled) model.set_noise_model_tq(noise_model_tq) elif getattr(model, 'nodes', None) is not None: # every node has a noise model because it is possible that # different nodes run on different QC for node in model.nodes: circ = tq2qiskit(node.q_device, node.q_layer) circ.measure(list(range(node.q_device.n_wires)), list(range(node.q_device.n_wires))) circ_transpiled = processor.transpile(circs=circ) q_layer = qiskit2tq(circ=circ_transpiled) node.measure.set_v_c_reg_mapping( get_v_c_reg_mapping(circ_transpiled)) node.q_layer = q_layer if configs.trainer.add_noise: # noise-aware training noise_model_tq = builder.make_noise_model_tq() noise_model_tq.is_add_noise = True noise_model_tq.v_c_reg_mapping = get_v_c_reg_mapping( circ_transpiled) noise_model_tq.p_c_reg_mapping = get_p_c_reg_mapping( circ_transpiled) noise_model_tq.p_v_reg_mapping = get_p_v_reg_mapping( circ_transpiled) node.set_noise_model_tq(noise_model_tq) if getattr(configs.model.arch, 'sample_arch', None) is not None and \ not configs.model.transpile_before_run: sample_arch = configs.model.arch.sample_arch logger.warning(f"Setting sample arch {sample_arch} from config file!") if isinstance(sample_arch, str): # this is the name of arch sample_arch = get_named_sample_arch(model.arch_space, sample_arch) logger.warning(f"Decoded sample arch: {sample_arch}") model.set_sample_arch(sample_arch) if configs.trainer.name == 'pruning_trainer': """ in pruning, convert the super layers to module list, otherwise the pruning ratio is difficulty to set """ logger.warning(f"Convert sampled layer to module list layer!") model.q_layer = build_module_from_op_list( build_module_op_list(model.q_layer)) model.to(device) # model = torch.nn.parallel.DistributedDataParallel( # model.cuda(), # device_ids=[dist.local_rank()], # find_unused_parameters=True) if getattr(model, 'sample_arch', None) is not None and \ not configs.model.transpile_before_run and \ not configs.trainer.name == 'pruning_trainer': n_params = model.count_sample_params() logger.info(f"Number of sampled params: {n_params}") total_params = sum(p.numel() for p in model.parameters()) logger.info(f'Model Size: {total_params}') # logger.info(f'Model MACs: {profile_macs(model, inputs)}') criterion = builder.make_criterion() optimizer = builder.make_optimizer(model) scheduler = builder.make_scheduler(optimizer) trainer = builder.make_trainer(model=model, criterion=criterion, optimizer=optimizer, scheduler=scheduler) trainer.solution = solution trainer.score = score # trainer state_dict will be loaded in a callback callbacks = builder.make_callbacks(dataflow, state_dict) trainer.train_with_defaults(dataflow['train'], num_epochs=configs.run.n_epochs, callbacks=callbacks)
def load(self): if self.grayscale: tran = [ transforms.ToTensor(), transforms.Grayscale(num_output_channels=1), transforms.Normalize( (0.2989 * 0.4914 + 0.587 * 0.4822 + 0.114 * 0.4465, ), (((0.2989 * 0.2023)**2 + (0.587 * 0.1994)**2 + (0.114 * 0.2010)**2)**0.5, )) ] else: tran = [ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)) ] if not self.center_crop == 32: tran.append(transforms.CenterCrop(self.center_crop)) if not self.resize == 32: tran.append( transforms.Resize(self.resize, interpolation=self.resize_mode)) transform = transforms.Compose(tran) if self.split == 'train' or self.split == 'valid': train_valid = datasets.CIFAR10(self.root, train=True, download=True, transform=transform) targets = torch.tensor(train_valid.targets) idx, _ = torch.stack([ targets == number for number in self.digits_of_interest ]).max(dim=0) # targets = targets[idx] train_valid.targets = targets[idx].numpy().tolist() train_valid.data = train_valid.data[idx] train_len = int(self.train_valid_split_ratio[0] * len(train_valid)) split = [train_len, len(train_valid) - train_len] train_subset, valid_subset = torch.utils.data.random_split( train_valid, split, generator=torch.Generator().manual_seed(1)) if self.split == 'train': self.data = train_subset else: if self.n_valid_samples is None: # use all samples in valid set self.data = valid_subset else: # use a subset of valid set, useful to speedup evo search valid_subset.indices = valid_subset.indices[:self. n_valid_samples] self.data = valid_subset logger.warning(f"Only use the front " f"{self.n_valid_samples} images as " f"VALID set.") else: test = datasets.CIFAR10(self.root, train=False, transform=transform) targets = torch.tensor(test.targets) idx, _ = torch.stack([ targets == number for number in self.digits_of_interest ]).max(dim=0) test.targets = targets[idx].numpy().tolist() test.data = test.data[idx] if self.n_test_samples is None: # use all samples as test set self.data = test else: # use a subset as test set test.targets = test.targets[:self.n_test_samples] test.data = test.data[:self.n_test_samples] self.data = test logger.warning(f"Only use the front {self.n_test_samples} " f"images as TEST set.")
def sample_noise_op(self, op_in): if not (self.mode == 'train' and self.is_add_noise): return [] op_name = op_in.name.lower() if op_name == 'paulix': op_name = 'x' elif op_name == 'cnot': op_name = 'cx' elif op_name in ['sx', 'id']: pass elif op_name == 'rz': # no noise return [] else: logger.warning(f"No noise model for {op_name} operation!") wires = op_in.wires p_wires = [self.p_v_reg_mapping['v2p'][wire] for wire in wires] if tuple(p_wires) in self.parsed_dict[op_name].keys(): inst_prob = self.parsed_dict[op_name][tuple(p_wires)] else: # not in the real coupling map, so only give a dummy one if len(p_wires) == 1: inst_prob = self.parsed_dict[op_name][(0, )] elif len(p_wires) == 2: inst_prob = self.parsed_dict[op_name][(0, 1)] inst = inst_prob['instructions'] if len(inst) == 0: return [] probs = inst_prob['probabilities'] magnified_probs = self.magnify_probs(probs) idx = np.random.choice(list(range(len(inst) + 1)), p=magnified_probs + [1 - sum(magnified_probs)]) if idx == len(inst): return [] instructions = inst[idx] ops = [] for instruction in instructions: v_wires = [ self.p_v_reg_mapping['p2v'][qubit] for qubit in instruction['qubits'] ] if instruction['name'] == 'x': op = tq.PauliX(wires=v_wires) elif instruction['name'] == 'y': op = tq.PauliY(wires=v_wires) elif instruction['name'] == 'z': op = tq.PauliZ(wires=v_wires) elif instruction['name'] == 'reset': op = tq.Reset(wires=v_wires) else: # ignore operations specified by self.ignored_ops # logger.warning(f"skip noise operation {instruction['name']}") continue ops.append(op) return ops
def load(self): tran = [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))] if not self.center_crop == 28: tran.append(transforms.CenterCrop(self.center_crop)) if not self.resize == 28: tran.append(transforms.Resize(self.resize, interpolation=self.resize_mode)) transform = transforms.Compose(tran) if self.split == 'train' or self.split == 'valid': if self.fashion: train_valid = datasets.FashionMNIST( self.root, train=True, download=True, transform=transform) else: train_valid = datasets.MNIST( self.root, train=True, download=True, transform=transform) idx, _ = torch.stack([train_valid.targets == number for number in self.digits_of_interest]).max(dim=0) train_valid.targets = train_valid.targets[idx] train_valid.data = train_valid.data[idx] train_len = int(self.train_valid_split_ratio[0] * len(train_valid)) split = [train_len, len(train_valid) - train_len] train_subset, valid_subset = torch.utils.data.random_split( train_valid, split, generator=torch.Generator().manual_seed(1)) if self.split == 'train': self.data = train_subset else: if self.n_valid_samples is None: # use all samples in valid set self.data = valid_subset else: # use a subset of valid set, useful to speedup evo search valid_subset.indices = valid_subset.indices[ :self.n_valid_samples] self.data = valid_subset logger.warning(f"Only use the front " f"{self.n_valid_samples} images as " f"VALID set.") else: if self.fashion: test = datasets.FashionMNIST(self.root, train=False, transform=transform) else: test = datasets.MNIST(self.root, train=False, transform=transform) idx, _ = torch.stack([test.targets == number for number in self.digits_of_interest]).max(dim=0) test.targets = test.targets[idx] test.data = test.data[idx] if self.n_test_samples is None: # use all samples as test set self.data = test else: # use a subset as test set test.targets = test.targets[:self.n_test_samples] test.data = test.data[:self.n_test_samples] self.data = test logger.warning(f"Only use the front {self.n_test_samples} " f"images as TEST set.")