{"id":1927,"date":"2025-02-19T07:03:20","date_gmt":"2025-02-19T07:03:20","guid":{"rendered":"https:\/\/mailitics.com\/index.php\/2025\/02\/19\/how-to-fine-tune-distilbert-for-emotion-classification\/"},"modified":"2025-02-19T07:03:20","modified_gmt":"2025-02-19T07:03:20","slug":"how-to-fine-tune-distilbert-for-emotion-classification","status":"publish","type":"post","link":"https:\/\/mailitics.com\/index.php\/2025\/02\/19\/how-to-fine-tune-distilbert-for-emotion-classification\/","title":{"rendered":"How to Fine-Tune DistilBERT for Emotion Classification"},"content":{"rendered":"<p>    How to Fine-Tune DistilBERT for Emotion Classification<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n    <!-- no image --><br \/>\n \t<BR><br \/>\n<BR><\/BR><\/p>\n<div>\n<p class=\"wp-block-paragraph\">The customer support teams were drowning with the overwhelming volume of customer inquiries at every company I\u2019ve worked at. Have you had similar experiences?<\/p>\n<p class=\"wp-block-paragraph\">What if I told you that you could use AI to automatically <strong>identify<\/strong>, <strong>categorize,<\/strong> and even <strong>resolve<\/strong> the most common issues?<\/p>\n<p class=\"wp-block-paragraph\">By fine-tuning a transformer model like BERT, you can build an automated system that tags tickets by issue type and routes them to the right team.<\/p>\n<p class=\"wp-block-paragraph\">In this tutorial, I\u2019ll show you how to fine-tune a transformer model for emotion classification in five steps:<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Set Up Your Environment<\/strong>: Prepare your dataset and install necessary libraries.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Load and Preprocess Data<\/strong>: Parse text files and organize your data.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Fine-Tune <a href=\"https:\/\/towardsdatascience.com\/tag\/distilbert\/\" title=\"Distilbert\">Distilbert<\/a><\/strong>: Train model to classify emotions using your dataset.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Evaluate Performance<\/strong>: Use metrics like accuracy, F1-score, and confusion matrices to measure model performance.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Interpret Predictions<\/strong>: Visualize and understand predictions using SHAP (SHapley Additive exPlanations).<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">By the end, you\u2019ll have a fine-tuned model that classifies emotions from text inputs with high accuracy, and you\u2019ll also learn how to interpret these predictions using SHAP.<\/p>\n<p class=\"wp-block-paragraph\">This same approach can be applied to real-world use cases beyond emotion classification, such as customer support automation, sentiment analysis, content moderation, and more.<\/p>\n<p class=\"wp-block-paragraph\">Let\u2019s dive in!<\/p>\n<h2 class=\"wp-block-heading\">Choosing the Right Transformer Model<\/h2>\n<p class=\"wp-block-paragraph\">When selecting a transformer model for <strong><a href=\"https:\/\/towardsdatascience.com\/tag\/text-classification\/\" title=\"Text Classification\">Text Classification<\/a><\/strong>, here\u2019s a quick breakdown of the most common models:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>BERT<\/strong>: Great for general NLP tasks, but computationally expensive for both training and inference.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>DistilBERT<\/strong>: 60% faster than BERT while retaining 97% of its capabilities, making it ideal for real-time applications.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>RoBERTa:<\/strong> A more robust version of BERT, but requires more resources.<\/li>\n<li class=\"wp-block-list-item\">\n<strong>XLM-RoBERTa<\/strong>: A multilingual variant of RoBERTa trained on 100 languages. It is perfect for multilingual tasks, but is quite resource-intensive.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">For this tutorial, I chose to fine-tune DistilBERT because it offers the best balance between performance and efficiency.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Step 1: Setup and Installing Dependencies<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Ensure you have the required libraries installed:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">!pip install datasets transformers torch scikit-learn shap<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Step 2: Load and Preprocess Data<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">I used the <a href=\"https:\/\/www.kaggle.com\/datasets\/praveengovi\/emotions-dataset-for-nlp\">Emotions dataset for NLP<\/a> by Praveen Govi, available on Kaggle and <a href=\"https:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\">licensed for commercial use<\/a>. It contains text labeled with emotions. The data comes in three <code>.txt<\/code> files: <strong>train, validation,<\/strong> and <strong>test<\/strong>.<\/p>\n<p class=\"wp-block-paragraph\">Each line contains a sentence and its corresponding emotion label, separated by a semicolon:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">text; emotion\n\"i didnt feel humiliated\"; \"sadness\"\n\"i am feeling grouchy\"; \"anger\"\n\"im updating my blog because i feel shitty\"; \"sadness\"<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Parsing the Dataset into a Pandas DataFrame<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Let\u2019s load the dataset:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def parse_emotion_file(file_path):\n\"\"\"\n\u00a0 \u00a0 Parses a text file with each line in the format: {text; emotion}\n\u00a0 \u00a0 and returns a pandas DataFrame with 'text' and 'emotion' columns.\n\n\u00a0 \u00a0 Args:\n\u00a0 \u00a0 - file_path (str): Path to the .txt file to be parsed\n\n\u00a0 \u00a0 Returns:\n\u00a0 \u00a0 - df (pd.DataFrame): DataFrame containing 'text' and 'emotion' columns\n\u00a0 \u00a0 \"\"\"\n\u00a0 \u00a0 texts = []\n\u00a0 \u00a0 emotions = []\n\u00a0 \u00a0\n\u00a0 \u00a0 with open(file_path, 'r', encoding='utf-8') as file:\n\u00a0 \u00a0 \u00a0 \u00a0 for line in file:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 try:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # Split each line by the semicolon separator\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 text, emotion = line.strip().split(';')\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # append text and emotion to separate lists\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 texts.append(text)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 emotions.append(emotion)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 except ValueError:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 continue\n\u00a0 \u00a0\n\u00a0 \u00a0 return pd.DataFrame({'text': texts, 'emotion': emotions})\n\n# Parse text files and store as Pandas DataFrames\ntrain_df = parse_emotion_file(\"train.txt\")\nval_df = parse_emotion_file(\"val.txt\")\ntest_df = parse_emotion_file(\"test.txt\")<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Understanding the Label Distribution<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">This dataset contains <strong>16k training examples<\/strong> and <strong>2k examples<\/strong> for the validation and testing. Here\u2019s the label distribution breakdown:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfdpdGG2nGefo5cz3tmpBuw7-Uefo3uu9UqCAPO6z3QEvruHA0xd2r_7Tx7qJNTEJWsRA5r7f3AVgmMPVm5o3D_mNCEe3TEh6xwgqoa9kdqGTtsORFAV3sYJbZUXXrj4zcwtNytMg?key=EdH2R_lZ0C0rh-CBHFDARV_1\" alt=\"\"><figcaption class=\"wp-element-caption\">Image by author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">The bar chart above shows that the dataset is <strong>imbalanced,<\/strong> with the majority of samples labels as joy and sadness.<\/p>\n<p class=\"wp-block-paragraph\">For a fine-tuning a production model, I would consider experimenting with different sampling techniques to overcome this class imbalance problem and improve the model\u2019s performance.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Step 3: Tokenization and Data Preprocessing<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Next, I loaded in DistilBERT\u2019s tokenizer:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from transformers import AutoTokenizer\n\n# Define the model path for DistilBERT\nmodel_name = \"distilbert-base-uncased\"\n\n# Load the tokenizer\ntokenizer = AutoTokenizer.from_pretrained(model_name)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Then, I used it to tokenize text data and transform the labels into numerical IDs:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Tokenize data\ndef preprocess_function(df, label2id):\n\u00a0 \u00a0 \"\"\"\n\u00a0 \u00a0 Tokenizes text data and transforms labels into numerical IDs.\n\n\u00a0 \u00a0 Args:\n\u00a0 \u00a0 \u00a0 \u00a0 df (dict or pandas.Series): A dictionary-like object containing \"text\" and \"emotion\" fields.\n\u00a0 \u00a0 \u00a0 \u00a0 label2id (dict): A mapping from emotion labels to numerical IDs.\n\n\u00a0 \u00a0 Returns:\n\u00a0 \u00a0 \u00a0 \u00a0 dict: A dictionary containing:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 - \"input_ids\": Encoded token sequences\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 - \"attention_mask\": Mask to indicate padding tokens\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 - \"label\": Numerical labels for classification\n\n\u00a0 \u00a0 Example usage:\n\u00a0 \u00a0 \u00a0 \u00a0 train_dataset = train_dataset.map(lambda x: preprocess_function(x, tokenizer, label2id), batched=True)\n\u00a0 \u00a0 \"\"\"\n\u00a0 \u00a0 tokenized_inputs = tokenizer(\n\u00a0 \u00a0 \u00a0 \u00a0 df[\"text\"],\n\u00a0 \u00a0 \u00a0 \u00a0 padding=\"longest\",\n\u00a0 \u00a0 \u00a0 \u00a0 truncation=True,\n\u00a0 \u00a0 \u00a0 \u00a0 max_length=512,\n\u00a0 \u00a0 \u00a0 \u00a0 return_tensors=\"pt\"\n\u00a0 \u00a0 )\n\n\u00a0 \u00a0 tokenized_inputs[\"label\"] = [label2id.get(emotion, -1) for emotion in df[\"emotion\"]]\n\u00a0 \u00a0 return tokenized_inputs\n\u00a0 \u00a0\n# Convert the DataFrames to HuggingFace Dataset format\ntrain_dataset = Dataset.from_pandas(train_df)\n\n# Apply the 'preprocess_function' to tokenize text data and transform labels\ntrain_dataset = train_dataset.map(lambda x: preprocess_function(x, label2id), batched=True)<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Step 4: Fine-Tuning Model<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Next, I loaded a pre-trained DistilBERT model with a classification head for our text classification text. I also specified what the labels for this dataset looks like:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Get the unique emotion labels from the 'emotion' column in the training DataFrame\nlabels = train_df[\"emotion\"].unique()\n\n# Create label-to-id and id-to-label mappings\nlabel2id = {label: idx for idx, label in enumerate(labels)}\nid2label = {idx: label for idx, label in enumerate(labels)}\n\n# Initialize model\nmodel = AutoModelForSequenceClassification.from_pretrained(\n\u00a0 \u00a0 model_name,\n\u00a0 \u00a0 num_labels=len(labels),\n\u00a0 \u00a0 id2label=id2label,\n\u00a0 \u00a0 label2id=label2id\n)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The pre-trained DistilBERT model for classification consists of <strong>five layers plus a classification head<\/strong>.<\/p>\n<p class=\"wp-block-paragraph\">To prevent overfitting, I <strong>froze the first four layers<\/strong>, preserving the knowledge learned during pre-training. This allows the model to retain general language understanding while only fine-tuning the fifth layer and classification head to adapt to my dataset. Here\u2019s how I did this:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># freeze base model parameters\nfor name, param in model.base_model.named_parameters():\n\u00a0 \u00a0 param.requires_grad = False\n\n# keep classifier trainable\nfor name, param in model.base_model.named_parameters():\n\u00a0 \u00a0 if \"transformer.layer.5\" in name or \"classifier\" in name:\n\u00a0 \u00a0 \u00a0 \u00a0 param.requires_grad = True<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Defining Metrics<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">Given the label imbalance, I thought accuracy may not be the most appropriate metric, so I chose to include other metrics suited for classification problems like precision, recall, F1-score, and AUC score.<\/p>\n<p class=\"wp-block-paragraph\">I also used \u201cweighted\u201d averaging for F1-score, precision, and recall to address the class imbalance problem. This parameter ensures that all classes contribute proportionally to the metric and prevent any single class from dominating the results:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def compute_metrics(p):\n\u00a0 \u00a0 \"\"\"\n\u00a0 \u00a0 Computes accuracy, F1 score, precision, and recall metrics for multiclass classification.\n\n\u00a0 \u00a0 Args:\n\u00a0 \u00a0 p (tuple): Tuple containing predictions and labels.\n\n\u00a0 \u00a0 Returns:\n\u00a0 \u00a0 dict: Dictionary with accuracy, F1 score, precision, and recall metrics, using weighted averaging\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 to account for class imbalance in multiclass classification tasks.\n\u00a0 \u00a0 \"\"\"\n\u00a0 \u00a0 logits, labels = p\n\u00a0 \u00a0\n\u00a0 \u00a0 # Convert logits to probabilities using softmax (PyTorch)\n\u00a0 \u00a0 softmax = torch.nn.Softmax(dim=1)\n\u00a0 \u00a0 probs = softmax(torch.tensor(logits))\n\u00a0 \u00a0\n\u00a0 \u00a0 # Convert logits to predicted class labels\n\u00a0 \u00a0 preds = probs.argmax(axis=1)\n\n\u00a0 \u00a0 return {\n\u00a0 \u00a0 \u00a0 \u00a0 \"accuracy\": accuracy_score(labels, preds),\u00a0 # Accuracy metric\n\u00a0 \u00a0 \u00a0 \u00a0 \"f1_score\": f1_score(labels, preds, average='weighted'),\u00a0 # F1 score with weighted average for imbalanced data\n\u00a0 \u00a0 \u00a0 \u00a0 \"precision\": precision_score(labels, preds, average='weighted'),\u00a0 # Precision score with weighted average\n\u00a0 \u00a0 \u00a0 \u00a0 \"recall\": recall_score(labels, preds, average='weighted'),\u00a0 # Recall score with weighted average\n\u00a0 \u00a0 \u00a0 \u00a0 \"auc_score\": roc_auc_score(labels, probs, average=\"macro\", multi_class=\"ovr\")\n\u00a0 \u00a0 }<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Let\u2019s set up the training process:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Define hyperparameters\nlr = 2e-5\nbatch_size = 16\nnum_epochs = 3\nweight_decay = 0.01\n\n# Set up training arguments for fine-tuning models\ntraining_args = TrainingArguments(\n\u00a0 \u00a0 output_dir=\".\/results\",\n\u00a0 \u00a0 evaluation_strategy=\"steps\",\n\u00a0 \u00a0 eval_steps=500,\n\u00a0 \u00a0 learning_rate=lr,\n\u00a0 \u00a0 per_device_train_batch_size=batch_size,\n\u00a0 \u00a0 per_device_eval_batch_size=batch_size,\n\u00a0 \u00a0 num_train_epochs=num_epochs,\n\u00a0 \u00a0 weight_decay=weight_decay,\n\u00a0 \u00a0 logging_dir=\".\/logs\",\n\u00a0 \u00a0 logging_steps=500,\n\u00a0 \u00a0 load_best_model_at_end=True,\n\u00a0 \u00a0 metric_for_best_model=\"eval_f1_score\",\n\u00a0 \u00a0 greater_is_better=True,\n)\n\n# Initialize the Trainer with the model, arguments, and datasets\ntrainer = Trainer(\n\u00a0 \u00a0 model=model,\n\u00a0 \u00a0 args=training_args,\n\u00a0 \u00a0 train_dataset=train_dataset,\n\u00a0 \u00a0 eval_dataset=val_dataset,\n\u00a0 \u00a0 tokenizer=tokenizer,\n\u00a0 \u00a0 compute_metrics=compute_metrics,\n)\n\n# Train the model\nprint(f\"Training {model_name}...\")\ntrainer.train()<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><strong>Step 5: Evaluating Model Performance<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">After training, I evaluated the model\u2019s performance on the test set:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Generate predictions on the test dataset with fine-tuned model\npredictions_finetuned_model = trainer.predict(test_dataset)\npreds_finetuned = predictions_finetuned_model.predictions.argmax(axis=1)\n\n# Compute evaluation metrics (accuracy, precision, recall, and F1 score)\neval_results_finetuned_model = compute_metrics((predictions_finetuned_model.predictions, test_dataset[\"label\"]))<\/code><\/pre>\n<p class=\"wp-block-paragraph\">This is how the fine-tuned DistilBERT model did on the test set compared to the pre-trained base model:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdmtFY_1j5ii7Ck3HYwJu5h5bOBtagiADiijo6ZizxSwdF0sd5-5dN48o0xM6vIZ4Jc8jg9_OtdDx99MpphTwdUyeBaadIWZ6RsV2Etd1IqmlTC-5eChfe3MazIZ45jw40CbPEIAA?key=EdH2R_lZ0C0rh-CBHFDARV_1\" alt=\"\"><figcaption class=\"wp-element-caption\"><em>Radar chart of fine-tuned DistilBERT model. Image by author<\/em>.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Before fine-tuning, the pre-trained model performed poorly on our dataset, because it hasn\u2019t seen the specific emotion labels before. It was essentially guessing at random, as reflected in an AUC score of 0.5 that indicates no better than chance.<\/p>\n<p class=\"wp-block-paragraph\">After fine-tuning, the model significantly <strong>improved across all metrics<\/strong>, achieving 83% accuracy in correctly identifying emotions. This demonstrates that the model has successfully learned meaningful patterns in the data, even with just 16k training samples.<\/p>\n<p class=\"wp-block-paragraph\">That\u2019s amazing!<\/p>\n<h3 class=\"wp-block-heading\"><strong>Step 6: Interpreting Predictions with SHAP<\/strong><\/h3>\n<p class=\"wp-block-paragraph\">I tested the fine-tuned model on three sentences and here are the emotions that it predicted:<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\u201c<em>The thought of speaking in front of a large crowd makes my heart race, and I start to feel overwhelmed with anxiety<\/em>.\u201d \u2192 fear <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f631.png?ssl=1\" alt=\"\ud83d\ude31\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\">\n<\/li>\n<li class=\"wp-block-list-item\">\n<em>\u201cI can\u2019t believe how disrespectful they were! I worked so hard on this project, and they just dismissed it without even listening. It\u2019s infuriating!\u201d<\/em> \u2192 anger <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f621.png?ssl=1\" alt=\"\ud83d\ude21\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\">\n<\/li>\n<li class=\"wp-block-list-item\">\n<em>\u201cI absolutely love this new phone! The camera quality is amazing, the battery lasts all day, and it\u2019s so fast. I couldn\u2019t be happier with my purchase, and I highly recommend it to anyone looking for a new phone.\u201d<\/em> \u2192 joy <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f600.png?ssl=1\" alt=\"\ud83d\ude00\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\">\n<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">Impressive, right?!<\/p>\n<p class=\"wp-block-paragraph\">I wanted to understand how the model made its predictions, I used using <a href=\"https:\/\/shap.readthedocs.io\/en\/latest\/example_notebooks\/text_examples\/sentiment_analysis\/Emotion%20classification%20multiclass%20example.html\">SHAP<\/a> (Shapley Additive exPlanations) to visualize feature importance.<\/p>\n<p class=\"wp-block-paragraph\">I started by creating an explainer:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Build a pipeline object for predictions\npreds = pipeline(\n\u00a0 \u00a0 \"text-classification\",\n\u00a0 \u00a0 model=model_finetuned,\n\u00a0 \u00a0 tokenizer=tokenizer,\n\u00a0 \u00a0 return_all_scores=True,\n)\n\n# Create an explainer\nexplainer = shap.Explainer(preds)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Then, I computed SHAP values using the explainer:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Compute SHAP values using explainer\nshap_values = explainer(example_texts)\n\n# Make SHAP text plot\nshap.plots.text(shap_values)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The plot below visualizes how each word in the input text contributes to the model\u2019s output using SHAP values:<\/p>\n<figure class=\"wp-block-image alignwide\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXd_aMzQqh8lbjBUKZiI0cNtQ0ND1mklPP49k1vcaa3_jAcUKNIWWlHK8a0yRFJ-LecTxMcTgbaxoh57L45sEYeZcWwM1-KJ5UQt6_f95CO2y0vuCJ5UAA2SsmbH1reR25ffwgiZ?key=EdH2R_lZ0C0rh-CBHFDARV_1\" alt=\"\"><figcaption class=\"wp-element-caption\">SHAP text plot. Image by author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">In this case, the plot shows that \u201canxiety\u201d is the most important factor in predicting \u201cfear\u201d as the emotion.<\/p>\n<p class=\"wp-block-paragraph\">The SHAP text plot is a nice, intuitive, and interactive way to understand predictions by breaking down how much each word influences the final prediction.<\/p>\n<h2 class=\"wp-block-heading\"><strong>Summary<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">You\u2019ve successfully learned to fine-tune DistilBERT for emotion classification from text data! (You can check out the model on Hugging Face <a href=\"https:\/\/huggingface.co\/ds-claudia\/classify_emotions_into_six_categories_with_distilbert\">here<\/a>).<\/p>\n<p class=\"wp-block-paragraph\">Transformer models can be fine-tuned for many real-world applications, including:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Tagging customer service tickets (as discussed in the introduction),<\/li>\n<li class=\"wp-block-list-item\">Flagging mental health risks in text-based conversations,<\/li>\n<li class=\"wp-block-list-item\">Detecting sentiment in product reviews.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">Fine-tuning is an effective and efficient way to adapt powerful pre-trained models to specific tasks with a relatively small dataset.<\/p>\n<p class=\"wp-block-paragraph\">What will you fine-tune next?<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<p class=\"wp-block-paragraph\"><strong>Want to build your AI skills?<\/strong><\/p>\n<p class=\"wp-block-paragraph\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f449-1f3fb.png?ssl=1\" alt=\"\ud83d\udc49\ud83c\udffb\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> I run the <a href=\"http:\/\/aiweekender.substack.com\/\"><strong>AI Weekender<\/strong><\/a><strong> and<\/strong> write weekly blog posts on data science, AI weekend projects, career advice for professionals in data.<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<p class=\"wp-block-paragraph\"><strong>Resources<\/strong><\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Jupyter notebook [<a href=\"https:\/\/colab.research.google.com\/drive\/1qlL6TteEnPMqHHfUGTQXEKcXFJ2qAcKO?authuser=3#scrollTo=3Vd6BWqGLYmP\">HERE<\/a>]<\/li>\n<li class=\"wp-block-list-item\">Model card on Hugging Face [<a href=\"https:\/\/huggingface.co\/ds-claudia\/classify_emotions_into_six_categories_with_distilbert\">HERE<\/a>]<\/li>\n<\/ul>\n<p>The post <a href=\"https:\/\/towardsdatascience.com\/how-to-fine-tune-distilbert-for-emotion-classification\/\">How to Fine-Tune DistilBERT for Emotion Classification<\/a> appeared first on <a href=\"https:\/\/towardsdatascience.com\/\">Towards Data Science<\/a>.<\/p>\n<\/div>\n<p> \t<BR><br \/>\n <BR><\/BR><br \/>\n    Claudia Ng<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n<a href=\"https:\/\/towardsdatascience.com\/how-to-fine-tune-distilbert-for-emotion-classification\/\">Go to original source<\/a><br \/>\n \t<BR><br \/>\n <BR><\/BR><\/p>\n","protected":false},"excerpt":{"rendered":"<p>How to Fine-Tune DistilBERT for Emotion Classification The customer support teams were drowning with the overwhelming volume of customer inquiries at every company I\u2019ve worked at. Have you had similar experiences? What if I told you that you could use AI to automatically identify, categorize, and even resolve the most common issues? By fine-tuning a [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[62,1789,1790,1112,70,1419,76],"tags":[135,103,1791],"class_list":["post-1927","post","type-post","status-publish","format-standard","hentry","category-aimldsaimlds","category-distilbert","category-emotion-analysis","category-fine-tuning","category-machine-learning","category-text-classification","category-transformer-model","tag-fine","tag-model","tag-tune"],"_links":{"self":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/1927"}],"collection":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/comments?post=1927"}],"version-history":[{"count":0,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/1927\/revisions"}],"wp:attachment":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/media?parent=1927"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/categories?post=1927"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/tags?post=1927"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}