| import torch |
| import gradio as gr |
| import tiktoken |
| import pandas as pd |
| import torch.nn as nn |
|
|
| GPT_CONFIG_124M = { |
| "vocab_size": 50257, |
| "context_length": 1024, |
| "emb_dim": 768, |
| "n_heads": 12, |
| "n_layers": 12, |
| "drop_rate": 0.1, |
| "qkv_bias": True |
| } |
|
|
| class multiheadv2(nn.Module): |
| def __init__(self, d_in, d_out, context_length, dropout, attention_head, boolbias): |
| super().__init__() |
| self.head_dim = d_out // attention_head |
| self.d_out = d_out |
| self.attention_head = attention_head |
| self.W_query = nn.Linear(d_in, d_out, bias=boolbias) |
| self.W_key = nn.Linear(d_in, d_out, bias=boolbias) |
| self.W_value = nn.Linear(d_in, d_out, bias=boolbias) |
| self.out_proj = nn.Linear(d_out, d_out) |
| self.dropout = nn.Dropout(dropout) |
| self.register_buffer('mask', torch.triu(torch.ones(context_length, context_length), diagonal=1)) |
|
|
| def forward(self, x): |
| b, num_token, d_out = x.shape |
| keys = self.W_key(x) |
| queries = self.W_query(x) |
| values = self.W_value(x) |
| keys = keys.view(b, num_token, self.attention_head, self.head_dim).transpose(1, 2) |
| queries = queries.view(b, num_token, self.attention_head, self.head_dim).transpose(1, 2) |
| values = values.view(b, num_token, self.attention_head, self.head_dim).transpose(1, 2) |
| attn_score = queries @ keys.transpose(2, 3) |
| mask_bool = self.mask.bool()[:num_token, :num_token] |
| attn_score.masked_fill_(mask_bool, -torch.inf) |
| attn_weights = torch.softmax(attn_score / keys.shape[-1]**0.5, dim=-1) |
| attn_weights = self.dropout(attn_weights) |
| context_vec = (attn_weights @ values).transpose(1, 2).contiguous().view(b, num_token, self.d_out) |
| context_vec = self.out_proj(context_vec) |
| return context_vec |
|
|
| class LayerNorm(nn.Module): |
| def __init__(self, emb_dim): |
| super().__init__() |
| self.eps = 1e-5 |
| self.scale_params = nn.Parameter(torch.ones(emb_dim)) |
| self.shift_params = nn.Parameter(torch.zeros(emb_dim)) |
|
|
| def forward(self, x): |
| mean = x.mean(dim=-1, keepdim=True) |
| var = x.var(dim=-1, keepdim=True, unbiased=False) |
| norm = (x - mean) / torch.sqrt(var + self.eps) |
| return norm * self.scale_params + self.shift_params |
|
|
| class GELU(nn.Module): |
| def forward(self, x): |
| return 0.5 * x * (1 + torch.tanh(torch.sqrt(torch.tensor(2.0 / torch.pi)) * (x + 0.044715 * torch.pow(x, 3)))) |
|
|
| class feedforward(nn.Module): |
| def __init__(self, config): |
| super().__init__() |
| self.layers = nn.Sequential( |
| nn.Linear(config['emb_dim'], config['emb_dim'] * 4), |
| GELU(), |
| nn.Linear(config['emb_dim'] * 4, config['emb_dim']), |
| ) |
|
|
| def forward(self, x): |
| return self.layers(x) |
|
|
| class TransformerBlock(nn.Module): |
| def __init__(self, config): |
| super().__init__() |
| self.attn = multiheadv2(d_in=config['emb_dim'], d_out=config['emb_dim'], context_length=config['context_length'], dropout=config['drop_rate'], attention_head=config['n_heads'], boolbias=config['qkv_bias']) |
| self.Layernorm1 = LayerNorm(config['emb_dim']) |
| self.Layernorm2 = LayerNorm(config['emb_dim']) |
| self.feedforw = feedforward(config) |
| self.dropout = nn.Dropout(config['drop_rate']) |
|
|
| def forward(self, x): |
| skip = x |
| x = self.Layernorm1(x) |
| x = self.attn(x) |
| x = self.dropout(x) |
| x = x + skip |
| skip = x |
| x = self.Layernorm2(x) |
| x = self.feedforw(x) |
| x = self.dropout(x) |
| x = x + skip |
| return x |
|
|
| class GPT_2(nn.Module): |
| def __init__(self, cfg, num_classes): |
| super().__init__() |
| self.token_emb = nn.Embedding(cfg['vocab_size'], cfg["emb_dim"]) |
| self.pos_emb = nn.Embedding(cfg['context_length'], cfg["emb_dim"]) |
| self.drop_emb = nn.Dropout(cfg["drop_rate"]) |
| self.trf_blocks = nn.Sequential(*[TransformerBlock(cfg) for _ in range(cfg["n_layers"])]) |
| self.final_norm = LayerNorm(cfg["emb_dim"]) |
| self.out_head = nn.Linear(cfg["emb_dim"], num_classes) |
|
|
| def forward(self, inputidx): |
| batch_size, seq = inputidx.shape |
| tokens = self.token_emb(inputidx) |
| pos_embeds = self.pos_emb(torch.arange(seq, device=inputidx.device)) |
| x = tokens + pos_embeds |
| x = self.drop_emb(x) |
| x = self.trf_blocks(x) |
| x = self.final_norm(x) |
| logits = self.out_head(x[:, -1]) |
| return logits |
|
|
| tokenizer = tiktoken.get_encoding("gpt2") |
| pad_token_id = tokenizer.eot_token |
|
|
| df_temp = pd.read_csv("train.csv") |
| label_mapping = dict(enumerate(df_temp["target"].astype("category").cat.categories)) |
| num_classes = len(label_mapping) |
| inv_label_mapping = {v: k for k, v in label_mapping.items()} |
|
|
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| model = GPT_2(GPT_CONFIG_124M, num_classes) |
| model.load_state_dict(torch.load("biofinetuned_partialEpoch1.pth", map_location=device)) |
| model.to(device) |
| model.eval() |
|
|
| def classify_review(text, max_length=128): |
| input_ids = tokenizer.encode(text)[:max_length] |
| input_ids += [pad_token_id] * (max_length - len(input_ids)) |
| input_tensor = torch.tensor(input_ids, device=device).unsqueeze(0) |
| with torch.no_grad(): |
| logits = model(input_tensor) |
| predicted_label = torch.argmax(logits, dim=-1).item() |
| return label_mapping[predicted_label] |
|
|
| iface = gr.Interface( |
| fn=classify_review, |
| inputs=gr.Textbox(label="Enter a biomedical abstract section (e.g., Background, Objective, Methodology, etc.)"), |
| outputs=gr.Textbox(label="Predicted Section Category"), |
| title="MedGPT", |
| description="A domain-specific classifier for biomedical abstract sections: Background, Objective, Methodology, Results, Conclusion." |
| ) |
|
|
|
|
| iface.launch() |
|
|