添加worker参数时差分进化失败

问题描述 投票:0回答:1

为了设置我的 Differential_evolve 曲线拟合函数,我大量借鉴了 https://bitbucket.org/zunzuncode/ramanspectroscopyfit/src/master/RamanSpectroscopyFit.py。 当我不使用“workers”时,我实现的功能运行完美。

我的最小可重现示例:

#### Python 3.9 ####
#### Windows 10 ####

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import warnings
from scipy.optimize import differential_evolution as DE


def LCR(f, L, C, R):
    TPF = 2*np.pi*f
    return np.sqrt(R**2 + (TPF*L - 1/(TPF*C))**2)

def sumOfSquaredError(parameterTuple):
    warnings.filterwarnings("ignore")
    return np.sum((ydata - LCR(xdata, *parameterTuple))**2)

def generateParameterBounds():
        parameterBounds = []
        parameterBounds.append([1,5]) # parameter bounds for L
        parameterBounds.append([1,5]) # parameter bounds for C
        parameterBounds.append([1,5]) # parameter bounds for R
        result = DE(sumOfSquaredError, parameterBounds, popsize=30, init='sobol', polish=False, seed=3)
        # result = DE(sumOfSquaredError, parameterBounds, popsize=30, init='sobol', polish=False, workers=2, seed=3)
        return result.x

xdata = np.linspace(1e-3,1,1000)
ydata = LCR(xdata,1.5,2,2.5) + np.random.randn(len(xdata))
plt.plot(xdata, ydata, 'b-', label='Measured')

#### REGULAR CURVE FIT ####
popt, pcov = curve_fit(LCR, xdata, ydata, bounds=([1, 1, 1], [5, 5, 5]))
print(*popt)
fit = LCR(xdata, *popt)
plt.plot(xdata, fit, 'g-')

#### DIFFERENTIAL EVOLUTION CURVE FIT ####
ParameterRanges = generateParameterBounds()
geneticParameters, pcov = curve_fit(LCR, xdata, ydata, ParameterRanges, maxfev=1000000)
print(*geneticParameters)
g_fit = LCR(xdata, *geneticParameters)
plt.plot(xdata, g_fit, 'r-')

plt.show()

当我注释/取消注释两个 result = DE(...) 行(添加了workers参数)时,出现以下错误。

错误:

RuntimeError:
    An attempt has been made to start a new process before the
    current process has finished its bootstrapping phase.

    This probably means that you are not using fork to start your
    child processes and you have forgotten to use the proper idiom
    in the main module:

        if __name__ == '__main__':
            freeze_support()
            ...

    The "freeze_support()" line can be omitted if the program
    is not going to be frozen to produce an executable.

我不确定如何利用此错误注释来更新我的代码。 如果可能的话,我想留在 scipy.optimize 包内。

python scipy curve-fitting genetic-algorithm scipy-optimize
1个回答
0
投票

您需要更改一些不同的内容才能使其正常工作。

当你的Python程序使用spawn start方法进行多处理时,对于任何你只想由父进程完成的工作,你需要用

if __name__ == '__main__':
包装。例如:

def main():
    # code that you had outside of any functions before
    # ...

if __name__ == '__main__':
    main()

(有一个例外,Linux 上 3.14 之前的 Python 版本,默认使用 fork 启动方法,允许你将代码放在主作用域中。这是因为 fork 是通过复制但是,使用

if __name__ == '__main__':
仍然是最佳实践。)

如果您不这样做,

differential_evolution()
将创建一个新进程来运行您的代码。这个新进程不会加载您的代码,因此它将导入它。导入代码将运行函数或
if __name__ == '__main__':
之外的所有内容,包括
differential_evolution()
。这是一个无限循环。

您需要更改的第二件事是您要运行的函数

sumOfSquaredError()
使用xdata和ydata变量作为全局变量。如果您应用我刚刚给出的建议,那么子进程中将不会有这些全局变量。相反,您需要使用
args
参数来传递这些。

示例:

def LCR(f, L, C, R):
    TPF = 2*np.pi*f
    return np.sqrt(R**2 + (TPF*L - 1/(TPF*C))**2)

def sumOfSquaredError(parameterTuple, xdata, ydata):
    warnings.filterwarnings("ignore")
    return np.sum((ydata - LCR(xdata, *parameterTuple))**2)

def generateParameterBounds(xdata, ydata):
    parameterBounds = []
    parameterBounds.append([1,5]) # parameter bounds for L
    parameterBounds.append([1,5]) # parameter bounds for C
    parameterBounds.append([1,5]) # parameter bounds for R
    result = DE(
        sumOfSquaredError,
        parameterBounds,
        args=(xdata, ydata),
        popsize=30,
        init='sobol',
        polish=False,
        seed=3,
        workers=2,
    )
    return result.x

请注意,我已更改

sumOfSquaredError()
generateParameterBounds()
以包含
xdata
ydata
的参数。我还在对
args=(xdata, ydata),
的调用中添加了
differential_evolution()
。这意味着当
differential_evolution()
调用您的函数时,它会将那些额外的参数添加到
sumOfSquaredError()
的参数末尾。

这是完整的更正代码。

#### Python 3.9 ####
#### Windows 10 ####

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import warnings
from scipy.optimize import differential_evolution as DE


def LCR(f, L, C, R):
    TPF = 2*np.pi*f
    return np.sqrt(R**2 + (TPF*L - 1/(TPF*C))**2)

def sumOfSquaredError(parameterTuple, xdata, ydata):
    warnings.filterwarnings("ignore")
    return np.sum((ydata - LCR(xdata, *parameterTuple))**2)

def generateParameterBounds(xdata, ydata):
    parameterBounds = []
    parameterBounds.append([1,5]) # parameter bounds for L
    parameterBounds.append([1,5]) # parameter bounds for C
    parameterBounds.append([1,5]) # parameter bounds for R
    result = DE(
        sumOfSquaredError,
        parameterBounds,
        args=(xdata, ydata),
        popsize=30,
        init='sobol',
        polish=False,
        seed=3,
        workers=2,
    )
    return result.x

    
def main():
    xdata = np.linspace(1e-3,1,1000)
    ydata = LCR(xdata,1.5,2,2.5) + np.random.randn(len(xdata))
    plt.plot(xdata, ydata, 'b-', label='Measured')

    #### REGULAR CURVE FIT ####
    popt, pcov = curve_fit(LCR, xdata, ydata, bounds=([1, 1, 1], [5, 5, 5]))
    print(*popt)
    fit = LCR(xdata, *popt)
    plt.plot(xdata, fit, 'g-', label='curve_fit only')

    #### DIFFERENTIAL EVOLUTION CURVE FIT ####
    ParameterRanges = generateParameterBounds(xdata, ydata)
    geneticParameters, pcov = curve_fit(LCR, xdata, ydata, ParameterRanges, maxfev=1000000)
    print(*geneticParameters)
    g_fit = LCR(xdata, *ParameterRanges)
    plt.plot(xdata, g_fit, 'r-', label='genetic + curve_fit')
    plt.legend()
    plt.show()


if __name__ == '__main__':
    # I used these two lines to reproduce your problem on Linux
    # Not required on Windows
    # import multiprocessing
    # multiprocessing.set_start_method('spawn')
    main()
© www.soinside.com 2019 - 2024. All rights reserved.