_ADD_COL_OPTIM_ENABLED参数

介绍了Oracle 11g中_ADD_COL_OPTIM_ENABLED参数的作用及影响。当设置为true时,新增NOT NULL且有默认值的列不会立即更新所有行,而是通过字典中的标志返回默认值,加快大型表的DDL操作速度。

参考自:

Init.ora Parameter "_ADD_COL_OPTIM_ENABLED" [Hidden] Reference Note (文档 ID 1492674.1)


This parameter is set to true by default if Parameter:COMPATIBLE >= 11 . The parameter relates specifically to the actions taken by Oracle for DDL of the form:

ALTER TABLE .. ADD COLUMN ( ... NOT NULL DEFAULT xxx )
In this very specific case of adding a NOT NULL column which has a DEFAULT value then Oracle has 2 options to perform this DDL:
  1. Before 11g or if _ADD_COL_OPTIM_ENABLED = FALSE:
    The DDL will cause the column to be added to the table defintion and every row of the table is updated with the new column and its default value. For large tables the update of all rows to add a column can take some time.
  2. In 11g onwards provided _ADD_COL_OPTIM_ENABLED = TRUE:
    The DDL adds the column to the table definition but there is no update of the actual table rows. Instead the dictionary stores a flag so that it knows that any row without the column value present should return the DEFAULT value instead. For large tables this can be much faster than option "1". Any code path that accesses the table has to honour the flag otherwise it may not return the correct data for the column.
The setting of the parameter only affects new ADD COLUMN commands. Once a column has been added using the optimized method a flag in the dictionary indicates that specific column as being optimized.

You can check which columns have been ADDed with the optimization active using SQL of the form below :

   select owner, object_name, name 
     from dba_objects, col$
    where bitand(col$.PROPERTY,1073741824)=1073741824
      and object_id=obj#;
If you encounter a bug issue related to _ADD_COL_OPTIM_ENABLED then typically any column listed by the above SQL might be affected. A workaround is typically to set _ADD_COL_OPTIM_ENABLED = FALSE and then recreate the problem table so that none of the columns show as optimized.
# basic lib import os import torch import numpy as np import os.path as osp from tqdm import tqdm # 导入进度条库 # data & options from options.opt_p2net import Options from torch.utils.data import DataLoader from data.common import P2NETCollate from data.dl_p2net import P2NETMatchDataset # networks & loss func from networks.d2f import D2F from networks.d3f import KPFCNN from networks.loss_p2net import p2net_criterion # tools import time import datetime from tensorboardX import SummaryWriter # Config opt = Options().parse() os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" os.environ["CUDA_VISIBLE_DEVICES"] = opt.gpus cuda = torch.cuda.is_available() opt.device = "cuda:0" if cuda else "cpu" writer = SummaryWriter(log_dir=opt.runs_dir) def validation(d2net, d3net, val_loader, total_epoch, loss_mode): d2net.eval() d3net.eval() val_steps = 0 tot_d_pos = 0 tot_d_neg = 0 tot_d_neg_row = 0 tot_d_neg_col = 0 tot_val_acc = 0 tot_val_loss = 0 toto_val_det_loss = 0 # 使用tqdm包装验证数据加载器 val_progress = tqdm(val_loader, desc=f"Validation Epoch {total_epoch + 1}", leave=False) for val_data in val_progress: val_data.to(opt.device) with torch.set_grad_enabled(False): d2_out = d2net(val_data.images, val_data.valid_depth_mask, opt) d3_out = d3net(val_data, opt) val_loss, val_det_loss, val_acc, d_pos, d_neg, d_neg_row, d_neg_col = p2net_criterion(d2_out, d3_out, val_data.pos_keypts_inds, opt, 1, loss_mode) if val_acc > 0: val_steps += 1 tot_d_pos += d_pos.item() tot_d_neg += d_neg.item() tot_d_neg_row += d_neg_row tot_d_neg_col += d_neg_col tot_val_acc += val_acc tot_val_loss += val_loss.item() toto_val_det_loss += val_det_loss.item() if val_steps == opt.val_size: break if val_steps > 0: mean_acc = tot_val_acc / val_steps mean_loss = tot_val_loss / val_steps mean_det_loss = toto_val_det_loss / val_steps mean_d_pos = tot_d_pos / val_steps mean_d_neg = tot_d_neg / val_steps mean_d_neg_row = tot_d_neg_row / val_steps mean_d_neg_col = tot_d_neg_col / val_steps else: mean_acc = 0 mean_loss = 0 mean_det_loss = 0 mean_d_pos = 0 mean_d_neg = 0 mean_d_neg_row = 0 mean_d_neg_col = 0 # 仅打印关键验证结果 print(f'\nValidation Epoch {total_epoch + 1} - ' f'Acc: {mean_acc:.4f}, Loss: {mean_loss:.4f}, Det Loss: {mean_det_loss:.4f}') writer.add_scalar('val_acc', mean_acc, total_epoch) writer.add_scalar('val_loss', mean_loss, total_epoch) writer.add_scalar('val_det_loss', mean_det_loss, total_epoch) writer.add_scalar('val_d_pos', mean_d_pos, total_epoch) writer.add_scalar('val_d_neg', mean_d_neg, total_epoch) writer.add_scalar('val_d_neg_row', mean_d_neg_row, total_epoch) writer.add_scalar('val_d_neg_col', mean_d_neg_col, total_epoch) torch.cuda.empty_cache() return mean_acc def train(d2net, d3net, train_loader, val_loader=None, ckpt=None): param_list = list(d2net.parameters()) + list(d3net.parameters()) if opt.optm_type == 'SGD': optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad, param_list), lr=opt.sgd_lr, momentum=opt.sgd_momentum, weight_decay=opt.sgd_weight_decay) scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.1 ** (2 / opt.epochs)) elif opt.optm_type == 'Adam': optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, param_list), lr=opt.adam_lr) scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.1 ** (1 / 240000)) else: raise NotImplementedError if opt.train_mode == 'continue': optimizer.load_state_dict(ckpt['optimizer_state_dict']) best_acc = 0 total_steps = 0 epoch_acc = [] epoch_loss = [] epoch_det_loss = [] epoch_d_pos = [] epoch_d_neg = [] epoch_d_neg_row = [] epoch_d_neg_col = [] loss_mode = 'Single' # 遍历训练周期 for epoch in range(opt.epochs): d2net.train() d3net.train() if epoch == opt.switch_epoch: loss_mode = opt.loss_mode # 使用tqdm包装训练数据加载器 train_progress = tqdm(train_loader, desc=f"Epoch {epoch + 1}/{opt.epochs}", leave=False) for train_data in train_progress: train_data.to(opt.device) with torch.set_grad_enabled(True): optimizer.zero_grad() d2_out = d2net(train_data.images, train_data.valid_depth_mask, opt) d3_out = d3net(train_data, opt) train_loss, train_det_loss, train_acc, d_pos, d_neg, d_neg_row, d_neg_col = p2net_criterion(d2_out, d3_out, train_data.pos_keypts_inds, opt, total_steps, loss_mode) # backward train_loss.backward() do_step = True for param in d3net.parameters(): if param.grad is not None: if (1 - torch.isfinite(param.grad).long()).sum() > 0: do_step = False break if do_step is True: if opt.grad_clip_norm > 0: torch.nn.utils.clip_grad_value_(d3net.parameters(), opt.grad_clip_norm) optimizer.step() scheduler.step() epoch_acc.append(train_acc) epoch_loss.append(train_loss.item()) epoch_det_loss.append(train_det_loss.item()) epoch_d_pos.append(d_pos.item()) epoch_d_neg.append(d_neg.item()) epoch_d_neg_row.append(d_neg_row.item()) epoch_d_neg_col.append(d_neg_col.item()) total_steps += 1 if total_steps == 1 or total_steps % opt.print_freq == 0: tmp_acc = np.mean(epoch_acc) tmp_loss = np.mean(epoch_loss) tmp_det_loss = np.mean(epoch_det_loss) tmp_d_pos = np.mean(epoch_d_pos) tmp_d_neg = np.mean(epoch_d_neg) tmp_d_neg_row = np.mean(epoch_d_neg_row) tmp_d_neg_col = np.mean(epoch_d_neg_col) epoch_acc = [] epoch_loss = [] epoch_det_loss = [] epoch_d_pos = [] epoch_d_neg = [] epoch_d_neg_row = [] epoch_d_neg_col = [] writer.add_scalar('train_acc', tmp_acc, total_steps) writer.add_scalar('train_loss', tmp_loss, total_steps) writer.add_scalar('train_det_loss', tmp_det_loss, total_steps) writer.add_scalar('train_d_pos', tmp_d_pos, total_steps) writer.add_scalar('train_d_neg', tmp_d_neg, total_steps) writer.add_scalar('train_d_neg_row', tmp_d_neg_row, total_steps) writer.add_scalar('train_d_neg_col', tmp_d_neg_col, total_steps) # 更新进度条描述,显示当前训练指标 train_progress.set_postfix({ 'Loss': f'{tmp_loss:.4f}', 'Acc': f'{tmp_acc:.4f}', 'd_pos': f'{tmp_d_pos:.4f}' }) # 每个周期结束后进行验证 tmp_val_acc = validation(d2net, d3net, val_loader, epoch, loss_mode) d2net.train() d3net.train() # 保存模型 if epoch > 4 and epoch % opt.save_freq == 0: print(f"\nSaving model of epoch {epoch + 1}") filename = osp.join(opt.models_dir, f'ckpt_{epoch + 1}.pth.tar') checkpoint_dict = {'epoch': epoch + 1, 'd2net_state_dict': d2net.state_dict(), 'd3net_state_dict': d3net.state_dict(), 'optimizer_state_dict': optimizer.state_dict()} torch.save(checkpoint_dict, filename) # 保存最佳模型 if tmp_val_acc > best_acc: print(f"Saving best model with accuracy {tmp_val_acc:.4f}") best_filename = osp.join(opt.models_dir, f'best.pth.tar') best_acc = tmp_val_acc torch.save(checkpoint_dict, best_filename) # 重建批处理数据索引 val_loader.dataset.reset_batch_list(opt.batchsize) train_loader.dataset.reset_batch_list(opt.batchsize) def main(): # 加载数据集 t1 = time.time() print("Preparing dataset...") test_set = P2NETMatchDataset(opt, 'test') train_set = P2NETMatchDataset(opt, 'train') kwargs = {'num_workers': 8, 'pin_memory': True} if cuda else {} test_loader = DataLoader(test_set, batch_size=8, collate_fn=P2NETCollate, shuffle=True, **kwargs) train_loader = DataLoader(train_set, batch_size=8, collate_fn=P2NETCollate, shuffle=True, **kwargs) t2 = time.time() print(f"\nDataset prepared in {t2 - t1:.2f} seconds") # 模型 print("Creating model...") d2net = D2F(opt) d3net = KPFCNN(opt) d2net.to(opt.device) d3net.to(opt.device) if opt.train_mode == 'from-scratch': print("Training mode: from scratch...") elif opt.train_mode == 'fine-tune': print("Training mode: with pre-trained models...") d2net_weights = f'./logs/{opt.d2net_logs}/models/{opt.d2net_ckpt}' d3net_weights = f'../CDF-master/logs/{opt.d3net_logs}/models/{opt.d3net_ckpt}' d2net_ckpt = torch.load(d2net_weights, map_location=opt.device) d3net_ckpt = torch.load(d3net_weights, map_location=opt.device) d2net.load_state_dict(d2net_ckpt['d2net_state_dict']) d3net.load_state_dict(d3net_ckpt['d3net_state_dict']) elif opt.train_mode == 'continue': print("Training mode: with pre-trained p2p weights...") weights = f'./logs/{opt.p2p_logs}/models/{opt.p2p_ckpt}' ckpt = torch.load(weights, map_location=opt.device) print(f"Loaded models from {opt.p2p_ckpt}") d2net.load_state_dict(ckpt['d2net_state_dict']) d3net.load_state_dict(ckpt['d3net_state_dict']) else: raise ValueError print(d2net) print(d3net) # 打印模型参数数量 def get_parameter_number(net): total_num = sum(p.numel() for p in net.parameters()) trainable_num = sum(p.numel() for p in net.parameters() if p.requires_grad) return {'Total': total_num, 'Trainable': trainable_num} print("Model parameters:") print(f"D2Net: {get_parameter_number(d2net)}") print(f"D3Net: {get_parameter_number(d3net)}") t3 = time.time() print(f"\nModel created in {t3 - t2:.2f} seconds") # 训练 print("\nStarting training...") start_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(f"Start time: {start_time}") if opt.train_mode == 'from-scratch': train(d2net, d3net, train_loader, test_loader) elif opt.train_mode == 'continue': validation(d2net, d3net, test_loader, 0) else: raise NotImplementedError end_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(f"\nTraining finished at {end_time}") writer.close() if __name__ == '__main__': main() GPU利用率很低
05-29
import os import time import torch import torch.nn as nn import torch.optim as optim import pandas as pd import numpy as np from torch.utils.data import Dataset, DataLoader, random_split from torchvision import transforms from PIL import Image from tqdm import tqdm import matplotlib.pyplot as plt os.system("") # 激活ANSI支持 torch.manual_seed(42) np.random.seed(42) # -------------------------- # 1. 数据集定义(保持不变) # -------------------------- class FluidImageDataset(Dataset): def __init__(self, blade_params, pressure_dir, velocity_u_dir, velocity_v_dir, velocity_w_dir, transform=None): self.blade_params = blade_params self.pressure_dir = pressure_dir self.velocity_u_dir = velocity_u_dir self.velocity_v_dir = velocity_v_dir self.velocity_w_dir = velocity_w_dir self.transform = transform or transforms.Compose([ transforms.Resize((256, 256)), transforms.ToTensor(), ]) def __len__(self): return len(self.blade_params) def __getitem__(self, idx): params = torch.tensor(self.blade_params.iloc[idx].values, dtype=torch.float32) img_id = idx + 1 # 简化图像加载 def load_img(path): try: return self.transform(Image.open(path).convert('L')) except: return torch.zeros(1, 256, 256) return {'params': params, 'outputs': { 'pressure': load_img(os.path.join(self.pressure_dir, f"Pressure_{img_id}.jpg")), 'velocity_u': load_img(os.path.join(self.velocity_u_dir, f"Velocity_u_{img_id}.jpg")), 'velocity_v': load_img(os.path.join(self.velocity_v_dir, f"Velocity_v_{img_id}.jpg")), 'velocity_w': load_img(os.path.join(self.velocity_w_dir, f"Velocity_w_{img_id}.jpg")), }} # -------------------------- # 2. 傅里叶KAN层(核心修改:使用傅里叶基函数替代原有非线性函数) # -------------------------- class FourierKANLayer(nn.Module): def __init__(self, input_dim, output_dim, grid_size=16, add_bias=True, smooth_initialization=True): super().__init__() self.input_dim = input_dim self.output_dim = output_dim self.grid_size = grid_size # 傅里叶频率数量 self.add_bias = add_bias # 傅里叶系数初始化(正弦和余弦) # 平滑初始化:高频系数衰减,保证初始函数平滑 grid_norm = (torch.arange(grid_size) + 1) **2 if smooth_initialization else np.sqrt(grid_size) self.fourier_coeffs = nn.Parameter( torch.randn(2, output_dim, input_dim, grid_size) / (np.sqrt(input_dim) * grid_norm) ) # 偏置项 if self.add_bias: self.bias = nn.Parameter(torch.zeros(1, output_dim)) def forward(self, x): # 处理向量数据 (B, input_dim) 或图像数据 (B, C, H, W) original_shape = x.shape if x.dim() == 4: # 图像数据展平为 (B*H*W, C) 便于处理 batch_size, channels, height, width = x.shape x = x.permute(0, 2, 3, 1).reshape(-1, channels) # (B*H*W, C) # 傅里叶基函数计算:cos(kx) 和 sin(kx) k = torch.arange(1, self.grid_size + 1, device=x.device).reshape(1, 1, 1, self.grid_size) # 频率 x_expanded = x.unsqueeze(1).unsqueeze(3) # (B, 1, input_dim, 1) cos_terms = torch.cos(k * x_expanded) # (B, 1, input_dim, grid_size) sin_terms = torch.sin(k * x_expanded) # (B, 1, input_dim, grid_size) # 傅里叶系数加权求和 y = torch.sum(cos_terms * self.fourier_coeffs[0:1], dim=(-2, -1)) # 余弦项贡献 y += torch.sum(sin_terms * self.fourier_coeffs[1:2], dim=(-2, -1)) # 正弦项贡献 # 添加偏置 if self.add_bias: y += self.bias # 恢复图像数据形状 if len(original_shape) == 4: y = y.reshape(batch_size, height, width, self.output_dim).permute(0, 3, 1, 2) # (B, output_dim, H, W) else: y = y.reshape(original_shape[:-1] + (self.output_dim,)) # 向量数据恢复形状 return y class KANFeatureExtractor(nn.Module): def __init__(self, input_dim): super().__init__() self.layers = nn.Sequential( FourierKANLayer(input_dim, 128, grid_size=16), # 傅里叶KAN层 nn.LayerNorm(128), FourierKANLayer(128, 128, grid_size=16), nn.LayerNorm(128), FourierKANLayer(128, 256, grid_size=16), nn.LayerNorm(256), FourierKANLayer(256, 256, grid_size=16) ) def forward(self, x): return self.layers(x) # -------------------------- # 3. U-Net结构(使用傅里叶KAN层替代原有激活函数) # -------------------------- class MiniUNetEncoder(nn.Module): def __init__(self, in_channels=8): super().__init__() self.conv1 = nn.Sequential( nn.Conv2d(in_channels, 16, kernel_size=3, padding=1), nn.GroupNorm(4, 16), FourierKANLayer(16, 16, grid_size=16), # 傅里叶KAN替代ReLU nn.Conv2d(16, 16, kernel_size=3, padding=1), nn.GroupNorm(4, 16), FourierKANLayer(16, 16, grid_size=16) ) self.pool1 = nn.MaxPool2d(2, 2) self.conv2 = nn.Sequential( nn.Conv2d(16, 32, kernel_size=3, padding=1), nn.GroupNorm(4, 32), FourierKANLayer(32, 32, grid_size=16), nn.Conv2d(32, 32, kernel_size=3, padding=1), nn.GroupNorm(4, 32), FourierKANLayer(32, 32, grid_size=16) ) self.pool2 = nn.MaxPool2d(2, 2) def forward(self, x): c1 = self.conv1(x) p1 = self.pool1(c1) c2 = self.conv2(p1) p2 = self.pool2(c2) return c1, c2, p2 class MiniUNetDecoder(nn.Module): def __init__(self, out_channels=1): super().__init__() self.up1 = nn.ConvTranspose2d(32, 16, kernel_size=2, stride=2) self.conv3 = nn.Sequential( nn.Conv2d(48, 16, kernel_size=3, padding=1), nn.GroupNorm(4, 16), FourierKANLayer(16, 16, grid_size=16) # 傅里叶KAN替代ReLU ) self.up2 = nn.ConvTranspose2d(16, 8, kernel_size=2, stride=2) self.final_conv = nn.Conv2d(24, out_channels, kernel_size=1) self.sigmoid = nn.Sigmoid() def forward(self, c1, c2, p2): u1 = self.up1(p2) cat1 = torch.cat([u1, c2], dim=1) d1 = self.conv3(cat1) u2 = self.up2(d1) cat2 = torch.cat([u2, c1], dim=1) out = self.final_conv(cat2) return self.sigmoid(out) class MiniUNetPredictor(nn.Module): def __init__(self): super().__init__() self.encoder = MiniUNetEncoder() self.decoder = MiniUNetDecoder() def forward(self, x): c1, c2, p2 = self.encoder(x) return self.decoder(c1, c2, p2) # -------------------------- # 4. 模型组装(保持结构不变,使用傅里叶KAN层) # -------------------------- class LightKANUNetModel(nn.Module): def __init__(self, input_dim): super().__init__() self.kan_feature = KANFeatureExtractor(input_dim) # 特征投影模块(使用傅里叶KAN) self.feature_proj = nn.Sequential( nn.Linear(256, 128), nn.LayerNorm(128), FourierKANLayer(128, 128, grid_size=16), # 傅里叶KAN替代ReLU # 生成初始特征图 nn.Linear(128, 8 * 16 * 16), nn.Unflatten(1, (8, 16, 16)), # 上采样卷积块 nn.Conv2d(8, 16, kernel_size=3, padding=1), nn.GroupNorm(4, 16), FourierKANLayer(16, 16, grid_size=16), nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True), nn.Conv2d(16, 32, kernel_size=3, padding=1), nn.GroupNorm(4, 32), FourierKANLayer(32, 32, grid_size=16), nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True), nn.Conv2d(32, 64, kernel_size=3, padding=1), nn.GroupNorm(4, 64), FourierKANLayer(64, 64, grid_size=16), nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True), nn.Conv2d(64, 32, kernel_size=3, padding=1), nn.GroupNorm(4, 32), FourierKANLayer(32, 32, grid_size=16), nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True), nn.Conv2d(32, 8, kernel_size=3, padding=1), nn.GroupNorm(4, 8), FourierKANLayer(8, 8, grid_size=16) ) self.predictors = nn.ModuleDict({ 'pressure': MiniUNetPredictor(), 'velocity_u': MiniUNetPredictor(), 'velocity_v': MiniUNetPredictor(), 'velocity_w': MiniUNetPredictor() }) def forward(self, x): features = self.kan_feature(x) feat_map = self.feature_proj(features) return {k: self.predictors[k](feat_map) for k in self.predictors} # -------------------------- # 5. 训练与工具函数(保持不变) # -------------------------- def load_data(blade_params_path, data_dir): blade_params = pd.read_excel(blade_params_path).iloc[:, 1:] print(f"叶片参数形状:{blade_params.shape}(样本数×参数数)") dataset = FluidImageDataset( blade_params, os.path.join(data_dir, "Pressure"), os.path.join(data_dir, "Velocity_u"), os.path.join(data_dir, "Velocity_v"), os.path.join(data_dir, "Velocity_w") ) total_size = len(dataset) train_size = int(0.8 * total_size) val_size = int(0.1 * total_size) test_size = total_size - train_size - val_size generator = torch.Generator().manual_seed(42) train_dataset, val_dataset, test_dataset = random_split( dataset, [train_size, val_size, test_size], generator=generator ) return ( DataLoader(train_dataset, batch_size=1, shuffle=True, num_workers=0), DataLoader(val_dataset, batch_size=1, shuffle=False, num_workers=0), DataLoader(test_dataset, batch_size=1, shuffle=False, num_workers=0), blade_params.shape[1] ) def train_model(model, train_loader, criterion, optimizer, device, epochs=3): model.train() if torch.cuda.is_available(): torch.cuda.reset_peak_memory_stats() print(f"初始GPU内存:{torch.cuda.memory_allocated() / 1e6:.1f} MB") for epoch in range(epochs): running_loss = 0.0 pbar = tqdm(train_loader, total=len(train_loader), desc=f"Epoch {epoch + 1}/{epochs}") for batch_idx, data in enumerate(pbar): start_time = time.time() params = data['params'].to(device) true_outputs = {k: v.to(device) for k, v in data['outputs'].items()} optimizer.zero_grad() with torch.amp.autocast('cuda', enabled=torch.cuda.is_available()): pred_outputs = model(params) loss = sum(criterion(pred_outputs[k], true_outputs[k]) for k in pred_outputs) loss.backward() optimizer.step() running_loss += loss.item() batch_time = time.time() - start_time if (batch_idx + 1) % 10 == 0 or batch_idx == len(train_loader) - 1: avg_loss = running_loss / (batch_idx + 1) gpu_mem = torch.cuda.memory_allocated() / 1e6 if torch.cuda.is_available() else 0 pbar.set_postfix({ "批损失": f"{loss.item():.4f}", "平均损失": f"{avg_loss:.4f}", "耗时": f"{batch_time:.2f}s", "GPU内存": f"{gpu_mem:.1f} MB" }) print(f"Epoch {epoch + 1} 完成,平均损失:{running_loss / len(train_loader):.4f}") return model def evaluate_model(model, test_loader, criterion, device): model.eval() metrics = {k: [] for k in ['pressure', 'velocity_u', 'velocity_v', 'velocity_w']} with torch.no_grad(): for data in test_loader: params = data['params'].to(device) true_outputs = {k: v.to(device) for k, v in data['outputs'].items()} pred_outputs = model(params) for k in metrics: metrics[k].append(criterion(pred_outputs[k], true_outputs[k]).item()) avg = {k: sum(v) / len(v) for k, v in metrics.items()} print("\n测试集结果:") print(f"总平均MSE:{sum(avg.values()) / 4:.4f}") for k, v in avg.items(): print(f" {k}:{v:.6f}") return avg def visualize_predictions(model, test_loader, device, num_samples=3): model.eval() save_dir = "KAN_UNet_Results" os.makedirs(save_dir, exist_ok=True) with torch.no_grad(): for i, data in enumerate(test_loader): if i >= num_samples: break params = data['params'].to(device) true = data['outputs'] pred = {k: v.cpu() for k, v in model(params).items()} fig, axes = plt.subplots(1, 9, figsize=(24, 5)) axes[0].text(0.1, 0.5, "参数:\n" + "\n".join( [f"p{j}: {v:.2f}" for j, v in enumerate(params[0].cpu().numpy().round(2))]), fontsize=9, va='center') axes[0].axis('off') for col, k in enumerate(['pressure', 'velocity_u', 'velocity_v', 'velocity_w']): axes[2 * col + 1].imshow(true[k][0].squeeze(), cmap='viridis') axes[2 * col + 1].set_title(f'真实{k}') axes[2 * col + 1].axis('off') axes[2 * col + 2].imshow(pred[k][0].squeeze(), cmap='viridis') axes[2 * col + 2].set_title(f'预测{k}') axes[2 * col + 2].axis('off') plt.tight_layout() plt.savefig(f"{save_dir}/样本_{i + 1}.png", dpi=200) plt.close() print(f"已保存样本 {i + 1} 可视化结果") def main(): save_dir = "KAN_UNet_Results" blade_params_path = r"C:\Users\ZYQ\PycharmProjects\2025.07.09\Data\Blade parameters.xlsx" data_dir = r"C:\Users\ZYQ\PycharmProjects\2025.07.09\Data" device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"使用设备:{device}") train_loader, val_loader, test_loader, input_dim = load_data(blade_params_path, data_dir) print(f"输入维度:{input_dim},训练批次:{len(train_loader)}") model = LightKANUNetModel(input_dim).to(device) total_params = sum(p.numel() for p in model.parameters()) print(f"模型参数量:{total_params / 1e6:.2f} M") criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5) print("\n开始训练...") model = train_model(model, train_loader, criterion, optimizer, device, epochs=3) evaluate_model(model, test_loader, criterion, device) visualize_predictions(model, test_loader, device) torch.save(model.state_dict(), f"{save_dir}/fourier_kan_unet.pth") print(f"模型保存至:{save_dir}/fourier_kan_unet.pth") if __name__ == "__main__": main()
最新发布
07-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值