← back
Your 'Gmail' can write code.

Your 'Gmail' can write code.

Gemini in Gmail drafted Python code to fine-tune a DeBERTa model for sentiment classification, complete with data loading, training loops, and evaluation.

Gmail drafter is powered by a language model, and it can do almost anything your chat assistant can. For example here I ask it to write python code to train a sentiment classification model.

My
prompt

write code for train.py to fine-tune deberta v3 large for sentiment classification into 3 labels: positive, neutral and negative data.csv as source headers: text,positive,neutral,negative (values for labels are 0 or 1) use tqdm and wandb for logging per step


:An email composition window containing a text prompt that asks for machine learning fine-tuning code.


It drafted the following email with a fully functional python code:

---

Hey [Name],

Here is the code for train.py to fine-tune DeBERTa-v3-large on your sentiment data. It reads from data.csv, sets up a 3-label classification, and handles logging via tqdm and Weights & Biases per step.

import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader
from transformers import AutoTokenizer, AutoModelForSequenceClassification, AdamW, get_scheduler
from sklearn.model_selection import train_test_split
import wandb
from tqdm import auto as tqdm_auto
import numpy as np

# Initialize wandb
wandb.init(project="deberta-sentiment-classification")

# Load data
df = pd.read_csv('data.csv')

# Map one-hot labels to a single target index
# Assumes headers are text, positive, neutral, negative
def get_label(row):
    if row['positive'] == 1: return 0
    if row['neutral'] == 1: return 1
    if row['negative'] == 1: return 2
    return -1

df['label'] = df.apply(get_label, axis=1)
df = df[df['label'] != -1].reset_index(drop=True)

train_df, val_df = train_test_split(df, test_size=0.1, random_state=42)

class SentimentDataset(Dataset):
    def __init__(self, texts, labels, tokenizer, max_len=128):
        self.texts = texts
        self.labels = labels
        self.tokenizer = tokenizer
        self.max_len = max_len
       
    def __len__(self):
        return len(self.texts)
   
    def __getitem__(self, idx):
        text = str(self.texts[idx])
        label = self.labels[idx]
        encoding = self.tokenizer(
            text,
            add_special_tokens=True,
            max_length=self.max_len,
            padding='max_length',
            truncation=True,
            return_tensors='pt'
        )
        return {
            'input_ids': encoding['input_ids'].flatten(),
            'attention_mask': encoding['attention_mask'].flatten(),
            'labels': torch.tensor(label, dtype=torch.long)
        }

# Model and Tokenizer setup
MODEL_NAME = "microsoft/deberta-v3-large"
tokenizer = AutoTokenizer.pretrained(MODEL_NAME)
model = AutoModelForSequenceClassification.pretrained(MODEL_NAME, num_labels=3)

train_dataset = SentimentDataset(train_df['text'].values, train_df['label'].values, tokenizer)
val_dataset = SentimentDataset(val_df['text'].values, val_df['label'].values, tokenizer)

train_loader = DataLoader(train_dataset, batch_size=8, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=16)

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)

optimizer = AdamW(model.parameters(), lr=2e-5)
num_epochs = 3
num_training_steps = num_epochs * len(train_loader)
lr_scheduler = get_scheduler("linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps)

wandb.config.update({
    "model": MODEL_NAME,
    "epochs": num_epochs,
    "batch_size": 8,
    "lr": 2e-5
})

global_step = 0
for epoch in range(num_epochs):
    model.train()
    train_bar = tqdm_auto.tqdm(train_loader, desc=f"Epoch {epoch+1}/{num_epochs} [Train]")
   
    for batch in train_bar:
        optimizer.zero_grad()
        input_ids = batch['input_ids'].to(device)
        attention_mask = batch['attention_mask'].to(device)
        labels = batch['labels'].to(device)
       
        outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
        loss = outputs.loss
        loss.backward()
       
        optimizer.step()
        lr_scheduler.step()
       
        global_step += 1
        wandb.log({"train_loss": loss.item(), "learning_rate": lr_scheduler.get_last_lr()[0]}, step=global_step)
        train_bar.set_postfix(loss=loss.item())

    # Validation loop
    model.eval()
    val_loss = 0
    correct = 0
    total = 0
    val_bar = tqdm_auto.tqdm(val_loader, desc=f"Epoch {epoch+1}/{num_epochs} [Val]")
   
    with torch.no_grad():
        for batch in val_bar:
            input_ids = batch['input_ids'].to(device)
            attention_mask = batch['attention_mask'].to(device)
            labels = batch['labels'].to(device)
           
            outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
            val_loss += outputs.loss.item()
           
            preds = torch.argmax(outputs.logits, dim=1)
            correct += (preds == labels).sum().item()
            total += labels.size(0)

    avg_val_loss = val_loss / len(val_loader)
    accuracy = correct / total
    wandb.log({"val_loss": avg_val_loss, "val_accuracy": accuracy}, step=global_step)
    print(f"Epoch {epoch+1} - Val Loss: {avg_val_loss:.4f}, Val Acc: {accuracy:.4f}")

model.save_pretrained("./sentiment_model")
tokenizer.save_pretrained("./sentiment_model")
wandb.finish()

Let me know if you need to adjust the batch size or max length constraints.

---

I also asked it to design me a new logo and it
gave me this

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 200" width="100%" height="100%">
  <defs>
    <!-- Clean, modern linear gradient for the logo mark -->
    <linearGradient id="dejanGrad" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="#0052CC" />
      <stop offset="100%" stop-color="#00A3BF" />
    </linearGradient>
  </defs>


  <g transform="translate(10, 10)">
    <!-- Placeholder for the DEJAN geometric icon/logo mark -->
    <path d="M 50 25 L 125 25 L 150 100 L 125 175 L 50 175 L 25 100 Z" fill="url(#dejanGrad)" />
    <path d="M 65 50 L 110 50 L 125 100 L 110 150 L 65 150 Z" fill="#FFFFFF" />
   
    <!-- DEJAN Typography -->
    <text x="190" y="135" font-family="Arial, Helvetica, sans-serif" font-size="90" font-weight="900" fill="#172B4D" letter-spacing="2">DEJAN</text>
  </g>
</svg>
:

PS: Cute, but I think I'll keep the one we have for now though ;-)

Dan Petrovic · Aug 31, 05:35