import%20marimo%0A%0A__generated_with%20%3D%20%220.14.8%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20torch%0A%20%20%20%20import%20torch.nn%20as%20nn%0A%20%20%20%20from%20transformers%20import%20ElectraModel%0A%0A%20%20%20%20class%20SpamUserClassifier(nn.Module)%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20pretrained_model_name%3D%22beomi%2Fkcelectra-base%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20super().__init__()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.encoder%20%3D%20ElectraModel.from_pretrained(pretrained_model_name)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%EB%B6%84%EB%A5%98%20%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dense1%20%3D%20nn.Linear(768%2C%20256)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.relu%20%3D%20nn.ReLU()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dropout1%20%3D%20nn.Dropout(0.3)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dense2%20%3D%20nn.Linear(256%2C%2064)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dropout2%20%3D%20nn.Dropout(0.2)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.output_layer%20%3D%20nn.Linear(64%2C%202)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.softmax%20%3D%20nn.Softmax(dim%3D1)%0A%0A%20%20%20%20%20%20%20%20def%20forward(self%2C%20input_ids%2C%20attention_mask%3DNone%2C%20token_type_ids%3DNone)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20kcElectra%20CLS%20%ED%86%A0%ED%81%B0%20%EC%B6%94%EC%B6%9C%0A%20%20%20%20%20%20%20%20%20%20%20%20outputs%20%3D%20self.encoder(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20input_ids%3Dinput_ids%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20attention_mask%3Dattention_mask%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20token_type_ids%3Dtoken_type_ids%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20cls_output%20%3D%20outputs.last_hidden_state%5B%3A%2C%200%2C%20%3A%5D%20%20%23%20%5Bbatch%2C%20768%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%EB%B6%84%EB%A5%98%20%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20self.dense1(cls_output)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20self.relu(x)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20self.dropout1(x)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20self.dense2(x)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20self.relu(x)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20self.dropout2(x)%0A%20%20%20%20%20%20%20%20%20%20%20%20logits%20%3D%20self.output_layer(x)%0A%20%20%20%20%20%20%20%20%20%20%20%20probs%20%3D%20self.softmax(logits)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20probs%0A%0A%20%20%20%20device%20%3D%20torch.device(%22cuda%22%20if%20torch.cuda.is_available()%20else%20%22cpu%22)%0A%20%20%20%20model%20%3D%20SpamUserClassifier().to(device)%0A%20%20%20%20return%20device%2C%20model%2C%20torch%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20datasets%20import%20load_dataset%0A%0A%20%20%20%20dataset_name%20%3D%20%22misilelab%2Fyoutube-bot-comments%22%0A%0A%20%20%20%20train_dataset%20%3D%20load_dataset(dataset_name%2C%20split%3D%22train%22).with_format(%22polars%22)%5B%3A%5D%0A%20%20%20%20valid_dataset%20%3D%20load_dataset(dataset_name%2C%20split%3D%22validation%22).with_format(%22polars%22)%5B%3A%5D%0A%20%20%20%20test_dataset%20%20%3D%20load_dataset(dataset_name%2C%20split%3D%22test%22).with_format(%22polars%22)%5B%3A%5D%0A%20%20%20%20return%20test_dataset%2C%20train_dataset%2C%20valid_dataset%0A%0A%0A%40app.cell%0Adef%20_(device%2C%20mo%2C%20model%2C%20test_dataset%2C%20torch%2C%20train_dataset%2C%20valid_dataset)%3A%0A%20%20%20%20from%20transformers%20import%20AutoTokenizer%0A%20%20%20%20from%20torch.utils.data%20import%20DataLoader%2C%20Dataset%0A%20%20%20%20import%20torch.nn.functional%20as%20F%0A%20%20%20%20from%20torch.optim%20import%20AdamW%0A%20%20%20%20import%20altair%20as%20alt%0A%20%20%20%20import%20polars%20as%20pl%0A%0A%20%20%20%20%23%20prepare%20tokenizer%0A%20%20%20%20tokenizer%20%3D%20AutoTokenizer.from_pretrained(%22beomi%2FKcELECTRA-base%22)%0A%0A%20%20%20%20%23%20dataset%20wrapper%0A%20%20%20%20class%20YTBotDataset(Dataset)%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20ds%2C%20tokenizer%2C%20max_length%3D128)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.texts%20%3D%20ds%5B%22content%22%5D.to_list()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.labels%20%3D%20%5Bint(x)%20for%20x%20in%20ds%5B%22is_bot_comment%22%5D.to_list()%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20self.tokenizer%20%3D%20tokenizer%0A%20%20%20%20%20%20%20%20%20%20%20%20self.max_length%20%3D%20max_length%0A%0A%20%20%20%20%20%20%20%20def%20__len__(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20len(self.labels)%0A%0A%20%20%20%20%20%20%20%20def%20__getitem__(self%2C%20idx)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20text%20%3D%20self.texts%5Bidx%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20encoding%20%3D%20self.tokenizer(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20truncation%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20padding%3D%22max_length%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20max_length%3Dself.max_length%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return_tensors%3D%22pt%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20item%20%3D%20%7Bk%3A%20v.squeeze(0)%20for%20k%2C%20v%20in%20encoding.items()%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20item%5B%22labels%22%5D%20%3D%20torch.tensor(self.labels%5Bidx%5D%2C%20dtype%3Dtorch.long)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20item%0A%0A%20%20%20%20%23%20create%20datasets%20and%20loaders%0A%20%20%20%20train_ds%20%3D%20YTBotDataset(train_dataset%2C%20tokenizer)%0A%20%20%20%20valid_ds%20%3D%20YTBotDataset(valid_dataset%2C%20tokenizer)%0A%20%20%20%20test_ds%20%20%3D%20YTBotDataset(test_dataset%2C%20tokenizer)%0A%0A%20%20%20%20batch_size%20%3D%20128%0A%20%20%20%20train_loader%20%3D%20DataLoader(train_ds%2C%20batch_size%3Dbatch_size%2C%20shuffle%3DTrue)%0A%20%20%20%20valid_loader%20%3D%20DataLoader(valid_ds%2C%20batch_size%3Dbatch_size)%0A%20%20%20%20test_loader%20%20%3D%20DataLoader(test_ds%2C%20batch_size%3Dbatch_size)%0A%0A%20%20%20%20%23%20optimizer%0A%20%20%20%20optimizer%20%3D%20AdamW(model.parameters()%2C%20lr%3D2e-5)%0A%0A%20%20%20%20%23%20training%20setup%0A%20%20%20%20num_epochs%20%3D%20100%0A%20%20%20%20patience%20%3D%205%0A%20%20%20%20best_valid_acc%20%3D%200.0%0A%20%20%20%20no_improve_epochs%20%3D%200%0A%0A%20%20%20%20%23%20Initialize%20training%20history%0A%20%20%20%20training_history%20%3D%20%7B%0A%20%20%20%20%20%20%20%20'epochs'%3A%20%5B%5D%2C%0A%20%20%20%20%20%20%20%20'train_losses'%3A%20%5B%5D%2C%0A%20%20%20%20%20%20%20%20'valid_losses'%3A%20%5B%5D%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23%20create%20a%20top-level%20progress%20bar%20for%20all%20epochs%0A%20%20%20%20for%20epoch%20in%20(progress_bar%20%3A%3D%20mo.status.progress_bar(range(1%2C%20num_epochs%20%2B%201)%2C%20show_eta%3DTrue%2C%20show_rate%3DTrue))%3A%0A%20%20%20%20%20%20%20%20%23%20training%0A%20%20%20%20%20%20%20%20progress_bar.completion_title%20%3D%20f%22epoch%20%7Bepoch%7D%22%0A%20%20%20%20%20%20%20%20model.train()%0A%20%20%20%20%20%20%20%20running_loss%20%3D%200.0%0A%20%20%20%20%20%20%20%20for%20i%2C%20batch%20in%20enumerate(mo.status.progress_bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20train_loader%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20subtitle%3Df%22Training%20Epoch%20%7Bepoch%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20show_eta%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20show_rate%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20remove_on_exit%3DTrue%0A%20%20%20%20%20%20%20%20))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20input_ids%20%3D%20batch%5B%22input_ids%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20attention_mask%20%3D%20batch%5B%22attention_mask%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20labels%20%3D%20batch%5B%22labels%22%5D.to(device)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20optimizer.zero_grad()%0A%20%20%20%20%20%20%20%20%20%20%20%20probs%20%3D%20model(input_ids%3Dinput_ids%2C%20attention_mask%3Dattention_mask)%0A%20%20%20%20%20%20%20%20%20%20%20%20loss%20%3D%20F.nll_loss(torch.log(probs)%2C%20labels)%0A%20%20%20%20%20%20%20%20%20%20%20%20loss.backward()%0A%20%20%20%20%20%20%20%20%20%20%20%20optimizer.step()%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20running_loss%20%2B%3D%20loss.item()%0A%20%20%20%20%20%20%20%20avg_train_loss%20%3D%20running_loss%20%2F%20len(train_loader)%0A%0A%20%20%20%20%20%20%20%20%23%20validation%0A%20%20%20%20%20%20%20%20model.eval()%0A%20%20%20%20%20%20%20%20correct%2C%20total%20%3D%200%2C%200%0A%20%20%20%20%20%20%20%20valid_running_loss%20%3D%200.0%0A%20%20%20%20%20%20%20%20for%20i%2C%20batch%20in%20enumerate(mo.status.progress_bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20valid_loader%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20subtitle%3Df%22Validating%20Epoch%20%7Bepoch%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20show_eta%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20show_rate%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20remove_on_exit%3DTrue%0A%20%20%20%20%20%20%20%20))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20with%20torch.no_grad()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20input_ids%20%3D%20batch%5B%22input_ids%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20attention_mask%20%3D%20batch%5B%22attention_mask%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20labels%20%3D%20batch%5B%22labels%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20probs%20%3D%20model(input_ids%3Dinput_ids%2C%20attention_mask%3Dattention_mask)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20loss%20%3D%20F.nll_loss(torch.log(probs)%2C%20labels)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20valid_running_loss%20%2B%3D%20loss.item()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20preds%20%3D%20probs.argmax(dim%3D1)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20correct%20%2B%3D%20(preds%20%3D%3D%20labels).sum().item()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20total%20%2B%3D%20labels.size(0)%0A%20%20%20%20%20%20%20%20valid_acc%20%3D%20correct%20%2F%20total%0A%20%20%20%20%20%20%20%20avg_valid_loss%20%3D%20valid_running_loss%20%2F%20len(valid_loader)%0A%0A%20%20%20%20%20%20%20%20%23%20Store%20training%20history%0A%20%20%20%20%20%20%20%20training_history%5B'epochs'%5D.append(epoch)%0A%20%20%20%20%20%20%20%20training_history%5B'train_losses'%5D.append(avg_train_loss)%0A%20%20%20%20%20%20%20%20training_history%5B'valid_losses'%5D.append(avg_valid_loss)%0A%0A%20%20%20%20%20%20%20%20%23%20early%20stopping%20check%0A%20%20%20%20%20%20%20%20if%20valid_acc%20%3E%20best_valid_acc%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20best_valid_acc%20%3D%20valid_acc%0A%20%20%20%20%20%20%20%20%20%20%20%20no_improve_epochs%20%3D%200%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20no_improve_epochs%20%2B%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20no_improve_epochs%20%3E%3D%20patience%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%0A%20%20%20%20%23%20Create%20and%20display%20final%20training%20chart%0A%20%20%20%20if%20training_history%5B'epochs'%5D%3A%0A%20%20%20%20%20%20%20%20epochs%20%3D%20training_history%5B'epochs'%5D%0A%20%20%20%20%20%20%20%20train_losses%20%3D%20training_history%5B'train_losses'%5D%0A%20%20%20%20%20%20%20%20valid_losses%20%3D%20training_history%5B'valid_losses'%5D%0A%0A%20%20%20%20%20%20%20%20_df%20%3D%20pl.DataFrame(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20'epoch'%3A%20epochs%20*%202%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20'loss'%3A%20train_losses%20%2B%20valid_losses%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20'type'%3A%20%5B'Train%20Loss'%5D%20*%20len(train_losses)%20%2B%20%5B'Validation%20Loss'%5D%20*%20len(valid_losses)%0A%20%20%20%20%20%20%20%20%7D)%0A%0A%20%20%20%20%20%20%20%20final_chart%20%3D%20alt.Chart(_df).mark_line(point%3DTrue).encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X('epoch%3AQ'%2C%20title%3D'Epoch')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y('loss%3AQ'%2C%20title%3D'Loss')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color('type%3AN'%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20scale%3Dalt.Scale(domain%3D%5B'Train%20Loss'%2C%20'Validation%20Loss'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20range%3D%5B'firebrick'%2C%20'royalblue'%5D))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tooltip%3D%5B'epoch%3AQ'%2C%20'loss%3AQ'%2C%20'type%3AN'%5D%0A%20%20%20%20%20%20%20%20).properties(%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D'Training%20and%20Validation%20Loss%20Over%20Epochs'%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3D700%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20height%3D400%0A%20%20%20%20%20%20%20%20).interactive()%0A%20%20%20%20return%20final_chart%2C%20test_loader%2C%20tokenizer%0A%0A%0A%40app.cell%0Adef%20_(final_chart)%3A%0A%20%20%20%20final_chart%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20model_save_path%20%3D%20%22model.pth%22%0A%20%20%20%20return%20(model_save_path%2C)%0A%0A%0A%40app.cell%0Adef%20_(model%2C%20model_save_path%2C%20torch)%3A%0A%20%20%20%20%23%20Save%20the%20trained%20model's%20state_dict%0A%20%20%20%20torch.save(model.state_dict()%2C%20model_save_path)%0A%20%20%20%20model_save_path%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Test%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(device%2C%20mo%2C%20model%2C%20model_save_path%2C%20test_loader%2C%20torch)%3A%0A%20%20%20%20def%20_()%3A%0A%20%20%20%20%20%20%20%20import%20seaborn%20as%20sns%0A%20%20%20%20%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20%20%20%20%20from%20sklearn.metrics%20import%20confusion_matrix%2C%20accuracy_score%0A%0A%20%20%20%20%20%20%20%20%23%20Load%20saved%20model%20state%0A%20%20%20%20%20%20%20%20model.load_state_dict(torch.load(model_save_path%2C%20map_location%3Ddevice))%0A%20%20%20%20%20%20%20%20model.to(device)%0A%20%20%20%20%20%20%20%20model.eval()%0A%0A%20%20%20%20%20%20%20%20all_preds%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20all_labels%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20with%20torch.no_grad()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20batch%20in%20mo.status.progress_bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20test_loader%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Computing%20Confusion%20Matrix%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20show_eta%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20show_rate%3DTrue%0A%20%20%20%20%20%20%20%20%20%20%20%20)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20input_ids%20%3D%20batch%5B%22input_ids%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20attention_mask%20%3D%20batch%5B%22attention_mask%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20labels%20%3D%20batch%5B%22labels%22%5D.to(device)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20probs%20%3D%20model(input_ids%3Dinput_ids%2C%20attention_mask%3Dattention_mask)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20If%20bot%20probability%20%3E%2090%25%20then%20classify%20as%20bot%20(1)%2C%20else%20user%20(0)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bot_probs%20%3D%20probs%5B%3A%2C%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20preds%20%3D%20(bot_probs%20%3E%200.9).long()%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20all_preds.extend(preds.cpu().numpy())%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20all_labels.extend(labels.cpu().numpy())%0A%0A%20%20%20%20%20%20%20%20%23%20Compute%20metrics%0A%20%20%20%20%20%20%20%20cm%20%3D%20confusion_matrix(all_labels%2C%20all_preds)%0A%20%20%20%20%20%20%20%20acc%20%3D%20accuracy_score(all_labels%2C%20all_preds)%0A%20%20%20%20%20%20%20%20print(f%22Accuracy%3A%20%7Bacc%20*%20100%3A.2f%7D%25%22)%0A%0A%20%20%20%20%20%20%20%20%23%20Plot%20heatmap%0A%20%20%20%20%20%20%20%20plt.figure(figsize%3D(6%2C%205))%0A%20%20%20%20%20%20%20%20sns.heatmap(%0A%20%20%20%20%20%20%20%20%20%20%20%20cm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20annot%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20fmt%3D'd'%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cmap%3D'Blues'%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20xticklabels%3D%5B'User'%2C%20'Bot'%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20yticklabels%3D%5B'User'%2C%20'Bot'%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20plt.xlabel('Predicted%20Label')%0A%20%20%20%20%20%20%20%20plt.ylabel('True%20Label')%0A%20%20%20%20%20%20%20%20plt.title('Confusion%20Matrix%20Heatmap')%0A%20%20%20%20%20%20%20%20plt.tight_layout()%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%0A%20%20%20%20_()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Evaluation%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(device%2C%20model%2C%20tokenizer%2C%20torch)%3A%0A%20%20%20%20def%20_()%3A%0A%20%20%20%20%20%20%20%20%23%20Evaluate%20a%20single%20user%20input%20comment%0A%20%20%20%20%20%20%20%20model.eval()%0A%20%20%20%20%20%20%20%20comment%20%3D%20input(%22Enter%20a%20YouTube%20comment%20to%20evaluate%3A%20%22)%0A%0A%20%20%20%20%20%20%20%20%23%20Tokenize%20and%20prepare%20tensors%0A%20%20%20%20%20%20%20%20encoding%20%3D%20tokenizer(%0A%20%20%20%20%20%20%20%20%20%20%20%20comment%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20truncation%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20padding%3D%22max_length%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20max_length%3D128%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20return_tensors%3D%22pt%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20input_ids%20%3D%20encoding%5B%22input_ids%22%5D.to(device)%0A%20%20%20%20%20%20%20%20attention_mask%20%3D%20encoding%5B%22attention_mask%22%5D.to(device)%0A%0A%20%20%20%20%20%20%20%20%23%20Predict%20probability%20of%20bot%0A%20%20%20%20%20%20%20%20with%20torch.no_grad()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20probs%20%3D%20model(input_ids%3Dinput_ids%2C%20attention_mask%3Dattention_mask)%0A%20%20%20%20%20%20%20%20%20%20%20%20bot_probability%20%3D%20probs%5B0%2C%201%5D.item()%0A%0A%20%20%20%20%20%20%20%20%23%20Print%20the%20probability%20as%20a%20percentage%0A%20%20%20%20%20%20%20%20return%20print(f%22Bot%20probability%3A%20%7Bbot_probability%20*%20100%3A.2f%7D%25%22)%0A%0A%0A%20%20%20%20_()%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
41628e515651489747009e42de14fe57b7bc9b903b1142913d59326427abc69e