Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Zero-shot classification

zero-shot-classification.livemd

Zero-shot classification

Mix.install([
  {:req, "~> 0.5"},
  {:hnswlib, "~> 0.1"},
  {:instructor, "~> 0.1"},
  {:bumblebee, "~> 0.6.0"},
  {:exla, "~> 0.9"},

  {:elixir_make, "~> 0.9", override: true}
], 
  config: [nx: [default_backend: EXLA.Backend]]
)

Application.put_env(:exla, :clients, cuda: [platform: :cuda, preallocate: false])

Setup

client = Req.new(base_url: "https://models.arrakis.upmaru.network")

defmodule QueryClassification do
  use Ecto.Schema
  use Instructor

  @llm_doc """
  Query classification
  
  ## Fields:
  - reply: Should the reply be list of results or a recommendation?
  - about: What is the query about? Location, character or general knowledge?
  """
  @primary_key false
  embedded_schema do
    field :reply, Ecto.Enum, values: [:results, :recommendation]
    field :about, Ecto.Enum, values: [:general, :character, :location]
  end
end

With embeddings

space = :cosine
dimensions = 1024
max_elements = 3

{:ok, index} = HNSWLib.Index.new(space, dimensions, max_elements)

body = %{
  input: ["query with no specific category", "query about movie character", "query related to the location or the setting of the movie"],
  model: "multilingual-e5-large",
  encoding_format: "float"
}
  
{:ok, %{body: response}} = Req.post(client, url: "/v1/embeddings", json: body)

%{"data" => embeddings} = response

embeddings = 
  Enum.sort_by(embeddings, fn e -> 
    e["index"]
  end)
  |> Enum.map(fn e -> e["embedding"] end)
  |> Nx.tensor()

HNSWLib.Index.add_items(index, embeddings)
original_query = "query: movies involving robots"

query_body = %{
  input: original_query,
  model: "multilingual-e5-large",
  encoding_format: "float"
}

{:ok, %{body: query}} = Req.post(client, url: "/v1/embeddings", json: query_body)

%{"data" => [%{"embedding" => embedding}]} = query

query = Nx.tensor(embedding)

{:ok, labels, dists} = HNSWLib.Index.knn_query(index, query, k: 3)

With reranking model

original_query = "query: movies involving robots"

body = %{
  query: original_query,
  documents: ["query is general", "query about characters in the movie", "query related to the location or the setting of the movie"],
  model: "bge-reranker-v2-m3"
}

{:ok, %{body: %{"results" => reranking_results}}} = Req.post(client, url: "/v1/rerank", json: body)

With LLM

instructor_config = [
  adapter: Instructor.Adapters.Llamacpp,
  api_url: "https://models.arrakis.upmaru.network"
]

{:ok, setting} = Instructor.chat_completion([
    model: "mistral-small-24b",
    mode: :json_schema,
    response_model: QueryClassification,
    messages: [
      %{
        role: "user",
        content: """
           Correctly identify what the query is about and what type of reply should be made
        
           
           Movies that is set in the sea or the ocean.
           
          """
      }
    ]
  ], instructor_config)

Using Zero-shot classification model

{:ok, model} = Bumblebee.load_model({:hf, "facebook/bart-large-mnli"})
{:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "facebook/bart-large-mnli"})

categories = ["general", "character", "location"]
categories_serving = Bumblebee.Text.zero_shot_classification(model, tokenizer, categories)

output = Nx.Serving.run(categories_serving, "Movies that take place in the mountains")