B - Magnets

磁力链接分组计数

Problem description

Mad scientist Mike entertains himself by arranging rows of dominoes. He doesn't need dominoes, though: he uses rectangular magnets instead. Each magnet has two poles, positive (a "plus") and negative (a "minus"). If two magnets are put together at a close distance, then the like poles will repel each other and the opposite poles will attract each other.

Mike starts by laying one magnet horizontally on the table. During each following step Mike adds one more magnet horizontally to the right end of the row. Depending on how Mike puts the magnet on the table, it is either attracted to the previous one (forming a group of multiple magnets linked together) or repelled by it (then Mike lays this magnet at some distance to the right from the previous one). We assume that a sole magnet not linked to others forms a group of its own.

Mike arranged multiple magnets in a row. Determine the number of groups that the magnets formed.

Input

The first line of the input contains an integer n (1 ≤ n ≤ 100000) — the number of magnets. Then n lines follow. The i-th line (1 ≤ i ≤ n) contains either characters "01", if Mike put the i-th magnet in the "plus-minus" position, or characters "10", if Mike put the magnet in the "minus-plus" position.

Output

On the single line of the output print the number of groups of magnets.

Examples

Input

6
10
10
10
01
10
10

Output

3

Input

4
01
01
10
10

Output

2

Note

The first testcase corresponds to the figure. The testcase has three groups consisting of three, one and two magnets.

The second testcase has two groups, each consisting of two magnets.

解题思路:很简单的一道题,就是求能分出多少块整体。做法:将其转化成字符串,从第三个字符开始,统计str[i]==str[i-1]的个数即为整体分成块的个数,水过!

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main(){
 4     int n,num=1;string str="",r;
 5     cin>>n;getchar();
 6     while(n--){cin>>r;str+=r;}
 7     for(unsigned int i=2;i<str.length();i+=2)
 8         if(str[i]==str[i-1])num++;
 9     cout<<num<<endl;
10     return 0;
11 }

 

转载于:https://www.cnblogs.com/acgoto/p/9162132.html

import os import csv import torch import scipy.io import numpy as np import pandas as pd import torch.nn as nn import torch.optim as optim import torch.nn.functional as F import matplotlib.pyplot as plt from copy import deepcopy from itertools import product from sklearn.metrics import mean_absolute_error, r2_score device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print(f"Using device: {device}") #####数据加载##### def load_multi_dun_exp_data(file_path, device, num_samples=None): """ 从单个.mat文件加载多墩墩数据 """ print(f"Loading data from: {file_path}") mat_data = scipy.io.loadmat(file_path) # 加载力数据 (总合力) fx = mat_data['fx'].flatten() fy = mat_data['fy'].flatten() fz = -mat_data['fz'].flatten() # fz反号 F_total = np.column_stack((fx, fy, fz)) # 加载磁场数据 B_processed = mat_data['B_processed'] # 形状: (N, cols) # 推断墩墩数量:cols / 18 total_cols = B_processed.shape[1] num_duns = total_cols // 18 if total_cols % 18 != 0: raise ValueError(f"B_processed列数({total_cols})不能被18整除") print(f"Inferred number of duns: {num_duns}") # 样本选择 total_samples = len(F_total) if num_samples is None or num_samples > total_samples: print(f"Using all {total_samples} samples") indices = np.arange(total_samples) else: indices = np.random.choice(total_samples, size=num_samples, replace=False) indices = np.sort(indices) print(f"Randomly selected {num_samples} samples from {total_samples}") # 选择数据 F_total_selected = F_total[indices] B_processed_selected = B_processed[indices, :] # 重新组织数据格式: (N, num_duns, 6, 3) B_array = np.zeros((len(indices), num_duns, 6, 3)) for dun_id in range(num_duns): col_start = dun_id * 18 col_end = (dun_id + 1) * 18 B_dun = B_processed_selected[:, col_start:col_end] # (N, 18) B_array[:, dun_id, :, :] = B_dun.reshape(-1, 6, 3) B_tensor = torch.Tensor(B_array).to(device) F_tensor = torch.Tensor(F_total_selected).to(device) print(f"Final data shape - B: {B_tensor.shape}, F: {F_tensor.shape}") return B_tensor, F_tensor, num_duns def load_train_data(train_data_path, device): """ 加载预训练数据(单个墩墩) """ train_data = pd.read_csv(train_data_path) force_cols = ['Fx_total', 'Fy_total', 'Fz_total'] field_cols = [f'B_{k}{j}' for k, j in product(range(1, 7), ['x', 'y', 'z'])] F_train = torch.Tensor(train_data[force_cols].values).to(device) B_train = torch.Tensor(train_data[field_cols].values).reshape(-1, 6, 3).to(device) print(f"Pretrain data - B: {B_train.shape}, F: {F_train.shape}") return B_train, F_train #####模型构建##### class PretrainedEncoder(nn.Module): """预训练编码器 - 从单个墩墩模型加载""" def __init__(self, input_dim=18, hidden_dim=64, output_dim=32, dropout_rate=0.3): super(PretrainedEncoder, self).__init__() self.network = nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.BatchNorm1d(hidden_dim), nn.GELU(), nn.Dropout(dropout_rate), nn.Linear(hidden_dim, output_dim), nn.BatchNorm1d(output_dim), nn.GELU(), nn.Dropout(dropout_rate), ) def forward(self, x): # x: (batch_size, 6, 3) -> (batch_size, 18) x = x.reshape(x.size(0), -1) return self.network(x) class ArrayForceInversionModel(nn.Module): """ 阵列力反演模型 架构: 6个预训练编码器 + Transformer交互 + 合力预测器 """ def __init__(self, num_duns, encoder_dim=32, dropout_rate=0.2): super(ArrayForceInversionModel, self).__init__() self.num_duns = num_duns self.encoder_dim = encoder_dim # 6个预训练编码器(每个墩墩一个) self.dun_encoders = nn.ModuleList([ PretrainedEncoder(output_dim=encoder_dim, dropout_rate=dropout_rate) for _ in range(num_duns) ]) # Transformer交互网络 encoder_layer = nn.TransformerEncoderLayer( d_model=encoder_dim, nhead=8, dim_feedforward=128, dropout=dropout_rate, batch_first=True ) self.interaction_network = nn.TransformerEncoder(encoder_layer, num_layers=3) # 位置编码 self.position_encoding = nn.Parameter(torch.randn(1, num_duns, encoder_dim)) # 合力预测器 self.force_predictor = nn.Sequential( nn.Linear(num_duns * encoder_dim, 128), nn.GELU(), nn.Dropout(dropout_rate), nn.Linear(128, 64), nn.GELU(), nn.Dropout(dropout_rate), nn.Linear(64, 3) # 输出三维合力 ) # 归一化参数 self.register_buffer('B_mean', torch.zeros(18)) self.register_buffer('B_std', torch.ones(18)) self.register_buffer('F_mean', torch.zeros(3)) self.register_buffer('F_std', torch.ones(3)) def set_normalization_params(self, B_mean, B_std, F_mean, F_std): """设置归一化参数""" self.B_mean = B_mean.to(device) self.B_std = B_std.to(device) self.F_mean = F_mean.to(device) self.F_std = F_std.to(device) def normalize_B(self, B): """归一化磁场数据""" batch_size, num_duns, num_magnets, dim = B.shape B_flat = B.reshape(batch_size, num_duns, -1) B_norm = (B_flat - self.B_mean) / (self.B_std + 1e-8) return B_norm.reshape(batch_size, num_duns, num_magnets, dim) def denormalize_F(self, F): """反归一化力数据""" return F * self.F_std + self.F_mean def forward(self, B_array, return_features=False): """ Args: B_array: (batch_size, num_duns, 6, 3) - 阵列磁场数据 return_features: 是否返回中间特征 Returns: F_total: (batch_size, 3) - 预测的总合力 features: (可选) 编码器特征 """ batch_size = B_array.size(0) # 归一化输入 B_norm = self.normalize_B(B_array) # 分别编码每个墩墩 dun_features = [] for dun_id in range(self.num_duns): B_dun = B_norm[:, dun_id, :, :] # (batch_size, 6, 3) features = self.dun_encoders[dun_id](B_dun) # (batch_size, encoder_dim) dun_features.append(features) # 堆叠特征并添加位置编码 features_tensor = torch.stack(dun_features, dim=1) # (batch_size, num_duns, encoder_dim) features_tensor = features_tensor + self.position_encoding # Transformer交互 interacted_features = self.interaction_network(features_tensor) # (batch_size, num_duns, encoder_dim) # 预测合力 flattened = interacted_features.reshape(batch_size, -1) # (batch_size, num_duns * encoder_dim) F_pred_norm = self.force_predictor(flattened) # (batch_size, 3) F_pred = self.denormalize_F(F_pred_norm) if return_features: return F_pred, dun_features, interacted_features return F_pred #####损失函数##### class ImprovedMMDLoss(nn.Module): """改进的MMD损失,支持多尺度核""" def __init__(self, kernel_mul=2.0, kernel_num=5): super(ImprovedMMDLoss, self).__init__() self.kernel_mul = kernel_mul self.kernel_num = kernel_num def guassian_kernel(self, source, target): n_samples = source.size(0) + target.size(0) total = torch.cat([source, target], dim=0) total0 = total.unsqueeze(0).expand(total.size(0), total.size(0), total.size(1)) total1 = total.unsqueeze(1).expand(total.size(0), total.size(0), total.size(1)) L2_distance = ((total0 - total1) ** 2).sum(2) bandwidth = torch.sum(L2_distance.data) / (n_samples ** 2 - n_samples) bandwidth /= self.kernel_mul ** (self.kernel_num // 2) bandwidth_list = [bandwidth * (self.kernel_mul ** i) for i in range(self.kernel_num)] kernel_val = [torch.exp(-L2_distance / bandwidth_temp) for bandwidth_temp in bandwidth_list] return sum(kernel_val) def forward(self, source, target): batch_size = source.size(0) kernels = self.guassian_kernel(source, target) XX = kernels[:batch_size, :batch_size] YY = kernels[batch_size:, batch_size:] XY = kernels[:batch_size, batch_size:] YX = kernels[batch_size:, :batch_size] loss = torch.mean(XX + YY - XY - YX) return loss class PhysicsConsistencyLoss(nn.Module): """物理一致性损失""" def __init__(self, symmetry_pairs=None): super(PhysicsConsistencyLoss, self).__init__() self.symmetry_pairs = symmetry_pairs or [(0,5), (1,4), (2,3)] # 默认对称对 def forward(self, dun_features): """ Args: dun_features: list of (batch_size, feature_dim) - 每个墩墩的特征 """ consistency_loss = 0.0 # 对称性约束 for i, j in self.symmetry_pairs: if i < len(dun_features) and j < len(dun_features): # 对称墩墩的特征应该相似 feat_i = dun_features[i] feat_j = dun_features[j] consistency_loss += F.mse_loss(feat_i, feat_j) # 特征平滑性约束 for i in range(len(dun_features) - 1): consistency_loss += 0.1 * F.mse_loss(dun_features[i], dun_features[i+1]) return consistency_loss #####评估指标##### def compute_metrics(F_pred, F_true): """计算评估指标""" F_pred_np = F_pred.cpu().numpy() F_true_np = F_true.cpu().numpy() metrics = {} force_components = ['Fx', 'Fy', 'Fz'] # 各分量指标 for i, comp in enumerate(force_components): pred_comp = F_pred_np[:, i] true_comp = F_true_np[:, i] metrics[comp] = { 'mae': mean_absolute_error(true_comp, pred_comp), 'r2': r2_score(true_comp, pred_comp) } # 总体指标 total_mae = mean_absolute_error(F_true_np, F_pred_np) total_r2 = r2_score(F_true_np, F_pred_np) metrics['overall'] = { 'mae': total_mae, 'r2': total_r2 } return metrics #####微调程序##### class ArrayForceInversionFineTuner: def __init__(self, pretrained_path, output_folder, num_duns=6): self.pretrained_path = pretrained_path self.output_folder = output_folder self.num_duns = num_duns self.model = None self.history = [] os.makedirs(output_folder, exist_ok=True) # 损失函数 self.mse_loss = nn.MSELoss() self.mmd_loss = ImprovedMMDLoss() self.physics_loss = PhysicsConsistencyLoss() def load_pretrained_encoders(self, B_train_sample, F_train_sample): """ 加载预训练权重到编码器 """ print("Loading pretrained encoders...") self.model = ArrayForceInversionModel( num_duns=self.num_duns, encoder_dim=32, dropout_rate=0.2 ).to(device) try: # 加载预训练权重 pretrained_state = torch.load(self.pretrained_path, map_location=device) print(f"✓ Loaded pretrained model from {self.pretrained_path}") # 提取MLP权重到所有编码器 mlp_state_dict = {} for k, v in pretrained_state.items(): if k.startswith('mlp.'): new_k = k.replace('mlp.', '', 1) mlp_state_dict[new_k] = v # 加载到所有墩墩编码器 if mlp_state_dict: for dun_encoder in self.model.dun_encoders: encoder_dict = dun_encoder.state_dict() # 匹配并加载权重 for key in encoder_dict.keys(): if key in mlp_state_dict: try: encoder_dict[key].copy_(mlp_state_dict[key]) except Exception as e: print(f" ✗ Failed to load {key}: {e}") print("✓ Pretrained weights loaded to all dun encoders") # 设置归一化参数 if 'x_mean' in pretrained_state: B_mean = pretrained_state['x_mean'].reshape(-1) B_std = pretrained_state['x_std'].reshape(-1) F_mean = pretrained_state['y_mean'].reshape(-1) F_std = pretrained_state['y_std'].reshape(-1) self.model.set_normalization_params(B_mean, B_std, F_mean, F_std) print("✓ Normalization parameters set") except Exception as e: print(f"⚠ Failed to load pretrained weights: {e}") print(" Using random initialization") # 统计参数 total_params = sum(p.numel() for p in self.model.parameters()) encoder_params = sum(p.numel() for p in self.model.dun_encoders.parameters()) interaction_params = sum(p.numel() for p in self.model.interaction_network.parameters()) predictor_params = sum(p.numel() for p in self.model.force_predictor.parameters()) print(f"\nModel Architecture:") print(f" Total Parameters: {total_params:,}") print(f" Encoder Parameters: {encoder_params:,} ({self.num_duns} × {encoder_params//self.num_duns:,})") print(f" Interaction Parameters: {interaction_params:,}") print(f" Predictor Parameters: {predictor_params:,}") return self.model def progressive_fine_tune(self, B_array, F_total, B_source=None, F_source=None, val_split=0.15, batch_size=64): """ 两阶段渐进式微调 """ # 数据分割 n_samples = B_array.size(0) indices = torch.randperm(n_samples) val_size = int(val_split * n_samples) train_idx, val_idx = indices[val_size:], indices[:val_size] B_train = B_array[train_idx] F_train = F_total[train_idx] B_val = B_array[val_idx] F_val = F_total[val_idx] print(f"Data split: Train={len(train_idx)}, Val={len(val_idx)}") # Stage 1: 冻结编码器,训练交互网络和预测器 print("\n" + "="*70) print("STAGE 1: Domain Adaptation (Frozen Encoders)") print("="*70) # 冻结编码器 for encoder in self.model.dun_encoders: for param in encoder.parameters(): param.requires_grad = False trainable_params = list(self.model.interaction_network.parameters()) + \ list(self.model.force_predictor.parameters()) + \ [self.model.position_encoding] stage1_history = self._train_stage( B_train, F_train, B_val, F_val, B_source, F_source, trainable_params=trainable_params, epochs=100, lr=1e-4, batch_size=batch_size, stage_name="Stage1" ) self.history.append({'stage': 'Stage1', 'history': stage1_history}) # Stage 2: 整体微调 print("\n" + "="*70) print("STAGE 2: End-to-End Fine-tuning") print("="*70) # 解冻所有参数 for param in self.model.parameters(): param.requires_grad = True stage2_history = self._train_stage( B_train, F_train, B_val, F_val, None, None, # 第二阶段不使用源域数据 trainable_params=self.model.parameters(), epochs=150, lr=5e-5, batch_size=batch_size, stage_name="Stage2" ) self.history.append({'stage': 'Stage2', 'history': stage2_history}) # 保存最终模型 torch.save(self.model.state_dict(), os.path.join(self.output_folder, 'model_final.pth')) print("✓ Final model saved") self._plot_training_history() def _train_stage(self, B_train, F_train, B_val, F_val, B_source, F_source, trainable_params, epochs, lr, batch_size, stage_name): """ 训练单个阶段 """ optimizer = optim.Adam(trainable_params, lr=lr, weight_decay=1e-5) scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs) # 数据加载器 train_dataset = torch.utils.data.TensorDataset(B_train, F_train) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) val_dataset = torch.utils.data.TensorDataset(B_val, F_val) val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size) # 源域数据加载器(用于域适应) source_loader = None if B_source is not None and F_source is not None: source_dataset = torch.utils.data.TensorDataset(B_source, F_source) source_loader = torch.utils.data.DataLoader(source_dataset, batch_size=batch_size, shuffle=True) history = { 'train_loss': [], 'train_task_loss': [], 'train_mmd_loss': [], 'train_physics_loss': [], 'val_loss': [], 'val_metrics': [], 'learning_rate': [] } best_val_loss = float('inf') patience, patience_counter = 20, 0 for epoch in range(epochs): # 训练 self.model.train() epoch_losses = {k: 0.0 for k in ['total', 'task', 'mmd', 'physics']} for batch_idx, (B_batch, F_batch) in enumerate(train_loader): optimizer.zero_grad() # 域适应:从源域采样批次 if source_loader is not None: try: source_iter = source_loader.__iter__() B_source_batch, F_source_batch = next(source_iter) except: source_iter = source_loader.__iter__() B_source_batch, F_source_batch = next(source_iter) # 对齐批次大小 min_size = min(B_batch.size(0), B_source_batch.size(0)) B_batch = B_batch[:min_size] F_batch = F_batch[:min_size] B_source_batch = B_source_batch[:min_size] # 前向传播 if source_loader is not None: # 域适应模式 F_pred, target_features, _ = self.model(B_batch, return_features=True) _, source_features, _ = self.model(B_source_batch, return_features=True) # 计算各种损失 task_loss = self.mse_loss(F_pred, F_batch) # MMD损失 mmd_loss = 0.0 for i in range(self.num_duns): mmd_loss += self.mmd_loss(source_features[i], target_features[i]) mmd_loss = mmd_loss / self.num_duns # 物理一致性损失 physics_loss = self.physics_loss(target_features) # 总损失 total_loss = task_loss + 0.3 * mmd_loss + 0.1 * physics_loss else: # 标准训练模式 F_pred = self.model(B_batch) task_loss = self.mse_loss(F_pred, F_batch) total_loss = task_loss mmd_loss = torch.tensor(0.0) physics_loss = torch.tensor(0.0) total_loss.backward() torch.nn.utils.clip_grad_norm_(trainable_params, max_norm=1.0) optimizer.step() # 记录损失 epoch_losses['total'] += total_loss.item() epoch_losses['task'] += task_loss.item() epoch_losses['mmd'] += mmd_loss.item() if isinstance(mmd_loss, torch.Tensor) else mmd_loss epoch_losses['physics'] += physics_loss.item() if isinstance(physics_loss, torch.Tensor) else physics_loss # 记录平均损失 num_batches = len(train_loader) history['train_loss'].append(epoch_losses['total'] / num_batches) history['train_task_loss'].append(epoch_losses['task'] / num_batches) history['train_mmd_loss'].append(epoch_losses['mmd'] / num_batches) history['train_physics_loss'].append(epoch_losses['physics'] / num_batches) history['learning_rate'].append(optimizer.param_groups[0]['lr']) # 验证 val_loss, val_metrics = self._validate(val_loader) history['val_loss'].append(val_loss) history['val_metrics'].append(val_metrics) scheduler.step() # 打印进度 if (epoch + 1) % 10 == 0 or epoch == 0: print(f"{stage_name} Epoch {epoch+1}/{epochs}:") print(f" Train Loss: {history['train_loss'][-1]:.6f}") print(f" Val Loss: {val_loss:.6f}") print(f" Force R²: {val_metrics['overall']['r2']:.4f}, MAE: {val_metrics['overall']['mae']:.4f}") if source_loader is not None: print(f" MMD Loss: {history['train_mmd_loss'][-1]:.6f}") # 早停 if val_loss < best_val_loss: best_val_loss = val_loss patience_counter = 0 # 保存最佳模型 torch.save(self.model.state_dict(), os.path.join(self.output_folder, f'model_{stage_name}_best.pth')) else: patience_counter += 1 if patience_counter >= patience: print(f"Early stopping at epoch {epoch+1}") # 加载最佳模型 self.model.load_state_dict(torch.load( os.path.join(self.output_folder, f'model_{stage_name}_best.pth'))) break return history def _validate(self, val_loader): """验证过程""" self.model.eval() val_loss = 0.0 all_preds, all_targets = [], [] with torch.no_grad(): for B_batch, F_batch in val_loader: F_pred = self.model(B_batch) loss = self.mse_loss(F_pred, F_batch) val_loss += loss.item() all_preds.append(F_pred.cpu()) all_targets.append(F_batch.cpu()) # 计算指标 all_preds = torch.cat(all_preds, dim=0) all_targets = torch.cat(all_targets, dim=0) metrics = compute_metrics(all_preds, all_targets) return val_loss / len(val_loader), metrics def evaluate(self, B_test, F_test, plot_name="final_evaluation"): """最终评估""" self.model.eval() with torch.no_grad(): F_pred = self.model(B_test) metrics = compute_metrics(F_pred, F_test) print(f"\n{'='*70}") print("FINAL EVALUATION RESULTS") print(f"{'='*70}") for comp in ['Fx', 'Fy', 'Fz']: print(f"{comp}: R² = {metrics[comp]['r2']:.6f}, MAE = {metrics[comp]['mae']:.6f}") print(f"Overall: R² = {metrics['overall']['r2']:.6f}, MAE = {metrics['overall']['mae']:.6f}") # 绘制结果 self._plot_results(F_pred.cpu().numpy(), F_test.cpu().numpy(), os.path.join(self.output_folder, f"{plot_name}.png")) return metrics def _plot_results(self, preds, targets, save_path): """绘制预测结果""" fig, axes = plt.subplots(1, 3, figsize=(15, 5)) components = ['Fx', 'Fy', 'Fz'] for i, (ax, comp) in enumerate(zip(axes, components)): true_vals = targets[:, i] pred_vals = preds[:, i] ax.scatter(true_vals, pred_vals, alpha=0.6, s=20) min_val, max_val = min(true_vals.min(), pred_vals.min()), max(true_vals.max(), pred_vals.max()) ax.plot([min_val, max_val], [min_val, max_val], 'r--', alpha=0.8) r2 = r2_score(true_vals, pred_vals) mae = mean_absolute_error(true_vals, pred_vals) ax.set_xlabel('True Value') ax.set_ylabel('Predicted Value') ax.set_title(f'{comp}\nR² = {r2:.4f}, MAE = {mae:.4f}') ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig(save_path, dpi=150, bbox_inches='tight') plt.close() print(f"✓ Evaluation plot saved: {save_path}") def _plot_training_history(self): """绘制训练历史""" fig, axes = plt.subplots(2, 2, figsize=(15, 10)) # 准备数据 all_train_loss, all_val_loss = [], [] all_val_r2 = [] stage_boundaries = [0] for stage_info in self.history: hist = stage_info['history'] all_train_loss.extend(hist['train_loss']) all_val_loss.extend(hist['val_loss']) all_val_r2.extend([m['overall']['r2'] for m in hist['val_metrics']]) stage_boundaries.append(len(all_train_loss)) epochs = range(len(all_train_loss)) # 损失曲线 axes[0,0].plot(epochs, all_train_loss, label='Train Loss', linewidth=2) axes[0,0].plot(epochs, all_val_loss, label='Val Loss', linewidth=2) for boundary in stage_boundaries[1:-1]: axes[0,0].axvline(x=boundary, color='red', linestyle='--', alpha=0.7, label='Stage Change') axes[0,0].set_ylabel('Loss') axes[0,0].set_title('Training and Validation Loss') axes[0,0].legend() axes[0,0].grid(True, alpha=0.3) axes[0,0].set_yscale('log') # R²曲线 axes[0,1].plot(epochs, all_val_r2, label='Force R²', color='green', linewidth=2) for boundary in stage_boundaries[1:-1]: axes[0,1].axvline(x=boundary, color='red', linestyle='--', alpha=0.7) axes[0,1].set_ylabel('R² Score') axes[0,1].set_title('Validation R² Score') axes[0,1].legend() axes[0,1].grid(True, alpha=0.3) axes[0,1].set_ylim(0, 1) # 损失分量(第一阶段) if len(self.history) > 0: stage1_hist = self.history[0]['history'] stages1_epochs = range(len(stage1_hist['train_loss'])) axes[1,0].plot(stages1_epochs, stage1_hist['train_task_loss'], label='Task Loss', linewidth=2) axes[1,0].plot(stages1_epochs, stage1_hist['train_mmd_loss'], label='MMD Loss', linewidth=2) axes[1,0].plot(stages1_epochs, stage1_hist['train_physics_loss'], label='Physics Loss', linewidth=2) axes[1,0].set_xlabel('Epochs') axes[1,0].set_ylabel('Loss') axes[1,0].set_title('Stage 1: Loss Components') axes[1,0].legend() axes[1,0].grid(True, alpha=0.3) axes[1,0].set_yscale('log') # 最终结果对比 final_r2 = [] stage_names = [] for stage_info in self.history: if stage_info['history']['val_metrics']: final_r2.append(stage_info['history']['val_metrics'][-1]['overall']['r2']) stage_names.append(stage_info['stage']) axes[1,1].bar(range(len(final_r2)), final_r2, color=['blue', 'orange'], alpha=0.7) axes[1,1].set_xticks(range(len(final_r2))) axes[1,1].set_xticklabels(stage_names) axes[1,1].set_ylabel('Final R² Score') axes[1,1].set_title('Final Performance by Stage') axes[1,1].grid(True, alpha=0.3, axis='y') plt.tight_layout() plt.savefig(os.path.join(self.output_folder, 'training_history.png'), dpi=150, bbox_inches='tight') plt.close() print("✓ Training history plot saved") ###主函数### def main(): # ===== 配置参数 ===== file_path = 'D:/Gen3/5_biaoding/figerpad_exp/IP03A/mat/大压头_all.mat' train_data_path = 'D:/Gen3/5_biaoding/Data_processed/Dun3_F2B_Ftotal_processed.csv' pretrained_path = 'D:/Gen3/4_B2F/MPL_Dun3_Ftotal_GymCenter_processed_force_GELU_64_32_1126/b_to_f_model_last.onnx' output_folder = 'D:/Gen3/5_biaoding/ArrayForceInversion_Transformer_1126' os.makedirs(output_folder, exist_ok=True) # 数据加载 print("Loading data...") B_array, F_total, num_duns = load_multi_dun_exp_data(file_path, device, num_samples=100000) B_pretrain, F_pretrain = load_train_data(train_data_path, device) # 创建单个墩墩的源域数据(用于域适应) B_source = B_pretrain.unsqueeze(1) # (N, 1, 6, 3) B_source = B_source.repeat(1, num_duns, 1, 1) # (N, num_duns, 6, 3) F_source = F_pretrain print(f"Source data: {B_source.shape}, {F_source.shape}") # 初始化微调器 print("\nInitializing fine-tuner...") tuner = ArrayForceInversionFineTuner(pretrained_path, output_folder, num_duns=num_duns) tuner.load_pretrained_encoders(B_pretrain, F_pretrain) # 执行两阶段微调 print("\nStarting progressive fine-tuning...") tuner.progressive_fine_tune( B_array, F_total, B_source=B_source, F_source=F_source, val_split=0.15, batch_size=64 ) # 最终评估 print("\nPerforming final evaluation...") # 使用30%数据作为测试集 n_samples = B_array.size(0) test_size = int(0.3 * n_samples) test_indices = torch.randperm(n_samples)[:test_size] B_test = B_array[test_indices] F_test = F_total[test_indices] metrics = tuner.evaluate(B_test, F_test) print(f"\n✓ All results saved to: {output_folder}") return tuner if __name__ == "__main__": tuner = main()
最新发布
11-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值