Spaces:
Sleeping
Sleeping
Download models/classifier.py from wjsdbqls/capstone-ai: direct link, hf CLI and curl.
- Browser
- Download file 4.3 kB
-
https://huggingface.co/spaces/wjsdbqls/capstone-ai/resolve/main/models/classifier.py
- Command line
-
hf download hf://spaces/wjsdbqls/capstone-ai/models/classifier.py
-
curl -L -o classifier.py https://huggingface.co/spaces/wjsdbqls/capstone-ai/resolve/main/models/classifier.py
4.3 kB
| """ | |
| KLUE BERT ๊ธฐ๋ฐ ๋ฌธ์ ์นดํ ๊ณ ๋ฆฌ ๋ถ๋ฅ ๋ชจ๋ธ. | |
| ๊ตฌ์กฐ: | |
| - klue/bert-base โ [CLS] ํ ํฐ โ Dropout โ Linear โ ์นดํ ๊ณ ๋ฆฌ ํ๋ฅ | |
| - ์นดํ ๊ณ ๋ฆฌ: ์๊ฐ์ ์ฒญ(0), ์ฑ์ (1), ์กธ์ (2), ์ฅํ๊ธ(3), ํด๋ณตํ(4), | |
| ๋ฑ๋ก๊ธ(5), ๊ธฐ์์ฌ(6), ๊ณต๊ฒฐ_์ถ์(7), ์ฆ๋ช ์(8), ๊ธฐํ(9) | |
| attention ๊ตฌํ: | |
| ์ต์ transformers์ ๊ธฐ๋ณธ SDPA ๊ตฌํ์ attention ๊ฐ์ค์น๋ฅผ ๋ฐํํ์ง ์์ผ๋ฏ๋ก | |
| ํ์ด๋ผ์ดํ ์ ์ํด eager ๊ตฌํ์ ๋ช ์ํ๋ค. | |
| """ | |
| import torch | |
| import torch.nn as nn | |
| from transformers import BertModel, BertTokenizer, AutoTokenizer | |
| # ์นดํ ๊ณ ๋ฆฌ ๋งคํ (generate_qa.py์ CATEGORIES์ ๋์ผํ๊ฒ ์ ์ง) | |
| CATEGORY_LABELS = [ | |
| "์๊ฐ์ ์ฒญ", "์ฑ์ ", "์กธ์ ", "์ฅํ๊ธ", "ํด๋ณตํ", | |
| "๋ฑ๋ก๊ธ", "๊ธฐ์์ฌ", "๊ณต๊ฒฐ_์ถ์", "์ฆ๋ช ์", "๊ธฐํ" | |
| ] | |
| NUM_CLASSES = len(CATEGORY_LABELS) | |
| MODEL_NAME = "klue/bert-base" | |
| class CategoryClassifier(nn.Module): | |
| """KLUE BERT ํ์ธํ๋ ๋ถ๋ฅ ๋ชจ๋ธ.""" | |
| def __init__(self, num_classes: int = NUM_CLASSES, dropout_prob: float = 0.3): | |
| super().__init__() | |
| # eager attention: output_attentions ์ง์์ ์ํด ๋ช ์ | |
| self.bert = BertModel.from_pretrained( | |
| MODEL_NAME, | |
| attn_implementation="eager", | |
| ) | |
| hidden_size = self.bert.config.hidden_size | |
| self.dropout = nn.Dropout(dropout_prob) | |
| self.classifier = nn.Linear(hidden_size, num_classes) | |
| def forward( | |
| self, | |
| input_ids: torch.Tensor, | |
| attention_mask: torch.Tensor, | |
| token_type_ids: torch.Tensor | None = None, | |
| ) -> torch.Tensor: | |
| outputs = self.bert( | |
| input_ids=input_ids, | |
| attention_mask=attention_mask, | |
| token_type_ids=token_type_ids, | |
| output_attentions=True, # ํ์ด๋ผ์ดํ ์ ์ํด attention ๋ฐํ | |
| ) | |
| # [CLS] ํ ํฐ์ pooled output ์ฌ์ฉ | |
| pooled = outputs.pooler_output # (batch, hidden) | |
| pooled = self.dropout(pooled) | |
| logits = self.classifier(pooled) # (batch, num_classes) | |
| # attentions: tuple of (batch, heads, seq, seq) โ ๋ง์ง๋ง ๋ ์ด์ด๋ง ๋ฐํ | |
| self._last_attentions = outputs.attentions # inference ์ ํ์ด๋ผ์ดํ ์ ์ฌ์ฉ | |
| return logits | |
| def get_attention_weights(self) -> torch.Tensor: | |
| """๋ง์ง๋ง forward์์์ ๋ง์ง๋ง ๋ ์ด์ด attention ๋ฐํ. highlight.py์์ ์ฌ์ฉ.""" | |
| if not hasattr(self, "_last_attentions"): | |
| raise RuntimeError("forward()๋ฅผ ๋จผ์ ํธ์ถํ์ธ์.") | |
| # ๋ง์ง๋ง ๋ ์ด์ด, ๋ชจ๋ ํค๋ ํ๊ท โ (batch, seq, seq) | |
| last_layer_attn = self._last_attentions[-1] # (batch, heads, seq, seq) | |
| return last_layer_attn.mean(dim=1) # (batch, seq, seq) | |
| def load_tokenizer() -> AutoTokenizer: | |
| return AutoTokenizer.from_pretrained(MODEL_NAME) | |
| def load_model(checkpoint_path: str | None = None, device: str = "cpu") -> CategoryClassifier: | |
| """ | |
| ๋ชจ๋ธ ๋ก๋. checkpoint_path๊ฐ ์์ผ๋ฉด ํ์ธํ๋๋ ๊ฐ์ค์น ๋ก๋. | |
| """ | |
| model = CategoryClassifier() | |
| if checkpoint_path: | |
| state = torch.load(checkpoint_path, map_location=device) | |
| model.load_state_dict(state) | |
| model.to(device) | |
| return model | |
| class InquiryDataset(torch.utils.data.Dataset): | |
| """ํ์ต/๊ฒ์ฆ ๋ฐ์ดํฐ์ .""" | |
| def __init__(self, data: list[dict], tokenizer: BertTokenizer, max_length: int = 128): | |
| self.tokenizer = tokenizer | |
| self.max_length = max_length | |
| self.texts = [item["question"] for item in data] | |
| self.labels = [item["label"] for item in data] | |
| def __len__(self): | |
| return len(self.texts) | |
| def __getitem__(self, idx): | |
| encoding = self.tokenizer( | |
| self.texts[idx], | |
| max_length=self.max_length, | |
| padding="max_length", | |
| truncation=True, | |
| return_tensors="pt", | |
| ) | |
| return { | |
| "input_ids": encoding["input_ids"].squeeze(0), | |
| "attention_mask": encoding["attention_mask"].squeeze(0), | |
| "token_type_ids": encoding.get("token_type_ids", torch.zeros(self.max_length, dtype=torch.long)).squeeze(0), | |
| "label": torch.tensor(self.labels[idx], dtype=torch.long), | |
| } | |