def pythagorean_test(self): self.logger.info( f"Starting pythagorean tests for x={self.conf['x']}, y={self.conf['x']}.." ) with timeit( custom_print='Numba pythagorean took {duration:.5f} sec(s)'): self.pythagorean_theorem(self.conf['x'], self.conf['y']) with timeit( custom_print='No Numba pythagorean took {duration:.5f} sec(s)' ): self.pythagorus(self.conf['x'], self.conf['y'])
def _loop_vectorized_jacob(num_clusters: int, num_points: int, cluster_assignments: np.ndarray, features: np.ndarray, centroids: np.ndarray, outputs_file: IO): loop_cnt = 0 t_time_dists = 0.0 t_time_expect = 0.0 t_time_maxim = 0.0 while True: loop_cnt += 1 # Compute distances from sample points to centroids timeit_obj = timeit(internal_only=True) with timeit_obj: centroid_distances = _compute_distances_vectorized_jacob( num_points, num_clusters, centroids, features) t_time_dists += timeit_obj.total # Expectation step: assign clusters timeit_obj = timeit(internal_only=True) with timeit_obj: centroid_distances, cluster_assignments, num_changed_assignments = \ _expectation_step_vectorized_jacob(num_points, num_clusters, centroid_distances, cluster_assignments) t_time_expect += timeit_obj.total # Maximization step: Update centroid for each cluster timeit_obj = timeit(internal_only=True) with timeit_obj: centroids = _maximization_step_vectorized_jacob( num_clusters, num_points, cluster_assignments, features, centroids) t_time_maxim += timeit_obj.total if num_changed_assignments == 0: break custom_print = '_compute_distances_vectorized_jacob K-Means using numba' + \ f' dataset took {t_time_dists:.4f} sec(s)\n' outputs_file.write(custom_print) custom_print = '_expectation_step_vectorized_jacob K-Means using numba' + \ f' dataset took {t_time_expect:.4f} sec(s)\n' outputs_file.write(custom_print) custom_print = '_maximization_step_vectorized_jacob K-Means using numba' + \ f' dataset took {t_time_maxim:.4f} sec(s)\n' outputs_file.write(custom_print) # return cluster centroids and assignments return centroids, cluster_assignments
def run_kmeans(conf: Dict) -> None: """ Runs the KMeans tests for the specified configuration. """ config = conf['config'] run_type = conf['type'] num_clusters = config['num_clusters'] logger.info( f"Invoking kmeans.py with type=`{run_type}` and num_clusters=`{num_clusters}`" ) sys_path = os.path.dirname(os.path.realpath(__file__)) run_file_path = os.path.join(sys_path, 'KMeans', 'kmeans.py') if run_type == 'mpi': nprocs = config['nprocs'] cmd = 'mpirun -n {nprocs} {python} {file} {num_clusters} {type}' \ .format(nprocs=nprocs, python=sys.executable, file=run_file_path, type=run_type, num_clusters=num_clusters) elif run_type in ('simple', 'vectorized', 'distributed'): cmd = '{python} {file} {num_clusters} {type}'.format( python=sys.executable, file=run_file_path, type=run_type, num_clusters=num_clusters) else: raise Exception(f'Argument {run_type} not recognized!') with timeit(custom_print= f'Running KMeans {run_type} for {num_clusters} clusters took' + ' {duration:2.5f} sec(s)'): os.system(cmd)
def run_vectorized_jacob(features: np.ndarray, num_clusters: int, outputs_file: IO): """Run k-means algorithm to convergence. Args: outputs_file: features: numpy.ndarray: An num_points-by-d array describing num_points data points each of dimension d num_clusters: int: The number of clusters desired """ num_points = features.shape[0] # num sample points # INITIALIZATION PHASE # initialize centroids randomly as distinct elements of xs np.random.seed(0) centroids_ids = np.random.choice(num_points, (num_clusters, ), replace=False) centroids = features[centroids_ids, :] cluster_assignments = np.zeros(num_points, dtype=np.uint8) # loop until convergence custom_print = f'_loop_vectorized_jacob K-Means using numba' + \ ' dataset took {duration:.4f} sec(s)\n' with timeit(file=outputs_file, custom_print=custom_print): centroids, cluster_assignments = \ _loop_vectorized_jacob(num_clusters, num_points, cluster_assignments, features, centroids, outputs_file) # return cluster centroids and assignments return centroids, cluster_assignments
def monte_carlo_pi_test(self): self.logger.info( f"Starting monte_carlo_pi tests for nsamples={self.conf['nsamples']}.." ) with timeit( custom_print='Numba monte_carlo_pi took {duration:.5f} sec(s)' ): self.monte_carlo_pi(self.conf['nsamples'])
def run(kmeans_obj: KMeansRunner, run_type: str, num_clusters: int, dataset: str): """ Args: kmeans_obj: num_clusters: The number of clusters to find dataset: The name or path of the dataset Returns: Info: features shape: (# points, # features) centroids shape: (# clusters, # features) centroid_distances shape: (# points, # clusters) """ # Setup func to run and dataset to use dataset_name = 'tcga' if dataset != 'iris' else dataset # Prepare output folders and names sys_path = os.path.dirname(os.path.realpath(__file__)) output_file_name = f'assignment3_{dataset_name}_{run_type}.txt' output_base_path = os.path.join(sys_path, '..', 'outputs') if not os.path.exists(output_base_path): os.makedirs(output_base_path) output_file_path = os.path.join(output_base_path, output_file_name) # Open results output file outputs_file = open(output_file_path, 'w') outputs_file.write( f'K-Means {run_type} version for the {dataset_name} dataset ' f'with {num_clusters} clusters .\n') # Load Dataset if not already loaded features = kmeans_obj._load_dataset(dataset_name, dataset) # Run Kmeans custom_print = f'`{run_type}` K-Means for the `{dataset_name}`' + \ ' dataset took {duration:.4f} sec(s)\n' with timeit(file=outputs_file, custom_print=custom_print): centroids, assignments = run_vectorized_jacob( features=features, num_clusters=num_clusters, outputs_file=outputs_file) # Save results kmeans_obj.logger.info(f"Final Cluster Assignments: \n{assignments}") outputs_file.write(f'Assignments:\n') outputs_file.write(f'{assignments.tolist()}\n') outputs_file.write(f'Centroids:\n') outputs_file.write(f'{centroids.tolist()}') # Close file stream outputs_file.close()
def logistic_regression_test(self): self.logger.info( f"Starting logistic_regression tests for " f"X={self.conf['x1']}, Y={self.conf['x2']}, " f"w={self.conf['w']}, iterations={self.conf['iterations']}..") with timeit(custom_print= 'Numba logistic_regression took {duration:.5f} sec(s)'): self.logistic_regression( np.random.rand(self.conf['x1'], self.conf['x2']), np.random.rand(self.conf['x1']), np.zeros([self.conf['x2']]), self.conf['iterations'])
def extra_2(conf_props: Dict): """ Extra Challenge 2 solution Parameters: conf_props: The config loaded from the yml file Example: pool_sizes: - 2 - 4 - 8 - 16 - 32 num_term: 8000000 """ num_term = int(conf_props["num_term"]) extra_ch_logger.info( "Will call `py_pi_better_with_queue` for pool_size in " f"{tuple(conf_props['pool_sizes'])}") for pool_size in conf_props["pool_sizes"]: pool_size = int(pool_size) # Create a multiprocessing manager and a Queue multi_manager = multiprocessing.Manager() multi_queue = multi_manager.Queue() # Slightly modified code from problem 3 extra_sub_ch_logger.info( f"Pool Size={pool_size}: Calling Async workers for N={num_term}") step = ceil(num_term / pool_size) i_start = range(1, num_term, step) i_stop = map( lambda el: el + step - 1 if el + step - 1 <= num_term else num_term, i_start) args = zip(repeat(num_term), i_start, i_stop, repeat(multi_queue)) # Setup manually a Pool custom_string = f'Pool Size={pool_size}: Calculation of pi for N={num_term} and ' + \ 'took: {duration:2.5f} sec(s) total' with timeit(custom_print=custom_string): pool = multiprocessing.Pool(processes=pool_size) pool.starmap_async(func=py_pi_better_with_queue, iterable=args) pi_chunks = [] while len(pi_chunks) < pool_size: pi_chunks.append(multi_queue.get()) calced_pi = sum(pi_chunks) real_pi = np.pi pi_diff = abs(real_pi - calced_pi) extra_sub_ch_logger.info( f"Pool Size={pool_size}: Pi({num_term}) = {calced_pi}" f"(Real is {real_pi}, difference is {pi_diff})") pool.close() pool.join()
def train_data_parallel( self, train_loader: DataLoader) -> Tuple[List, List, List]: my_model = nn.parallel.DistributedDataParallel(self.my_model) learning_rate = self.learning_rate * dist.get_world_size() optimizer = optim.SGD(my_model.parameters(), lr=learning_rate) size_train_dataset = len(train_loader.dataset) epoch_losses = [] epoch_accuracies = [] epoch_times = [] self.my_model.train() if self.rank == 0: iter_epochs = tqdm(range(self.epochs), desc='Training Epochs') else: iter_epochs = range(self.epochs) for _ in iter_epochs: timeit_ = timeit(internal_only=True) epoch_loss = 0.0 correct = 0 num_mini_batches = 0 with timeit_: iter_mini_batches = enumerate(train_loader) for num_mini_batches, (X, Y) in iter_mini_batches: optimizer.zero_grad() pred = self.my_model(X) pred_val = torch.flatten(pred.data.max(1, keepdim=True)[1]) # correct += pred_val.eq(Y.data.view_as(pred_val)).sum().item() correct += (pred_val == Y).sum().item() loss = self.loss_function(pred, Y) iter_loss = loss.item() epoch_loss += iter_loss loss.backward() optimizer.step() epoch_loss /= (num_mini_batches + 1) epoch_losses.append(epoch_loss) epoch_accuracy = correct / (size_train_dataset / dist.get_world_size()) epoch_accuracies.append(epoch_accuracy) epoch_time = timeit_.total epoch_times.append(epoch_time) if self.rank == 0: iter_epochs.set_postfix(epoch_accuracy=epoch_accuracy, epoch_loss=epoch_loss, epoch_time=epoch_time) return epoch_accuracies, epoch_losses, epoch_times
def problem3(conf: Dict) -> None: """ Problem 3 solution Parameters: conf: The config loaded from the yml file Example: properties: pool_size: 4 chunk_size: 1 num_terms: - 100 - 500 - 1000 - 2000 - 10000 - 50000 conf_type: required """ p3_logger.info("Starting Problem 3..") conf_props = conf['properties'] p3_logger.info( f"Will call `py_pi_better` for N in {tuple(conf_props['num_terms'])}") # Run the pi calculation once for each number of terms requested in the yml for num_term in conf_props["num_terms"]: # Split the work of `num_terms` into `pool_size` number of parts step = ceil(num_term / conf_props["pool_size"]) i_start = range(1, num_term, step) i_stop = map( lambda el: el + step - 1 if el + step - 1 <= num_term else num_term, i_start) # Zip N with the i_start and i_stop iterables. Propagate the same N value using repeat args = zip(repeat(num_term), i_start, i_stop) # Call py_pi_better() using pool.starmap() (starmap accepts iterable with multiple arguments) with multiprocessing.Pool(processes=conf_props['pool_size']) as pool: # timeit can be used as a context manager too. Pass it a custom string and count the # total time to calculate pi custom_string = f'N={num_term}: Parallel calculation of pi took: ' + \ '{duration:2.5f} sec(s) total' with timeit(custom_print=custom_string): # https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool.map pi_chunks = pool.starmap(func=py_pi_better, iterable=args, chunksize=conf_props['chunk_size']) calced_pi = sum(pi_chunks) real_pi = np.pi pi_diff = abs(real_pi - calced_pi) p3_logger.info( f"N={num_term}: Pi({num_term}) = {calced_pi} (Real is {real_pi}, " f"difference is {pi_diff})")
def extra_1(conf_props: Dict): """ Extra Challenge 1 solution Parameters: conf_props: The config loaded from the yml file Example: pool_sizes: - 2 - 4 - 8 - 16 - 32 chunk_size: 1 num_term: 8000000 """ num_term = int(conf_props["num_term"]) extra_ch_logger.info("Will call `py_pi_better` for pool_size in " f"{tuple(conf_props['pool_sizes'])}") for pool_size in conf_props["pool_sizes"]: pool_size = int(pool_size) # Slightly modified code from problem 3 extra_sub_ch_logger.info( f"Pool Size={pool_size}: Calling workers for N={num_term}") step = ceil(num_term / pool_size) i_start = range(1, num_term, step) i_stop = map( lambda el: el + step - 1 if el + step - 1 <= num_term else num_term, i_start) args = zip(repeat(num_term), i_start, i_stop) with multiprocessing.Pool(processes=pool_size) as pool: custom_string = f'Pool Size={pool_size}: Calculation of pi for N={num_term} took: ' + \ '{duration:2.5f} sec(s) total' with timeit(custom_print=custom_string): pi_chunks = pool.starmap(func=py_pi_better, iterable=args, chunksize=conf_props['chunk_size']) calced_pi = sum(pi_chunks) real_pi = np.pi pi_diff = abs(real_pi - calced_pi) extra_sub_ch_logger.info( f"Pool Size={pool_size}: Pi({num_term}) = {calced_pi} " f"(Real is {real_pi}, difference is {pi_diff})")
def prange_test(self): self.logger.info(f"Starting prange tests for A={self.conf['A']}..") with timeit(custom_print='Numba prange took {duration:.5f} sec(s)'): self.prange(np.arange(self.conf['A']))