-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpytorch_agentic_supply_chain_optimization.py
314 lines (276 loc) · 12.4 KB
/
pytorch_agentic_supply_chain_optimization.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import numpy as np
# Define the SupplyChainAgent class to represent individual supply chain agents
class SupplyChainAgent:
def __init__(self, agent_id, role, decision_model):
self.agent_id = agent_id
self.role = role
self.decision_model = decision_model
self.observations = []
self.actions = []
def observe(self, environment):
# Collect observations from the agent's perspective (simulated)
observation = self.simulate_observation(environment)
self.observations.append(observation)
def simulate_observation(self, environment):
# Simulate the observation process (simulated)
if self.role == 'supplier':
observation = {
'inventory_level': environment.get_inventory_level(),
'demand_forecast': environment.get_demand_forecast(),
'lead_time': environment.get_lead_time()
}
elif self.role == 'manufacturer':
observation = {
'inventory_level': environment.get_inventory_level(),
'production_capacity': environment.get_production_capacity(),
'order_quantity': environment.get_order_quantity()
}
elif self.role == 'distributor':
observation = {
'inventory_level': environment.get_inventory_level(),
'order_quantity': environment.get_order_quantity(),
'transportation_cost': environment.get_transportation_cost()
}
return observation
def decide(self):
# Make a decision based on the observations and the decision model
observation = self.observations[-1]
action = self.decision_model.predict(observation)
self.actions.append(action)
def act(self, environment):
# Execute the decided action (simulated)
action = self.actions[-1]
if self.role == 'supplier':
if action == 'increase_inventory':
environment.increase_inventory()
elif action == 'decrease_inventory':
environment.decrease_inventory()
elif self.role == 'manufacturer':
if action == 'increase_production':
environment.increase_production()
elif action == 'decrease_production':
environment.decrease_production()
elif self.role == 'distributor':
if action == 'increase_order':
environment.increase_order()
elif action == 'decrease_order':
environment.decrease_order()
# Define the DecisionModel class to represent the decision-making model
class DecisionModel(nn.Module):
def __init__(self, input_size, output_size):
super(DecisionModel, self).__init__()
self.fc1 = nn.Linear(input_size, 64)
self.fc2 = nn.Linear(64, 32)
self.fc3 = nn.Linear(32, output_size)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
def predict(self, observation):
# Preprocess the observation data
input_data = self.preprocess_observation(observation)
# Convert the input data to a PyTorch tensor
input_tensor = torch.tensor(input_data, dtype=torch.float32)
# Make a prediction using the trained model
with torch.no_grad():
output_tensor = self.forward(input_tensor)
action_index = torch.argmax(output_tensor).item()
# Map the action index to a specific action
action = self.index_to_action(action_index)
return action
def preprocess_observation(self, observation):
# Preprocess the observation data
input_data = list(observation.values())
return input_data
def index_to_action(self, index):
# Map the action index to a specific action based on the agent's role
if self.role == 'supplier':
actions = ['increase_inventory', 'decrease_inventory']
elif self.role == 'manufacturer':
actions = ['increase_production', 'decrease_production']
elif self.role == 'distributor':
actions = ['increase_order', 'decrease_order']
return actions[index]
# Define the SupplyChainEnvironment class to represent the supply chain environment
class SupplyChainEnvironment:
def __init__(self, num_agents, num_timesteps):
self.num_agents = num_agents
self.num_timesteps = num_timesteps
self.agents = self.deploy_agents()
self.inventory_level = 100
self.production_capacity = 50
self.order_quantity = 30
self.transportation_cost = 0.1
def deploy_agents(self):
# Deploy supply chain agents with different roles and decision models
agents = []
for i in range(self.num_agents):
if i % 3 == 0:
role = 'supplier'
input_size = 3
elif i % 3 == 1:
role = 'manufacturer'
input_size = 3
else:
role = 'distributor'
input_size = 3
decision_model = DecisionModel(input_size=input_size, output_size=2)
agent = SupplyChainAgent(i, role, decision_model)
agents.append(agent)
return agents
def get_inventory_level(self):
# Get the current inventory level
return self.inventory_level
def get_demand_forecast(self):
# Simulate demand forecast (replace with actual data if available)
return np.random.randint(80, 121)
def get_lead_time(self):
# Simulate lead time (replace with actual data if available)
return np.random.randint(1, 8)
def get_production_capacity(self):
# Get the current production capacity
return self.production_capacity
def get_order_quantity(self):
# Get the current order quantity
return self.order_quantity
def get_transportation_cost(self):
# Get the current transportation cost
return self.transportation_cost
def increase_inventory(self):
# Simulate increasing inventory
self.inventory_level += 10
def decrease_inventory(self):
# Simulate decreasing inventory
self.inventory_level = max(0, self.inventory_level - 10)
def increase_production(self):
# Simulate increasing production
self.production_capacity += 5
def decrease_production(self):
# Simulate decreasing production
self.production_capacity = max(0, self.production_capacity - 5)
def increase_order(self):
# Simulate increasing order quantity
self.order_quantity += 5
def decrease_order(self):
# Simulate decreasing order quantity
self.order_quantity = max(0, self.order_quantity - 5)
def step(self):
# Perform one step of the supply chain optimization process
for agent in self.agents:
agent.observe(self)
agent.decide()
agent.act(self)
def train_decision_models(self, num_epochs):
# Train the decision models of the agents using simulated data
for epoch in range(num_epochs):
for agent in self.agents:
# Simulate training data (replace with actual data if available)
training_data = self.simulate_training_data(agent.role)
# Train the decision model
self.train_model(agent.decision_model, training_data)
def simulate_training_data(self, role):
# Simulate training data for decision models (replace with actual data if available)
# This is just a placeholder example
if role == 'supplier':
training_data = {
'inputs': [
[100, 110, 3],
[80, 90, 5],
[120, 130, 2]
],
'outputs': [
[1, 0],
[0, 1],
[1, 0]
]
}
elif role == 'manufacturer':
training_data = {
'inputs': [
[100, 50, 30],
[90, 60, 25],
[110, 40, 35]
],
'outputs': [
[1, 0],
[0, 1],
[1, 0]
]
}
elif role == 'distributor':
training_data = {
'inputs': [
[100, 30, 0.1],
[90, 35, 0.15],
[110, 25, 0.08]
],
'outputs': [
[1, 0],
[0, 1],
[1, 0]
]
}
return training_data
def train_model(self, model, training_data):
# Train the decision model using the training data
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
inputs = torch.tensor(training_data['inputs'], dtype=torch.float32)
outputs = torch.tensor(training_data['outputs'], dtype=torch.long)
for _ in range(100): # Adjust the number of training iterations as needed
optimizer.zero_grad()
predicted_outputs = model(inputs)
loss = criterion(predicted_outputs, torch.argmax(outputs, dim=1))
loss.backward()
optimizer.step()
def run_simulation(self):
# Run the supply chain optimization simulation for the specified number of timesteps
for t in range(self.num_timesteps):
print(f"Timestep {t + 1}:")
self.step()
print()
# Set the random seed for reproducibility
torch.manual_seed(42)
np.random.seed(42)
# Define the simulation parameters
num_agents = 9
num_timesteps = 10
num_training_epochs = 10
# Create an instance of the SupplyChainEnvironment
env = SupplyChainEnvironment(num_agents, num_timesteps)
# Train the decision models of the agents
env.train_decision_models(num_training_epochs)
# Run the supply chain optimization simulation
env.run_simulation()
# Possible Errors and Solutions:
# 1. Error: No module named 'torch'
# Solution: Make sure you have PyTorch installed. You can install it using pip: `pip install torch`.
#
# 2. Error: ValueError: too many dimensions
# Solution: This error can occur if the input data passed to the decision model is not in the expected format.
# Make sure that the input data is properly preprocessed and has the correct dimensions.
# Check the `preprocess_observation` method and ensure that it returns a list of numerical values.
#
# 3. Error: RuntimeError: expected scalar type Float but found Double
# Solution: This error can happen if the data types of tensors are inconsistent.
# Make sure that all tensors have the same data type (e.g., float32).
# Use `dtype=torch.float32` when creating tensors to ensure consistency.
#
# 4. Error: Inefficient or suboptimal supply chain decisions
# Solution: If the supply chain agents are making inefficient or suboptimal decisions, consider the following:
# - Review the decision model architecture and hyperparameters to ensure they are suitable for the task.
# - Increase the complexity of the decision model or use a different neural network architecture.
# - Incorporate more advanced techniques such as reinforcement learning or optimization algorithms.
# - Gather more diverse and representative training data to improve the decision models' performance.
# - Implement mechanisms for agents to share information and coordinate their actions effectively.
# Note: The code provided here is a simplified simulation and may not cover all the complexities of real-world supply chain optimization.
# In practice, you would need to integrate with the actual supply chain systems, data sources, and business processes
# to deploy the multi-agent system effectively. The simulation can be extended to incorporate more realistic supply chain
# dynamics, constraints, and performance metrics based on the specific industry and scenario.
# The training data for the decision models would typically be obtained from historical supply chain data, demand forecasts,
# and domain expertise, depending on the availability and relevance of the data.