整线优化第一版论文定稿工程

增加了整线批量测试
修改了现有min-max模型路径
修改了遗传算法整体框架
估计器增加异常数据剔除
封装优化结果类
修改供料器扫描算法中重复吸嘴组的判定
This commit is contained in:
2024-06-26 09:44:08 +08:00
parent cbeba48da0
commit 37f4e5b02c
14 changed files with 749 additions and 669 deletions

View File

@ -1,10 +1,58 @@
import copy
import random
from generator import *
from base_optimizer.optimizer_interface import *
def exact_assembly_time(pcb_data, component_data):
component_result, cycle_result, feeder_slot_result = feeder_priority_assignment(component_data, pcb_data,
hinter=False)
placement_result, head_sequence_result = greedy_placement_route_generation(component_data, pcb_data,
component_result, cycle_result,
feeder_slot_result, hinter=False)
opt_res = OptResult(component_result, cycle_result, feeder_slot_result, placement_result, head_sequence_result)
info = placement_info_evaluation(component_data, pcb_data, opt_res)
# return info.metric()
return info.total_time
def error_info(pred_val, real_val, type='train'):
absolute_error = np.array([])
for idx, (t1, t2) in enumerate(np.nditer([pred_val, real_val])):
absolute_error = np.append(absolute_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
if absolute_error[-1] > 15:
print(f'\033[0;31;31midx: {idx + 1: d}, net: {t1: .3f}, real: {t2: .3f}, '
f'gap: {absolute_error[-1]: .3f}\033[0m')
print('')
print(f'mean absolute prediction error for {type} data : {np.average(absolute_error): .2f}% ')
print(f'maximum absolute prediction error for {type} data : {np.max(absolute_error): .2f}% ')
def converter(pcb_data, component_data, assignment):
cp_items = defaultdict(list)
board_width, board_height = pcb_data['x'].max() - pcb_data['x'].min(), pcb_data['y'].max() - pcb_data['y'].min()
_, partial_component_data = convert_line_assigment(None, component_data, assignment)
for machine_index in range(len(assignment)):
cp_item_index = 0
cp_points, cp_nozzle = defaultdict(int), defaultdict(str)
for _, data in partial_component_data[machine_index].iterrows():
feeder_limit, total_points = data.fdn, data.points
surplus_points = total_points % feeder_limit
for _ in range(feeder_limit):
div_points = math.floor(total_points / feeder_limit)
if surplus_points:
div_points += 1
surplus_points -= 1
cp_points[cp_item_index], cp_nozzle[cp_item_index] = div_points, data.nz
cp_item_index += 1
cp_items[machine_index] = [cp_points, cp_nozzle, board_width, board_height]
return cp_items
class Net(torch.nn.Module):
def __init__(self, input_size, hidden_size=1000, output_size=1):
super(Net, self).__init__()
@ -61,7 +109,10 @@ class NeuralEstimator(Estimator):
self.net = Net(input_size=self.data_mgr.get_feature(), output_size=1).to(device)
self.net_file = 'model/net_model.pth'
if os.path.exists(self.net_file):
self.net.load_state_dict(torch.load(self.net_file))
try:
self.net.load_state_dict(torch.load(self.net_file))
except:
warnings.warn('the parameters of neural net model load failed', UserWarning)
def init_weights(self):
for m in self.net.modules():
@ -71,6 +122,7 @@ class NeuralEstimator(Estimator):
def training(self, params):
self.init_weights() # 初始化参数
data = data_mgr.loader('opt/' + params.train_file)
x_train = np.array(data_mgr.neural_encode(data[0][::data_mgr.get_update_round()]))
y_train = np.array(data[1][::data_mgr.get_update_round()])
@ -97,57 +149,23 @@ class NeuralEstimator(Estimator):
net_predict = self.net(x_train).view(-1)
pred_time, real_time = net_predict.cpu().detach().numpy(), y_train.view(-1).cpu().detach().numpy()
error_info(pred_time, real_time)
pred_error = np.array([])
for t1, t2 in np.nditer([pred_time, real_time]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for train data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for train data : {np.max(pred_error): .2f}% ')
mse = np.linalg.norm((net_predict - y_train.view(-1)).cpu().detach().numpy())
print(f'mean square error for training data result : {mse: 2f} ')
if params.save:
if not os.path.exists('model'):
os.mkdir('model')
torch.save(self.net.state_dict(), self.net_file)
# self.net.load_state_dict(torch.load(self.net_file))
def testing(self, params):
data = data_mgr.loader('opt/' + params.test_file)
x_test, y_test = np.array(data_mgr.neural_encode(data[0])), np.array(data[1])
x_test, y_test = np.array(data_mgr.neural_encode(data[0])), np.array(data[1])
x_test = torch.from_numpy(x_test.reshape((-1, np.shape(x_test)[1]))).float().to(device)
self.net.eval()
with torch.no_grad():
pred_time = self.net(x_test).view(-1).cpu().detach().numpy()
# x_test = x_test.cpu().detach().numpy()
over_set = []
pred_idx, pred_error = 0, np.array([])
for t1, t2 in np.nditer([pred_time, y_test.reshape(-1)]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
if pred_error[-1] > 5:
over_set.append(pred_idx + 1)
print(f'\033[0;31;31midx: {pred_idx + 1: d}, net: {t1: .3f}, real: {t2: .3f}, '
f'gap: {pred_error[-1]: .3f}\033[0m')
# else:
# print(f'idx: {pred_idx + 1: d}, net: {t1: .3f}, real: {t2: .3f}, gap: {pred_error[-1]: .3f}')
pred_idx += 1
print('over:', over_set)
print('size:', len(over_set))
print('--------------------------------------')
print(f'average prediction error for test data : {np.average(pred_error): .3f}% ')
print(f'maximum prediction error for test data : {np.max(pred_error): .3f}% ')
mse = np.linalg.norm(pred_time - y_test.reshape(-1))
print(f'mean square error for test data result : {mse: 2f} ')
error_info(pred_time, y_test.reshape(-1), 'test')
def predict(self, cp_points, cp_nozzle, board_width=None, board_height=None):
assert board_width is not None and board_height is not None
@ -179,13 +197,7 @@ class HeuristicEstimator(Estimator):
pickle.dump(self.lr, f)
y_predict = self.lr.predict(x_fit)
pred_error = np.array([])
for t1, t2 in np.nditer([y_fit, y_predict]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for train data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for train data : {np.max(pred_error): .2f}% ')
error_info(y_fit, y_predict)
def testing(self, params):
data = data_mgr.loader('opt/' + params.test_file)
@ -193,13 +205,7 @@ class HeuristicEstimator(Estimator):
y_fit = np.array([data[1]]).T
y_predict = self.lr.predict(x_fit)
pred_error = np.array([])
for t1, t2 in np.nditer([y_fit, y_predict]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for test data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for test data : {np.max(pred_error): .2f}% ')
error_info(y_fit, y_predict, 'test')
def predict(self, cp_points, cp_nozzle, board_width=None, board_height=None):
return self.lr.predict(np.array(self.heuristic_genetic(cp_points, cp_nozzle)).reshape(1, -1))
@ -288,12 +294,12 @@ class HeuristicEstimator(Estimator):
return [nl, wl, ul]
class RegressionEstimator(Estimator):
class ReconfigEstimator(Estimator):
def __init__(self):
super().__init__()
self.lr = LinearRegression()
self.pickle_file = 'model/params_lr_model.pkl'
self.pickle_file = 'model/reconfig_model.pkl'
if os.path.exists(self.pickle_file):
with open(self.pickle_file, 'rb') as f:
self.lr = pickle.load(f)
@ -311,13 +317,7 @@ class RegressionEstimator(Estimator):
pickle.dump(self.lr, f)
y_predict = self.lr.predict(x_fit)
pred_error = np.array([])
for t1, t2 in np.nditer([y_fit, y_predict]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for train data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for train data : {np.max(pred_error): .2f}% ')
error_info(y_fit, y_predict)
def testing(self, params):
data = data_mgr.loader('opt/' + params.test_file)
@ -325,19 +325,15 @@ class RegressionEstimator(Estimator):
y_fit = np.array([data[1]]).T
y_predict = self.lr.predict(x_fit)
pred_error = np.array([])
for t1, t2 in np.nditer([y_fit, y_predict]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for test data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for test data : {np.max(pred_error): .2f}% ')
error_info(y_fit, y_predict, 'test')
def predict(self, cp_points, cp_nozzle, board_width=None, board_height=None):
return self.lr.predict(np.array(self.heuristic_reconfig(cp_points, cp_nozzle)).reshape(1, -1))
return self.lr.predict(np.array(self.heuristic_reconfig(cp_points, cp_nozzle)).reshape(1, -1))[0, 0]
def heuristic_reconfig(self, cp_points, cp_nozzle):
task_block_number, total_point_number = 0, sum(cp_points.values())
if total_point_number == 0:
return [total_point_number, task_block_number]
nozzle_points, nozzle_heads = defaultdict(int), defaultdict(int)
for part, points in cp_points.items():
@ -437,13 +433,7 @@ class SVREstimator(Estimator):
input = [[np.average(predict_y[i:i + self.num_folds])] for i in range(len(predict_y) // self.num_folds)]
predict_val = self.svr_list[-1].predict(input)
pred_error = np.array([])
for t1, t2 in np.nditer([data[1], predict_val]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for train data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for train data : {np.max(pred_error): .2f}% ')
error_info(data[1], predict_val)
def sos_svr_training(self, x_train, y_train):
population = []
@ -533,14 +523,7 @@ class SVREstimator(Estimator):
input = [[np.average(predict_y[i:i + self.num_folds])] for i in range(len(predict_y) // self.num_folds)]
predict_val = self.svr_list[-1].predict(input)
pred_error = np.array([])
for t1, t2 in np.nditer([data[1], predict_val]):
pred_error = np.append(pred_error, abs(t1 - t2) / (t2 + 1e-10) * 100)
print('--------------------------------------')
print(f'average prediction error for test data : {np.average(pred_error): .2f}% ')
print(f'maximum prediction error for test data : {np.max(pred_error): .2f}% ')
error_info(data[1], predict_val, 'test')
def predict(self, cp_points, cp_nozzle, board_width=None, board_height=None):
pass
@ -564,18 +547,29 @@ class SVREstimator(Estimator):
return np.average(pred_error)
def exact_assembly_time(pcb_data, component_data):
component_result, cycle_result, feeder_slot_result = feeder_priority_assignment(component_data, pcb_data,
hinter=False)
placement_result, head_sequence_result = greedy_placement_route_generation(component_data, pcb_data,
component_result, cycle_result,
feeder_slot_result, hinter=False)
info = placement_info_evaluation(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
placement_result, head_sequence_result)
# regression_info = [[info.cycle_counter, info.nozzle_change_counter, info.anc_round_counter,
# info.pickup_counter, info.total_points]]
# return self.lr.predict(regression_info)[0, 0]
return info.total_time
class MetricEstimator(Estimator):
def __init__(self):
super().__init__()
self.lr = LinearRegression()
self.pickle_file = 'model/metric_model.pkl'
if os.path.exists(self.pickle_file):
with open(self.pickle_file, 'rb') as f:
self.lr = pickle.load(f)
def training(self, params):
x_fit, y_fit = data_mgr.metric('opt/' + params.train_file)
self.lr.fit(x_fit, y_fit)
print(self.lr.coef_)
def testing(self, params):
x_fit, y_fit = data_mgr.metric('opt/' + params.test_file)
y_predict = self.lr.predict(x_fit)
error_info(y_fit, y_predict, 'test')
def predict(self, cp_points, cp_nozzle, board_width=None, board_height=None):
pass
if __name__ == '__main__':
@ -587,13 +581,13 @@ if __name__ == '__main__':
help='determine whether saving the parameters of network, linear regression model, etc.')
parser.add_argument('--overwrite', default=False, type=bool,
help='determine whether overwriting the training and testing data')
parser.add_argument('--train_file', default='train_data - bp.txt', type=str, help='training file path')
parser.add_argument('--test_file', default='test_data - bp.txt', type=str, help='testing file path')
parser.add_argument('--num_epochs', default=10000, type=int, help='number of epochs for training process')
parser.add_argument('--batch_size', default=1000, type=int, help='size of training batch')
parser.add_argument('--train_file', default='train_data.txt', type=str, help='training file path')
parser.add_argument('--test_file', default='test_data.txt', type=str, help='testing file path')
parser.add_argument('--num_epochs', default=8000, type=int, help='number of epochs for training process')
parser.add_argument('--batch_size', default=2000, type=int, help='size of training batch')
parser.add_argument('--lr', default=1e-5, type=float, help='learning rate for the network')
parser.add_argument('--model', default='neural-network', help='method for assembly time estimation')
parser.add_argument('--machine_optimizer', default='feeder-scan', type=str, help='optimizer for single machine')
params = parser.parse_args()
data_mgr = DataMgr()
@ -611,14 +605,13 @@ if __name__ == '__main__':
# data_mgr.remover() # remove the last saved data
# data_mgr.saver('data/' + file_name, pcb_data) # save new data
info = base_optimizer(1, pcb_data, component_data,
feeder_data=pd.DataFrame(columns=['slot', 'part', 'arg']),
method='feeder-scan', hinter=True)
info = base_optimizer(1, pcb_data, component_data, pd.DataFrame(columns=['slot', 'part', 'arg']),
params, hinter=True)
data_mgr.recorder(f, info, pcb_data, component_data)
f.close()
estimator = NeuralEstimator()
estimator = MetricEstimator()
estimator.training(params)
estimator.testing(params)