QUBOのハイパーパラメータサーチ

QUBOのハイパーパラメータサーチ#

ここでは、QUMOモデルのハイパーパラメータ空間を探索するために、MINTOがどのように使えるかを簡単な例を通して説明します。 この例では、2次割当定式化を用いて巡回セールスマン問題を扱います。 巡回セールスマン問題についての詳細は、ぜひ他のリソースを参照ください。

import minto
import matplotlib.pyplot as plt
import jijmodeling as jm
import minto.problems.tsp

tsp = minto.problems.tsp.QuadTSP()
tsp_problem = tsp.problem()

n = 8
tsp_data = tsp.data(n=n)

tsp_problem
\[\begin{split}\begin{array}{cccc}\text{Problem:} & \text{QuadTSP} & & \\& & \min \quad \displaystyle \sum_{i = 0}^{n - 1} \sum_{j = 0}^{n - 1} d_{i, j} \cdot \sum_{t = 0}^{n - 1} x_{i, t} \cdot x_{j, \left(t + 1\right) \bmod n} & \\\text{{s.t.}} & & & \\ & \text{one-city} & \displaystyle \sum_{\ast_{1} = 0}^{n - 1} x_{i, \ast_{1}} = 1 & \forall i \in \left\{0,\ldots,n - 1\right\} \\ & \text{one-time} & \displaystyle \sum_{\ast_{0} = 0}^{n - 1} x_{\ast_{0}, t} = 1 & \forall t \in \left\{0,\ldots,n - 1\right\} \\\text{{where}} & & & \\& x & 2\text{-dim binary variable}\\\end{array}\end{split}\]
interpreter = jm.Interpreter(tsp_data)
instance = interpreter.eval_problem(tsp_problem)

QUBO formulation#

\[ E(x; A) = \sum_{i=0}^{n-1} \sum_{j=0}^{n-1} d_{ij} \sum_{t=0}^{n-1} x_{it} x_{j, (t+1)\mod n} + A \left[ \sum_i \left(\sum_{t} x_{i, t} - 1\right)^2 + \sum_t \left(\sum_{i} x_{i, t} - 1\right)^2 \right] \]

The parameter \(A\) is a hyperparameter that controls the strength of the constraints.

In OMMX, we can tune this parameter using the .to_qubo(uniform_penalty_weight=...) method and argument uniform_penalty_weight to set the value of \(A\).

import ommx_openjij_adapter as oj_ad

parameter_values = [0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

experiment = minto.Experiment(auto_saving=False, verbose_logging=False)
for A in parameter_values:
    with experiment.run() as run:
        ox_sampleset = oj_ad.OMMXOpenJijSAAdapter.sample(instance, uniform_penalty_weight=A, num_reads=30)
        run.log_sampleset(ox_sampleset)
        run.log_parameter("A", A)
table = experiment.get_run_table()
table
sampleset_0 parameter metadata
num_samples obj_mean obj_std obj_min obj_max feasible name A run_id elapsed_time
run_id
0 30 3.353026 0.499013 2.355019 4.268100 0 0 0.4 0 0.042427
1 30 3.383542 0.700817 2.340510 4.839428 0 0 0.5 1 0.034157
2 30 6.323973 1.107701 4.669342 8.462845 0 0 0.6 2 0.036005
3 30 2.939773 0.576959 2.220747 4.255948 16 0 0.7 3 0.028858
4 30 2.536650 0.234261 2.220747 3.052677 29 0 0.8 4 0.028297
5 30 2.686100 0.275722 2.220747 3.506836 30 0 0.9 5 0.021842
6 30 2.722490 0.341214 2.220747 3.609280 30 0 1.0 6 0.022454
fig, ax1 = plt.subplots()

# First y-axis for objective value
ax1.set_xlabel("Parameter A")
ax1.set_ylabel("Objective Value", color="tab:blue")
ax1.plot(table["parameter"]["A"], table["sampleset_0"]["obj_mean"], "-o", color="tab:blue")
ax1.tick_params(axis="y", labelcolor="tab:blue")

# Second y-axis for feasible count
ax2 = ax1.twinx()
ax2.set_ylabel("Feasible Count", color="tab:orange")
ax2.plot(table["parameter"]["A"], table["sampleset_0"]["feasible"], "-o", color="tab:orange")
ax2.tick_params(axis="y", labelcolor="tab:orange")

plt.title("Objective Value and Feasible Count vs Parameter A")
fig.tight_layout()
../_images/b88bea5f03212ecd46840e58c2f7d47190fd85027363fc425037cf6d0efeefd6.png