You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让SciPy minimize优化器的首个参数仅为奇数整数?

问题描述

我尝试使用SciPy optimize模块的minimize函数对自定义代价函数进行优化:

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

初始参数设置如下:

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

但minimize会在31附近迭代出浮点数,导致我的代价函数崩溃。我需要首个参数始终为奇数整数(例如31、29、33这类),想知道是否可以通过设置边界与约束实现这一点?另外我了解到可能需要改用differential_evolution替代minimize,希望确认该方案是否必要,或是否有其他解决办法。

代价函数代码:

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. 临时修复:在代价函数中强制转换参数为奇数整数

这是最快的解决方式,无需更换优化器。在代价函数开头对第一个参数做处理,确保它是奇数整数:

def cost_function(params, text_img, binary_mask):
    # 将blockSize转为最近的奇数整数
    blockSize = int(np.round(params[0]))
    if blockSize % 2 == 0:
        blockSize += 1  # 若为偶数则加1变奇数,也可根据需求改为减1
    C, h = params[1], params[2]
    # 后续原有代码保持不变...

这种方式允许minimize正常迭代浮点数,但实际传入OpenCV函数的是处理后的合法奇数参数。缺点是代价函数会变成非光滑函数,可能影响BFGS这类依赖梯度的优化器的收敛效率,但如果参数范围不大,实际使用中往往能满足需求。

2. 变量映射配合整数约束(效果有限)

可以将第一个参数映射为整数变量:令blockSize = 2*k + 1,其中k为整数。此时优化变量变为[k, C, h],初始参数对应k=(31-1)/2=15,即initial_params = np.array([15, 2, -7])。之后在代价函数中计算blockSize = 2*k +1。

但BFGS仍会将k迭代为浮点数,因此最终还是需要在代价函数中将k转为整数,本质上和第一种方案类似,只是变量形式不同,没有解决根本问题。

3. 改用支持离散/整数变量的优化器(推荐长期方案)

BFGS这类基于梯度的优化器是为连续变量设计的,天生不适合处理离散约束。如果临时修复的收敛效果不理想,更换优化器是更合理的选择:

  • differential_evolution:支持通过integer参数指定哪些变量为整数,之后只需在代价函数中确保第一个整数参数为奇数即可。示例代码:
    from scipy.optimize import differential_evolution
    
    # 定义参数边界,第一个参数范围设为合理的整数区间
    bounds = [(1, 51), (-10, 10), (-10, 10)]
    # 指定第一个变量为整数
    result = differential_evolution(cost_function, bounds, args=(TEXT_IMG, BINARY_MASK), integer=[0])
    
    同时修改代价函数确保blockSize为奇数:
    def cost_function(params, text_img, binary_mask):
        blockSize = params[0]
        if blockSize % 2 == 0:
            blockSize += 1  # 强制转为奇数
        # 后续原有代码保持不变...
    
  • 此外,shgo、dual_annealing等全局优化器也能更好地适配离散变量场景,可根据需求选择。

总结

  • 若仅需快速解决问题,优先选择代价函数内强制转换参数的方案,无需更换优化器,但可能影响收敛效率。
  • 若追求更稳定的优化效果,改用differential_evolution这类支持整数变量的优化器是必要的,BFGS本质上无法妥善处理离散约束。

内容的提问来源于stack exchange,提问作者Javier Blanco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:54:54