Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save shibanovp/35f7f015c6b174a7c9527800bc3065f6 to your computer and use it in GitHub Desktop.
Save shibanovp/35f7f015c6b174a7c9527800bc3065f6 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"MIT License\n",
"\n",
"Copyright (c) 2023 Pavel Shibanov https://blog.experienced.dev/\n",
"\n",
"Permission is hereby granted, free of charge, to any person obtaining a copy\n",
"of this software and associated documentation files (the \"Software\"), to deal\n",
"in the Software without restriction, including without limitation the rights\n",
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n",
"copies of the Software, and to permit persons to whom the Software is\n",
"furnished to do so, subject to the following conditions:\n",
"\n",
"The above copyright notice and this permission notice shall be included in all\n",
"copies or substantial portions of the Software.\n",
"\n",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n",
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n",
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n",
"SOFTWARE."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAUDBAoICAgICAgQCAgICAgICAgICAgICAgICAgICAgICAgICxALCAgOCQgIDRUNDhERExMTCAsWGBYSGBASExIBBQUFCAcIDwkJDxISEhAVEhYVFRISFRYWFxYVFRYXFRgWFRgVGBgVFhISEhcSFRcWFxUVFRcVFhYYExISEhUWFv/AABEIAWgB4AMBIgACEQEDEQH/xAAcAAEAAgIDAQAAAAAAAAAAAAAABgcBBQIECAP/xABWEAABBAECAwMIBQYICwYGAwABAAIDBBEFEgYTIQcxUxQXIjJBUZPTCGFxgZEVIzM1QrEkUnN0daGztDRDVWJygpKistHSFiUmNoTEN2ODpMHhJ0Rl/8QAGwEBAAIDAQEAAAAAAAAAAAAAAAEEAgMFBgf/xABBEQABAwIEAgcGBAUBCAMAAAABAAIRAwQFEiExQVETFBYiYXGSBlJTgZHwMqGx0RVCcsHhYiMzNHOCwtLxJDWy/9oADAMBAAIRAxEAPwDxkiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIin/AJqL3jQ/En+SnmoveND8Sf5K7H8AxD4Tlb6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/wCai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/AJqL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf8AmoveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/wCai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/AJqL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf8AmoveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/5qL3jQ/En+SnmoveND8Sf5Kdn8Q+C5Oo1/dKgCKf+ai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90qAIp/wCai940PxJ/kp5qL3jQ/En+SnZ/EPguTqNf3SoAin/moveND8Sf5Keai940PxJ/kp2fxD4Lk6jX90q6CiFF9nC9gBoiIilIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhCiFECkbIiIilERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERCiFYQLMDRZRYREhZRYWcfUiQiJj6kRIREwsIkLKJhESERYWHuDRlxAHvJAH4lCYSFyRcWkEZByPeMEfiFlEhZRfN8zWna54DvcXAH8CvooBBTRETCwpSFlEwsIkLKLCIk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ymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQmUymEwiQuRWFkrCBZAaIiIimERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIREREhERESERERIWEWcJhApGywizhMIpWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEWEWcJhEUz7F+Ha+q6s2ncaXwGtPKQyR8Tt8Zj2newg49I9FpeLeF7untlmnoy16xklbDNLG4MIDncoOd+w4tAwH4JUt+jjMyPXmOkeGN8jtDc9wa3JMOBl3TPRTjiOWahofEH5Z1aPUm6k2VulRRy89294l5b42lo2Dc6B/LZlkYrkgnK8vd4lWt8QyNhwIpDIc0mXEHLGkgameAXCuL6pRvMo1BFPumZMuIOXhIGpngFA+17guKjqVKlpcEkjrNKKbktdLZlfM6WdriwHLtu2MHA6AAnp1UP4g4fuaeWi9Ukq7wSwzMIY/AyQ2QZY5wHUgHI9q9F2NdqR68xrrMcM9nh6GtTtudG6OGfymy50ReTgPcTE4NPrckDvIB0Oo6n+R9Jr1uIb7NUunWKdyJscrrUkFaCzWllk3PY2RzWsjskbmjPPEY6KjY45ctbTplmckN3zZ3zMlpiIZEGfyVW1xWu0MYW5jA3nM6ZkjhDY1n8lUTOA9Wc1jxpU5bI3cw+TvyR06ub60Z6jo4AlRsOyM56Yzn6l6x4TmNjW7V2HX471CzUzW0yGdshh5ZgY+XlNcRGGP3AuADibADsbRmh+AtEhow6Hr1u1E+q7UI4pag9KeHlmQNneM+kGPjbKWgZDdp65wr9hjzqof0oEgMyhodJc4POXUbjJE7TxVuzxZ1QP6QCQGwAHSS4OOXUbjLE7LQalwnqFauLdjT5oaxAPOkhe1rQe4yD1oWk4GXhvUj3hZfwnqDZoq50+YTTsfJDFyXl0scYBe9mBhzWgtyf85vvGfQXGGtCrFql9sENulZqlgkfxFPJHcjka1gjradJC+vH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",
"text/html": [
"\n",
" <iframe\n",
" width=\"560\"\n",
" height=\"315\"\n",
" src=\"https://www.youtube.com/embed/FhY8rx_X97k\"\n",
" frameborder=\"0\"\n",
" allowfullscreen\n",
" \n",
" ></iframe>\n",
" "
],
"text/plain": [
"<IPython.lib.display.YouTubeVideo at 0x7fbc93328370>"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import YouTubeVideo\n",
"\n",
"YouTubeVideo(\"FhY8rx_X97k\", width=\"560\", height=\"315\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install langchain text-generation transformers runpod python-dotenv"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from dotenv import load_dotenv, find_dotenv\n",
"\n",
"_ = load_dotenv(find_dotenv())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import runpod\n",
"import os\n",
"from IPython.display import display, Markdown\n",
"\n",
"runpod.api_key = os.getenv(\"RUNPOD_API_KEY\", \"your_runpod_api_key\")\n",
"\n",
"if runpod.api_key == \"your_runpod_api_key\":\n",
" display(\n",
" Markdown(\n",
" \"It appears that you don't have a RunPod API key. You can obtain one at [runpod.io](https://runpod.io?ref=s7508tca)\"\n",
" )\n",
" )\n",
" raise AssertionError(\"Missing RunPod API key\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"gpu_count = 2\n",
"\n",
"pod = runpod.create_pod(\n",
" name=\"Falcon-40B-Instruct\",\n",
" image_name=\"ghcr.io/huggingface/text-generation-inference:0.8\",\n",
" gpu_type_id=\"NVIDIA A100 80GB PCIe\",\n",
" cloud_type=\"COMMUNITY\",\n",
" docker_args=f\"--model-id tiiuae/falcon-40b-instruct --num-shard {gpu_count}\",\n",
" gpu_count=gpu_count,\n",
" volume_in_gb=195,\n",
" container_disk_in_gb=5,\n",
" ports=\"80/http\",\n",
" volume_mount_path=\"/data\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain.llms import HuggingFaceTextGenInference\n",
"\n",
"inference_server_url = f'https://{pod[\"id\"]}-80.proxy.runpod.net'\n",
"llm = HuggingFaceTextGenInference(\n",
" inference_server_url=inference_server_url,\n",
" max_new_tokens=1000,\n",
" top_k=10,\n",
" top_p=0.95,\n",
" typical_p=0.95,\n",
" temperature=0.1,\n",
" repetition_penalty=1.03,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import display, Markdown\n",
"from langchain import PromptTemplate\n",
"from langchain.chains import LLMChain\n",
"\n",
"prompt = PromptTemplate(\n",
" input_variables=[\"num_trees\", \"num_apples\"],\n",
" template=\"A farmer has {num_trees} apple trees. Each apple tree has {num_apples} apples. How many apples does the farmer have in total?\",\n",
")\n",
"\n",
"chain = LLMChain(llm=llm, prompt=prompt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"display(Markdown(chain.run({\"num_trees\": 100, \"num_apples\": 10})))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"display(Markdown(chain.run({\"num_trees\": 6, \"num_apples\": 8})))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"runpod.stop_pod(pod[\"id\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"runpod.resume_pod(pod[\"id\"], gpu_count=gpu_count)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"prompts = [\n",
" \"Imagine you are a tree experiencing its first winter. Describe your sensations.\",\n",
" \"If you could give advice to a snowflake about to fall, what would it be?\",\n",
" \"What conversation would a pair of shoes have at the end of a long day?\",\n",
" \"Describe the first sunrise, as seen by the moon.\",\n",
" \"You've just discovered a new planet; what do you name it and why?\",\n",
" \"Write a letter from the perspective of an old, forgotten book in a dusty library.\",\n",
" \"Narrate a day in the life of a cloud above a bustling city.\",\n",
" \"How would a Martian describe the earth after its first visit?\",\n",
" \"What would you say to convince a star to wish upon a human?\",\n",
" \"You found a door in your house that wasn't there before. Where does it lead?\",\n",
" \"Tell the story of a sunset from the viewpoint of a sailor at sea.\",\n",
" \"Imagine you're a whisper traveling across a quiet room. What's your journey like?\",\n",
" \"Describe the most adventurous day of a coffee bean, from the tree to the cup.\",\n",
" \"What secret does the oldest animal in the zoo hold?\",\n",
" \"How would you describe a rainbow to a blind alien?\",\n",
" \"What conversation would a lighthouse have with the sea during a storm?\",\n",
" \"What happens when a shooting star gets lost?\",\n",
" \"Write about a day in the life of the person whose job it is to paint the colors of the autumn leaves.\",\n",
" \"What do the northern lights gossip about?\",\n",
" \"How would a single note from a forgotten song feel?\",\n",
" \"Imagine the story a forgotten toy has to tell.\",\n",
" \"What would an old, wise mountain tell a young, eager volcano?\",\n",
" \"What advice does the last leaf of autumn give to the first snowflake of winter?\",\n",
" \"What secret does a mirror hide from its own reflection?\",\n",
" \"Describe the journey of a message in a bottle tossed into the sea 100 years ago.\",\n",
" \"What happens when the moon falls in love with a comet?\",\n",
" \"Imagine a heated debate between two contrasting colors.\",\n",
" \"Describe a game of chess from the perspective of the pawns.\",\n",
" \"How does a forgotten word feel when it is finally spoken again?\",\n",
" \"What does a raindrop feel when it hits the sea?\",\n",
" \"How would the first raindrop to touch the earth describe its experience?\",\n",
" \"What is the life story of a piece of popcorn?\",\n",
" \"If flowers could talk, what secrets would they reveal?\",\n",
" \"What happens when an echo gets lost?\",\n",
" \"How does a book feel when it is opened for the first time?\",\n",
" \"What happens in a world where people can see music?\",\n",
" \"Describe a city inhabited by shadows.\",\n",
" \"How does the ocean feel about the sand on the beach?\",\n",
" \"Tell the story of a grain of sand lost in the desert.\",\n",
" \"What would you do if you found a diary from the future?\",\n",
" \"Imagine you're a clock that can control time. What do you do?\",\n",
" \"What would you see if you looked through a window into a world where dreams are reality?\",\n",
" \"Tell the tale of the love between the North Wind and the South Wind.\",\n",
" \"What happens when a forgotten fairy tale comes back to life?\",\n",
" \"How would you describe the taste of happiness?\",\n",
" \"Describe the sensation of a thought being born.\",\n",
" \"If you could touch a memory, what would it feel like?\",\n",
" \"Write about the moment a firefly realizes it can shine.\",\n",
" \"How does a piece of music feel when it is played for the first time?\",\n",
" \"What adventure awaits a paper boat set on a river?\",\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"len(prompts)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from timeit import default_timer as timer\n",
"\n",
"start = timer()\n",
"llm_result = llm.generate(prompts)\n",
"end = timer()\n",
"runpod.stop_pod(pod[\"id\"])\n",
"dt = end - start\n",
"dt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"len(llm_result.generations)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"total_tokens = sum([llm.get_num_tokens(g[0].text) for g in llm_result.generations])\n",
"total_tokens"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tokens_per_second = total_tokens / dt\n",
"tokens_per_second"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import display, Markdown\n",
"\n",
"for prompt, generation in zip(prompts, llm_result.generations):\n",
" display(Markdown(f\"### {prompt} \\n {generation[0].text}\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"runpod.stop_pod(pod[\"id\"])\n",
"runpod.terminate_pod(pod[\"id\"])"
]
}
],
"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.10.10"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment