Spaces:
Sleeping
Sleeping
Commit
·
f2a4894
1
Parent(s):
efbecf0
feat: main features
Browse files
app.py
ADDED
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
import numpy as np
|
3 |
+
import gradio as gr
|
4 |
+
import pandas as pd
|
5 |
+
from deap import base, creator, tools
|
6 |
+
|
7 |
+
# 全局变量存储优化状态
|
8 |
+
state = {
|
9 |
+
"toolbox": None,
|
10 |
+
"population": None,
|
11 |
+
"current_idx": 0,
|
12 |
+
"current_gen": 0,
|
13 |
+
"history": [],
|
14 |
+
"best_ind": None,
|
15 |
+
"running": False,
|
16 |
+
"params": {}
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
def create_individual(min_max):
|
21 |
+
return [
|
22 |
+
random.uniform(min_max["kp_min"], min_max["kp_max"]),
|
23 |
+
random.uniform(min_max["ki_min"], min_max["ki_max"]),
|
24 |
+
random.uniform(min_max["kd_min"], min_max["kd_max"])
|
25 |
+
]
|
26 |
+
|
27 |
+
|
28 |
+
def init_toolbox(min_max):
|
29 |
+
if "FitnessMax" in creator.__dict__:
|
30 |
+
del creator.FitnessMax
|
31 |
+
if "Individual" in creator.__dict__:
|
32 |
+
del creator.Individual
|
33 |
+
|
34 |
+
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
|
35 |
+
creator.create("Individual", list, fitness=creator.FitnessMax)
|
36 |
+
|
37 |
+
toolbox = base.Toolbox()
|
38 |
+
toolbox.register("individual", tools.initIterate, creator.Individual,
|
39 |
+
lambda: create_individual(min_max))
|
40 |
+
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
|
41 |
+
toolbox.register("mate", tools.cxBlend, alpha=0.5)
|
42 |
+
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=0.1, indpb=0.2)
|
43 |
+
toolbox.register("select", tools.selTournament, tournsize=3)
|
44 |
+
return toolbox
|
45 |
+
|
46 |
+
|
47 |
+
def start_optimization(kp_min, kp_max, ki_min, ki_max, kd_min, kd_max,
|
48 |
+
pop_size, max_gen, cx_prob, mut_prob):
|
49 |
+
state.update({
|
50 |
+
"params": {
|
51 |
+
"kp_range": (kp_min, kp_max),
|
52 |
+
"ki_range": (ki_min, ki_max),
|
53 |
+
"kd_range": (kd_min, kd_max),
|
54 |
+
"pop_size": pop_size,
|
55 |
+
"max_gen": max_gen,
|
56 |
+
"cx_prob": cx_prob,
|
57 |
+
"mut_prob": mut_prob
|
58 |
+
},
|
59 |
+
"current_gen": 0,
|
60 |
+
"history": [],
|
61 |
+
"best_ind": None,
|
62 |
+
"running": True
|
63 |
+
})
|
64 |
+
|
65 |
+
min_max = {
|
66 |
+
"kp_min": kp_min, "kp_max": kp_max,
|
67 |
+
"ki_min": ki_min, "ki_max": ki_max,
|
68 |
+
"kd_min": kd_min, "kd_max": kd_max
|
69 |
+
}
|
70 |
+
|
71 |
+
toolbox = init_toolbox(min_max)
|
72 |
+
population = toolbox.population(n=pop_size)
|
73 |
+
|
74 |
+
state.update({
|
75 |
+
"toolbox": toolbox,
|
76 |
+
"population": population,
|
77 |
+
"current_idx": 0
|
78 |
+
})
|
79 |
+
|
80 |
+
first_ind = population[0]
|
81 |
+
return {
|
82 |
+
current_params: f"Kp: {first_ind[0]:.4f}, Ki: {first_ind[1]:.4f}, Kd: {first_ind[2]:.4f}",
|
83 |
+
fitness_input: "",
|
84 |
+
history_output: pd.DataFrame(columns=["Kp", "Ki", "Kd", "Fitness"]),
|
85 |
+
best_output: "最佳参数:尚未找到"
|
86 |
+
}
|
87 |
+
|
88 |
+
|
89 |
+
def submit_fitness(fitness):
|
90 |
+
if not state["running"]:
|
91 |
+
return {current_params: "优化未运行"}
|
92 |
+
|
93 |
+
population = state["population"]
|
94 |
+
idx = state["current_idx"]
|
95 |
+
ind = population[idx]
|
96 |
+
|
97 |
+
# 记录适应度
|
98 |
+
ind.fitness.values = (float(fitness),)
|
99 |
+
state["history"].append({
|
100 |
+
"Kp": ind[0], "Ki": ind[1], "Kd": ind[2], "Fitness": float(fitness)
|
101 |
+
})
|
102 |
+
|
103 |
+
# 更新最佳个体
|
104 |
+
if state["best_ind"] is None or ind.fitness > state["best_ind"].fitness:
|
105 |
+
state["best_ind"] = ind
|
106 |
+
|
107 |
+
# 移动到下一个个体
|
108 |
+
state["current_idx"] += 1
|
109 |
+
|
110 |
+
# 检查是否完成当前种群评估
|
111 |
+
if state["current_idx"] >= len(population):
|
112 |
+
evolve_population()
|
113 |
+
state["current_idx"] = 0
|
114 |
+
state["current_gen"] += 1
|
115 |
+
|
116 |
+
# 检查终止条件
|
117 |
+
if state["current_gen"] >= state["params"]["max_gen"]:
|
118 |
+
state["running"] = False
|
119 |
+
return {
|
120 |
+
current_params: "优化完成!",
|
121 |
+
best_output: format_best(state["best_ind"])
|
122 |
+
}
|
123 |
+
|
124 |
+
next_ind = population[state["current_idx"]]
|
125 |
+
return {
|
126 |
+
current_params: f"Kp: {next_ind[0]:.4f}, Ki: {next_ind[1]:.4f}, Kd: {next_ind[2]:.4f}",
|
127 |
+
fitness_input: "",
|
128 |
+
history_output: pd.DataFrame(state["history"]),
|
129 |
+
best_output: format_best(state["best_ind"])
|
130 |
+
}
|
131 |
+
|
132 |
+
|
133 |
+
def evolve_population():
|
134 |
+
params = state["params"]
|
135 |
+
toolbox = state["toolbox"]
|
136 |
+
population = state["population"]
|
137 |
+
|
138 |
+
# 选择
|
139 |
+
offspring = toolbox.select(population, len(population))
|
140 |
+
offspring = list(map(toolbox.clone, offspring))
|
141 |
+
|
142 |
+
# 交叉
|
143 |
+
for child1, child2 in zip(offspring[::2], offspring[1::2]):
|
144 |
+
if random.random() < params["cx_prob"]:
|
145 |
+
toolbox.mate(child1, child2)
|
146 |
+
del child1.fitness.values
|
147 |
+
del child2.fitness.values
|
148 |
+
|
149 |
+
# 变异
|
150 |
+
for mutant in offspring:
|
151 |
+
if random.random() < params["mut_prob"]:
|
152 |
+
toolbox.mutate(mutant)
|
153 |
+
# 参数裁剪
|
154 |
+
mutant[0] = np.clip(mutant[0], *params["kp_range"])
|
155 |
+
mutant[1] = np.clip(mutant[1], *params["ki_range"])
|
156 |
+
mutant[2] = np.clip(mutant[2], *params["kd_range"])
|
157 |
+
del mutant.fitness.values
|
158 |
+
|
159 |
+
state["population"] = offspring
|
160 |
+
|
161 |
+
|
162 |
+
def stop_optimization():
|
163 |
+
state["running"] = False
|
164 |
+
return {
|
165 |
+
current_params: "优化已终止",
|
166 |
+
fitness_input: ""
|
167 |
+
}
|
168 |
+
|
169 |
+
|
170 |
+
def format_best(ind):
|
171 |
+
if ind is None:
|
172 |
+
return "最佳参数:尚未找到"
|
173 |
+
return f"最佳参数:Kp={ind[0]:.4f}, Ki={ind[1]:.4f}, Kd={ind[2]:.4f} 适应度={ind.fitness.values[0]:.4f}"
|
174 |
+
|
175 |
+
|
176 |
+
with gr.Blocks(title="青云调参", css_paths="./style.css") as demo:
|
177 |
+
gr.HTML("<h1 style='text-align: center;'>青云调参</h1><div style='text-align: center;'>适者存千代竞逐,精微处三昧调弦</div>")
|
178 |
+
|
179 |
+
with gr.Row():
|
180 |
+
with gr.Column(scale=1):
|
181 |
+
with gr.Row():
|
182 |
+
start_btn = gr.Button("开始优化", variant="primary")
|
183 |
+
stop_btn = gr.Button("终止优化")
|
184 |
+
|
185 |
+
with gr.Row():
|
186 |
+
kp_min = gr.Number(label="Kp最小值", value=0.0)
|
187 |
+
kp_max = gr.Number(label="Kp最大值", value=10.0)
|
188 |
+
|
189 |
+
with gr.Row():
|
190 |
+
ki_min = gr.Number(label="Ki最小值", value=0.0)
|
191 |
+
ki_max = gr.Number(label="Ki最大值", value=10.0)
|
192 |
+
|
193 |
+
with gr.Row():
|
194 |
+
kd_min = gr.Number(label="Kd最小值", value=0.0)
|
195 |
+
kd_max = gr.Number(label="Kd最大值", value=10.0)
|
196 |
+
|
197 |
+
pop_size = gr.Slider(2, 50, value=5, step=1, label="种群大小")
|
198 |
+
max_gen = gr.Slider(1, 50, value=10, step=1, label="迭代次数")
|
199 |
+
cx_prob = gr.Slider(0.0, 1.0, value=0.7, step=0.05, label="交叉概率")
|
200 |
+
mut_prob = gr.Slider(0.0, 1.0, value=0.2, step=0.05, label="变异概率")
|
201 |
+
|
202 |
+
with gr.Column(scale=2):
|
203 |
+
current_params = gr.Textbox(label="当前参数组合", interactive=False)
|
204 |
+
with gr.Row():
|
205 |
+
fitness_input = gr.Number(label="输入适应度值")
|
206 |
+
submit_btn = gr.Button("提交适应度")
|
207 |
+
|
208 |
+
gr.Markdown("## 最佳参数")
|
209 |
+
best_output = gr.Textbox(label="当前最佳参数", interactive=False)
|
210 |
+
|
211 |
+
gr.Markdown("## 优化历史")
|
212 |
+
history_output = gr.Dataframe(
|
213 |
+
headers=["Kp", "Ki", "Kd", "Fitness"],
|
214 |
+
datatype=["number", "number", "number", "number"],
|
215 |
+
interactive=False
|
216 |
+
)
|
217 |
+
|
218 |
+
start_btn.click(
|
219 |
+
start_optimization,
|
220 |
+
inputs=[kp_min, kp_max, ki_min, ki_max, kd_min, kd_max,
|
221 |
+
pop_size, max_gen, cx_prob, mut_prob],
|
222 |
+
outputs=[current_params, fitness_input, history_output, best_output]
|
223 |
+
)
|
224 |
+
|
225 |
+
submit_btn.click(
|
226 |
+
submit_fitness,
|
227 |
+
inputs=fitness_input,
|
228 |
+
outputs=[current_params, fitness_input, history_output, best_output]
|
229 |
+
)
|
230 |
+
|
231 |
+
stop_btn.click(
|
232 |
+
stop_optimization,
|
233 |
+
outputs=[current_params, fitness_input]
|
234 |
+
)
|
235 |
+
|
236 |
+
if __name__ == "__main__":
|
237 |
+
demo.launch()
|
style.css
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
textarea {
|
2 |
+
font-family: var(--font-mono);
|
3 |
+
}
|
4 |
+
|
5 |
+
footer {
|
6 |
+
display: none !important;
|
7 |
+
}
|