Skip to content

Commit 68ed03e

Browse files
committed
Simpler GNN and graph + better multi-stage fine tuning
1 parent d6feb8f commit 68ed03e

9 files changed

+350
-244
lines changed

debug/debug_gns.py

-48
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,6 @@
77
__version__ = "1.0.0"
88
__license__ = "Apache 2.0 License"
99

10-
def check_completeness(graph: GraphInstance, debug_print: Callable):
11-
NOT_YET = -1
12-
for item_id in graph.loop_items():
13-
outsourced = graph.item(item_id, 'outsourced')
14-
e = graph.items_g2i[item_id]
15-
if graph.item(item_id, 'remaining_physical_time')>0:
16-
debug_print(f"PROBLEM ITEM {e} [outsourced={outsourced}] STILL HAS {graph.item(item_id, 'remaining_physical_time')} OF PHYSICAL TIME TO DO!")
17-
if graph.item(item_id, 'remaining_design_time')>0:
18-
debug_print(f"PROBLEM ITEM {e} [outsourced={outsourced}] STILL HAS {graph.item(item_id, 'remaining_design_time')} OF DESIGN TIME TO DO!")
19-
if graph.item(item_id, 'outsourced')==NOT_YET:
20-
debug_print(f"PROBLEM ITEM {e} [outsourced={outsourced}] STILL NO OUTSOURCING DECISIONS!")
21-
if graph.item(item_id, 'is_possible')==NOT_YET:
22-
debug_print(f"PROBLEM ITEM {e} [outsourced={outsourced}] STILL NOT POSSIBLE!")
23-
for material_id in graph.loop_materials():
24-
m = graph.materials_g2i[material_id]
25-
if graph.material(material_id, 'remaining_demand')>0:
26-
debug_print(f"PROBLEM MATERIAL {m} STILL HAS {graph.material(material_id, 'remaining_demand')} OF REMAINING DEMAND!")
27-
for resource_id in graph.loop_resources():
28-
r = graph.resources_g2i[resource_id]
29-
if graph.resource(resource_id, 'remaining_operations')>0:
30-
debug_print(f"PROBLEM RESOURCE {r} STILL HAS {graph.resource(resource_id, 'remaining_operations')} OF REMAINING OPERATION!")
31-
need_for_mat_idx, _, loop_mat = graph.loop_need_for_material()
32-
for i in loop_mat:
33-
operation_id = need_for_mat_idx[0, i]
34-
material_id = need_for_mat_idx[1, i]
35-
p, o = graph.operations_g2i[operation_id]
36-
m = graph.materials_g2i[material_id]
37-
if graph.need_for_material(operation_id, material_id, 'status') == NOT_YET:
38-
debug_print(f"PROBLEM NEED OF MATERIAL op=({p},{o}), mat={m} STATUS STILL NO YET!")
39-
need_for_res_idx, _, loop_res = graph.loop_need_for_resource()
40-
for i in loop_res:
41-
operation_id = need_for_res_idx[0, i]
42-
resource_id = need_for_res_idx[1, i]
43-
p, o = graph.operations_g2i[operation_id]
44-
r = graph.resources_g2i[resource_id]
45-
if graph.need_for_resource(operation_id, resource_id, 'status') == NOT_YET:
46-
debug_print(f"PROBLEM NEED OF RESOURCE op=({p},{o}), res={r} STATUS STILL NO YET!")
47-
for operation_id in graph.loop_operations():
48-
p, o = graph.operations_g2i[operation_id]
49-
if graph.operation(operation_id, 'is_possible')==NOT_YET:
50-
debug_print(f"PROBLEM OPERATION ({p},{o}) STILL NOT POSSIBLE!")
51-
if graph.operation(operation_id, 'remaining_resources')>0:
52-
debug_print(f"PROBLEM OPERATION ({p},{o}) STILL {graph.operation(operation_id, 'remaining_resources')} REMAINING RESOURCES!")
53-
if graph.operation(operation_id, 'remaining_materials')>0:
54-
debug_print(f"PROBLEM OPERATION ({p},{o}) STILL {graph.operation(operation_id, 'remaining_materials')} REMAINING MATERIALS!")
55-
if graph.operation(operation_id, 'remaining_time')>0:
56-
debug_print(f"PROBLEM OPERATION ({p},{o}) STILL {graph.operation(operation_id, 'remaining_time')} REMAINING TIME!")
57-
5810
def debug_printer(mode):
5911
if mode:
6012
def debug_print(*args):

gns_solver.py

+18-27
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from torch.nn import Module
1414
from translators.instance2graph_translator import translate
1515
from translators.graph2solution_translator import translate_solution
16-
from debug.debug_gns import check_completeness, debug_printer
16+
from debug.debug_gns import debug_printer
1717
from multi_stage_pre_training import multi_stage_pre_train, load_training_dataset
1818
from model.agent import MultiAgent_OneInstance
1919
import pickle
@@ -35,12 +35,12 @@
3535
AGENT = 0
3636
SOLVING_REPETITIONS = 10
3737
GNN_CONF = {
38-
'resource_and_material_embedding_size': 16,
39-
'operation_and_item_embedding_size': 24,
38+
'resource_and_material_embedding_size': 12,
39+
'operation_and_item_embedding_size': 12,
4040
'nb_layers': 2,
41-
'embedding_hidden_channels': 128,
42-
'value_hidden_channels': 256,
43-
'actor_hidden_channels': 256}
41+
'embedding_hidden_channels': 64,
42+
'value_hidden_channels': 128,
43+
'actor_hidden_channels': 128}
4444
small_steps: float = 0.85
4545
big_steps: float = 0.15
4646

@@ -50,12 +50,12 @@
5050

5151
def reccursive_outourcing_actions(instance: Instance, graph: GraphInstance, item_id: int):
5252
actions = []
53-
external = graph.item(item_id, 'external')
53+
p, e = graph.items_g2i[item_id]
54+
external: bool = instance.external[p][e]
5455
decision_made = graph.item(item_id, 'outsourced')
5556
available = graph.item(item_id, 'is_possible')
5657
if available==YES:
57-
if external==YES and decision_made==NOT_YET:
58-
p, e = graph.items_g2i[item_id]
58+
if external and decision_made==NOT_YET:
5959
need_to_be_outsourced = False
6060
for o in instance.loop_item_operations(p,e):
6161
for rt in instance.required_rt(p, o):
@@ -68,7 +68,7 @@ def reccursive_outourcing_actions(instance: Instance, graph: GraphInstance, item
6868
actions.append((item_id, YES))
6969
else:
7070
actions.extend([(item_id, YES), (item_id, NO)])
71-
elif external==NO or decision_made==NO:
71+
elif not external or decision_made==NO:
7272
for child in graph.get_direct_children(instance, item_id):
7373
actions.extend(reccursive_outourcing_actions(instance, graph, child))
7474
return actions
@@ -89,7 +89,7 @@ def get_scheduling_and_material_use_actions(instance: Instance, graph: GraphInst
8989
item_id = graph.items_i2g[p][e]
9090
timescale = 60*instance.H if instance.in_days[p][o] else 60 if instance.in_hours[p][o] else 1
9191
if graph.item(item_id, 'is_possible')==YES \
92-
and (graph.item(item_id, 'external')==NO or graph.item(item_id, 'outsourced')==NO) \
92+
and graph.item(item_id, 'outsourced')==NO \
9393
and graph.operation(operation_id, 'is_possible') == YES \
9494
and graph.operation(operation_id, 'available_time') <= current_time \
9595
and current_time % timescale == 0:
@@ -250,12 +250,10 @@ def outsource_item(graph: GraphInstance, instance: Instance, item_id: int, t: in
250250
graph.update_item(item_id, [
251251
('outsourced', YES),
252252
('is_possible', YES),
253-
('remaining_physical_time', 0),
254-
('remaining_design_time', 0),
253+
('remaining_time', 0),
255254
('children_time', 0),
256255
('start_time', outsourcing_start_time),
257256
('end_time', end_date)])
258-
graph.executed_items += 1
259257
graph.oustourced_items += 1
260258
for o in instance.loop_item_operations(p,e):
261259
op_id = graph.operations_i2g[p][o]
@@ -354,7 +352,7 @@ def schedule_operation(graph: GraphInstance, instance: Instance, operation_id: i
354352
rt = instance.get_resource_familly(r)
355353
estimated_processing_time = instance.operation_resource_time(p, o, rt, max_load=True)
356354
item_id = graph.items_i2g[p][e]
357-
graph.inc_resource(resource_id, [('executed_operations', 1), ('remaining_operations', -1)])
355+
graph.inc_resource(resource_id, [('remaining_operations', -1)])
358356
graph.update_resource(resource_id, [('available_time', operation_end)])
359357
graph.update_need_for_resource(operation_id, resource_id, [
360358
('status', YES),
@@ -379,14 +377,11 @@ def schedule_operation(graph: GraphInstance, instance: Instance, operation_id: i
379377
graph, _max_next_operation_end = shift_next_operations(graph, instance, p, e, o, shift)
380378
_end_of_item = max(_max_next_operation_end, operation_end)
381379
graph.update_item(item_id, [('start_time', current_time)], minn=True)
380+
graph.inc_item(item_id, [('remaining_time', -estimated_processing_time)])
382381
if instance.is_design[p][o]:
383-
graph.inc_item(item_id, [('remaining_design_time', -estimated_processing_time)])
384382
graph, _max_end_of_children = shift_children_and_operations(graph, instance, p, e, shift)
385383
_end_of_item = max(_end_of_item, _max_end_of_children)
386384
else:
387-
graph.inc_item(item_id, [('remaining_physical_time', -estimated_processing_time)])
388-
if graph.item(item_id, 'remaining_physical_time')<= 0:
389-
graph.executed_items += 1
390385
for child in instance.get_children(p, e, direct=False):
391386
graph.inc_item(graph.items_i2g[p][child], [('parents_physical_time', -estimated_processing_time)])
392387
graph.update_item(item_id, [('end_time', _end_of_item)], maxx=True)
@@ -482,10 +477,11 @@ def policy(probabilities: Tensor, greedy: bool=True):
482477
def update_processing_time(instance: Instance, graph: GraphInstance, op_id: int, res_id: int):
483478
p, o = graph.operations_g2i[op_id]
484479
r = graph.resources_g2i[res_id]
480+
basic_processing_time = instance.execution_time[r][p][o]
485481
op_setup_time = 0 if (instance.get_operation_type(p, o) == graph.current_operation_type[res_id] or graph.current_operation_type[res_id]<0) else instance.operation_setup[r]
486482
for d in range(instance.nb_settings):
487483
op_setup_time += 0 if (graph.current_design_value[res_id][d] == instance.design_value[p][o][d] or graph.current_design_value[res_id][d]<0) else instance.design_setup[r][d]
488-
return graph.need_for_resource(op_id, res_id, 'basic_processing_time') + op_setup_time
484+
return basic_processing_time + op_setup_time
489485

490486
def next_possible_time(instance: Instance, current_time: int, p: int, o: int):
491487
scale = 60*instance.H if instance.in_days[p][o] else 60 if instance.in_hours[p][o] else 1
@@ -532,21 +528,16 @@ def manage_queue_of_possible_actions(instance: Instance, graph: GraphInstance, u
532528
DEBUG_PRINT(f"New current time t={t}...")
533529
return graph, utilization, t, False
534530
else:
535-
if debug_mode:
536-
DEBUG_PRINT("End of solving stage!")
537-
check_completeness(graph, DEBUG_PRINT)
538531
return graph, utilization, t, True
539532

540533
def reward(init_cmax: int, init_cost: int, makespan_old: int, makespan_new: int, last_op_old: int, last_op_new: int, cost_old: int=-1, cost_new: int=-1, a: float=-1, use_cost: bool=False):
541534
"""
542535
Compute the reward for each decision
543536
"""
544-
_r = None
545537
if use_cost:
546-
_r = a * (big_steps * (makespan_old - makespan_new) + small_steps * (last_op_old - last_op_new)) + (1-a) * (cost_old - cost_new)
538+
return a * (big_steps * (makespan_old - makespan_new) + small_steps * (last_op_old - last_op_new)) + (1-a) * (cost_old - cost_new)
547539
else:
548-
_r = a * (big_steps * makespan_old - makespan_new + small_steps * (last_op_old - last_op_new))
549-
return _r / (a*init_cmax + (1-a)*init_cost)
540+
return a * (big_steps * makespan_old - makespan_new + small_steps * (last_op_old - last_op_new))
550541

551542
def solve_one(instance: Instance, agents: list[(Module, str)], trainable: list, train: bool, device: str, debug_mode: bool, greedy: bool = False):
552543
graph, current_cmax, current_cost, previous_operations, next_operations, related_items, parent_items = translate(i=instance, device=device)

model/gnn.py

+25-37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import torch
22
from torch_geometric.data.storage import EdgeStorage
3-
from torch.nn import Sequential, Linear, ELU, Tanh, Parameter, LeakyReLU, Module, ModuleList
3+
from torch.nn import Sequential, Linear, ReLU, Tanh, Parameter, LeakyReLU, Module, ModuleList
44
import torch.nn.functional as F
55
from torch import Tensor
66
from .graph import FeatureConfiguration, State
@@ -13,8 +13,6 @@
1313
__version__ = "1.0.0"
1414
__license__ = "Apache 2.0 License"
1515

16-
STATE_VECTOR_SIZE = {"decoded": 10, "hidden_1": 32, "hidden_2": 16, "encoded": 8}
17-
1816
class MaterialEmbeddingLayer(Module):
1917
def __init__(self, material_dimension: int, operation_dimension: int, embedding_dimension: int):
2018
super(MaterialEmbeddingLayer, self).__init__()
@@ -107,29 +105,25 @@ def __init__(self, operation_dimension: int, item_dimension: int, hidden_channel
107105
first_dimension = hidden_channels
108106
second_dimension = int(hidden_channels/2)
109107
self.mlp_combined = Sequential(
110-
Linear(4 * out_channels, first_dimension), ELU(),
111-
Linear(first_dimension, second_dimension), ELU(),
108+
Linear(4 * out_channels, first_dimension), ReLU(),
109+
Linear(first_dimension, second_dimension), ReLU(),
112110
Linear(second_dimension, out_channels)
113111
)
114112
self.mlp_operations = Sequential(
115-
Linear(operation_dimension, first_dimension), ELU(),
116-
Linear(first_dimension, second_dimension), ELU(),
117-
Linear(second_dimension, out_channels)
113+
Linear(operation_dimension, first_dimension), ReLU(),
114+
Linear(first_dimension, out_channels)
118115
)
119116
self.mlp_parent = Sequential(
120-
Linear(item_dimension, first_dimension), ELU(),
121-
Linear(first_dimension, second_dimension), ELU(),
122-
Linear(second_dimension, out_channels)
117+
Linear(item_dimension, first_dimension), ReLU(),
118+
Linear(first_dimension, out_channels)
123119
)
124120
self.mlp_children = Sequential(
125-
Linear(item_dimension, first_dimension), ELU(),
126-
Linear(first_dimension, second_dimension), ELU(),
127-
Linear(second_dimension, out_channels)
121+
Linear(item_dimension, first_dimension), ReLU(),
122+
Linear(first_dimension, out_channels)
128123
)
129124
self.mlp_self = Sequential(
130-
Linear(item_dimension, first_dimension), ELU(),
131-
Linear(first_dimension, second_dimension), ELU(),
132-
Linear(second_dimension, out_channels)
125+
Linear(item_dimension, first_dimension), ReLU(),
126+
Linear(first_dimension, out_channels)
133127
)
134128

135129
def forward(self, items: Tensor, parents: Tensor, operations: Tensor, item_assembly: EdgeStorage, operation_assembly: EdgeStorage):
@@ -157,39 +151,33 @@ def __init__(self, operation_dimension: int, item_dimension: int, resources_dime
157151
first_dimension = hidden_channels
158152
second_dimension = int(hidden_channels/2)
159153
self.mlp_combined = Sequential(
160-
Linear(4 * out_channels + resources_dimension + material_dimension, first_dimension), ELU(),
161-
Linear(first_dimension, second_dimension), ELU(),
154+
Linear(4 * out_channels + resources_dimension + material_dimension, first_dimension), ReLU(),
155+
Linear(first_dimension, second_dimension), ReLU(),
162156
Linear(second_dimension, out_channels)
163157
)
164158
self.mlp_items = Sequential(
165-
Linear(item_dimension, first_dimension), ELU(),
166-
Linear(first_dimension, second_dimension), ELU(),
167-
Linear(second_dimension, out_channels)
159+
Linear(item_dimension, first_dimension), ReLU(),
160+
Linear(first_dimension, out_channels)
168161
)
169162
self.mlp_predecessors = Sequential(
170-
Linear(operation_dimension, first_dimension), ELU(),
171-
Linear(first_dimension, second_dimension), ELU(),
172-
Linear(second_dimension, out_channels)
163+
Linear(operation_dimension, first_dimension), ReLU(),
164+
Linear(first_dimension, out_channels)
173165
)
174166
self.mlp_successors = Sequential(
175-
Linear(operation_dimension, first_dimension), ELU(),
176-
Linear(first_dimension, second_dimension), ELU(),
177-
Linear(second_dimension, out_channels)
167+
Linear(operation_dimension, first_dimension), ReLU(),
168+
Linear(first_dimension, out_channels)
178169
)
179170
self.mlp_resources = Sequential(
180-
Linear(resources_dimension, first_dimension), ELU(),
181-
Linear(first_dimension, second_dimension), ELU(),
182-
Linear(second_dimension, resources_dimension)
171+
Linear(resources_dimension, first_dimension), ReLU(),
172+
Linear(first_dimension, resources_dimension)
183173
)
184174
self.mlp_materials = Sequential(
185-
Linear(material_dimension, first_dimension), ELU(),
186-
Linear(first_dimension, second_dimension), ELU(),
187-
Linear(second_dimension, material_dimension)
175+
Linear(material_dimension, first_dimension), ReLU(),
176+
Linear(first_dimension, material_dimension)
188177
)
189178
self.mlp_self = Sequential(
190-
Linear(operation_dimension, first_dimension), ELU(),
191-
Linear(first_dimension, second_dimension), ELU(),
192-
Linear(second_dimension, out_channels)
179+
Linear(operation_dimension, first_dimension), ReLU(),
180+
Linear(first_dimension, out_channels)
193181
)
194182

195183
def forward(self, operations: Tensor, items: Tensor, related_items: Tensor, materials: Tensor, resources: Tensor, need_for_resources: EdgeStorage, need_for_materials: EdgeStorage, precedences: EdgeStorage):

0 commit comments

Comments
 (0)