model laboratory (#95)

pull/98/head
Harrison Chase 2 years ago committed by GitHub
parent 2ddab88c06
commit db37bd089f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,147 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "ab9e95ad",
"metadata": {},
"outputs": [],
"source": [
"from langchain import LLMChain, OpenAI, Cohere, HuggingFaceHub, Prompt\n",
"from langchain.model_laboratory import ModelLaboratory"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "32cb94e6",
"metadata": {},
"outputs": [],
"source": [
"llms = [OpenAI(temperature=0), Cohere(model=\"command-xlarge-20221108\", max_tokens=20, temperature=0), HuggingFaceHub(repo_id=\"google/flan-t5-xl\", model_kwargs={\"temperature\":1})]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "14cde09d",
"metadata": {},
"outputs": [],
"source": [
"model_lab = ModelLaboratory(llms)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f186c741",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1mInput:\u001b[0m\n",
"What color is a flamingo?\n",
"\n",
"\u001b[1mOpenAI\u001b[0m\n",
"Params: {'model': 'text-davinci-002', 'temperature': 0.0, 'max_tokens': 256, 'top_p': 1, 'frequency_penalty': 0, 'presence_penalty': 0, 'n': 1, 'best_of': 1}\n",
"\u001b[104m\n",
"\n",
"Flamingos are pink.\u001b[0m\n",
"\n",
"\u001b[1mCohere\u001b[0m\n",
"Params: {'model': 'command-xlarge-20221108', 'max_tokens': 20, 'temperature': 0.0, 'k': 0, 'p': 1, 'frequency_penalty': 0, 'presence_penalty': 0}\n",
"\u001b[103m\n",
"\n",
"Pink\u001b[0m\n",
"\n",
"\u001b[1mHuggingFaceHub\u001b[0m\n",
"Params: {'repo_id': 'google/flan-t5-xl', 'temperature': 1}\n",
"\u001b[101mpink\u001b[0m\n",
"\n"
]
}
],
"source": [
"model_lab.compare(\"What color is a flamingo?\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "248b652a",
"metadata": {},
"outputs": [],
"source": [
"prompt = Prompt(template=\"What is the capital of {state}?\", input_variables=[\"state\"])\n",
"model_lab_with_prompt = ModelLaboratory(llms, prompt=prompt)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "f64377ac",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1mInput:\u001b[0m\n",
"New York\n",
"\n",
"\u001b[1mOpenAI\u001b[0m\n",
"Params: {'model': 'text-davinci-002', 'temperature': 0.0, 'max_tokens': 256, 'top_p': 1, 'frequency_penalty': 0, 'presence_penalty': 0, 'n': 1, 'best_of': 1}\n",
"\u001b[104m\n",
"\n",
"The capital of New York is Albany.\u001b[0m\n",
"\n",
"\u001b[1mCohere\u001b[0m\n",
"Params: {'model': 'command-xlarge-20221108', 'max_tokens': 20, 'temperature': 0.0, 'k': 0, 'p': 1, 'frequency_penalty': 0, 'presence_penalty': 0}\n",
"\u001b[103m\n",
"\n",
"The capital of New York is Albany.\u001b[0m\n",
"\n",
"\u001b[1mHuggingFaceHub\u001b[0m\n",
"Params: {'repo_id': 'google/flan-t5-xl', 'temperature': 1}\n",
"\u001b[101mst john s\u001b[0m\n",
"\n"
]
}
],
"source": [
"model_lab_with_prompt.compare(\"New York\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "54336dbf",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

@ -15,13 +15,13 @@ def get_color_mapping(
return color_mapping return color_mapping
def print_text(text: str, color: Optional[str] = None) -> None: def print_text(text: str, color: Optional[str] = None, end: str = "") -> None:
"""Print text with highlighting and no end characters.""" """Print text with highlighting and no end characters."""
if color is None: if color is None:
print(text, end="") print(text, end=end)
else: else:
color_str = _COLOR_MAPPING[color] color_str = _COLOR_MAPPING[color]
print(f"\x1b[{color_str}m{text}\x1b[0m", end="") print(f"\x1b[{color_str}m{text}\x1b[0m", end=end)
class ChainedInput: class ChainedInput:

@ -1,6 +1,6 @@
"""Base interface for large language models to expose.""" """Base interface for large language models to expose."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import List, Optional from typing import Any, List, Mapping, Optional
class LLM(ABC): class LLM(ABC):
@ -9,3 +9,13 @@ class LLM(ABC):
@abstractmethod @abstractmethod
def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str: def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""Run the LLM on the given prompt and input.""" """Run the LLM on the given prompt and input."""
@property
@abstractmethod
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
def __str__(self) -> str:
"""Get a string representation of the object for printing."""
cls_name = f"\033[1m{self.__class__.__name__}\033[0m"
return f"{cls_name}\nParams: {self._identifying_params}"

@ -1,6 +1,6 @@
"""Wrapper around Cohere APIs.""" """Wrapper around Cohere APIs."""
import os import os
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Mapping, Optional
from pydantic import BaseModel, Extra, root_validator from pydantic import BaseModel, Extra, root_validator
@ -8,7 +8,7 @@ from langchain.llms.base import LLM
from langchain.llms.utils import enforce_stop_tokens from langchain.llms.utils import enforce_stop_tokens
class Cohere(BaseModel, LLM): class Cohere(LLM, BaseModel):
"""Wrapper around Cohere large language models. """Wrapper around Cohere large language models.
To use, you should have the ``cohere`` python package installed, and the To use, you should have the ``cohere`` python package installed, and the
@ -73,6 +73,23 @@ class Cohere(BaseModel, LLM):
) )
return values return values
@property
def _default_params(self) -> Mapping[str, Any]:
"""Get the default parameters for calling Cohere API."""
return {
"max_tokens": self.max_tokens,
"temperature": self.temperature,
"k": self.k,
"p": self.p,
"frequency_penalty": self.frequency_penalty,
"presence_penalty": self.presence_penalty,
}
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
return {**{"model": self.model}, **self._default_params}
def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str: def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""Call out to Cohere's generate endpoint. """Call out to Cohere's generate endpoint.
@ -89,15 +106,7 @@ class Cohere(BaseModel, LLM):
response = cohere("Tell me a joke.") response = cohere("Tell me a joke.")
""" """
response = self.client.generate( response = self.client.generate(
model=self.model, model=self.model, prompt=prompt, stop_sequences=stop, **self._default_params
prompt=prompt,
max_tokens=self.max_tokens,
temperature=self.temperature,
k=self.k,
p=self.p,
frequency_penalty=self.frequency_penalty,
presence_penalty=self.presence_penalty,
stop_sequences=stop,
) )
text = response.generations[0].text text = response.generations[0].text
# If stop tokens are provided, Cohere's endpoint returns them. # If stop tokens are provided, Cohere's endpoint returns them.

@ -1,6 +1,6 @@
"""Wrapper around HuggingFace APIs.""" """Wrapper around HuggingFace APIs."""
import os import os
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Mapping, Optional
from pydantic import BaseModel, Extra, root_validator from pydantic import BaseModel, Extra, root_validator
@ -11,7 +11,7 @@ DEFAULT_REPO_ID = "gpt2"
VALID_TASKS = ("text2text-generation", "text-generation") VALID_TASKS = ("text2text-generation", "text-generation")
class HuggingFaceHub(BaseModel, LLM): class HuggingFaceHub(LLM, BaseModel):
"""Wrapper around HuggingFaceHub models. """Wrapper around HuggingFaceHub models.
To use, you should have the ``huggingface_hub`` python package installed, and the To use, you should have the ``huggingface_hub`` python package installed, and the
@ -74,6 +74,12 @@ class HuggingFaceHub(BaseModel, LLM):
) )
return values return values
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
_model_kwargs = self.model_kwargs or {}
return {**{"repo_id": self.repo_id}, **_model_kwargs}
def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str: def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""Call out to HuggingFace Hub's inference endpoint. """Call out to HuggingFace Hub's inference endpoint.
@ -89,7 +95,8 @@ class HuggingFaceHub(BaseModel, LLM):
response = hf("Tell me a joke.") response = hf("Tell me a joke.")
""" """
response = self.client(inputs=prompt, params=self.model_kwargs) _model_kwargs = self.model_kwargs or {}
response = self.client(inputs=prompt, params=_model_kwargs)
if "error" in response: if "error" in response:
raise ValueError(f"Error raised by inference API: {response['error']}") raise ValueError(f"Error raised by inference API: {response['error']}")
if self.client.task == "text-generation": if self.client.task == "text-generation":

@ -7,7 +7,7 @@ from pydantic import BaseModel, Extra, root_validator
from langchain.llms.base import LLM from langchain.llms.base import LLM
class NLPCloud(BaseModel, LLM): class NLPCloud(LLM, BaseModel):
"""Wrapper around NLPCloud large language models. """Wrapper around NLPCloud large language models.
To use, you should have the ``nlpcloud`` python package installed, and the To use, you should have the ``nlpcloud`` python package installed, and the
@ -106,6 +106,11 @@ class NLPCloud(BaseModel, LLM):
"num_return_sequences": self.num_return_sequences, "num_return_sequences": self.num_return_sequences,
} }
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
return {**{"model_name": self.model_name}, **self._default_params}
def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str: def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""Call out to NLPCloud's create endpoint. """Call out to NLPCloud's create endpoint.

@ -7,7 +7,7 @@ from pydantic import BaseModel, Extra, root_validator
from langchain.llms.base import LLM from langchain.llms.base import LLM
class OpenAI(BaseModel, LLM): class OpenAI(LLM, BaseModel):
"""Wrapper around OpenAI large language models. """Wrapper around OpenAI large language models.
To use, you should have the ``openai`` python package installed, and the To use, you should have the ``openai`` python package installed, and the
@ -81,6 +81,11 @@ class OpenAI(BaseModel, LLM):
"best_of": self.best_of, "best_of": self.best_of,
} }
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
return {**{"model": self.model_name}, **self._default_params}
def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str: def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""Call out to OpenAI's create endpoint. """Call out to OpenAI's create endpoint.

@ -0,0 +1,50 @@
"""Experiment with different models."""
from typing import List, Optional
from langchain.chains.llm import LLMChain
from langchain.input import get_color_mapping, print_text
from langchain.llms.base import LLM
from langchain.prompts.prompt import Prompt
class ModelLaboratory:
"""Experiment with different models."""
def __init__(self, llms: List[LLM], prompt: Optional[Prompt] = None):
"""Initialize with LLMs to experiment with and optional prompt.
Args:
llms: list of LLMs to experiment with
prompt: Optional prompt to use to prompt the LLMs. Defaults to None.
If a prompt was provided, it should only have one input variable.
"""
self.llms = llms
llm_range = [str(i) for i in range(len(self.llms))]
self.llm_colors = get_color_mapping(llm_range)
if prompt is None:
self.prompt = Prompt(input_variables=["_input"], template="{_input}")
else:
if len(prompt.input_variables) != 1:
raise ValueError(
"Currently only support prompts with one input variable, "
f"got {prompt}"
)
self.prompt = prompt
def compare(self, text: str) -> None:
"""Compare model outputs on an input text.
If a prompt was provided with starting the laboratory, then this text will be
fed into the prompt. If no prompt was provided, then the input text is the
entire prompt.
Args:
text: input text to run all models on.
"""
print(f"\033[1mInput:\033[0m\n{text}\n")
for i, llm in enumerate(self.llms):
print_text(str(llm), end="\n")
chain = LLMChain(llm=llm, prompt=self.prompt)
llm_inputs = {self.prompt.input_variables[0]: text}
output = chain.predict(**llm_inputs)
print_text(output, color=self.llm_colors[str(i)], end="\n\n")

@ -1,6 +1,6 @@
"""Test functionality related to natbot.""" """Test functionality related to natbot."""
from typing import List, Optional from typing import Any, List, Mapping, Optional
from langchain.chains.natbot.base import NatBotChain from langchain.chains.natbot.base import NatBotChain
from langchain.llms.base import LLM from langchain.llms.base import LLM
@ -16,6 +16,10 @@ class FakeLLM(LLM):
else: else:
return "bar" return "bar"
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {}
def test_proper_inputs() -> None: def test_proper_inputs() -> None:
"""Test that natbot shortens inputs correctly.""" """Test that natbot shortens inputs correctly."""

@ -1,6 +1,6 @@
"""Unit tests for ReAct.""" """Unit tests for ReAct."""
from typing import List, Optional, Union from typing import Any, List, Mapping, Optional, Union
import pytest import pytest
@ -35,6 +35,10 @@ class FakeListLLM(LLM):
self.i += 1 self.i += 1
return self.responses[self.i] return self.responses[self.i]
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {}
class FakeDocstore(Docstore): class FakeDocstore(Docstore):
"""Fake docstore for testing purposes.""" """Fake docstore for testing purposes."""

@ -1,5 +1,5 @@
"""Fake LLM wrapper for testing purposes.""" """Fake LLM wrapper for testing purposes."""
from typing import List, Mapping, Optional from typing import Any, List, Mapping, Optional
from langchain.llms.base import LLM from langchain.llms.base import LLM
@ -19,3 +19,7 @@ class FakeLLM(LLM):
return "foo" return "foo"
else: else:
return "bar" return "bar"
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {}

Loading…
Cancel
Save