SciPy minimize: providing only odd integer numbers as a parameter to the cost function

56 Views Asked by At

I'm trying to apply minimize from the SciPy optimize module to a cost function of my own:

result = minimize(cost_function, initial_params, args = (TEXT_IMG, BINARY_MASK), method = 'BFGS')

I need the first param to be an odd integer number, like 31:

initial_params = np.array([31, 2, -7])

But minimize starts iterating around 31, with just float numbers, and my cost function crashes; is it possible to implement bounds and constraints so minimize keeps providing numbers like 31, 29, 33, etc.?

I have read that I might need to use differential_evolution instead of minimize, but just to make sure.

EDIT:

This is the cost function:

def abs_diff(mask1, mask2):

    diff = np.abs(mask1 - mask2)
    mean_diff = np.mean(diff)

    return mean_diff

def cost_function(params, text_img, binary_mask):
    
    blockSize, C, h = params
    hColor = -3
    templateWSize = 5
    searchWSize = 5

    denoised = cv2.fastNlMeansDenoisingColored(text_img, h, hColor, templateWSize, searchWSize)
    gray_denoised = cv2.cvtColor(denoised, cv2.COLOR_BGR2GRAY)
    imgf = cv2.adaptiveThreshold(gray_denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, blockSize, C)

    error = abs_diff(binary_mask * 255, imgf)
            
    return error
1

There are 1 best solutions below

0
maxy On

Methods like BFGS are not so good for discrete-valued parameters.

The pragmatic solution is to run your optimization for all 16 blockSize values and pick the best result.

Or you could "cheat" by scaling and rounding the blockSize before use in such a way that the initial distribution has a good coverage.

If you have more discrete parameters (especially boolean ones), then another option is to see this problem as hyper-parameter optimization. Either just do random search over those parameters, or use something like ray tune, which is basically a parallel random search that also supports early stopping on the inner "training loop" when it starts looking bad. (The inner loop would optimize the remaining continuous parameters with a stronger algorithm than random search.)

Another alternative would be the CEM (Cross-Entropy Method), which allows mixing discrete and continuous distributions. But for real-valued parameters it may converge to a much worse solutions than something like BFGS. A genetic algorithm may work, too, but given that you're using scipy.optimize it will probably involve too much setup and hand-crafting.