{"id":14327,"date":"2023-07-05T00:00:30","date_gmt":"2023-07-05T00:00:30","guid":{"rendered":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/"},"modified":"2024-11-26T20:14:10","modified_gmt":"2024-11-26T20:14:10","slug":"building-a-conformal-chatbot-in-julia-1ed23363a280","status":"publish","type":"post","link":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/","title":{"rendered":"Building a Conformal Chatbot in Julia"},"content":{"rendered":"<h3 class=\"wp-block-heading\">Conformal Prediction, LLMs and HuggingFace &#8211; Part 1<\/h3>\n<p class=\"wp-block-paragraph\">Large Language Models (LLM) are all the buzz right now. They are used for a variety of tasks, including text classification, question answering, and text generation. In this tutorial, we will show how to conformalize a transformer language model for text classification using <code>[ConformalPrediction.jl](https:\/\/juliatrustworthyai.github.io\/ConformalPrediction.jl\/dev\/)<\/code>.<\/p>\n<h2 class=\"wp-block-heading\">\ud83d\udc40  At a Glance<\/h2>\n<p class=\"wp-block-paragraph\">In particular, we are interested in the task of intent classification as illustrated in the sketch below. Firstly, we feed a customer query into an LLM to generate embeddings. Next, we train a classifier to match these embeddings to possible intents. Of course, for this supervised learning problem we need training data consisting of inputs &#8211; queries &#8211; and outputs &#8211; labels indicating the true intent. Finally, we apply Conformal Predition to quantify the predictive uncertainty of our classifier.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Conformal Prediction (CP) is a rapidly emerging methodology for Predictive Uncertainty Quantification. If you&#8217;re unfamiliar with CP, you may want to first check out my 3-part introductory series on the topic starting with this <a href=\"https:\/\/medium.com\/towards-data-science\/conformal-prediction-in-julia-351b81309e30\">post<\/a>.<\/p><\/blockquote>\n<p class=\"wp-block-paragraph\"><\/p>\n<h2 class=\"wp-block-heading\">\ud83e\udd17 HuggingFace<\/h2>\n<p class=\"wp-block-paragraph\">We will use the <a href=\"https:\/\/arxiv.org\/abs\/2003.04807\">Banking77<\/a> dataset (Casanueva et al., 2020), which consists of 13,083 queries from 77 intents related to banking. On the model side, we will use the <a href=\"https:\/\/huggingface.co\/mrm8488\/distilroberta-finetuned-banking77\">Distil<a href=\"https:\/\/arxiv.org\/abs\/1907.11692\">RoBERTa<\/a><\/a> model, which is a distilled version of RoBERTa (Liu et al., 2019) fine-tuned on the Banking77 dataset.<\/p>\n<p class=\"wp-block-paragraph\">The model can be loaded from HF straight into our running Julia session using the <code>[Transformers.jl](https:\/\/github.com\/chengchingwen\/Transformers.jl\/tree\/master)<\/code> package.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>This package makes working with HF models remarkably easy in Julia. Kudos to the devs! <em>\ud83d\ude4f<\/em> <\/p><\/blockquote>\n<p class=\"wp-block-paragraph\">Below we load the tokenizer <code>tkr<\/code> and the model <code>mod<\/code>. The tokenizer is used to convert the text into a sequence of integers, which is then fed into the model. The model outputs a hidden state, which is then fed into a classifier to get the logits for each class. Finally, the logits are then passed through a softmax function to get the corresponding predicted probabilities. Below we run a few queries through the model to see how it performs.<\/p>\n<pre class=\"wp-block-code\"><code># Load model from HF \ud83e\udd17:\ntkr = hgf&quot;mrm8488\/distilroberta-finetuned-banking77:tokenizer&quot;\nmod = hgf&quot;mrm8488\/distilroberta-finetuned-banking77:ForSequenceClassification&quot;\n\n# Test model:\nquery = [\n    &quot;What is the base of the exchange rates?&quot;,\n    &quot;Why is my card not working?&quot;,\n    &quot;My Apple Pay is not working, what should I do?&quot;,\n]\na = encode(tkr, query)\nb = mod.model(a)\nc = mod.cls(b.hidden_state)\nd = softmax(c.logit)\n[labels[i] for i in Flux.onecold(d)]<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>3-element Vector{String}:\n &quot;exchange_rate&quot;\n &quot;card_not_working&quot;\n &quot;apple_pay_or_google_pay&quot;<\/code><\/pre>\n<h2 class=\"wp-block-heading\">\ud83d\udd01  <code>MLJ<\/code> Interface<\/h2>\n<p class=\"wp-block-paragraph\">Since our package is interfaced to <code>[MLJ.jl](https:\/\/alan-turing-institute.github.io\/MLJ.jl\/dev\/)<\/code>, we need to define a wrapper model that conforms to the <code>MLJ<\/code> interface. In order to add the model for general use, we would probably go through <code>[MLJFlux.jl](https:\/\/github.com\/FluxML\/MLJFlux.jl)<\/code>, but for this tutorial, we will make our life easy and simply overload the <code>MLJBase.fit<\/code> and <code>MLJBase.predict<\/code> methods.<\/p>\n<p class=\"wp-block-paragraph\">Since the model from HF is already pre-trained and we are not interested in further fine-tuning, we will simply return the model object in the <code>MLJBase.fit<\/code> method. The <code>MLJBase.predict<\/code> method will then take the model object and the query and return the predicted probabilities. We also need to define the <code>MLJBase.target_scitype<\/code> and <code>MLJBase.predict_mode<\/code> methods. The former tells <code>MLJ<\/code> what the output type of the model is, and the latter can be used to retrieve the label with the highest predicted probability.<\/p>\n<pre class=\"wp-block-code\"><code>struct IntentClassifier &amp;lt;: MLJBase.Probabilistic\n    tkr::TextEncoders.AbstractTransformerTextEncoder\n    mod::HuggingFace.HGFRobertaForSequenceClassification\nend\n\nfunction IntentClassifier(;\n    tkr::TextEncoders.AbstractTransformerTextEncoder, \n    mod::HuggingFace.HGFRobertaForSequenceClassification,\n)\n    IntentClassifier(tkr, mod)\nend\n\nfunction get_hidden_state(clf::IntentClassifier, query::Union{AbstractString, Vector{&amp;lt;:AbstractString}})\n    token = encode(clf.tkr, query)\n    hidden_state = clf.mod.model(token).hidden_state\n    return hidden_state\nend\n\n# This doesn&#039;t actually retrain the model, but it retrieves the classifier object\nfunction MLJBase.fit(clf::IntentClassifier, verbosity, X, y)\n    cache=nothing\n    report=nothing\n    fitresult = (clf = clf.mod.cls, labels = levels(y))\n    return fitresult, cache, report\nend\n\nfunction MLJBase.predict(clf::IntentClassifier, fitresult, Xnew)\n    output = fitresult.clf(get_hidden_state(clf, Xnew))\n    p\u0302 = UnivariateFinite(fitresult.labels,softmax(output.logit)&#039;,pool=missing)\n    return p\u0302\nend\n\nMLJBase.target_scitype(clf::IntentClassifier) = AbstractVector{&amp;lt;:Finite}\n\nMLJBase.predict_mode(clf::IntentClassifier, fitresult, Xnew) = mode.(MLJBase.predict(clf, fitresult, Xnew))<\/code><\/pre>\n<p class=\"wp-block-paragraph\">To test that everything is working as expected, we fit the model and generated predictions for a subset of the test data:<\/p>\n<pre class=\"wp-block-code\"><code>clf = IntentClassifier(tkr, mod)\ntop_n = 10\nfitresult, _, _ = MLJBase.fit(clf, 1, nothing, y_test[1:top_n])\n@time y\u0302 = MLJBase.predict(clf, fitresult, queries_test[1:top_n]);<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>6.818024 seconds (11.29 M allocations: 799.165 MiB, 2.47% gc time, 91.04% compilation time)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Note that even though the LLM we&#8217;re using here isn&#8217;t really that large at all, even a simple forward pass does take considerable time.<\/p>\n<h2 class=\"wp-block-heading\">\ud83e\udd16 Conformal Chatbot<\/h2>\n<p class=\"wp-block-paragraph\">To turn the wrapped, pre-trained model into a conformal intent classifier, we can now rely on standard API calls. We first wrap our atomic model where we also specify the desired coverage rate and method. Since even simple forward passes are computationally expensive for our (small) LLM, we rely on Simple Inductive Conformal Classification.<\/p>\n<pre class=\"wp-block-code\"><code>conf_model = conformal_model(clf; coverage=0.95, method=:simple_inductive, train_ratio=train_ratio)\nmach = machine(conf_model, queries, y)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Finally, we use our conformal LLM to build a simple yet powerful chatbot that runs directly in the Julia REPL. Without dwelling on the details too much, the <code>conformal_chatbot<\/code> works as follows:<\/p>\n<ol class=\"wp-block-list\">\n<li>Prompt user to explain their intent.<\/li>\n<li>Feed user input through conformal LLM and present the output to the user.<\/li>\n<li>If the conformal prediction set includes more than one label, prompt the user to either refine their input or choose one of the options included in the set.<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">The following code implements these ideas:<\/p>\n<pre class=\"wp-block-code\"><code>function prediction_set(mach, query::String)\n    p\u0302 = MLJBase.predict(mach, query)[1]\n    probs = pdf.(p\u0302, collect(1:77))\n    in_set = findall(probs .!= 0)\n    labels_in_set = labels[in_set]\n    probs_in_set = probs[in_set]\n    _order = sortperm(-probs_in_set)\n    plt = UnicodePlots.barplot(labels_in_set[_order], probs_in_set[_order], title=&quot;Possible Intents&quot;)\n    return labels_in_set, plt\nend\n\nfunction conformal_chatbot()\n    println(&quot;\ud83d\udc4b   Hi, I&#039;m a Julia, your conformal chatbot. I&#039;m here to help you with your banking query. Ask me anything or type &#039;exit&#039; to exit ...n&quot;)\n    completed = false\n    queries = &quot;&quot;\n    while !completed\n        query = readline()\n        queries = queries * &quot;,&quot; * query\n        labels, plt = prediction_set(mach, queries)\n        if length(labels) &amp;gt; 1\n            println(&quot;\ud83e\udd14 Hmmm ... I can think of several options here. If any of these applies, simply type the corresponding number (e.g. &#039;1&#039; for the first option). Otherwise, can you refine your question, please?n&quot;)\n            println(plt)\n        else\n            println(&quot;\ud83e\udd73 I think you mean $(labels[1]). Correct?&quot;)\n        end\n\n        # Exit:\n        if query == &quot;exit&quot;\n            println(&quot;\ud83d\udc4b   Bye!&quot;)\n            break\n        end\n        if query \u2208 string.(collect(1:77))\n            println(&quot;\ud83d\udc4d  Great! You&#039;ve chosen &#039;$(labels[parse(Int64, query)])&#039;. I&#039;m glad I could help you. Have a nice day!&quot;)\n            completed = true\n        end\n    end\nend<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Below we show the output for two example queries. The first one is very ambiguous (and misspelled as I just realised): &quot;transfer mondey?&quot;. As expected, the size of the prediction set is therefore large.<\/p>\n<pre class=\"wp-block-code\"><code>ambiguous_query = &quot;transfer mondey?&quot;\nprediction_set(mach, ambiguous_query)[2]<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>                                                        Possible Intents              \n                                           \u250c                                        \u2510 \n                   beneficiary_not_allowed \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.150517   \n   balance_not_updated_after_bank_transfer \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.111409           \n                     transfer_into_account \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.0939535             \n        transfer_not_received_by_recipient \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.091163               \n            top_up_by_bank_transfer_charge \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.089306               \n                           failed_transfer \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.0888322              \n                           transfer_timing \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.0641952                   \n                      transfer_fee_charged \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.0361131                         \n                          pending_transfer \u2524\u25a0\u25a0\u25a0\u25a0\u25a0 0.0270795                           \n                           receiving_money \u2524\u25a0\u25a0\u25a0\u25a0\u25a0 0.0252126                           \n                         declined_transfer \u2524\u25a0\u25a0\u25a0 0.0164443                             \n                           cancel_transfer \u2524\u25a0\u25a0\u25a0 0.0150444                             \n                                           \u2514                                        \u2518 <\/code><\/pre>\n<p class=\"wp-block-paragraph\">The following is a more refined version of the prompt: &quot;I tried to transfer money to my friend, but it failed&quot;. It yields a smaller prediction set, since less ambiguous prompts result in lower predictive uncertainty.<\/p>\n<pre class=\"wp-block-code\"><code>refined_query = &quot;I tried to transfer money to my friend, but it failed.&quot;\nprediction_set(mach, refined_query)[2]<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>                                                        Possible Intents              \n                                           \u250c                                        \u2510 \n                           failed_transfer \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.59042   \n                   beneficiary_not_allowed \u2524\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0 0.139806                          \n        transfer_not_received_by_recipient \u2524\u25a0\u25a0 0.0449783                              \n   balance_not_updated_after_bank_transfer \u2524\u25a0\u25a0 0.037894                               \n                         declined_transfer \u2524\u25a0 0.0232856                               \n                     transfer_into_account \u2524\u25a0 0.0108771                               \n                           cancel_transfer \u2524 0.00876369                               \n                                           \u2514                                        \u2518 <\/code><\/pre>\n<p class=\"wp-block-paragraph\">The video below shows the REPL-based chatbot in action. You can recreate this yourself and run the bot right from you terminal. To do so, just check out the original <a href=\"https:\/\/www.paltmeyer.com\/blog\/posts\/conformal-llm\/\">post<\/a> on my blog to find the full source code.<\/p>\n<p class=\"wp-block-paragraph\"><\/p>\n<h2 class=\"wp-block-heading\">\ud83c\udf2f  Wrapping Up<\/h2>\n<p class=\"wp-block-paragraph\">This work was done in collaboration with colleagues at ING as part of the ING Analytics 2023 Experiment Week. Our team demonstrated that Conformal Prediction provides a powerful and principled alternative to top-<em>K<\/em> intent classification. We won the first prize by popular vote.<\/p>\n<p class=\"wp-block-paragraph\">Of course, there are a lot of things that can be improved here. As far as Large LMs are concerned, we have used a small one. In terms of Conformal Prediction, we have only looked at simple inductive conformal classification. This is a good starting point, but there are more advanced methods available, which are implemented in the package and were investigated during the competition. Another thing we did not take into consideration here is that we have many outcome classes and may in practice be interested in achieving class-conditional coverage. Stay tuned for more on this in future posts.<\/p>\n<p class=\"wp-block-paragraph\">If you&#8217;re interested in finding out more about Conformal Prediction in Julia, go ahead and check out the <a href=\"https:\/\/github.com\/JuliaTrustworthyAI\/ConformalPrediction.jl\">repo<\/a> and <a href=\"https:\/\/juliatrustworthyai.github.io\/ConformalPrediction.jl\/dev\/\">docs<\/a>.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\ud83c\udf89  JuliaCon 2023 is around the corner and this year I will be giving a <a href=\"https:\/\/pretalx.com\/juliacon2023\/talk\/JQWNNP\/\">talk<\/a> about <em>ConformalPrediction.jl.<\/em> Check out the details of my talk <a href=\"https:\/\/pretalx.com\/juliacon2023\/talk\/JQWNNP\/\">here<\/a> and have a look at the full jam-packed conference <a href=\"https:\/\/pretalx.com\/juliacon2023\/schedule\/\">schedule<\/a>.<\/p><\/blockquote>\n<h2 class=\"wp-block-heading\">\ud83c\udf93  References<\/h2>\n<p class=\"wp-block-paragraph\">Casanueva, I\u00f1igo, Tadas Tem\u010dinas, Daniela Gerz, Matthew Henderson, and Ivan Vuli\u0107. 2020. &quot;Efficient Intent Detection with Dual Sentence Encoders.&quot; In <em>Proceedings of the 2nd Workshop on Natural Language Processing for Conversational AI<\/em> , 38\u201345. Online: Association for Computational Linguistics. <a href=\"https:\/\/doi.org\/10.18653\/v1\/2020.nlp4convai-1.5\"><a href=\"https:\/\/doi.org\/10.18653\/v1\/2020.nlp4convai-1.5\">https:\/\/doi.org\/10.18653\/v1\/2020.nlp4convai-1.5<\/a><\/a>.<\/p>\n<p class=\"wp-block-paragraph\">Liu, Yinhan, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Danqi Chen, Omer Levy, Mike Lewis, Luke Zettlemoyer, and Veselin Stoyanov. 2019. &quot;RoBERTa: A Robustly Optimized BERT Pretraining Approach.&quot; arXiv. <a href=\"https:\/\/doi.org\/10.48550\/arXiv.1907.11692\"><a href=\"https:\/\/doi.org\/10.48550\/arXiv.1907.11692\">https:\/\/doi.org\/10.48550\/arXiv.1907.11692<\/a><\/a>.<\/p>\n<h3 class=\"wp-block-heading\">\ud83d\udcbe  Data and Model<\/h3>\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/arxiv.org\/abs\/2003.04807\">Banking77<\/a> dataset was retrieved from HuggingFace. It is published under the Creative Commons Attribution 4.0 International license (CC BY 4.0) and curated by <a href=\"https:\/\/github.com\/PolyAI-LDN\">PolyAI<\/a> and was originally published by Casanueva et al. (2020). With thanks also to <a href=\"https:\/\/twitter.com\/mrm8488\">Manuel Romero<\/a> who contributed the fine-tuned <a href=\"https:\/\/huggingface.co\/mrm8488\/distilroberta-finetuned-banking77\">DistilRoBERTa<\/a> to HuggingFace.<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n<p class=\"wp-block-paragraph\"><em>Originally published at <a href=\"https:\/\/www.paltmeyer.com\/blog\/posts\/conformal-llm\/\"><a href=\"https:\/\/www.paltmeyer.com\">https:\/\/www.paltmeyer.com<\/a><\/a> on July 5, 2023.<\/em><\/p>","protected":false},"excerpt":{"rendered":"<p>Conformal Prediction, LLMs and HuggingFace &#8211; Part 1 Large Language Models (LLM) are all the buzz right now. They are used for a variety of tasks, including text classification, question answering, and text generation. In this tutorial, we will show how to conformalize a transformer language model for text classification using [ConformalPrediction.jl](https:\/\/juliatrustworthyai.github.io\/ConformalPrediction.jl\/dev\/). \ud83d\udc40 At a [&hellip;]<\/p>\n","protected":false},"author":18,"featured_media":14328,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"is_member_only":true,"sub_heading":"Conformal Prediction, LLMs and HuggingFace\u200a-\u200aPart 1","footnotes":""},"categories":[21,22],"tags":[3002,1303,942,450,446],"sponsor":[],"coauthors":[30610],"class_list":["post-14327","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-large-language-models","category-machine-learning","tag-conformal-prediction","tag-hugging-face","tag-julia","tag-large-language-models","tag-machine-learning"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Building a Conformal Chatbot in Julia | Towards Data Science<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a Conformal Chatbot in Julia | Towards Data Science\" \/>\n<meta property=\"og:description\" content=\"Conformal Prediction, LLMs and HuggingFace &#8211; Part 1 Large Language Models (LLM) are all the buzz right now. They are used for a variety of tasks, including text classification, question answering, and text generation. In this tutorial, we will show how to conformalize a transformer language model for text classification using [ConformalPrediction.jl](https:\/\/juliatrustworthyai.github.io\/ConformalPrediction.jl\/dev\/). \ud83d\udc40 At a [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\" \/>\n<meta property=\"og:site_name\" content=\"Towards Data Science\" \/>\n<meta property=\"article:published_time\" content=\"2023-07-05T00:00:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-11-26T20:14:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"2240\" \/>\n\t<meta property=\"og:image:height\" content=\"827\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Patrick Altmeyer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@TDataScience\" \/>\n<meta name=\"twitter:site\" content=\"@TDataScience\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Patrick Altmeyer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\"},\"author\":{\"name\":\"TDS Editors\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee\"},\"headline\":\"Building a Conformal Chatbot in Julia\",\"datePublished\":\"2023-07-05T00:00:30+00:00\",\"dateModified\":\"2024-11-26T20:14:10+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\"},\"wordCount\":1093,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/towardsdatascience.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg\",\"keywords\":[\"Conformal Prediction\",\"Hugging Face\",\"Julia\",\"Large Language Models\",\"Machine Learning\"],\"articleSection\":[\"Large Language Models\",\"Machine Learning\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\",\"url\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\",\"name\":\"Building a Conformal Chatbot in Julia | Towards Data Science\",\"isPartOf\":{\"@id\":\"https:\/\/towardsdatascience.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg\",\"datePublished\":\"2023-07-05T00:00:30+00:00\",\"dateModified\":\"2024-11-26T20:14:10+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage\",\"url\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg\",\"contentUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg\",\"width\":2240,\"height\":827},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/towardsdatascience.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a Conformal Chatbot in Julia\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/towardsdatascience.com\/#website\",\"url\":\"https:\/\/towardsdatascience.com\/\",\"name\":\"Towards Data Science\",\"description\":\"Publish AI, ML &amp; data-science insights to a global community of data professionals.\",\"publisher\":{\"@id\":\"https:\/\/towardsdatascience.com\/#organization\"},\"alternateName\":\"TDS\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/towardsdatascience.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/towardsdatascience.com\/#organization\",\"name\":\"Towards Data Science\",\"alternateName\":\"TDS\",\"url\":\"https:\/\/towardsdatascience.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg\",\"contentUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg\",\"width\":696,\"height\":696,\"caption\":\"Towards Data Science\"},\"image\":{\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/TDataScience\",\"https:\/\/www.youtube.com\/c\/TowardsDataScience\",\"https:\/\/www.linkedin.com\/company\/towards-data-science\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee\",\"name\":\"TDS Editors\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/person\/image\/23494c9101089ad44ae88ce9d2f56aac\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g\",\"caption\":\"TDS Editors\"},\"description\":\"Building a vibrant data science and machine learning community. Share your insights and projects with our global audience: bit.ly\/write-for-tds\",\"url\":\"https:\/\/towardsdatascience.com\/author\/towardsdatascience\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building a Conformal Chatbot in Julia | Towards Data Science","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/","og_locale":"en_US","og_type":"article","og_title":"Building a Conformal Chatbot in Julia | Towards Data Science","og_description":"Conformal Prediction, LLMs and HuggingFace &#8211; Part 1 Large Language Models (LLM) are all the buzz right now. They are used for a variety of tasks, including text classification, question answering, and text generation. In this tutorial, we will show how to conformalize a transformer language model for text classification using [ConformalPrediction.jl](https:\/\/juliatrustworthyai.github.io\/ConformalPrediction.jl\/dev\/). \ud83d\udc40 At a [&hellip;]","og_url":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/","og_site_name":"Towards Data Science","article_published_time":"2023-07-05T00:00:30+00:00","article_modified_time":"2024-11-26T20:14:10+00:00","og_image":[{"width":2240,"height":827,"url":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg","type":"image\/jpeg"}],"author":"Patrick Altmeyer","twitter_card":"summary_large_image","twitter_creator":"@TDataScience","twitter_site":"@TDataScience","twitter_misc":{"Written by":"Patrick Altmeyer","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#article","isPartOf":{"@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/"},"author":{"name":"TDS Editors","@id":"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee"},"headline":"Building a Conformal Chatbot in Julia","datePublished":"2023-07-05T00:00:30+00:00","dateModified":"2024-11-26T20:14:10+00:00","mainEntityOfPage":{"@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/"},"wordCount":1093,"commentCount":0,"publisher":{"@id":"https:\/\/towardsdatascience.com\/#organization"},"image":{"@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage"},"thumbnailUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg","keywords":["Conformal Prediction","Hugging Face","Julia","Large Language Models","Machine Learning"],"articleSection":["Large Language Models","Machine Learning"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/","url":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/","name":"Building a Conformal Chatbot in Julia | Towards Data Science","isPartOf":{"@id":"https:\/\/towardsdatascience.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage"},"image":{"@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage"},"thumbnailUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg","datePublished":"2023-07-05T00:00:30+00:00","dateModified":"2024-11-26T20:14:10+00:00","breadcrumb":{"@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#primaryimage","url":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg","contentUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2023\/07\/16sR4avVO7_a1P6V3Bsm6vg.jpeg","width":2240,"height":827},{"@type":"BreadcrumbList","@id":"https:\/\/towardsdatascience.com\/building-a-conformal-chatbot-in-julia-1ed23363a280\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/towardsdatascience.com\/"},{"@type":"ListItem","position":2,"name":"Building a Conformal Chatbot in Julia"}]},{"@type":"WebSite","@id":"https:\/\/towardsdatascience.com\/#website","url":"https:\/\/towardsdatascience.com\/","name":"Towards Data Science","description":"Publish AI, ML &amp; data-science insights to a global community of data professionals.","publisher":{"@id":"https:\/\/towardsdatascience.com\/#organization"},"alternateName":"TDS","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/towardsdatascience.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/towardsdatascience.com\/#organization","name":"Towards Data Science","alternateName":"TDS","url":"https:\/\/towardsdatascience.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/","url":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg","contentUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg","width":696,"height":696,"caption":"Towards Data Science"},"image":{"@id":"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/TDataScience","https:\/\/www.youtube.com\/c\/TowardsDataScience","https:\/\/www.linkedin.com\/company\/towards-data-science\/"]},{"@type":"Person","@id":"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee","name":"TDS Editors","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/towardsdatascience.com\/#\/schema\/person\/image\/23494c9101089ad44ae88ce9d2f56aac","url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","caption":"TDS Editors"},"description":"Building a vibrant data science and machine learning community. Share your insights and projects with our global audience: bit.ly\/write-for-tds","url":"https:\/\/towardsdatascience.com\/author\/towardsdatascience\/"}]}},"distributor_meta":false,"distributor_terms":false,"distributor_media":false,"distributor_original_site_name":"Towards Data Science","distributor_original_site_url":"https:\/\/towardsdatascience.com","push-errors":false,"_links":{"self":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/posts\/14327","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/users\/18"}],"replies":[{"embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/comments?post=14327"}],"version-history":[{"count":0,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/posts\/14327\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/media\/14328"}],"wp:attachment":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/media?parent=14327"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/categories?post=14327"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/tags?post=14327"},{"taxonomy":"sponsor","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/sponsor?post=14327"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/coauthors?post=14327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}