import pickle import torch import torch.nn as nn import numpy as np import pandas as pd from matplotlib import pyplot as plt from torch.utils.data import Dataset, DataLoader import net_BNN import gradio as gr from gradio.components import * # 使用已训练的模型进行推理 class SingleDataset(Dataset): def __init__(self, data, attrib_x, attrib_y, max_len, C_rated, min_val=None, max_val=None, mode='train'): self.data = data self.cycle_indices = data['Cycle_Index'].unique() self.attrib_x = attrib_x self.attrib_y = attrib_y self.C_rated = C_rated self.mode = mode self.max_len = max_len self.data['Current'] /= self.C_rated if mode == 'train': self.min_val = data[attrib_x].values.min(axis=0) self.max_val = data[attrib_x].values.max(axis=0) with open('./para_BNN/min_max_values.pkl', 'wb') as f: pickle.dump((self.min_val, self.max_val), f) else: self.min_val = min_val self.max_val = max_val def get_min_max_values(self): if self.mode != 'train': return None return self.min_val, self.max_val def __len__(self): return len(self.cycle_indices) def get_data_by_cycle_index(self, cycle_index): # 获取指定 cycle_index 的数据 cycle_data = self.data[self.data['Cycle_Index'] == cycle_index].copy() # 提取特征和标签 features = cycle_data[self.attrib_x].values label = cycle_data[self.attrib_y].values[0] # 标准化特征 features = (features - self.min_val) / (self.max_val - self.min_val) pad_len = self.max_len - len(features) features = torch.tensor(features, dtype=torch.float32).clone().detach() features = torch.cat([features, torch.full((pad_len, features.shape[1]), 0)]) label = torch.tensor(label, dtype=torch.float32) return features, label def __getitem__(self, index): cycle_index = self.cycle_indices[index] cycle_data = self.data[self.data['Cycle_Index'] == cycle_index].copy() # cycle_data['Current'] /= self.C_rated # 提取特征和标签 features = cycle_data[self.attrib_x].values # C_ini = cycle_data[self.attrib_y].values[0] label = cycle_data[self.attrib_y].values[0] # # 标准化特征 features = (features - self.min_val) / (self.max_val - self.min_val) # label = (label - self.y_mean) / self.y_std # features = (features - self.min_val) / self.max_val pad_len = self.max_len - len(features) features = torch.tensor(features, dtype=torch.float32).clone().detach() # 在 features 后面填充固定值 features = torch.cat([features, torch.full((pad_len, features.shape[1]), 0)]) # 转换为张量 # features = torch.tensor(padded_features, dtype=torch.float32) label = torch.tensor(label, dtype=torch.float32) # label = label.view(1,1) return features, label # global max_cycle_index def test(use_default, csv_path, pos): attrib_feature = ['Current', 'Voltage', 'Environment_Temperature', 'Cell_Temperature', 'SOC'] attrib_label = ['SOH'] max_len = 200 input_dim = len(attrib_feature) output_dim = 1 hidden_dim = 64 num_layers = 2 num_heads = 4 lr = 1e-3 max_seq_len = 200 batch_size = 1 C_rated = 1.1 base = './测试用例/' model_path = base + 'model.pt' var_path = base + 'variables.pkl' if use_default: csv_path = base + 'Test_Data_0.5_3C.csv' else: csv_path = csv_path.name # model_path = model_path.name # var_path = var_path.name # csv_path = csv_path.name with open(var_path, 'rb') as f: min_val, max_val = pickle.load(f) test_data = pd.read_csv(csv_path) # max_cycle_index = test_data['Cycle_Index'].max() test_data['SOH'] = test_data['cycle capacity'] / test_data['cycle capacity'].values[0] # C_val = val_data[attrib_label].values[0] # scaler_val = train_dataset.scaler dataset = SingleDataset( data=test_data, attrib_x=attrib_feature, attrib_y=attrib_label, max_len=max_len, C_rated=C_rated, min_val=min_val, max_val=max_val, mode='test') features, label = dataset.get_data_by_cycle_index(pos) features = torch.unsqueeze(features, dim=0) # 导入网络结构 model = net_BNN.ATBNN_Model( input_dim=input_dim, output_dim=output_dim, hidden_dim=hidden_dim, num_layers=num_layers, num_heads=num_heads, batch_size=batch_size, max_seq_len=max_seq_len) # model.load_state_dict(torch.load("./model_B/model_epoch634_Trainloss0.00013560_ValLoss0.00107357.pt")) #LOSS=0 # model.load_state_dict(torch.load("./model_B/model_epoch2168_Trainloss0.00001729_ValLoss0.00107112.pt")) model.load_state_dict(torch.load(model_path,map_location=torch.device("cpu"))) # model.load_state_dict(torch.load("./model/model_epoch1.pt")) device = torch.device('cpu') # device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') num_sample = 100 model.eval() with torch.no_grad(): predictions = [] # true_labels = [] cov = [] # upp = [] # low = [] # outputs = model(test_features.to(device)) # MC sample sample_output = torch.zeros(num_sample, label.shape[0]).to(device) for i in range(num_sample): sample_output[i] = model(features.to(device)).reshape(-1) outputs = C_rated * torch.Tensor(sample_output.mean(dim=0).unsqueeze(1)).to(device) covs = C_rated * torch.Tensor(sample_output.std(dim=0).unsqueeze(1)).to(device) results = "{:.4f}±{:.4f}".format(outputs.item(), covs.item()) # true_labels.append((test_labels).tolist()) return results default_checkbox = Checkbox(label="使用默认文件", default=False) # inputs = [ default_checkbox, File(label="上传CSV测试数据"), Number(label='选择循环次数(1~4004)') ] outputs = [ Textbox(label="最大可用容量估计结果/Ah"), ] gr.Interface(fn=test, inputs=inputs, outputs=outputs, title="ATBNN Model", description="加载预训练模型,加载测试数据并进行预测,得到当前循环的最大可用容量。").launch()