์ถ๋ก ์ ์ํ Pipeline[[pipelines-for-inference]]
[pipeline
]์ ์ฌ์ฉํ๋ฉด ์ธ์ด, ์ปดํจํฐ ๋น์ , ์ค๋์ค ๋ฐ ๋ฉํฐ๋ชจ๋ฌ ํ์คํฌ์ ๋ํ ์ถ๋ก ์ ์ํด Hub์ ์ด๋ค ๋ชจ๋ธ์ด๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํน์ ๋ถ์ผ์ ๋ํ ๊ฒฝํ์ด ์๊ฑฐ๋, ๋ชจ๋ธ์ ์ด๋ฃจ๋ ์ฝ๋๊ฐ ์ต์ํ์ง ์์ ๊ฒฝ์ฐ์๋ [pipeline
]์ ์ฌ์ฉํด์ ์ถ๋ก ํ ์ ์์ด์! ์ด ํํ ๋ฆฌ์ผ์์๋ ๋ค์์ ๋ฐฐ์๋ณด๊ฒ ์ต๋๋ค.
- ์ถ๋ก ์ ์ํด [
pipeline
]์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ - ํน์ ํ ํฌ๋์ด์ ๋๋ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- ์ธ์ด, ์ปดํจํฐ ๋น์ , ์ค๋์ค ๋ฐ ๋ฉํฐ๋ชจ๋ฌ ํ์คํฌ์์ [
pipeline
]์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
์ง์ํ๋ ๋ชจ๋ ํ์คํฌ์ ์ธ ์ ์๋ ๋งค๊ฐ๋ณ์๋ฅผ ๋ด์ ๋ชฉ๋ก์ [pipeline
] ์ค๋ช
์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
Pipeline ์ฌ์ฉํ๊ธฐ[[pipeline-usage]]
๊ฐ ํ์คํฌ๋ง๋ค ๊ณ ์ ์ [pipeline
]์ด ์์ง๋ง, ๊ฐ๋ณ ํ์ดํ๋ผ์ธ์ ๋ด๊ณ ์๋ ์ถ์ํ๋ [pipeline
]๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ผ๋ก ๋ ๊ฐ๋จํฉ๋๋ค. [pipeline
]์ ํ์คํฌ์ ์๋ง๊ฒ ์ถ๋ก ์ด ๊ฐ๋ฅํ ๊ธฐ๋ณธ ๋ชจ๋ธ๊ณผ ์ ์ฒ๋ฆฌ ํด๋์ค๋ฅผ ์๋์ผ๋ก ๋ก๋ํฉ๋๋ค.
- ๋จผ์ [
pipeline
]์ ์์ฑํ๊ณ ํ์คํฌ๋ฅผ ์ง์ ํ์ธ์.
>>> from transformers import pipeline
>>> generator = pipeline(task="automatic-speech-recognition")
- ๊ทธ๋ฆฌ๊ณ [
pipeline
]์ ์ ๋ ฅ์ ๋ฃ์ด์ฃผ์ธ์.
>>> generator("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
{'text': 'I HAVE A DREAM BUT ONE DAY THIS NATION WILL RISE UP LIVE UP THE TRUE MEANING OF ITS TREES'}
๊ธฐ๋ํ๋ ๊ฒฐ๊ณผ๊ฐ ์๋๊ฐ์? Hub์์ ๊ฐ์ฅ ๋ง์ด ๋ค์ด๋ก๋๋ ์๋ ์์ฑ ์ธ์ ๋ชจ๋ธ๋ก ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋์ง ํ์ธํด๋ณด์ธ์. ๋ค์์ openai/whisper-large๋ก ์๋ํด๋ณด๊ฒ ์ต๋๋ค.
>>> generator = pipeline(model="openai/whisper-large")
>>> generator("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
{'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'}
ํจ์ฌ ๋ ๋์์ก๊ตฐ์! Hub์ ๋ชจ๋ธ๋ค์ ์ฌ๋ฌ ๋ค์ํ ์ธ์ด์ ์ ๋ฌธ๋ถ์ผ๋ฅผ ์์ฐ๋ฅด๊ธฐ ๋๋ฌธ์ ๊ผญ ์์ ์ ์ธ์ด๋ ๋ถ์ผ์ ํนํ๋ ๋ชจ๋ธ์ ์ฐพ์๋ณด์๊ธฐ ๋ฐ๋๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฅผ ๋ฒ์ด๋ ํ์์์ด Hub์์ ์ง์ ๋ชจ๋ธ์ ์ถ๋ ฅ์ ํ์ธํ๊ณ ๋ค๋ฅธ ๋ชจ๋ธ๊ณผ ๋น๊ตํด์ ์์ ์ ์ํฉ์ ๋ ์ ํฉํ์ง, ์ ๋งคํ ์ ๋ ฅ์ ๋ ์ ์ฒ๋ฆฌํ๋์ง๋ ํ์ธํ ์ ์์ต๋๋ค. ๋ง์ฝ ์ํฉ์ ์๋ง๋ ๋ชจ๋ธ์ ์๋ค๋ฉด ์ธ์ ๋ ์ง์ ํ๋ จ์ํฌ ์ ์์ต๋๋ค!
์ ๋ ฅ์ด ์ฌ๋ฌ ๊ฐ ์๋ ๊ฒฝ์ฐ, ๋ฆฌ์คํธ ํํ๋ก ์ ๋ฌํ ์ ์์ต๋๋ค.
generator(
[
"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac",
"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/1.flac",
]
)
์ ์ฒด ๋ฐ์ดํฐ์ธํธ์ ์ํํ๊ฑฐ๋ ์น์๋ฒ์ ์ฌ๋ ค๋์ด ์ถ๋ก ์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด, ๊ฐ ์์ธ ํ์ด์ง๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐ์ดํฐ์ธํธ์์ Pipeline ์ฌ์ฉํ๊ธฐ
์น์๋ฒ์์ Pipeline ์ฌ์ฉํ๊ธฐ
๋งค๊ฐ๋ณ์[[parameters]]
[pipeline
]์ ๋ง์ ๋งค๊ฐ๋ณ์๋ฅผ ์ง์ํฉ๋๋ค. ํน์ ํ์คํฌ์ฉ์ธ ๊ฒ๋ ์๊ณ , ๋ฒ์ฉ์ธ ๊ฒ๋ ์์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ํ๋ ์์น์ ์ด๋๋ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฃ์ ์ ์์ต๋๋ค.
generator(model="openai/whisper-large", my_parameter=1)
out = generate(...) # This will use `my_parameter=1`.
out = generate(..., my_parameter=2) # This will override and use `my_parameter=2`.
out = generate(...) # This will go back to using `my_parameter=1`.
์ค์ํ 3๊ฐ์ง ๋งค๊ฐ๋ณ์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๊ธฐ๊ธฐ(device)[[device]]
device=n
์ฒ๋ผ ๊ธฐ๊ธฐ๋ฅผ ์ง์ ํ๋ฉด ํ์ดํ๋ผ์ธ์ด ์๋์ผ๋ก ํด๋น ๊ธฐ๊ธฐ์ ๋ชจ๋ธ์ ๋ฐฐ์นํฉ๋๋ค.
ํ์ดํ ์น์์๋ ํ
์ํ๋ก์ฐ์์๋ ๋ชจ๋ ์๋ํฉ๋๋ค.
generator(model="openai/whisper-large", device=0)
๋ชจ๋ธ์ด GPU ํ๋์ ๋์๊ฐ๊ธฐ ๋ฒ๊ฒ๋ค๋ฉด, device_map="auto"
๋ฅผ ์ง์ ํด์ ๐ค Accelerate๊ฐ ๋ชจ๋ธ ๊ฐ์ค์น๋ฅผ ์ด๋ป๊ฒ ๋ก๋ํ๊ณ ์ ์ฅํ ์ง ์๋์ผ๋ก ๊ฒฐ์ ํ๋๋ก ํ ์ ์์ต๋๋ค.
#!pip install accelerate
generator(model="openai/whisper-large", device_map="auto")
๋ฐฐ์น ์ฌ์ด์ฆ[[batch-size]]
๊ธฐ๋ณธ์ ์ผ๋ก ํ์ดํ๋ผ์ธ์ ์ฌ๊ธฐ์ ๋์จ ์ด์ ๋ก ์ถ๋ก ์ ์ผ๊ด ์ฒ๋ฆฌํ์ง ์์ต๋๋ค. ๊ฐ๋จํ ์ค๋ช ํ์๋ฉด ์ผ๊ด ์ฒ๋ฆฌ๊ฐ ๋ฐ๋์ ๋ ๋น ๋ฅด์ง ์๊ณ ์คํ๋ ค ๋ ๋๋ ค์ง ์๋ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํ์ง๋ง ์์ ์ ์ํฉ์ ์ ํฉํ๋ค๋ฉด, ์ด๋ ๊ฒ ์ฌ์ฉํ์ธ์.
generator(model="openai/whisper-large", device=0, batch_size=2)
audio_filenames = [f"audio_{i}.flac" for i in range(10)]
texts = generator(audio_filenames)
ํ์ดํ๋ผ์ธ ์ ์ ๊ณต๋ 10๊ฐ์ ์ค๋์ค ํ์ผ์ ์ถ๊ฐ๋ก ์ฒ๋ฆฌํ๋ ์ฝ๋ ์์ด (์ผ๊ด ์ฒ๋ฆฌ์ ๋ณด๋ค ํจ๊ณผ์ ์ธ GPU ์) ๋ชจ๋ธ์ 2๊ฐ์ฉ ์ ๋ฌํฉ๋๋ค. ์ถ๋ ฅ์ ์ผ๊ด ์ฒ๋ฆฌํ์ง ์์์ ๋์ ๋๊ฐ์์ผ ํฉ๋๋ค. ํ์ดํ๋ผ์ธ์์ ์๋๋ฅผ ๋ ๋ผ ์๋ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋์ผ ๋ฟ์ ๋๋ค.
ํ์ดํ๋ผ์ธ์ ์ผ๊ด ์ฒ๋ฆฌ์ ๋ณต์กํ ๋ถ๋ถ์ ์ค์ฌ์ฃผ๊ธฐ๋ ํฉ๋๋ค. (์๋ฅผ ๋ค์ด ๊ธด ์ค๋์ค ํ์ผ์ฒ๋ผ) ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๋๋ ์ผ ๋ชจ๋ธ์ด ์ฒ๋ฆฌํ ์ ์๋ ๊ฒ์ chunk batching์ด๋ผ๊ณ ํ๋๋ฐ, ํ์ดํ๋ผ์ธ์ ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก ๋๋ ์ค๋๋ค.
ํน์ ํ์คํฌ์ฉ ๋งค๊ฐ๋ณ์[[task-specific-parameters]]
๊ฐ ํ์คํฌ๋ง๋ค ๊ตฌํํ ๋ ์ ์ฐ์ฑ๊ณผ ์ต์
์ ์ ๊ณตํ๊ธฐ ์ํด ํ์คํฌ์ฉ ๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด [transformers.AutomaticSpeechRecognitionPipeline.__call__
] ๋ฉ์๋์๋ ๋์์์ ์๋ง์ ๋ฃ์ ๋ ์ ์ฉํ ๊ฒ ๊ฐ์ return_timestamps
๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค.
>>> # Not using whisper, as it cannot provide timestamps.
>>> generator = pipeline(model="facebook/wav2vec2-large-960h-lv60-self", return_timestamps="word")
>>> generator("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
{'text': 'I HAVE A DREAM BUT ONE DAY THIS NATION WILL RISE UP AND LIVE OUT THE TRUE MEANING OF ITS CREED', 'chunks': [{'text': 'I', 'timestamp': (1.22, 1.24)}, {'text': 'HAVE', 'timestamp': (1.42, 1.58)}, {'text': 'A', 'timestamp': (1.66, 1.68)}, {'text': 'DREAM', 'timestamp': (1.76, 2.14)}, {'text': 'BUT', 'timestamp': (3.68, 3.8)}, {'text': 'ONE', 'timestamp': (3.94, 4.06)}, {'text': 'DAY', 'timestamp': (4.16, 4.3)}, {'text': 'THIS', 'timestamp': (6.36, 6.54)}, {'text': 'NATION', 'timestamp': (6.68, 7.1)}, {'text': 'WILL', 'timestamp': (7.32, 7.56)}, {'text': 'RISE', 'timestamp': (7.8, 8.26)}, {'text': 'UP', 'timestamp': (8.38, 8.48)}, {'text': 'AND', 'timestamp': (10.08, 10.18)}, {'text': 'LIVE', 'timestamp': (10.26, 10.48)}, {'text': 'OUT', 'timestamp': (10.58, 10.7)}, {'text': 'THE', 'timestamp': (10.82, 10.9)}, {'text': 'TRUE', 'timestamp': (10.98, 11.18)}, {'text': 'MEANING', 'timestamp': (11.26, 11.58)}, {'text': 'OF', 'timestamp': (11.66, 11.7)}, {'text': 'ITS', 'timestamp': (11.76, 11.88)}, {'text': 'CREED', 'timestamp': (12.0, 12.38)}]}
๋ณด์๋ค์ํผ ๋ชจ๋ธ์ด ํ ์คํธ๋ฅผ ์ถ๋ก ํ ๋ฟ๋ง ์๋๋ผ ๊ฐ ๋จ์ด๋ฅผ ๋งํ ์์ ๊น์ง๋ ์ถ๋ ฅํ์ต๋๋ค.
ํ์คํฌ๋ง๋ค ๋ค์ํ ๋งค๊ฐ๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ์. ์ํ๋ ํ์คํฌ์ API๋ฅผ ์ฐธ์กฐํด์ ๋ฐ๊ฟ๋ณผ ์ ์๋ ์ฌ๋ฌ ๋งค๊ฐ๋ณ์๋ฅผ ์ดํด๋ณด์ธ์!
์ง๊ธ๊น์ง ๋ค๋ค๋ณธ [~transformers.AutomaticSpeechRecognitionPipeline
]์๋ chunk_length_s
๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค. ์ํ๋ 1์๊ฐ ๋ถ๋์ ๋์์์ ์๋ง ์์
์ ํ ๋์ฒ๋ผ, ์ผ๋ฐ์ ์ผ๋ก ๋ชจ๋ธ์ด ์์ฒด์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ ๋งค์ฐ ๊ธด ์ค๋์ค ํ์ผ์ ์ฒ๋ฆฌํ ๋ ์ ์ฉํ์ฃ .
๋์์ด ๋ ๋งํ ๋งค๊ฐ๋ณ์๋ฅผ ์ฐพ์ง ๋ชปํ๋ค๋ฉด ์ธ์ ๋ ์ง ์์ฒญํด์ฃผ์ธ์!
๋ฐ์ดํฐ์ธํธ์์ Pipeline ์ฌ์ฉํ๊ธฐ[[using-pipelines-on-a-dataset]]
ํ์ดํ๋ผ์ธ์ ๋๊ท๋ชจ ๋ฐ์ดํฐ์ธํธ์์๋ ์ถ๋ก ์์ ์ ํ ์ ์์ต๋๋ค. ์ด๋ ์ดํฐ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฑธ ์ถ์ฒ๋๋ฆฝ๋๋ค.
def data():
for i in range(1000):
yield f"My example {i}"
pipe = pipe(model="gpt2", device=0)
generated_characters = 0
for out in pipe(data()):
generated_characters += len(out["generated_text"])
์ดํฐ๋ ์ดํฐ data()
๋ ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ํธ์ถ๋ง๋ค ์์ฑํ๊ณ , ํ์ดํ๋ผ์ธ์ ์
๋ ฅ์ด ์ํํ ์ ์๋ ์๋ฃ๊ตฌ์กฐ์์ ์๋์ผ๋ก ์ธ์ํ์ฌ GPU์์ ๊ธฐ์กด ๋ฐ์ดํฐ๊ฐ ์ฒ๋ฆฌ๋๋ ๋์ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์์ํฉ๋๋ค.(์ด๋ ๋ด๋ถ์ ์ผ๋ก DataLoader๋ฅผ ์ฌ์ฉํด์.) ์ด ๊ณผ์ ์ ์ ์ฒด ๋ฐ์ดํฐ์ธํธ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฌํ์ง ์๊ณ ๋ GPU์ ์ต๋ํ ๋น ๋ฅด๊ฒ ์๋ก์ด ์์
์ ๊ณต๊ธํ ์ ์๊ธฐ ๋๋ฌธ์ ์ค์ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ผ๊ด ์ฒ๋ฆฌ๊ฐ ๋ ๋น ๋ฅผ ์ ์๊ธฐ ๋๋ฌธ์, batch_size
๋งค๊ฐ๋ณ์๋ฅผ ์กฐ์ ํด๋ด๋ ์ข์์.
๋ฐ์ดํฐ์ธํธ๋ฅผ ์ํํ๋ ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ๐ค Datasets๋ฅผ ํ์ฉํ๋ ๊ฒ์ธ๋ฐ์.
# KeyDataset is a util that will just output the item we're interested in.
from transformers.pipelines.pt_utils import KeyDataset
pipe = pipeline(model="hf-internal-testing/tiny-random-wav2vec2", device=0)
dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation[:10]")
for out in pipe(KeyDataset(dataset["audio"])):
print(out)
์น์๋ฒ์์ Pipeline ์ฌ์ฉํ๊ธฐ[[using-pipelines-for-a-webserver]]
์ถ๋ก ์์ง์ ๋ง๋๋ ๊ณผ์ ์ ๋ฐ๋ก ํ์ด์ง๋ฅผ ์์ฑํ ๋งํ ๋ณต์กํ ์ฃผ์ ์ ๋๋ค.๋น์ Pipeline[[vision-pipeline]]
๋น์ ํ์คํฌ๋ฅผ ์ํด [pipeline
]์ ์ฌ์ฉํ๋ ์ผ์ ๊ฑฐ์ ๋์ผํฉ๋๋ค.
ํ์คํฌ๋ฅผ ์ง์ ํ๊ณ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฅ๊ธฐ์ ์ ๋ฌํ๋ฉด ๋ฉ๋๋ค. ์ด๋ฏธ์ง๋ ์ธํฐ๋ท ๋งํฌ ๋๋ ๋ก์ปฌ ๊ฒฝ๋ก์ ํํ๋ก ์ ๋ฌํด์ฃผ์ธ์. ์๋ฅผ ๋ค์ด ์๋์ ํ์๋ ๊ณ ์์ด๋ ์ด๋ค ์ข ์ธ๊ฐ์?
>>> from transformers import pipeline
>>> vision_classifier = pipeline(model="google/vit-base-patch16-224")
>>> preds = vision_classifier(
... images="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
... )
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
>>> preds
[{'score': 0.4335, 'label': 'lynx, catamount'}, {'score': 0.0348, 'label': 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor'}, {'score': 0.0324, 'label': 'snow leopard, ounce, Panthera uncia'}, {'score': 0.0239, 'label': 'Egyptian cat'}, {'score': 0.0229, 'label': 'tiger cat'}]
ํ ์คํธ Pipeline[[text-pipeline]]
NLP ํ์คํฌ๋ฅผ ์ํด [pipeline
]์ ์ฌ์ฉํ๋ ์ผ๋ ๊ฑฐ์ ๋์ผํฉ๋๋ค.
>>> from transformers import pipeline
>>> # This model is a `zero-shot-classification` model.
>>> # It will classify text, except you are free to choose any label you might imagine
>>> classifier = pipeline(model="facebook/bart-large-mnli")
>>> classifier(
... "I have a problem with my iphone that needs to be resolved asap!!",
... candidate_labels=["urgent", "not urgent", "phone", "tablet", "computer"],
... )
{'sequence': 'I have a problem with my iphone that needs to be resolved asap!!', 'labels': ['urgent', 'phone', 'computer', 'not urgent', 'tablet'], 'scores': [0.504, 0.479, 0.013, 0.003, 0.002]}
๋ฉํฐ๋ชจ๋ฌ Pipeline[[multimodal-pipeline]]
[pipeline
]์ ์ฌ๋ฌ ๋ชจ๋ฌ๋ฆฌํฐ(์ญ์ฃผ: ์ค๋์ค, ๋น๋์ค, ํ
์คํธ์ ๊ฐ์ ๋ฐ์ดํฐ ํํ)๋ฅผ ์ง์ํฉ๋๋ค. ์์๋ก ์๊ฐ์ ์ง์์๋ต(VQA; Visual Question Answering) ํ์คํฌ๋ ํ
์คํธ์ ์ด๋ฏธ์ง๋ฅผ ๋ชจ๋ ์ฌ์ฉํฉ๋๋ค. ๊ทธ ์ด๋ค ์ด๋ฏธ์ง ๋งํฌ๋ ๋ฌป๊ณ ์ถ์ ์ง๋ฌธ๋ ์์ ๋กญ๊ฒ ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด๋ฏธ์ง๋ URL ๋๋ ๋ก์ปฌ ๊ฒฝ๋ก์ ํํ๋ก ์ ๋ฌํด์ฃผ์ธ์.
์๋ฅผ ๋ค์ด ์ด ๊ฑฐ๋๋ช ์ธ์ ์ฌ์ง์์ ๊ฑฐ๋๋ช ์ธ์ ๋ฒํธ๋ฅผ ๋ฌป๊ณ ์ถ๋ค๋ฉด,
>>> from transformers import pipeline
>>> vqa = pipeline(model="impira/layoutlm-document-qa")
>>> vqa(
... image="https://huggingface.co/spaces/impira/docquery/resolve/2359223c1837a7587402bda0f2643382a6eefeab/invoice.png",
... question="What is the invoice number?",
... )
[{'score': 0.42514941096305847, 'answer': 'us-001', 'start': 16, 'end': 16}]