| # ็ณป็ปๆถๆๆๆกฃ | |
| ๆฌๆๆกฃ่ฏฆ็ปๆ่ฟฐไบๆ ็ปชไธ็็็ถๆๅๅ้ขๆตๆจกๅ็็ณป็ปๆถๆใ่ฎพ่ฎกๅๅๅๅฎ็ฐ็ป่ใ | |
| ## ็ฎๅฝ | |
| 1. [็ณป็ปๆฆ่ฟฐ](#็ณป็ปๆฆ่ฟฐ) | |
| 2. [ๆดไฝๆถๆ](#ๆดไฝๆถๆ) | |
| 3. [ๆจกๅๆถๆ](#ๆจกๅๆถๆ) | |
| 4. [ๆฐๆฎๅค็ๆต็จ](#ๆฐๆฎๅค็ๆต็จ) | |
| 5. [่ฎญ็ปๆต็จ](#่ฎญ็ปๆต็จ) | |
| 6. [ๆจ็ๆต็จ](#ๆจ็ๆต็จ) | |
| 7. [ๆจกๅ่ฎพ่ฎก](#ๆจกๅ่ฎพ่ฎก) | |
| 8. [่ฎพ่ฎกๆจกๅผ](#่ฎพ่ฎกๆจกๅผ) | |
| 9. [ๆง่ฝไผๅ](#ๆง่ฝไผๅ) | |
| 10. [ๆฉๅฑๆง่ฎพ่ฎก](#ๆฉๅฑๆง่ฎพ่ฎก) | |
| ## ็ณป็ปๆฆ่ฟฐ | |
| ### ่ฎพ่ฎก็ฎๆ | |
| ๆฌ็ณป็ปๆจๅจๅฎ็ฐไธไธช้ซๆใๅฏๆฉๅฑใๆ็ปดๆค็ๆ ็ปชไธ็็็ถๆๅๅ้ขๆตๆจกๅ๏ผไธป่ฆ่ฎพ่ฎก็ฎๆ ๅ ๆฌ๏ผ | |
| 1. **้ซๆง่ฝ**: ๆฏๆGPUๅ ้๏ผไผๅๆจ็้ๅบฆ | |
| 2. **ๆจกๅๅ**: ๆธ ๆฐ็ๆจกๅๅๅ๏ผไพฟไบ็ปดๆคๅๆฉๅฑ | |
| 3. **ๅฏ้ ็ฝฎ**: ็ตๆดป็้ ็ฝฎ็ณป็ป๏ผๆฏๆ่ถ ๅๆฐ่ฐไผ | |
| 4. **ๆ็จๆง**: ๅฎๆด็CLIๅทฅๅ ทๅPython API | |
| 5. **ๅฏๆฉๅฑ**: ๆฏๆๆฐ็ๆจกๅๆถๆๅๆๅคฑๅฝๆฐ | |
| 6. **ๅฏ่งๆต**: ๅฎๆด็ๆฅๅฟๅ็ๆง็ณป็ป | |
| ### ๆๆฏๆ | |
| - **ๆทฑๅบฆๅญฆไน ๆกๆถ**: PyTorch 1.12+ | |
| - **ๆฐๆฎๅค็**: NumPy, Pandas, scikit-learn | |
| - **้ ็ฝฎ็ฎก็**: PyYAML, OmegaConf | |
| - **ๅฏ่งๅ**: Matplotlib, Seaborn, Plotly | |
| - **ๅฝไปค่ก**: argparse, Click | |
| - **ๆฅๅฟ็ณป็ป**: Loguru | |
| - **ๅฎ้ช่ท่ธช**: MLflow, Weights & Biases | |
| - **ๆง่ฝๅๆ**: py-spy, memory-profiler | |
| ## ๆดไฝๆถๆ | |
| ### ็ณป็ปๆถๆๅพ | |
| ``` | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ ็จๆทๆฅๅฃๅฑ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ CLIๅทฅๅ ท โ Python API โ Web API โ Jupyter Notebook โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ไธๅก้ป่พๅฑ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ่ฎญ็ป็ฎก็ๅจ โ ๆจ็ๅผๆ โ ่ฏไผฐๅจ โ ้ ็ฝฎ็ฎก็ๅจ โ ๆฅๅฟ็ฎก็ๅจ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ๆ ธๅฟๆจกๅๅฑ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ PAD้ขๆตๅจ โ ๆๅคฑๅฝๆฐ โ ่ฏไผฐๆๆ โ ๆจกๅๅทฅๅ โ ไผๅๅจ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ๆฐๆฎๅค็ๅฑ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ๆฐๆฎๅ ่ฝฝๅจ โ ้ขๅค็ๅจ โ ๆฐๆฎๅขๅผบๅจ โ ๅๆๆฐๆฎ็ๆๅจ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ๅบ็ก่ฎพๆฝๅฑ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ ๆไปถ็ณป็ป โ GPU่ฎก็ฎ โ ๅ ๅญ็ฎก็ โ ๅผๅธธๅค็ โ ๅทฅๅ ทๅฝๆฐ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ``` | |
| ### ๆจกๅไพ่ตๅ ณ็ณป | |
| ``` | |
| CLIๆจกๅ โ ไธๅก้ป่พๅฑ โ ๆ ธๅฟๆจกๅๅฑ โ ๆฐๆฎๅค็ๅฑ โ ๅบ็ก่ฎพๆฝๅฑ | |
| โ | |
| ้ ็ฝฎ็ฎก็ๅจ โ ๆๆๆจกๅ | |
| โ | |
| ๆฅๅฟ็ฎก็ๅจ โ ๆๆๆจกๅ | |
| ``` | |
| ## ๆจกๅๆถๆ | |
| ### ็ฝ็ป็ปๆ | |
| PAD้ขๆตๅจ้็จๅคๅฑๆ็ฅๆบ(MLP)ๆถๆ๏ผ | |
| ``` | |
| ่พๅ ฅๅฑ (7็ปด) | |
| โ | |
| ้่ๅฑ1 (128็ฅ็ปๅ ) + ReLU + Dropout(0.3) | |
| โ | |
| ้่ๅฑ2 (64็ฅ็ปๅ ) + ReLU + Dropout(0.3) | |
| โ | |
| ้่ๅฑ3 (32็ฅ็ปๅ ) + ReLU | |
| โ | |
| ่พๅบๅฑ (5็ฅ็ปๅ ) + Linearๆฟๆดป | |
| ``` | |
| ### ็ฝ็ป็ปไปถ่ฏฆ่งฃ | |
| #### ่พๅ ฅๅฑ | |
| - **็ปดๅบฆ**: 7็ปด็นๅพๅ้ | |
| - **็นๅพ็ปๆ**: | |
| - User PAD: 3็ปด (Pleasure, Arousal, Dominance) | |
| - Vitality: 1็ปด (็็ๆดปๅๅผ) | |
| - Current PAD: 3็ปด (ๅฝๅๆ ็ปช็ถๆ) | |
| #### ้่ๅฑ่ฎพ่ฎกๅๅ | |
| 1. **้ๅฑๅ็ผฉ**: ไป128 โ 64 โ 32๏ผ้ๅฑๅๅฐ็ฅ็ปๅ ๆฐ้ | |
| 2. **ๆฟๆดปๅฝๆฐ**: ไฝฟ็จReLUๆฟๆดปๅฝๆฐ๏ผ้ฟๅ ๆขฏๅบฆๆถๅคฑ | |
| 3. **ๆญฃๅๅ**: ๅจๅไธคๅฑไฝฟ็จDropout้ฒๆญข่ฟๆๅ | |
| 4. **ๆ้ๅๅงๅ**: ไฝฟ็จXavierๅๅๅๅงๅ๏ผ้ๅReLUๆฟๆดป | |
| #### ่พๅบๅฑ่ฎพ่ฎก | |
| - **็ปดๅบฆ**: 3็ปด่พๅบๅ้ | |
| - **่พๅบ็ปๆ**: | |
| - ฮPAD: 3็ปด (ๆ ็ปชๅๅ้๏ผฮPleasure, ฮArousal, ฮDominance) | |
| - ฮPressure: ้่ฟ PAD ๅๅๅจๆ่ฎก็ฎ๏ผๅ ฌๅผ๏ผ1.0ร(-ฮP) + 0.8ร(ฮA) + 0.6ร(-ฮD)๏ผ | |
| - **ๆฟๆดปๅฝๆฐ**: ็บฟๆงๆฟๆดป๏ผ้็จไบๅๅฝไปปๅก | |
| ### ๆจกๅ้ ็ฝฎ็ณป็ป | |
| ```python | |
| # ้ป่ฎคๆถๆ้ ็ฝฎ | |
| DEFAULT_ARCHITECTURE = { | |
| 'input_dim': 7, | |
| 'output_dim': 3, | |
| 'hidden_dims': [512, 256, 128], | |
| 'dropout_rate': 0.3, | |
| 'activation': 'relu', | |
| 'weight_init': 'xavier_uniform', | |
| 'bias_init': 'zeros' | |
| } | |
| # ๅฏ้ ็ฝฎๅๆฐ | |
| CONFIGURABLE_PARAMS = { | |
| 'hidden_dims': { | |
| 'type': list, | |
| 'default': [128, 64, 32], | |
| 'constraints': [ | |
| lambda x: len(x) >= 1, | |
| lambda x: all(isinstance(n, int) and n > 0 for n in x), | |
| lambda x: x == sorted(x, reverse=True) # ้ๅๅบๅ | |
| ] | |
| }, | |
| 'dropout_rate': { | |
| 'type': float, | |
| 'default': 0.3, | |
| 'range': [0.0, 0.9] | |
| }, | |
| 'activation': { | |
| 'type': str, | |
| 'default': 'relu', | |
| 'choices': ['relu', 'tanh', 'sigmoid', 'leaky_relu'] | |
| } | |
| } | |
| ``` | |
| ## ๆฐๆฎๅค็ๆต็จ | |
| ### ๆฐๆฎๆตๆฐด็บฟ | |
| ``` | |
| ๅๅงๆฐๆฎ โ ๆฐๆฎ้ช่ฏ โ ็นๅพๆๅ โ ๆฐๆฎ้ขๅค็ โ ๆฐๆฎๅขๅผบ โ ๆนๆฌก็ๆ | |
| โ | |
| ๆจกๅ่ฎญ็ป/ๆจ็ | |
| ``` | |
| ### ๆฐๆฎ้ขๅค็ๆต็จ | |
| #### 1. ๆฐๆฎ้ช่ฏ | |
| ```python | |
| class DataValidator: | |
| """ๆฐๆฎ้ช่ฏๅจ๏ผ็กฎไฟๆฐๆฎ่ดจ้""" | |
| def validate_input_shape(self, data: np.ndarray) -> bool: | |
| """้ช่ฏ่พๅ ฅๆฐๆฎๅฝข็ถ""" | |
| return data.shape[1] == 7 | |
| def validate_value_ranges(self, data: np.ndarray) -> Dict[str, bool]: | |
| """้ช่ฏๆฐๅผ่ๅด""" | |
| return { | |
| 'pad_features_valid': np.all(data[:, :6] >= -1) and np.all(data[:, :6] <= 1), | |
| 'vitality_valid': np.all(data[:, 3] >= 0) and np.all(data[:, 3] <= 100) | |
| } | |
| def check_missing_values(self, data: np.ndarray) -> Dict[str, Any]: | |
| """ๆฃๆฅ็ผบๅคฑๅผ""" | |
| return { | |
| 'has_missing': np.isnan(data).any(), | |
| 'missing_count': np.isnan(data).sum(), | |
| 'missing_ratio': np.isnan(data).mean() | |
| } | |
| ``` | |
| #### 2. ็นๅพๅทฅ็จ | |
| ```python | |
| class FeatureEngineer: | |
| """็นๅพๅทฅ็จๅจ""" | |
| def extract_pad_features(self, data: np.ndarray) -> np.ndarray: | |
| """ๆๅPAD็นๅพ""" | |
| user_pad = data[:, :3] | |
| current_pad = data[:, 4:7] | |
| return np.hstack([user_pad, current_pad]) | |
| def compute_pad_differences(self, data: np.ndarray) -> np.ndarray: | |
| """่ฎก็ฎPADๅทฎๅผ""" | |
| user_pad = data[:, :3] | |
| current_pad = data[:, 4:7] | |
| return user_pad - current_pad | |
| def create_interaction_features(self, data: np.ndarray) -> np.ndarray: | |
| """ๅๅปบไบคไบ็นๅพ""" | |
| user_pad = data[:, :3] | |
| current_pad = data[:, 4:7] | |
| # PADๅ ็งฏ | |
| pad_interaction = np.sum(user_pad * current_pad, axis=1, keepdims=True) | |
| # PADๆฌงๆฐ่ท็ฆป | |
| pad_distance = np.linalg.norm(user_pad - current_pad, axis=1, keepdims=True) | |
| return np.hstack([data, pad_interaction, pad_distance]) | |
| ``` | |
| #### 3. ๆฐๆฎๆ ๅๅ | |
| ```python | |
| class DataNormalizer: | |
| """ๆฐๆฎๆ ๅๅๅจ""" | |
| def __init__(self, method: str = 'standard'): | |
| self.method = method | |
| self.scalers = {} | |
| def fit_pad_features(self, features: np.ndarray): | |
| """ๆๅPAD็นๅพๆ ๅๅๅจ""" | |
| if self.method == 'standard': | |
| self.scalers['pad'] = StandardScaler() | |
| elif self.method == 'minmax': | |
| self.scalers['pad'] = MinMaxScaler(feature_range=(-1, 1)) | |
| self.scalers['pad'].fit(features) | |
| def fit_vitality_feature(self, features: np.ndarray): | |
| """ๆๅๆดปๅๅผๆ ๅๅๅจ""" | |
| if self.method == 'standard': | |
| self.scalers['vitality'] = StandardScaler() | |
| elif self.method == 'minmax': | |
| self.scalers['vitality'] = MinMaxScaler(feature_range=(0, 1)) | |
| self.scalers['vitality'].fit(features.reshape(-1, 1)) | |
| ``` | |
| ### ๆฐๆฎๅขๅผบ็ญ็ฅ | |
| ```python | |
| class DataAugmenter: | |
| """ๆฐๆฎๅขๅผบๅจ""" | |
| def __init__(self, noise_std: float = 0.01, mixup_alpha: float = 0.2): | |
| self.noise_std = noise_std | |
| self.mixup_alpha = mixup_alpha | |
| def add_gaussian_noise(self, features: np.ndarray) -> np.ndarray: | |
| """ๆทปๅ ้ซๆฏๅชๅฃฐ""" | |
| noise = np.random.normal(0, self.noise_std, features.shape) | |
| return features + noise | |
| def mixup_augmentation(self, features: np.ndarray, labels: np.ndarray) -> tuple: | |
| """Mixupๆฐๆฎๅขๅผบ""" | |
| batch_size = features.shape[0] | |
| lam = np.random.beta(self.mixup_alpha, self.mixup_alpha) | |
| # ้ๆบๆไนฑ็ดขๅผ | |
| index = np.random.permutation(batch_size) | |
| # ๆททๅ็นๅพๅๆ ็ญพ | |
| mixed_features = lam * features + (1 - lam) * features[index] | |
| mixed_labels = lam * labels + (1 - lam) * labels[index] | |
| return mixed_features, mixed_labels | |
| ``` | |
| ## ่ฎญ็ปๆต็จ | |
| ### ่ฎญ็ปๆถๆ | |
| ``` | |
| ้ ็ฝฎๅ ่ฝฝ โ ๆฐๆฎๅๅค โ ๆจกๅๅๅงๅ โ ่ฎญ็ปๅพช็ฏ โ ๆจกๅไฟๅญ โ ็ปๆ่ฏไผฐ | |
| ``` | |
| ### ่ฎญ็ป็ฎก็ๅจ่ฎพ่ฎก | |
| ```python | |
| class ModelTrainer: | |
| """ๆจกๅ่ฎญ็ป็ฎก็ๅจ""" | |
| def __init__(self, model, preprocessor=None, device='auto'): | |
| self.model = model | |
| self.preprocessor = preprocessor | |
| self.device = self._setup_device(device) | |
| self.logger = logging.getLogger(__name__) | |
| # ่ฎญ็ป็ถๆ | |
| self.training_state = { | |
| 'epoch': 0, | |
| 'best_loss': float('inf'), | |
| 'patience_counter': 0, | |
| 'training_history': [] | |
| } | |
| def setup_training(self, config: Dict[str, Any]): | |
| """่ฎพ็ฝฎ่ฎญ็ป็ฏๅข""" | |
| # ไผๅๅจ่ฎพ็ฝฎ | |
| self.optimizer = self._create_optimizer(config['optimizer']) | |
| # ๅญฆไน ็่ฐๅบฆๅจ | |
| self.scheduler = self._create_scheduler(config['scheduler']) | |
| # ๆๅคฑๅฝๆฐ | |
| self.criterion = self._create_criterion(config['loss']) | |
| # ๆฉๅๆบๅถ | |
| self.early_stopping = self._setup_early_stopping(config['early_stopping']) | |
| # ๆฃๆฅ็น็ฎก็ | |
| self.checkpoint_manager = CheckpointManager(config['checkpointing']) | |
| def train_epoch(self, train_loader: DataLoader) -> Dict[str, float]: | |
| """่ฎญ็ปไธไธชepoch""" | |
| self.model.train() | |
| epoch_loss = 0.0 | |
| num_batches = len(train_loader) | |
| for batch_idx, (features, labels) in enumerate(train_loader): | |
| features = features.to(self.device) | |
| labels = labels.to(self.device) | |
| # ๅๅไผ ๆญ | |
| self.optimizer.zero_grad() | |
| outputs = self.model(features) | |
| loss = self.criterion(outputs, labels) | |
| # ๅๅไผ ๆญ | |
| loss.backward() | |
| # ๆขฏๅบฆ่ฃๅช | |
| torch.nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=1.0) | |
| # ๅๆฐๆดๆฐ | |
| self.optimizer.step() | |
| epoch_loss += loss.item() | |
| # ๆฅๅฟ่ฎฐๅฝ | |
| if batch_idx % 100 == 0: | |
| self.logger.debug(f'Batch {batch_idx}/{num_batches}, Loss: {loss.item():.6f}') | |
| return {'train_loss': epoch_loss / num_batches} | |
| def validate_epoch(self, val_loader: DataLoader) -> Dict[str, float]: | |
| """้ช่ฏไธไธชepoch""" | |
| self.model.eval() | |
| val_loss = 0.0 | |
| num_batches = len(val_loader) | |
| with torch.no_grad(): | |
| for features, labels in val_loader: | |
| features = features.to(self.device) | |
| labels = labels.to(self.device) | |
| outputs = self.model(features) | |
| loss = self.criterion(outputs, labels) | |
| val_loss += loss.item() | |
| return {'val_loss': val_loss / num_batches} | |
| ``` | |
| ### ่ฎญ็ป็ญ็ฅ | |
| #### 1. ๅญฆไน ็่ฐๅบฆ | |
| ```python | |
| class LearningRateScheduler: | |
| """ๅญฆไน ็่ฐๅบฆ็ญ็ฅ""" | |
| @staticmethod | |
| def cosine_annealing_scheduler(optimizer, T_max, eta_min=1e-6): | |
| """ไฝๅผฆ้็ซ่ฐๅบฆๅจ""" | |
| return torch.optim.lr_scheduler.CosineAnnealingLR( | |
| optimizer, T_max=T_max, eta_min=eta_min | |
| ) | |
| @staticmethod | |
| def reduce_on_plateau_scheduler(optimizer, patience=5, factor=0.5): | |
| """ๅนณๅฐ่กฐๅ่ฐๅบฆๅจ""" | |
| return torch.optim.lr_scheduler.ReduceLROnPlateau( | |
| optimizer, mode='min', patience=patience, factor=factor | |
| ) | |
| @staticmethod | |
| def warmup_cosine_scheduler(optimizer, warmup_epochs, total_epochs): | |
| """้ข็ญไฝๅผฆ่ฐๅบฆๅจ""" | |
| def lr_lambda(epoch): | |
| if epoch < warmup_epochs: | |
| return epoch / warmup_epochs | |
| else: | |
| progress = (epoch - warmup_epochs) / (total_epochs - warmup_epochs) | |
| return 0.5 * (1 + math.cos(math.pi * progress)) | |
| return torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda) | |
| ``` | |
| #### 2. ๆฉๅๆบๅถ | |
| ```python | |
| class EarlyStopping: | |
| """ๆฉๅๆบๅถ""" | |
| def __init__(self, patience=10, min_delta=1e-4, mode='min'): | |
| self.patience = patience | |
| self.min_delta = min_delta | |
| self.mode = mode | |
| self.counter = 0 | |
| self.best_score = None | |
| if mode == 'min': | |
| self.is_better = lambda x, y: x < y - min_delta | |
| else: | |
| self.is_better = lambda x, y: x > y + min_delta | |
| def __call__(self, score): | |
| if self.best_score is None: | |
| self.best_score = score | |
| return False | |
| if self.is_better(score, self.best_score): | |
| self.best_score = score | |
| self.counter = 0 | |
| return False | |
| else: | |
| self.counter += 1 | |
| return self.counter >= self.patience | |
| ``` | |
| ## ๆจ็ๆต็จ | |
| ### ๆจ็ๆถๆ | |
| ``` | |
| ๆจกๅๅ ่ฝฝ โ ่พๅ ฅ้ช่ฏ โ ๆฐๆฎ้ขๅค็ โ ๆจกๅๆจ็ โ ็ปๆๅๅค็ โ ่พๅบๆ ผๅผๅ | |
| ``` | |
| ### ๆจ็ๅผๆ่ฎพ่ฎก | |
| ```python | |
| class InferenceEngine: | |
| """้ซๆง่ฝๆจ็ๅผๆ""" | |
| def __init__(self, model, preprocessor=None, device='auto'): | |
| self.model = model | |
| self.preprocessor = preprocessor | |
| self.device = self._setup_device(device) | |
| self.model.to(self.device) | |
| self.model.eval() | |
| # ๆง่ฝไผๅ | |
| self._optimize_model() | |
| # ้ข็ญ | |
| self._warmup_model() | |
| def _optimize_model(self): | |
| """ๆจกๅๆง่ฝไผๅ""" | |
| # TorchScriptไผๅ | |
| try: | |
| self.model = torch.jit.script(self.model) | |
| self.logger.info("ๆจกๅๅทฒไผๅไธบTorchScriptๆ ผๅผ") | |
| except Exception as e: | |
| self.logger.warning(f"TorchScriptไผๅๅคฑ่ดฅ: {e}") | |
| # ๆททๅ็ฒพๅบฆ | |
| if self.device.type == 'cuda': | |
| self.scaler = torch.cuda.amp.GradScaler() | |
| def _warmup_model(self, num_warmup=5): | |
| """ๆจกๅ้ข็ญ""" | |
| dummy_input = torch.randn(1, 7).to(self.device) | |
| with torch.no_grad(): | |
| for _ in range(num_warmup): | |
| _ = self.model(dummy_input) | |
| self.logger.info(f"ๆจกๅ้ข็ญๅฎๆ๏ผ้ข็ญๆฌกๆฐ: {num_warmup}") | |
| def predict_single(self, input_data: Union[List, np.ndarray]) -> Dict[str, Any]: | |
| """ๅๆ ทๆฌๆจ็""" | |
| # ่พๅ ฅ้ช่ฏ | |
| validated_input = self._validate_input(input_data) | |
| # ๆฐๆฎ้ขๅค็ | |
| processed_input = self._preprocess_input(validated_input) | |
| # ๆจกๅๆจ็ | |
| with torch.no_grad(): | |
| if self.device.type == 'cuda': | |
| with torch.cuda.amp.autocast(): | |
| output = self.model(processed_input) | |
| else: | |
| output = self.model(processed_input) | |
| # ็ปๆๅๅค็ | |
| result = self._postprocess_output(output) | |
| return result | |
| def predict_batch(self, input_batch: Union[List, np.ndarray]) -> List[Dict[str, Any]]: | |
| """ๆน้ๆจ็""" | |
| # ่พๅ ฅ้ช่ฏๅ้ขๅค็ | |
| validated_batch = self._validate_batch(input_batch) | |
| processed_batch = self._preprocess_batch(validated_batch) | |
| # ๅๆนๆจ็ | |
| batch_size = min(32, len(processed_batch)) | |
| results = [] | |
| for i in range(0, len(processed_batch), batch_size): | |
| batch_input = processed_batch[i:i+batch_size] | |
| with torch.no_grad(): | |
| if self.device.type == 'cuda': | |
| with torch.cuda.amp.autocast(): | |
| batch_output = self.model(batch_input) | |
| else: | |
| batch_output = self.model(batch_input) | |
| # ๅๅค็ | |
| batch_results = self._postprocess_batch(batch_output) | |
| results.extend(batch_results) | |
| return results | |
| ``` | |
| ### ๆง่ฝไผๅ็ญ็ฅ | |
| #### 1. ๅ ๅญไผๅ | |
| ```python | |
| class MemoryOptimizer: | |
| """ๅ ๅญไผๅๅจ""" | |
| @staticmethod | |
| def optimize_memory_usage(): | |
| """ไผๅๅ ๅญไฝฟ็จ""" | |
| # ๆธ ็GPU็ผๅญ | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| # ่ฎพ็ฝฎๅ ๅญๅ้ ็ญ็ฅ | |
| if torch.cuda.is_available(): | |
| torch.cuda.set_per_process_memory_fraction(0.9) | |
| @staticmethod | |
| def monitor_memory_usage(): | |
| """็ๆงๅ ๅญไฝฟ็จ""" | |
| if torch.cuda.is_available(): | |
| allocated = torch.cuda.memory_allocated() / 1024**3 # GB | |
| cached = torch.cuda.memory_reserved() / 1024**3 # GB | |
| return {'allocated': allocated, 'cached': cached} | |
| return {'allocated': 0, 'cached': 0} | |
| ``` | |
| #### 2. ่ฎก็ฎไผๅ | |
| ```python | |
| class ComputeOptimizer: | |
| """่ฎก็ฎไผๅๅจ""" | |
| @staticmethod | |
| def enable_tf32(): | |
| """ๅฏ็จTF32ๅ ้๏ผAmpereๆถๆGPU๏ผ""" | |
| if torch.cuda.is_available(): | |
| torch.backends.cuda.matmul.allow_tf32 = True | |
| torch.backends.cudnn.allow_tf32 = True | |
| @staticmethod | |
| def optimize_dataloader(dataloader, num_workers=4, pin_memory=True): | |
| """ไผๅๆฐๆฎๅ ่ฝฝๅจ""" | |
| return DataLoader( | |
| dataloader.dataset, | |
| batch_size=dataloader.batch_size, | |
| shuffle=dataloader.shuffle, | |
| num_workers=num_workers, | |
| pin_memory=pin_memory and torch.cuda.is_available(), | |
| persistent_workers=True if num_workers > 0 else False | |
| ) | |
| ``` | |
| ## ๆจกๅ่ฎพ่ฎก | |
| ### ๆ ธๅฟๆจกๅ | |
| #### 1. ๆจกๅๆจกๅ (`src.models/`) | |
| ```python | |
| # ๆจกๅๆจกๅ็ปๆ | |
| src/models/ | |
| โโโ __init__.py | |
| โโโ pad_predictor.py # ๆ ธๅฟ้ขๆตๅจ | |
| โโโ loss_functions.py # ๆๅคฑๅฝๆฐ | |
| โโโ metrics.py # ่ฏไผฐๆๆ | |
| โโโ model_factory.py # ๆจกๅๅทฅๅ | |
| โโโ base_model.py # ๅบ็กๆจกๅ็ฑป | |
| ``` | |
| **่ฎพ่ฎกๅๅ**: | |
| - ๅไธ่่ดฃ๏ผๆฏไธช็ฑปๅช่ด่ดฃไธไธช็นๅฎๅ่ฝ | |
| - ๅผ้ญๅๅ๏ผๅฏนๆฉๅฑๅผๆพ๏ผๅฏนไฟฎๆนๅฐ้ญ | |
| - ไพ่ตๅ็ฝฎ๏ผไพ่ตๆฝ่ฑก่้ๅ ทไฝๅฎ็ฐ | |
| #### 2. ๆฐๆฎๆจกๅ (`src.data/`) | |
| ```python | |
| # ๆฐๆฎๆจกๅ็ปๆ | |
| src/data/ | |
| โโโ __init__.py | |
| โโโ dataset.py # ๆฐๆฎ้็ฑป | |
| โโโ data_loader.py # ๆฐๆฎๅ ่ฝฝๅจ | |
| โโโ preprocessor.py # ๆฐๆฎ้ขๅค็ๅจ | |
| โโโ synthetic_generator.py # ๅๆๆฐๆฎ็ๆๅจ | |
| โโโ data_validator.py # ๆฐๆฎ้ช่ฏๅจ | |
| ``` | |
| **่ฎพ่ฎกๆจกๅผ**: | |
| - ็ญ็ฅๆจกๅผ๏ผไธๅ็ๆฐๆฎ้ขๅค็็ญ็ฅ | |
| - ๅทฅๅๆจกๅผ๏ผๆฐๆฎ็ๆๅจๅทฅๅ | |
| - ่งๅฏ่ ๆจกๅผ๏ผๆฐๆฎ่ดจ้็ๆง | |
| #### 3. ๅทฅๅ ทๆจกๅ (`src.utils/`) | |
| ```python | |
| # ๅทฅๅ ทๆจกๅ็ปๆ | |
| src/utils/ | |
| โโโ __init__.py | |
| โโโ inference_engine.py # ๆจ็ๅผๆ | |
| โโโ trainer.py # ่ฎญ็ปๅจ | |
| โโโ logger.py # ๆฅๅฟๅทฅๅ ท | |
| โโโ config.py # ้ ็ฝฎ็ฎก็ | |
| โโโ exceptions.py # ่ชๅฎไนๅผๅธธ | |
| ``` | |
| **ๅ่ฝ็นๆง**: | |
| - ้ซๆง่ฝๆจ็ๅผๆ | |
| - ็ตๆดป็่ฎญ็ป็ฎก็ | |
| - ็ปๆๅๆฅๅฟ็ณป็ป | |
| - ็ปไธ็้ ็ฝฎ็ฎก็ | |
| ## ่ฎพ่ฎกๆจกๅผ | |
| ### 1. ๅทฅๅๆจกๅผ (Factory Pattern) | |
| ```python | |
| class ModelFactory: | |
| """ๆจกๅๅทฅๅ็ฑป""" | |
| _models = { | |
| 'pad_predictor': PADPredictor, | |
| 'advanced_predictor': AdvancedPADPredictor, | |
| 'ensemble_predictor': EnsemblePredictor | |
| } | |
| @classmethod | |
| def create_model(cls, model_type: str, config: Dict[str, Any]): | |
| """ๅๅปบๆจกๅๅฎไพ""" | |
| if model_type not in cls._models: | |
| raise ValueError(f"ไธๆฏๆ็ๆจกๅ็ฑปๅ: {model_type}") | |
| model_class = cls._models[model_type] | |
| return model_class(**config) | |
| @classmethod | |
| def register_model(cls, name: str, model_class): | |
| """ๆณจๅๆฐ็ๆจกๅ็ฑปๅ""" | |
| cls._models[name] = model_class | |
| ``` | |
| ### 2. ็ญ็ฅๆจกๅผ (Strategy Pattern) | |
| ```python | |
| class LossStrategy(ABC): | |
| """ๆๅคฑ็ญ็ฅๆฝ่ฑกๅบ็ฑป""" | |
| @abstractmethod | |
| def compute_loss(self, predictions, targets): | |
| pass | |
| class WeightedMSELoss(LossStrategy): | |
| """ๅ ๆๅๆน่ฏฏๅทฎๆๅคฑ""" | |
| def compute_loss(self, predictions, targets): | |
| # ๅฎ็ฐๅ ๆMSE | |
| pass | |
| class HuberLoss(LossStrategy): | |
| """Huberๆๅคฑ""" | |
| def compute_loss(self, predictions, targets): | |
| # ๅฎ็ฐHuberๆๅคฑ | |
| pass | |
| class LossContext: | |
| """ๆๅคฑไธไธๆ""" | |
| def __init__(self, strategy: LossStrategy): | |
| self._strategy = strategy | |
| def set_strategy(self, strategy: LossStrategy): | |
| self._strategy = strategy | |
| def compute_loss(self, predictions, targets): | |
| return self._strategy.compute_loss(predictions, targets) | |
| ``` | |
| ### 3. ่งๅฏ่ ๆจกๅผ (Observer Pattern) | |
| ```python | |
| class TrainingObserver(ABC): | |
| """่ฎญ็ป่งๅฏ่ ๆฝ่ฑกๅบ็ฑป""" | |
| @abstractmethod | |
| def on_epoch_start(self, epoch, metrics): | |
| pass | |
| @abstractmethod | |
| def on_epoch_end(self, epoch, metrics): | |
| pass | |
| class LoggingObserver(TrainingObserver): | |
| """ๆฅๅฟ่งๅฏ่ """ | |
| def on_epoch_end(self, epoch, metrics): | |
| self.logger.info(f"Epoch {epoch}: {metrics}") | |
| class CheckpointObserver(TrainingObserver): | |
| """ๆฃๆฅ็น่งๅฏ่ """ | |
| def on_epoch_end(self, epoch, metrics): | |
| if self.should_save_checkpoint(metrics): | |
| self.save_checkpoint(epoch, metrics) | |
| class TrainingSubject: | |
| """่ฎญ็ปไธป้ข""" | |
| def __init__(self): | |
| self._observers = [] | |
| def attach(self, observer: TrainingObserver): | |
| self._observers.append(observer) | |
| def detach(self, observer: TrainingObserver): | |
| self._observers.remove(observer) | |
| def notify_epoch_end(self, epoch, metrics): | |
| for observer in self._observers: | |
| observer.on_epoch_end(epoch, metrics) | |
| ``` | |
| ### 4. ๅปบ้ ่ ๆจกๅผ (Builder Pattern) | |
| ```python | |
| class ModelBuilder: | |
| """ๆจกๅๅปบ้ ่ """ | |
| def __init__(self): | |
| self.input_dim = 7 | |
| self.output_dim = 3 | |
| self.hidden_dims = [128, 64, 32] | |
| self.dropout_rate = 0.3 | |
| self.activation = 'relu' | |
| def with_dimensions(self, input_dim, output_dim): | |
| self.input_dim = input_dim | |
| self.output_dim = output_dim | |
| return self | |
| def with_hidden_layers(self, hidden_dims): | |
| self.hidden_dims = hidden_dims | |
| return self | |
| def with_dropout(self, dropout_rate): | |
| self.dropout_rate = dropout_rate | |
| return self | |
| def with_activation(self, activation): | |
| self.activation = activation | |
| return self | |
| def build(self): | |
| return PADPredictor( | |
| input_dim=self.input_dim, | |
| output_dim=self.output_dim, | |
| hidden_dims=self.hidden_dims, | |
| dropout_rate=self.dropout_rate | |
| ) | |
| # ไฝฟ็จ็คบไพ | |
| model = (ModelBuilder() | |
| .with_dimensions(7, 5) | |
| .with_hidden_layers([256, 128, 64]) | |
| .with_dropout(0.3) | |
| .build()) | |
| ``` | |
| ## ๆง่ฝไผๅ | |
| ### 1. ๆจกๅไผๅ | |
| #### ้ๅ | |
| ```python | |
| class ModelQuantizer: | |
| """ๆจกๅ้ๅๅจ""" | |
| @staticmethod | |
| def quantize_model(model, calibration_data): | |
| """ๅจๆ้ๅๆจกๅ""" | |
| model.eval() | |
| # ๅจๆ้ๅ | |
| quantized_model = torch.quantization.quantize_dynamic( | |
| model, {nn.Linear}, dtype=torch.qint8 | |
| ) | |
| return quantized_model | |
| @staticmethod | |
| def quantize_aware_training(model, train_loader): | |
| """้ๅๆ็ฅ่ฎญ็ป""" | |
| model.eval() | |
| model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm') | |
| torch.quantization.prepare_qat(model, inplace=True) | |
| # ้ๅๆ็ฅ่ฎญ็ป | |
| for epoch in range(num_epochs): | |
| for batch in train_loader: | |
| # ่ฎญ็ปๆญฅ้ชค | |
| pass | |
| # ่ฝฌๆขไธบ้ๅๆจกๅ | |
| quantized_model = torch.quantization.convert(model.eval(), inplace=False) | |
| return quantized_model | |
| ``` | |
| #### ๆจกๅๅชๆ | |
| ```python | |
| class ModelPruner: | |
| """ๆจกๅๅชๆๅจ""" | |
| @staticmethod | |
| def prune_model(model, pruning_ratio=0.2): | |
| """็ปๆๅๅชๆ""" | |
| import torch.nn.utils.prune as prune | |
| # ๅชๆๆๆ็บฟๆงๅฑ | |
| for name, module in model.named_modules(): | |
| if isinstance(module, nn.Linear): | |
| prune.l1_unstructured(module, name='weight', amount=pruning_ratio) | |
| return model | |
| @staticmethod | |
| def remove_pruning(model): | |
| """็งป้คๅชๆ้ๅๆฐๅ""" | |
| import torch.nn.utils.prune as prune | |
| for name, module in model.named_modules(): | |
| if isinstance(module, nn.Linear): | |
| prune.remove(module, 'weight') | |
| return model | |
| ``` | |
| ### 2. ๆจ็ไผๅ | |
| #### ๆน้ๆจ็ไผๅ | |
| ```python | |
| class BatchInferenceOptimizer: | |
| """ๆน้ๆจ็ไผๅๅจ""" | |
| def __init__(self, model, device): | |
| self.model = model | |
| self.device = device | |
| self.optimal_batch_size = self._find_optimal_batch_size() | |
| def _find_optimal_batch_size(self): | |
| """ๅฏปๆพๆไผๆนๆฌกๅคงๅฐ""" | |
| batch_sizes = [1, 2, 4, 8, 16, 32, 64, 128] | |
| best_batch_size = 1 | |
| best_throughput = 0 | |
| dummy_input = torch.randn(1, 7).to(self.device) | |
| for batch_size in batch_sizes: | |
| try: | |
| # ๆต่ฏๆนๆฌกๅคงๅฐ | |
| batch_input = dummy_input.repeat(batch_size, 1) | |
| start_time = time.time() | |
| with torch.no_grad(): | |
| for _ in range(10): | |
| _ = self.model(batch_input) | |
| end_time = time.time() | |
| throughput = (batch_size * 10) / (end_time - start_time) | |
| if throughput > best_throughput: | |
| best_throughput = throughput | |
| best_batch_size = batch_size | |
| except RuntimeError: | |
| break # ๅ ๅญไธ่ถณ | |
| return best_batch_size | |
| ``` | |
| ## ๆฉๅฑๆง่ฎพ่ฎก | |
| ### 1. ๆไปถ็ณป็ป | |
| ```python | |
| class PluginManager: | |
| """ๆไปถ็ฎก็ๅจ""" | |
| def __init__(self): | |
| self.plugins = {} | |
| self.hooks = defaultdict(list) | |
| def register_plugin(self, name: str, plugin): | |
| """ๆณจๅๆไปถ""" | |
| self.plugins[name] = plugin | |
| # ๆณจๅๆไปถ้ฉๅญ | |
| if hasattr(plugin, 'get_hooks'): | |
| for hook_name, hook_func in plugin.get_hooks().items(): | |
| self.hooks[hook_name].append(hook_func) | |
| def execute_hooks(self, hook_name: str, *args, **kwargs): | |
| """ๆง่ก้ฉๅญ""" | |
| for hook_func in self.hooks[hook_name]: | |
| hook_func(*args, **kwargs) | |
| class PluginBase(ABC): | |
| """ๆไปถๅบ็ฑป""" | |
| @abstractmethod | |
| def initialize(self, config): | |
| pass | |
| @abstractmethod | |
| def cleanup(self): | |
| pass | |
| def get_hooks(self): | |
| return {} | |
| ``` | |
| ### 2. ้ ็ฝฎๆฉๅฑ | |
| ```python | |
| class ConfigManager: | |
| """้ ็ฝฎ็ฎก็ๅจ""" | |
| def __init__(self): | |
| self.config_schemas = {} | |
| self.config_validators = {} | |
| def register_config_schema(self, name: str, schema: Dict): | |
| """ๆณจๅ้ ็ฝฎๆจกๅผ""" | |
| self.config_schemas[name] = schema | |
| def register_validator(self, name: str, validator: callable): | |
| """ๆณจๅ้ ็ฝฎ้ช่ฏๅจ""" | |
| self.config_validators[name] = validator | |
| def validate_config(self, config: Dict[str, Any]) -> bool: | |
| """้ช่ฏ้ ็ฝฎ""" | |
| for name, validator in self.config_validators.items(): | |
| if name in config: | |
| if not validator(config[name]): | |
| raise ValueError(f"้ ็ฝฎ้ช่ฏๅคฑ่ดฅ: {name}") | |
| return True | |
| ``` | |
| ### 3. ๆจกๅๆณจๅ็ณป็ป | |
| ```python | |
| class ModelRegistry: | |
| """ๆจกๅๆณจๅ็ณป็ป""" | |
| _models = {} | |
| _model_metadata = {} | |
| @classmethod | |
| def register(cls, name: str, metadata: Dict = None): | |
| """ๆจกๅๆณจๅ่ฃ ้ฅฐๅจ""" | |
| def decorator(model_class): | |
| cls._models[name] = model_class | |
| cls._model_metadata[name] = metadata or {} | |
| return model_class | |
| return decorator | |
| @classmethod | |
| def create_model(cls, name: str, **kwargs): | |
| """ๅๅปบๆจกๅ""" | |
| if name not in cls._models: | |
| raise ValueError(f"ๆชๆณจๅ็ๆจกๅ: {name}") | |
| model_class = cls._models[name] | |
| return model_class(**kwargs) | |
| @classmethod | |
| def list_models(cls): | |
| """ๅๅบๆๆๆณจๅ็ๆจกๅ""" | |
| return list(cls._models.keys()) | |
| # ไฝฟ็จ็คบไพ | |
| @ModelRegistry.register("advanced_pad", | |
| {"description": "้ซ็บงPAD้ขๆตๅจ", "version": "2.0"}) | |
| class AdvancedPADPredictor(nn.Module): | |
| def __init__(self, **kwargs): | |
| super().__init__() | |
| # ๆจกๅๅฎ็ฐ | |
| pass | |
| ``` | |
| --- | |
| ๆฌๆถๆๆๆกฃๆ่ฟฐไบ็ณป็ป็ๆดไฝ่ฎพ่ฎกๅๅฎ็ฐ็ป่ใ้็้กน็ฎ็ๅๅฑ๏ผๆถๆไผๆ็ปญไผๅๅๆฉๅฑใๅฆๆๅปบ่ฎฎๆ้ฎ้ข๏ผ่ฏท้่ฟGitHub Issuesๅ้ฆใ |