사실상, Epoch 수가 높다고 해서 무조건 다 좋은 것 같진 않다.
직전에 했던 립러닝에서도, 소폭 감소하더니 나중가선 미친듯한 발산을 보여주기도 했고, 그 외에도 이것저것 문제가 많다.
그래서, 우리는 채크썸을 활용해서 중간중간 값을 가지고, 이를 통해서 유동적으로 학습율 값을 변동시키는 드으이 방식으로 딥러닝을 보다 효율적으로 돌아가게 하곤 한다.
또한, loss값이 개선되지 않으면 조기에 딥러닝을 종료하고 꺼버리는 등의 다양한 방식으로 딥러닝을 진행한다.
하지만, 체크썸의 데이터가 많아지면 50기가가 넘어갈 떄도 다반수이며, 3070 정도의 GPU를 사용하더라고 몇십 시간식 걸리는 것도 일상 다반사 이다. 이러면 어떻게 해야 이걸 좀 더 효율적으로 딥러닝 할 수 있을까?
이런거 쑤셔 박으면, 엄청 걸리고, 자원도 많이 먹지만, 그래도 F1 스코어는 엄청 잘 나온다.
model.config.hidden_dropout_prob = 0.3
model.config.attention_probs_dropout_prob = 0.3
def get_optimizer_grouped_parameters(model, base_lr=1e-5, weight_decay=0.1):
no_decay = ["bias", "LayerNorm.weight"]
optimizer_grouped_parameters = []
num_layers = model.config.num_hidden_layers
for i, (name, param) in enumerate(model.named_parameters()):
if "classifier" in name:
lr = base_lr * 2.0
else:
layer_idx = min(i // 2, num_layers - 1)
lr = base_lr * (0.95 ** (num_layers - layer_idx))
wd = weight_decay if not any(nd in name for nd in no_decay) else 0
optimizer_grouped_parameters.append({"params": param, "lr": lr, "weight_decay": wd})
return optimizer_grouped_parameters
trainer = CustomTrainer(
optimizers=(torch.optim.AdamW(get_optimizer_grouped_parameters(model), eps=1e-8, amsgrad=True), None),
)
training_args = TrainingArguments(
output_dir=output_dir,
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1",
)
model.save_pretrained(model_save_path)
tokenizer.save_pretrained(model_save_path)
label_map = {'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4}
train_df['label'] = train_df['Segment'].map(label_map)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
if torch.cuda.is_available():
logger.info(f"GPU를 사용합니다: {torch.cuda.get_device_name(0)}")
else:
logger.warning("GPU에 연결되지 않았습니다. CPU로 전환합니다.")
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=5).to(device)
label_counts = Counter(train_df['label'])
n_samples = len(train_df)
n_classes = 5
class_weights = [n_samples / (n_classes * label_counts[i]) for i in range(n_classes)]
class_weights = torch.tensor(class_weights, dtype=torch.float).to(device)
class CustomTrainer(Trainer):
def compute_loss(self, model, inputs, return_outputs=False):
labels = inputs.pop("labels")
outputs = model(**inputs)
logits = outputs.logits
loss_fct = torch.nn.CrossEntropyLoss(weight=class_weights.to(logits.device))
loss = loss_fct(logits, labels)
return (loss, outputs) if return_outputs else loss
train_df = train_df.dropna(subset=['label']).replace([np.inf, -np.inf], np.nan).dropna()
train_df['label'] = train_df['label'].astype(int)
training_args = TrainingArguments(
fp16=True if torch.cuda.is_available() else False,
)
training_args = TrainingArguments(
lr_scheduler_type="cosine",
)
training_args = TrainingArguments(
max_grad_norm=0.5,
)
training_args = TrainingArguments(
label_smoothing_factor=0.05,
)
for folder in tqdm(folders, desc="폴더 로드 진행"):
# ...
for customer_id in tqdm(all_ids, desc="고객 데이터 통합 진행"):
# ...
def tokenize_function(texts):
encodings = tokenizer(texts, padding="max_length", truncation=True, max_length=128, return_tensors='pt')
return encodings
class CustomDataset(Dataset):
def __init__(self, encodings, labels=None):
self.encodings = {key: val.to(device) for key, val in encodings.items()}
self.labels = labels
def __getitem__(self, idx):
item = {key: val[idx].clone().detach() for key, val in self.encodings.items()}
if self.labels is not None:
item['labels'] = torch.tensor(self.labels[idx], dtype=torch.long).to(device)
return item
def __len__(self):
return len(self.encodings['input_ids'])
def compute_metrics(pred):
labels = pred.label_ids
preds = pred.predictions.argmax(-1)
f1 = f1_score(labels, preds, average='weighted')
return {"f1": f1}
training_args = TrainingArguments(
warmup_steps=20,
)
training_args = TrainingArguments(
gradient_accumulation_steps=8,
)
사실, 딥러닝 시간과 성능은 서로 비례한다.
가법게 한다 접근하면 이게 잘 될 수가 없다.
더 많으 자원을 소모할수록, 더 많은 시간을 부을수록 완성되는 AI의 F1스코어는 올라간다.
아쉽게도, 이거 안변하는거 같다.
여기서 효율 치는거에 성공하면, DeepGEMM처럼 혁신에 성공하는 그런거다.
역시 집에서의 딥러닝에는 한계가 너무 명확하다.
연구실 가야하는 이유가 이렇게 또 하나 늘어나는 것 같다.