Simple example for a compute function using a feed forward network.
		It is trained on the MNIST dataset.
		The input parameter "config" (dictionary) contains the sampled configurations passed by the bohb optimizer

def compute(self, config, budget, working_directory, *args, **kwargs):
		"""
		Simple example for a compute function using a feed forward network.
		It is trained on the MNIST dataset.
		The input parameter "config" (dictionary) contains the sampled configurations passed by the bohb optimizer
		"""

		# device = torch.device('cpu')
		model = MNISTConvNet(num_conv_layers=config['num_conv_layers'],
							num_filters_1=config['num_filters_1'],
							num_filters_2=config['num_filters_2'] if 'num_filters_2' in config else None,
							num_filters_3=config['num_filters_3'] if 'num_filters_3' in config else None,
							dropout_rate=config['dropout_rate'],
							num_fc_units=config['num_fc_units'],
							kernel_size=3
		)

		criterion = torch.nn.CrossEntropyLoss()
		if config['optimizer'] == 'Adam':
			optimizer = torch.optim.Adam(model.parameters(), lr=config['lr'])
		else:
			optimizer = torch.optim.SGD(model.parameters(), lr=config['lr'], momentum=config['sgd_momentum'])

		for epoch in range(int(budget)):
			loss = 0
			model.train()
			for i, (x, y) in enumerate(self.train_loader):
				optimizer.zero_grad()
				output = model(x)
				loss = F.nll_loss(output, y)
				loss.backward()
				optimizer.step()

		train_accuracy = self.evaluate_accuracy(model, self.train_loader)
		validation_accuracy = self.evaluate_accuracy(model, self.validation_loader)
		test_accuracy = self.evaluate_accuracy(model, self.test_loader)

		return ({
			'loss': 1-validation_accuracy, # remember: HpBandSter always minimizes!
			'info': {	'test accuracy': test_accuracy,
						'train accuracy': train_accuracy,
						'validation accuracy': validation_accuracy,
						'number of parameters': model.number_of_parameters(),
					}
						
		})