Skip to content

Commit

Permalink
init function calling
Browse files Browse the repository at this point in the history
Signed-off-by: SumanthRH <sumanthrh@anyscale.com>
  • Loading branch information
SumanthRH committed May 14, 2024
1 parent 67bab48 commit 58bd5df
Show file tree
Hide file tree
Showing 11 changed files with 2,253 additions and 0 deletions.
166 changes: 166 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# jobs output
./jobs

# Vim
*.swp
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ repos:
rev: v3.2.0
hooks:
- id: check-added-large-files
args: ['--maxkb=10000']
- id: trailing-whitespace
# README might be auto-generated
exclude: templates/.+/README.md
Expand Down
1,366 changes: 1,366 additions & 0 deletions templates/fine-tune-function-calling/fc_template.ipynb

Large diffs are not rendered by default.

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
Data format validation function from https://docs.endpoints.anyscale.com/endpoints/fine-tuning/dataset-prep/#context-length
"""


class FormattingError(Exception):
pass


def convert_message_list_to_text(messages: list) -> str:
# special tokens are for the Llama-2 model
B_INST, E_INST = "[INST]", "[/INST]"
B_SYS, E_SYS = "<<SYS>>\n", "\n<</SYS>>\n\n"
text = ""

if messages[0]["role"] == "system":
messages = [
{
"role": messages[1]["role"],
"content": B_SYS
+ messages[0]["content"]
+ E_SYS
+ messages[1]["content"],
}
] + messages[2:]

assert all([msg["role"] == "user" for msg in messages[::2]]) and all(
[msg["role"] == "assistant" for msg in messages[1::2]]
), (
"model only supports 'system','user' and 'assistant' roles, "
"starting with user and alternating (u/a/u/a/u...)"
)

texts = []
for prompt, answer in zip(messages[::2], messages[1::2]):
texts.append(
f"{B_INST} {(prompt['content']).strip()} {E_INST} {(answer['content']).strip()} "
)

text = "</s><s>".join(texts)
# add the bos and eos token at the beginning of the first turn and the end of the last turn
text = "<s>" + text + " </s>"
# During training last message should be from assistant (not from a user)
assert (
messages[-1]["role"] == "assistant"
), f"Last message must be from assistant, got {messages[-1]['role']}"

return text
141 changes: 141 additions & 0 deletions templates/fine-tune-function-calling/fc_utils/data_viz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import datasets
import matplotlib.pyplot as plt
import numpy as np
import ray.data

from fc_utils.preprocessing import initial_mapper, pprint_example

hf_ds = datasets.load_dataset(
"glaiveai/glaive-function-calling-v2", split="train"
).shuffle()
train_hf_ds = hf_ds.select(range(int(len(hf_ds) * 0.1)))
test_hf_ds = hf_ds.select(range(int(len(hf_ds) * 0.1), int(len(hf_ds) * 0.11)))
ray_ds = ray.data.from_huggingface(hf_ds)
openai_fmt_ds = ray_ds.map(initial_mapper)

pprint_example(openai_fmt_ds.take(1)[0])


def get_counts(ds):
counts = {
"Normal-Single": [0, 0, 0],
"Normal-Multi": [0, 0, 0],
"Tool-Single": [0, 0, 0],
"Tool-Multi": [0, 0, 0],
}
for ex in ds.iter_rows():
count = len(eval(ex["tools"]) if ex["tools"] else [])
roles = [message["role"] for message in ex["messages"]]
num_user = len([role for role in roles if role == "user"])
is_multi = num_user > 1 if roles[-1] != "user" else num_user > 2
if count == 0:
if is_multi:
counts["Normal-Multi"][0] += 1
else:
counts["Normal-Single"][0] += 1
elif count == 1:
if "tool" not in roles:
if is_multi:
counts["Normal-Multi"][1] += 1
else:
counts["Normal-Single"][1] += 1
else:
if is_multi:
counts["Tool-Multi"][1] += 1
else:
counts["Tool-Single"][1] += 1
else:
if "tool" not in roles:
if is_multi:
counts["Normal-Multi"][2] += 1
else:
counts["Normal-Single"][2] += 1
else:
if is_multi:
counts["Tool-Multi"][2] += 1
else:
counts["Tool-Single"][2] += 1
return counts


counts = get_counts(openai_fmt_ds)


# Number of bars per group
n_groups = 3
fig, ax = plt.subplots()
index = np.arange(n_groups)
bar_width = 0.2
opacity = 0.8

total_count = openai_fmt_ds.count()
normal_single = 100 * np.array(counts["Normal-Single"]) / total_count
normal_multi = 100 * np.array(counts["Normal-Multi"]) / total_count
tool_single = 100 * np.array(counts["Tool-Single"]) / total_count
tool_multi = 100 * np.array(counts["Tool-Multi"]) / total_count

# code for pie chart version
# labels = ['0 Funcs; Normal Response; Single Turn', '0 Funcs; Normal Response; Multi Turn', '1 Func; Normal Response; Single Turn', '1 Func; Normal Response; Multi Turn', '1 Func; Tool Call; Single Turn', '1 Func; Tool Call; Multi Turn', '2 Funcs; Tool Call; Single Turn', '2 Funcs; Tool Call; Multi Turn']
# sizes = [normal_single[0], normal_multi[0], normal_single[1], normal_multi[1], tool_single[1], tool_multi[1], tool_single[2], tool_multi[2]]

# fig, ax = plt.subplots()
# ax.pie(sizes, labels=labels, autopct='%1.2f%%')

rects1 = plt.bar(
index, normal_single, bar_width, alpha=opacity, color="b", label="Normal-Single"
)
rects2 = plt.bar(
index + bar_width,
normal_multi,
bar_width,
alpha=opacity,
color="g",
label="Normal-Multi",
)
rects3 = plt.bar(
index + 2 * bar_width,
tool_single,
bar_width,
alpha=opacity,
color="r",
label="Tool-Single",
)
rects4 = plt.bar(
index + 3 * bar_width,
tool_multi,
bar_width,
alpha=opacity,
color="y",
label="Tool-Multi",
)


# Adding percentages on top of the bars
def add_labels(rects):
for rect in rects:
height = rect.get_height()
ax.annotate(
f"{height:.1f}%",
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3),
textcoords="offset points",
ha="center",
va="bottom",
fontsize=10,
)


for rect in [rects1, rects2, rects3, rects4]:
add_labels(rect)

# add_labels([rects1, rects2, rects3, rects4])


plt.xlabel("Number of Tools")
plt.ylabel("Percentage")
plt.title("Distribution of Responses and Turns with Number of Tools")
plt.xticks(index + bar_width * 1.5, [0, 1, 2])
plt.legend()

plt.tight_layout()
plt.show()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 58bd5df

Please sign in to comment.