Browse Source

Refreshed notebooks, particularly with new Week 1

pull/14/head
Edward Donner 6 months ago
parent
commit
21c7a8155c
  1. 2
      .gitignore
  2. 247
      README.md
  3. 177
      SETUP-PC.md
  4. BIN
      SETUP-PC.pdf
  5. 182
      SETUP-mac.md
  6. BIN
      SETUP-mac.pdf
  7. 1
      environment.yml
  8. 8
      requirements.txt
  9. 256
      week1/Guide to Jupyter.ipynb
  10. 464
      week1/Intermediate Python.ipynb
  11. 73
      week1/day1.ipynb
  12. 167
      week1/day2 EXERCISE.ipynb
  13. 59
      week1/day5.ipynb
  14. 463
      week1/solutions/day2 SOLUTION.ipynb
  15. 176
      week1/solutions/week1 SOLUTION.ipynb
  16. 20
      week1/troubleshooting.ipynb
  17. 104
      week1/week1 EXERCISE.ipynb
  18. 61
      week2/day1.ipynb
  19. 28
      week2/day2.ipynb
  20. 26
      week2/day3.ipynb
  21. 8
      week2/day4.ipynb
  22. 14
      week2/day5.ipynb
  23. 4
      week3/day1.ipynb
  24. 8
      week5/day1.ipynb
  25. 17
      week5/day3.ipynb
  26. 20
      week5/day4.ipynb
  27. 16
      week5/day5.ipynb
  28. 17
      week6/day1.ipynb
  29. 2
      week6/day3.ipynb
  30. 71
      week6/day5.ipynb
  31. 6
      week6/items.py
  32. 20
      week8/day1.ipynb
  33. 12
      week8/day2.1.ipynb
  34. 2
      week8/day2.2.ipynb

2
.gitignore vendored

@ -129,6 +129,8 @@ venv/
ENV/
env.bak/
venv.bak/
llms/
llms.bak/
# Spyder project settings
.spyderproject

247
README.md

@ -11,156 +11,44 @@ I'm so happy you're joining me on this path. We'll be building immensely satisfy
I'm here to help you be most successful with your learning! If you hit any snafus, or if you have any ideas on how I can improve the course, please do reach out in the platform or by emailing me direct (ed@edwarddonner.com). It's always great to connect with people on LinkedIn to build up the community - you'll find me here:
https://www.linkedin.com/in/eddonner/
### An important point on API costs
Resources to accompany the course, including the slides and useful links, are here:
https://edwarddonner.com/2024/11/13/llm-engineering-resources/
During the course, I'll suggest you try out the leading models at the forefront of progress, known as the Frontier models. I'll also suggest you run open-source models using Google Colab. These services have some charges, but I'll keep cost minimal - like, a few cents at a time.
## Instant Gratification instructions for Week 1, Day 1
Please do monitor your API usage to ensure you're comfortable with spend; I've included links below. There's no need to spend anything more than a couple of dollars for the entire course. You may find that AI providers such as OpenAI requires a minimum credit like \$5 for your region; we should only spend a fraction of it, but you'll have plenty of opportunity to put it to good use in your own projects. During Week 7 you have an option to spend a bit more if you're enjoying the process - I spend about $10 myself and the results make me very happy indeed! But it's not necessary in the least; the important part is that you focus on learning.
We will start the course by installing Ollama so you can see results immediately!
1. Download and install Ollama from https://ollama.com
2. On a PC, start a Command prompt / Powershell (Press Win + R, type `cmd`, and press Enter). On a Mac, start a Terminal (Applications > Utilities > Terminal).
3. Run `ollama run llama3.2` or for smaller machines try `ollama run llama3.2:1b`
4. If this doesn't work, you may need to run `ollama serve` in another Powershell (Windows) or Terminal (Mac), and try step 3 again
5. And if that doesn't work on your box, I've set up this on the cloud. This is on Google Colab, which will need you to have a Google account to sign in, but is free: https://colab.research.google.com/drive/1-_f5XZPsChvfU1sJ0QqCePtIuc55LSdu?usp=sharing
### How this Repo is organized
There are folders for each of the "weeks", representing modules of the class, culminating in a powerful autonomous Agentic AI solution in Week 8 that draws on many of the prior weeks.
Follow the setup instructions below, then open the Week 1 folder and prepare for joy.
### The most important part
The mantra of the course is: the best way to learn is by **DOING**. You should work along with me, running each cell, inspecting the objects to get a detailed understanding of what's happening. Then tweak the code and make it your own. There are juicy challenges for you throughout the course. I'd love it if you wanted to push your code so I can follow along with your progress, and I can make your solutions available to others so we share in your progress. While the projects are enjoyable, they are first and foremost designed to be _educational_, teaching you business skills that can be put into practice in your work.
## Setup instructions
I should confess up-front: setting up a powerful environment to work at the forefront of AI is not as simple as I'd like. For most people these instructions will go great; but in some cases, for whatever reason, you'll hit a problem. Please don't hesitate to reach out - I am here to get you up and running quickly. There's nothing worse than feeling _stuck_. Message me, email me or LinkedIn message me and I will unstick you quickly!
The recommended approach is to use Anaconda for your environment. It's a powerful tool that builds a complete science environment. Anaconda ensures that you're working with the right version of Python and all your packages are compatible with mine, even if we're on different platforms.
**Update** Some people have had problems with Anaconda - horrors! The idea of Anaconda is to make it really smooth and simple to be working with the same environment. If you hit any problems with the instructions below, please skip to near the end of this README for the alternative approach using `pip` with `virtualenv`, and hopefully you'll be up and running fast. And please do message me if I can help with anything.
We'll be mostly using Jupyter Lab in this course. For those new to Jupyter Lab / Jupyter Notebook, it's a delightful Data Science environment where you can simply hit shift+return in any cell to run it; start at the top and work your way down! When we move to Google Colab in Week 3, you'll experience the same interface for Python runtimes in the cloud.
### For Windows Users
1. **Install Git** (if not already installed):
- Download Git from https://git-scm.com/download/win
- Run the installer and follow the prompts, using default options
2. **Open Command Prompt:**
- Press Win + R, type `cmd`, and press Enter
3. **Navigate to your projects folder:**
If you have a specific folder for projects, navigate to it using the cd command. For example:
`cd C:\Users\YourUsername\Documents\Projects`
If you don't have a projects folder, you can create one:
```
mkdir C:\Users\YourUsername\Documents\Projects
cd C:\Users\YourUsername\Documents\Projects
```
(Replace YourUsername with your actual Windows username)
3. **Clone the repository:**
- Go to the course's GitHub page
- Click the green 'Code' button and copy the URL
- In the Command Prompt, type this, replacing everything after the word 'clone' with the copied URL: `git clone <paste-url-here>`
4. **Install Anaconda:**
- Download Anaconda from https://docs.anaconda.com/anaconda/install/windows/
- Run the installer and follow the prompts
- A student mentioned that if you are prompted to upgrade Anaconda to a newer version during the install, you shouldn't do it, as there might be problems with the very latest update for PC. (Thanks for the pro-tip!)
5. **Set up the environment:**
- Open Anaconda Prompt (search for it in the Start menu)
- Navigate to the cloned repository folder using `cd path\to\repo` (replace `path\to\repo` with the actual path to the llm_engineering directory, your locally cloned version of the repo)
- Create the environment: `conda env create -f environment.yml`
- Wait for a few minutes for all packages to be installed
- Activate the environment: `conda activate llms`
You should see `(llms)` in your prompt, which indicates you've activated your new environment.
6. **Start Jupyter Lab:**
- In the Anaconda Prompt, from within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipnbk`.
### For Mac Users
1. **Install Git** if not already installed (it will be in most cases)
- Open Terminal (Applications > Utilities > Terminal)
- Type `git --version` If not installed, you'll be prompted to install it
2. **Navigate to your projects folder:**
If you have a specific folder for projects, navigate to it using the cd command. For example:
`cd ~/Documents/Projects`
If you don't have a projects folder, you can create one:
```
mkdir ~/Documents/Projects
cd ~/Documents/Projects
```
3. **Clone the repository**
- Go to the course's GitHub page
- Click the green 'Code' button and copy the URL
- In Terminal, type this, replacing everything after the word 'clone' with the copied URL: `git clone <paste-url-here>`
4. **Install Anaconda:**
- Download Anaconda from https://docs.anaconda.com/anaconda/install/mac-os/
- Double-click the downloaded file and follow the installation prompts
Any problems, please contact me!
5. **Set up the environment:**
## Then, Setup instructions
- Open Terminal
- Navigate to the cloned repository folder using `cd path/to/repo` (replace `path/to/repo` with the actual path to the llm_engineering directory, your locally cloned version of the repo)
- Create the environment: `conda env create -f environment.yml`
- Wait for a few minutes for all packages to be installed
- Activate the environment: `conda activate llms`
- PC people please follow the instructions in [SETUP-PC.md](SETUP-PC.md)
- Mac people please follow the instructions in [SETUP-mac.md](SETUP-mac.md)
- Linux people, the Mac instructions should be close enough!
You should see `(llms)` in your prompt, which indicates you've activated your new environment.
### An important point on API costs (which are optional! No need to spend if you don't wish)
6. **Start Jupyter Lab:**
During the course, I'll suggest you try out the leading models at the forefront of progress, known as the Frontier models. I'll also suggest you run open-source models using Google Colab. These services have some charges, but I'll keep cost minimal - like, a few cents at a time. And I'll provide alternatives if you'd prefer not to use them.
- In Terminal, from within the `llm_engineering` folder, type: `jupyter lab`
Please do monitor your API usage to ensure you're comfortable with spend; I've included links below. There's no need to spend anything more than a couple of dollars for the entire course. Some AI providers such as OpenAI require a minimum credit like \$5 or local equivalent; we should only spend a fraction of it, and you'll have plenty of opportunity to put it to good use in your own projects. During Week 7 you have an option to spend a bit more if you're enjoying the process - I spend about $10 myself and the results make me very happy indeed! But it's not necessary in the least; the important part is that you focus on learning.
...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipnbk`.
I'll also show you an alternative if you'd rather not spend anything on APIs.
### When we get to it, creating your API keys
Particularly during weeks 1 and 2 of the course, you'll be writing code to call the APIs of Frontier models (models at the forefront of progress). You'll need to join me in setting up accounts and API keys.
- [GPT API](https://platform.openai.com/) from OpenAI
- [Claude API](https://console.anthropic.com/) from Anthropic
- [Gemini API](https://ai.google.dev/gemini-api) from Google
Initially we'll only use OpenAI, so you can start with that, and we'll cover the others soon afterwards. The webpage where you set up your OpenAI key is [here](https://platform.openai.com/api-keys). See the extra note on API costs below if that's a concern. One student mentioned to me that OpenAI can take a few minutes to register; if you initially get an error about being out of quota, wait a few minutes and try again. Another reason you might encounter the out of quota error is if you haven't yet added a valid payment method to your OpenAI account. You can do this by clicking your profile picture on the OpenAI website then clicking "Your profile." Once you are redirected to your profile page, choose "Billing" on the left-pane menu. You will need to enter a valid payment method and charge your account with a small advance payment. It is recommended that you **disable** the automatic recharge as an extra failsafe. If it's still a problem, see more troubleshooting tips in the Week 1 Day 1 notebook, and/or message me!
Later in the course you'll be using the fabulous HuggingFace platform; an account is available for free at [HuggingFace](https://huggingface.co) - you can create an API token from the Avatar menu >> Settings >> Access Tokens.
And in Week 6/7 you'll be using the terrific [Weights & Biases](https://wandb.ai) platform to watch over your training batches. Accounts are also free, and you can set up a token in a similar way.
When you have these keys, please create a new file called `.env` in your project root directory. This file won't appear in Jupyter Lab because it's a hidden file; you should create it using something like Notepad (PC) or nano (Mac / Linux). I've put detailed instructions at the end of this README.
### How this Repo is organized
It should have contents like this, and to start with you only need the first line:
There are folders for each of the "weeks", representing modules of the class, culminating in a powerful autonomous Agentic AI solution in Week 8 that draws on many of the prior weeks.
Follow the setup instructions above, then open the Week 1 folder and prepare for joy.
```
OPENAI_API_KEY=xxxx
GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx
```
### The most important part
This file is listed in the `.gitignore` file, so it won't get checked in and your keys stay safe.
If you have any problems with this process, there's a simple workaround which I explain in the video.
The mantra of the course is: the best way to learn is by **DOING**. I don't type all the code during the course; I execute it for you to see the results. You should work along with me or after each lecture, running each cell, inspecting the objects to get a detailed understanding of what's happening. Then tweak the code and make it your own. There are juicy challenges for you throughout the course. I'd love it if you wanted to push your code so I can follow along with your progress, and I can make your solutions available to others so we share in your progress. While the projects are enjoyable, they are first and foremost designed to be _educational_, teaching you business skills that can be put into practice in your work.
### Starting in Week 3, we'll also be using Google Colab for running with GPUs
## Starting in Week 3, we'll also be using Google Colab for running with GPUs
You should be able to use the free tier or minimal spend to complete all the projects in the class. I personally signed up for Colab Pro+ and I'm loving it - but it's not required.
@ -183,91 +71,4 @@ The charges for the exercsies in this course should always be quite low, but if
2. For Anthropic: Always use model `claude-3-haiku-20240307` in the code instead of the other Claude models
3. During week 7, look out for my instructions for using the cheaper dataset
## And that's it! Happy coding!
### Alternative Setup Instructions if Anaconda is giving you problems
First please run:
`python --version`
To find out which python you're on. Ideally you'd be using Python 3.11.x, so we're completely in sync. You can download python at
https://www.python.org/downloads/
Here are the steps:
After cloning the repo, cd into the project root directory `llm_engineering`.
Then:
1. Create a new virtual environment: `python -m venv venv`
2. Activate the virtual environment with
On a Mac: `source venv/bin/activate`
On a PC: `venv\Scripts\activate`
3. Run `pip install -r requirements.txt`
4. Create a file called `.env` in the project root directory and add any private API keys, such as below. (The next section has more detailed instructions for this, if you prefer.)
```
OPENAI_API_KEY=xxxx
GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx
```
5. Run `jupyter lab` to launch Jupyter and head over to the intro folder to get started.
Let me know if you hit problems.
### Guide to creating the `.env` file
**For PC users:**
1. Open the Notepad (Windows + R to open the Run box, enter notepad)
2. In the Notepad, type the contents of the file, such as:
```
OPENAI_API_KEY=xxxx
GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx
```
Double check there are no spaces before or after the `=` sign, and no spaces at the end of the key.
3. Go to File > Save As. In the "Save as type" dropdown, select All Files. In the "File name" field, type ".env". Choose the root of the project folder (the folder called `llm_engineering`) and click Save.
4. Navigate to the foler where you saved the file in Explorer and ensure it was saved as ".env" not ".env.txt" - if necessary rename it to ".env" - you might need to ensure that "Show file extensions" is set to "On" so that you see the file extensions. Message or email me if that doesn't make sense!
**For Mac users:**
1. Open Terminal (Command + Space to open Spotlight, type Terminal and press Enter)
2. cd to your project root directory
cd /path/to/your/project
(in other words, change to the directory like `/Users/your_name/Projects/llm_engineering`, or wherever you have cloned llm_engineering).
3. Create the .env file with
nano .env
4. Then type your API keys into nano:
```
OPENAI_API_KEY=xxxx
GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx
```
5. Save the file:
Control + O
Enter (to confirm save the file)
Control + X to exit the editor
6. Use this command to list files in your file
`ls -a`
And confirm that the `.env` file is there.
Please do message me or email me at ed@edwarddonner.com if this doesn't work or if I can help with anything. I can't wait to hear how you get on.

177
SETUP-PC.md

@ -0,0 +1,177 @@
# LLM Engineering - Master AI and LLMs
## Setup instructions for Windows
Welcome, PC people!
I should confess up-front: setting up a powerful environment to work at the forefront of AI is not as simple as I'd like. For most people these instructions will go great; but in some cases, for whatever reason, you'll hit a problem. Please don't hesitate to reach out - I am here to get you up and running quickly. There's nothing worse than feeling _stuck_. Message me, email me or LinkedIn message me and I will unstick you quickly!
Email: ed@edwarddonner.com
LinkedIn: https://www.linkedin.com/in/eddonner/
I use a platform called Anaconda to set up your environment. It's a powerful tool that builds a complete science environment. Anaconda ensures that you're working with the right version of Python and all your packages are compatible with mine, even if our systems are completely different. It takes more time to set up, and it uses more hard drive space (5+ GB) but it's very reliable once its working.
Having said that: if you have any problems with Anaconda, I've provided an alternative approach. It's faster and simpler and should have you running quickly, with less of a guarantee around compatibility.
### Part 1: Clone the Repo
This gets you a local copy of the code on your box.
1. **Install Git** (if not already installed):
- Download Git from https://git-scm.com/download/win
- Run the installer and follow the prompts, using default options (press OK lots of times!)
2. **Open Command Prompt:**
- Press Win + R, type `cmd`, and press Enter
3. **Navigate to your projects folder:**
If you have a specific folder for projects, navigate to it using the cd command. For example:
`cd C:\Users\YourUsername\Documents\Projects`
Replacing YourUsername with your actual Windows user
If you don't have a projects folder, you can create one:
```
mkdir C:\Users\YourUsername\Documents\Projects
cd C:\Users\YourUsername\Documents\Projects
```
4. **Clone the repository:**
Enter this in the command prompt in the Projects folder:
`git clone https://github.com/ed-donner/llm_engineering.git`
This creates a new directory `llm_engineering` within your Projects folder and downloads the code for the class. Do `cd llm_engineering` to go into it. This `llm_engineering` directory is known as the "project root directory".
### Part 2: Install Anaconda environment
There is an alternative to Part 2 if this gives you problems.
1. **Install Anaconda:**
- Download Anaconda from https://docs.anaconda.com/anaconda/install/windows/
- Run the installer and follow the prompts. Note that it takes up several GB and take a while to install, but it will be a powerful platform for you to use in the future.
2. **Set up the environment:**
- Open **Anaconda Prompt** (search for it in the Start menu)
- Navigate to the "project root directory" by entering something like `cd C:\Users\YourUsername\Documents\Projects\llm_engineering` using the actual path to your llm_engineering project root directory. Do a `dir` and check you can see subdirectories for each week of the course.
- Create the environment: `conda env create -f environment.yml`
- Wait for a few minutes for all packages to be installed - in some cases, this can literally take 20-30 minutes if you've not used Anaconda before, and even longer depending on your internet connection. Important stuff is happening! If this runs for more than 1 hour 15 mins, or gives you other problems, please go to Part 2B instead.
- You have now built an isolated, dedicated AI environment for engineering LLMs, running vector datastores, and so much more! You now need to **activate** it using this command: `conda activate llms`
You should see `(llms)` in your prompt, which indicates you've activated your new environment.
3. **Start Jupyter Lab:**
- In the Anaconda Prompt, from within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up in a browser. If you've not seen Jupyter Lab before, I'll explain it in a moment! Now close the jupyter lab browser tab, and close the Anaconda prompt, and move on to Part 3.
### Part 2B - Alternative to Part 2 if Anaconda gives you trouble
1. **Open Command Prompt**
Press Win + R, type `cmd`, and press Enter
Run `python --version` to find out which python you're on. Ideally you'd be using a version of Python 3.11, so we're completely in sync.
If not, it's not a big deal, but we might need to come back to this later if you have compatibility issues.
You can download python here:
https://www.python.org/downloads/
2. Navigate to the "project root directory" by entering something like `cd C:\Users\YourUsername\Documents\Projects\llm_engineering` using the actual path to your llm_engineering project root directory. Do a `dir` and check you can see subdirectories for each week of the course.
Then, create a new virtual environment with this command:
`python -m venv llms`
3. Activate the virtual environment with
`llms\Scripts\activate`
You should see (llms) in your command prompt, which is your sign that things are going well.
4. Run `pip install -r requirements.txt`
This may take a few minutes to install.
5. **Start Jupyter Lab:**
From within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipynb`. Success! Now close down jupyter lab and move on to Part 3.
If there are any problems, contact me!
### Part 3 - OpenAI key (OPTIONAL but recommended)
Particularly during weeks 1 and 2 of the course, you'll be writing code to call the APIs of Frontier models (models at the forefront of AI).
For week 1, you'll only need OpenAI, and you can add the others if you wish later on.
1. Create an OpenAI account if you don't have one by visiting:
https://platform.openai.com/
2. OpenAI asks for a minimum credit to use the API. For me in the US, it's \$5. The API calls will spend against this \$5. On this course, we'll only use a small portion of this. I do recommend you make the investment as you'll be able to put it to excellent use. But if you'd prefer not to pay for the API, I give you an alternative in the course using Ollama.
You can add your credit balance to OpenAI at Settings > Billing:
https://platform.openai.com/settings/organization/billing/overview
I recommend you disable the automatic recharge!
3. Create your API key
The webpage where you set up your OpenAI key is at https://platform.openai.com/api-keys - press the green 'Create new secret key' button and press 'Create secret key'. Keep a record of the API key somewhere private; you won't be able to retrieve it from the OpenAI screens in the future. It should start `sk-proj-`.
In week 2 we will also set up keys for Anthropic and Google, which you can do here when we get there.
- Claude API at https://console.anthropic.com/ from Anthropic
- Gemini API at https://ai.google.dev/gemini-api from Google
Later in the course you'll be using the fabulous HuggingFace platform; an account is available for free at https://huggingface.co - you can create an API token from the Avatar menu >> Settings >> Access Tokens.
And in Week 6/7 you'll be using the terrific Weights & Biases at https://wandb.ai to watch over your training batches. Accounts are also free, and you can set up a token in a similar way.
### PART 4 - .env file
When you have these keys, please create a new file called `.env` in your project root directory. The filename needs to be exactly the four characters ".env" rather than "my-keys.env" or ".env.txt". Here's how to do it:
1. Open the Notepad (Windows + R to open the Run box, enter `notepad`)
2. In the Notepad, type this, replacing xxxx with your API key (starting `sk-proj-`).
```
OPENAI_API_KEY=xxxx
```
If you have other keys, you can add them too, or come back to this in future weeks:
```
GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx
```
Double check there are no spaces before or after the `=` sign, and no spaces at the end of the key.
3. Go to File > Save As. In the "Save as type" dropdown, select All Files. In the "File name" field, type exactly **.env** as the filename. Choose to save this in the project root directory (the folder called `llm_engineering`) and click Save.
4. Navigate to the folder where you saved the file in Explorer and ensure it was saved as ".env" not ".env.txt" - if necessary rename it to ".env" - you might need to ensure that "Show file extensions" is set to "On" so that you see the file extensions. Message or email me if that doesn't make sense!
This file won't appear in Jupyter Lab because jupyter hides files starting with a dot. This file is listed in the `.gitignore` file, so it won't get checked in and your keys stay safe.
### Part 5 - Showtime!!
- Open **Anaconda Prompt** (search for it in the Start menu)
- Navigate to the "project root directory" by entering something like `cd C:\Users\YourUsername\Documents\Projects\llm_engineering` using the actual path to your llm_engineering project root directory. Do a `dir` and check you can see subdirectories for each week of the course.
- Activate your environment with `conda activate llms` (or `llms\Scripts\activate` if you used the alternative approach in Part 2B)
- You should see (llms) in your prompt which is your sign that all is well. And now, type: `jupyter lab` and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipynb`.
And you're off to the races!
Note that any time you start jupyter lab in the future, you'll need to follow these Part 5 instructions to start it from within the `llm_engineering` directory with the `llms` environment activated.
For those new to Jupyter Lab / Jupyter Notebook, it's a delightful Data Science environment where you can simply hit shift+return in any cell to run it; start at the top and work your way down! There's a notebook in the week1 folder with a [Guide to Jupyter Lab](week1/Guide%20to%20Jupyter.ipynb), and an [Intermediate Python](week1/Intermediate%20Python.ipynb) tutorial, if that would be helpful. When we move to Google Colab in Week 3, you'll experience the same interface for Python runtimes in the cloud.
If you have any problems, I've included a notebook in week1 called [troubleshooting.ipynb](week1/troubleshooting.ipynb) to figure it out.
Please do message me or email me at ed@edwarddonner.com if this doesn't work or if I can help with anything. I can't wait to hear how you get on.

BIN
SETUP-PC.pdf

Binary file not shown.

182
SETUP-mac.md

@ -0,0 +1,182 @@
# LLM Engineering - Master AI and LLMs
## Setup instructions for Mac
Welcome, Mac people!
I should confess up-front: setting up a powerful environment to work at the forefront of AI is not as simple as I'd like. For most people these instructions will go great; but in some cases, for whatever reason, you'll hit a problem. Please don't hesitate to reach out - I am here to get you up and running quickly. There's nothing worse than feeling _stuck_. Message me, email me or LinkedIn message me and I will unstick you quickly!
Email: ed@edwarddonner.com
LinkedIn: https://www.linkedin.com/in/eddonner/
I use a platform called Anaconda to set up your environment. It's a powerful tool that builds a complete science environment. Anaconda ensures that you're working with the right version of Python and all your packages are compatible with mine, even if our systems are completely different. It takes more time to set up, and it uses more hard drive space (5+ GB) but it's very reliable once its working.
Having said that: if you have any problems with Anaconda, I've provided an alternative approach. It's faster and simpler and should have you running quickly, with less of a guarantee around compatibility.
### Part 1: Clone the Repo
This gets you a local copy of the code on your box.
1. **Install Git** if not already installed (it will be in most cases)
- Open Terminal (Applications > Utilities > Terminal)
- Type `git --version` If not installed, you'll be prompted to install it
2. **Navigate to your projects folder:**
If you have a specific folder for projects, navigate to it using the cd command. For example:
`cd ~/Documents/Projects`
If you don't have a projects folder, you can create one:
```
mkdir ~/Documents/Projects
cd ~/Documents/Projects
```
3. **Clone the repository:**
Enter this in the terminal in the Projects folder:
`git clone https://github.com/ed-donner/llm_engineering.git`
This creates a new directory `llm_engineering` within your Projects folder and downloads the code for the class. Do `cd llm_engineering` to go into it. This `llm_engineering` directory is known as the "project root directory".
### Part 2: Install Anaconda environment
There is an alternative to Part 2 if this gives you problems.
1. **Install Anaconda:**
- Download Anaconda from https://docs.anaconda.com/anaconda/install/mac-os/
- Double-click the downloaded file and follow the installation prompts. Note that it takes up several GB and take a while to install, but it will be a powerful platform for you to use in the future.
2. **Set up the environment:**
- Open a new Terminal (Applications > Utilities > Terminal)
- Navigate to the "project root directory" using `cd ~/Documents/Projects/llm_engineering` (replace this path as needed with the actual path to the llm_engineering directory, your locally cloned version of the repo). Do `ls` and check you can see subdirectories for each week of the course.
- Create the environment: `conda env create -f environment.yml`
- Wait for a few minutes for all packages to be installed - in some cases, this can literally take 20-30 minutes if you've not used Anaconda before, and even longer depending on your internet connection. Important stuff is happening! If this runs for more than 1 hour 15 mins, or gives you other problems, please go to Part 2B instead.
- You have now built an isolated, dedicated AI environment for engineering LLMs, running vector datastores, and so much more! You now need to **activate** it using this command: `conda activate llms`
You should see `(llms)` in your prompt, which indicates you've activated your new environment.
3. **Start Jupyter Lab:**
- In the Terminal window, from within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up in a browser. If you've not seen Jupyter Lab before, I'll explain it in a moment! Now close the jupyter lab browser tab, and close the Terminal, and move on to Part 3.
### Part 2B - Alternative to Part 2 if Anaconda gives you trouble
1. **Open a new Terminal** (Applications > Utilities > Terminal)
Run `python --version` to find out which python you're on. Ideally you'd be using a version of Python 3.11, so we're completely in sync.
If not, it's not a big deal, but we might need to come back to this later if you have compatibility issues.
You can download python here:
https://www.python.org/downloads/
2. Navigate to the "project root directory" using `cd ~/Documents/Projects/llm_engineering` (replace this path with the actual path to the llm_engineering directory, your locally cloned version of the repo). Do `ls` and check you can see subdirectories for each week of the course.
Then, create a new virtual environment with this command:
`python -m venv llms`
3. Activate the virtual environment with
`source llms/bin/activate`
You should see (llms) in your command prompt, which is your sign that things are going well.
4. Run `pip install -r requirements.txt`
This may take a few minutes to install.
5. **Start Jupyter Lab:**
From within the `llm_engineering` folder, type: `jupyter lab`
...and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipynb`. Success! Now close down jupyter lab and move on to Part 3.
If there are any problems, contact me!
### Part 3 - OpenAI key (OPTIONAL but recommended)
Particularly during weeks 1 and 2 of the course, you'll be writing code to call the APIs of Frontier models (models at the forefront of AI).
For week 1, you'll only need OpenAI, and you can add the others if you wish later on.
1. Create an OpenAI account if you don't have one by visiting:
https://platform.openai.com/
2. OpenAI asks for a minimum credit to use the API. For me in the US, it's \$5. The API calls will spend against this \$5. On this course, we'll only use a small portion of this. I do recommend you make the investment as you'll be able to put it to excellent use. But if you'd prefer not to pay for the API, I give you an alternative in the course using Ollama.
You can add your credit balance to OpenAI at Settings > Billing:
https://platform.openai.com/settings/organization/billing/overview
I recommend you disable the automatic recharge!
3. Create your API key
The webpage where you set up your OpenAI key is at https://platform.openai.com/api-keys - press the green 'Create new secret key' button and press 'Create secret key'. Keep a record of the API key somewhere private; you won't be able to retrieve it from the OpenAI screens in the future. It should start `sk-proj-`.
In week 2 we will also set up keys for Anthropic and Google, which you can do here when we get there.
- Claude API at https://console.anthropic.com/ from Anthropic
- Gemini API at https://ai.google.dev/gemini-api from Google
Later in the course you'll be using the fabulous HuggingFace platform; an account is available for free at https://huggingface.co - you can create an API token from the Avatar menu >> Settings >> Access Tokens.
And in Week 6/7 you'll be using the terrific Weights & Biases at https://wandb.ai to watch over your training batches. Accounts are also free, and you can set up a token in a similar way.
### PART 4 - .env file
When you have these keys, please create a new file called `.env` in your project root directory. The filename needs to be exactly the four characters ".env" rather than "my-keys.env" or ".env.txt". Here's how to do it:
1. Open Terminal (Applications > Utilities > Terminal)
2. Navigate to the "project root directory" using `cd ~/Documents/Projects/llm_engineering` (replace this path with the actual path to the llm_engineering directory, your locally cloned version of the repo).
3. Create the .env file with
nano .env
4. Then type your API keys into nano, replacing xxxx with your API key (starting `sk-proj-`).
```
OPENAI_API_KEY=xxxx
```
If you have other keys, you can add them too, or come back to this in future weeks:
```
GOOGLE_API_KEY=xxxx
ANTHROPIC_API_KEY=xxxx
HF_TOKEN=xxxx
```
5. Save the file:
Control + O
Enter (to confirm save the file)
Control + X to exit the editor
6. Use this command to list files in your project root directory:
`ls -a`
And confirm that the `.env` file is there.
This file won't appear in Jupyter Lab because jupyter hides files starting with a dot. This file is listed in the `.gitignore` file, so it won't get checked in and your keys stay safe.
### Part 5 - Showtime!!
- Open Terminal (Applications > Utilities > Terminal)
- Navigate to the "project root directory" using `cd ~/Documents/Projects/llm_engineering` (replace this path with the actual path to the llm_engineering directory, your locally cloned version of the repo). Do `ls` and check you can see subdirectories for each week of the course.
- Activate your environment with `conda activate llms` (or `source llms/bin/activate` if you used the alternative approach in Part 2B)
- You should see (llms) in your prompt which is your sign that all is well. And now, type: `jupyter lab` and Jupyter Lab should open up, ready for you to get started. Open the `week1` folder and double click on `day1.ipynb`.
And you're off to the races!
Note that any time you start jupyter lab in the future, you'll need to follow these Part 5 instructions to start it from within the `llm_engineering` directory with the `llms` environment activated.
For those new to Jupyter Lab / Jupyter Notebook, it's a delightful Data Science environment where you can simply hit shift+return in any cell to run it; start at the top and work your way down! I've included a notebook called 'Guide to Jupyter' that shows you more features. When we move to Google Colab in Week 3, you'll experience the same interface for Python runtimes in the cloud.
If you have any problems, I've included a notebook in week1 called [troubleshooting.ipynb](week1/troubleshooting.ipynb) to figure it out.
Please do message me or email me at ed@edwarddonner.com if this doesn't work or if I can help with anything. I can't wait to hear how you get on.

BIN
SETUP-mac.pdf

Binary file not shown.

1
environment.yml

@ -44,4 +44,5 @@ dependencies:
- gradio
- gensim
- modal
- ollama

8
requirements.txt

@ -10,9 +10,6 @@ matplotlib
gensim
torch
transformers
accelerate
sentencepiece
bitsandbytes
tqdm
openai
gradio
@ -35,3 +32,8 @@ plotly
jupyter-dash
beautifulsoup4
pydub
modal
ollama
accelerate
sentencepiece
bitsandbytes

256
week1/Guide to Jupyter.ipynb

@ -10,7 +10,7 @@
"## A Quick Start Guide\n",
"\n",
"Welcome to the wonderful world of Jupyter lab! \n",
"This is a Data Science playground where you can easily write code that builds and builds. It's an ideal environment for: \n",
"This is a Data Science playground where you can easily write code and investigate the results. It's an ideal environment for: \n",
"- Research & Development\n",
"- Prototyping\n",
"- Learning (that's us!)\n",
@ -21,7 +21,7 @@
"\n",
"A long time ago, Jupyter used to be called \"IPython\", and so the extensions of notebooks are \".ipynb\" which stands for \"IPython Notebook\".\n",
"\n",
"On the left is a File Browser that lets you navigate around the weeks and choose different notebooks. But you probably know that already, or you wouldn't have got here!\n",
"On the left is a File Browser that lets you navigate around the directories and choose different notebooks. But you probably know that already, or you wouldn't have got here!\n",
"\n",
"The notebook consists of a series of square boxes called \"cells\". Some of them contain text, like this cell, and some of them contain code, like the cell below.\n",
"\n",
@ -37,6 +37,8 @@
"metadata": {},
"outputs": [],
"source": [
"# Click anywhere in this cell and press Shift + Return\n",
"\n",
"2 + 2"
]
},
@ -47,7 +49,7 @@
"source": [
"## Congrats!\n",
"\n",
"Now run the next cell which sets a value, followed by the cell after it to print the value"
"Now run the next cell which sets a value, followed by the cells after it to print the value"
]
},
{
@ -62,6 +64,18 @@
"favorite_fruit = \"bananas\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "07792faa-761d-46cb-b9b7-2bbf70bb1628",
"metadata": {},
"outputs": [],
"source": [
"# The result of the last statement is shown after you run it\n",
"\n",
"favorite_fruit"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -91,10 +105,13 @@
"id": "9442d5c9-f57d-4839-b0af-dce58646c04f",
"metadata": {},
"source": [
"# Now go back and rerun the prior cell with the print statement\n",
"## Now go back and rerun the cell with the print statement, two cells back\n",
"\n",
"See how it prints something different, even though favorite_fruit was changed afterwards? \n",
"The order that code appears in the notebook doesn't matter. What matters is the order that the code is **executed**."
"See how it prints something different, even though favorite_fruit was changed further down in the notebook? \n",
"\n",
"The order that code appears in the notebook doesn't matter. What matters is the order that the code is **executed**. There's a python process sitting behind this notebook in which the variables are being changed.\n",
"\n",
"This catches some people out when they first use Jupyter."
]
},
{
@ -104,16 +121,239 @@
"metadata": {},
"outputs": [],
"source": [
"# More coming here soon!"
"# Then run this cell twice, and see if you understand what's going on\n",
"\n",
"print(f\"My favorite fruit is {favorite_fruit}\")\n",
"\n",
"favorite_fruit = \"apples\""
]
},
{
"cell_type": "markdown",
"id": "a29dab2d-bab9-4a54-8504-05e62594cc6f",
"metadata": {},
"source": [
"# Explaining the 'kernel'\n",
"\n",
"Sitting behind this notebook is a Python process which executes each cell when you run it. That Python process is known as the Kernel. Each notebook has its own separate Kernel.\n",
"\n",
"You can go to the Kernel menu and select \"Restart Kernel\".\n",
"\n",
"If you then try to run the next cell, you'll get an error, because favorite_fruit is no longer defined. You'll need to run the cells from the top of the notebook again. Then the next cell should run fine."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "84b1e410-5eda-4e2c-97ce-4eebcff816c5",
"metadata": {},
"outputs": [],
"source": [
"print(f\"My favorite fruit is {favorite_fruit}\")"
]
},
{
"cell_type": "markdown",
"id": "4d4188fc-d9cc-42be-8b4e-ae8630456764",
"metadata": {},
"source": [
"# Adding and moving cells\n",
"\n",
"Click in this cell, then click the \\[+\\] button in the toolbar above to create a new cell immediately below this one. Copy and paste in the code in the prior cell, then run it! There are also icons in the top right of the selected cell to delete it (bin), duplicate it, and move it up and down.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b51950ca-b512-4829-974f-442bd50e29a5",
"id": "ce258424-40c3-49a7-9462-e6fa25014b03",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "30e71f50-8f01-470a-9d7a-b82a6cef4236",
"metadata": {},
"source": [
"# Cell output\n",
"\n",
"When you execute a cell, the standard output and the result of the last statement is written to the area immediately under the code, known as the 'cell output'. When you save a Notebook from the file menu (or command+S), the output is also saved, making it a useful record of what happened.\n",
"\n",
"You can clean this up by going to Edit menu >> Clear Outputs of All Cells, or Kernel menu >> Restart Kernel and Clear Outputs of All Cells."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a4d021e2-c284-411f-8ab1-030530cfbe72",
"metadata": {},
"outputs": [],
"source": [
"spams = [\"spam\"] * 1000\n",
"print(spams)\n",
"\n",
"# Might be worth clearing output after running this!"
]
},
{
"cell_type": "markdown",
"id": "eac060f2-7a71-46e7-8235-b6ad0a76f5f8",
"metadata": {},
"source": [
"# Using markdown\n",
"\n",
"So what's going on with these areas with writing in them, like this one? Well, there's actually a different kind of cell called a 'Markdown' cell for adding explanations like this. Click the + button to add a cell. Then in the toolbar, click where it says 'Code' and change it to 'Markdown'.\n",
"\n",
"Add some comments using Markdown format, perhaps copying and pasting from here:\n",
"\n",
"```\n",
"# This is a heading\n",
"## This is a sub-head\n",
"### And a sub-sub-head\n",
"\n",
"I like Jupyter Lab because it's\n",
"- Easy\n",
"- Flexible\n",
"- Satisfying\n",
"```\n",
"\n",
"And to turn this into formatted text simply with Shift+Return in the cell.\n",
"Click in the cell and press the Bin icon if you want to remove it."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1586320-c90f-4f22-8b39-df6865484950",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "1330c83c-67ac-4ca0-ac92-a71699e0c31b",
"metadata": {},
"source": [
"# The exclamation point\n",
"\n",
"There's a super useful feature of jupyter labs; you can type a command with a ! in front of it in a code cell, like:\n",
"\n",
"!pip install \\[some_package\\]\n",
"\n",
"And it will run it at the command line (as if in Windows Powershell or Mac Terminal) and print the result"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "82042fc5-a907-4381-a4b8-eb9386df19cd",
"metadata": {},
"outputs": [],
"source": [
"# list the current directory\n",
"\n",
"!ls"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4fc3e3da-8a55-40cc-9706-48bf12a0e20e",
"metadata": {},
"outputs": [],
"source": [
"# ping cnn.com - press the stop button in the toolbar when you're bored\n",
"\n",
"!ping cnn.com"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a58e9462-89a2-4b4f-b4aa-51c4bd9f796b",
"metadata": {},
"outputs": [],
"source": [
"# This is a useful command that ensures your Anaconda environment \n",
"# is up to date with any new upgrades to packages;\n",
"# But it might take a minute and will print a lot to output\n",
"\n",
"!conda env update -f ../environment.yml --prune"
]
},
{
"cell_type": "markdown",
"id": "4688baaf-a72c-41b5-90b6-474cb24790a7",
"metadata": {},
"source": [
"# Minor things we encounter on the course\n",
"\n",
"This isn't necessarily a feature of Jupyter, but it's a nice package to know about that is useful in Jupyter Labs, and I use it in the course.\n",
"\n",
"The package `tqdm` will print a nice progress bar if you wrap any iterable."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2646a4e5-3c23-4aee-a34d-d623815187d2",
"metadata": {},
"outputs": [],
"source": [
"# Here's some code with no progress bar\n",
"# It will take 10 seconds while you wonder what's happpening..\n",
"\n",
"import time\n",
"\n",
"spams = [\"spam\"] * 1000\n",
"\n",
"for spam in spams:\n",
" time.sleep(0.01)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6e96be3d-fa82-42a3-a8aa-b81dd20563a5",
"metadata": {},
"outputs": [],
"source": [
"# And now, with a nice little progress bar:\n",
"\n",
"import time\n",
"from tqdm import tqdm\n",
"\n",
"spams = [\"spam\"] * 1000\n",
"\n",
"for spam in tqdm(spams):\n",
" time.sleep(0.01)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "63c788dd-4618-4bb4-a5ce-204411a38ade",
"metadata": {},
"outputs": [],
"source": [
"# On a different topic, here's a useful way to print output in markdown\n",
"\n",
"from IPython.display import Markdown, display\n",
"\n",
"display(Markdown(\"# This is a big heading!\\n\\n- And this is a bullet-point\\n- So is this\\n- Me, too!\"))\n"
]
},
{
"cell_type": "markdown",
"id": "9d14c1fb-3321-4387-b6ca-9af27676f980",
"metadata": {},
"source": [
"# That's it! You're up to speed on Jupyter Lab.\n",
"\n",
"## Want to be even more advanced?\n",
"\n",
"If you want to become a pro at Jupyter Lab, you can read their tutorial [here](https://jupyterlab.readthedocs.io/en/latest/). But this isn't required for our course; just a good technique for hitting Shift + Return and enjoying the result!"
]
}
],
"metadata": {

464
week1/Intermediate Python.ipynb

@ -0,0 +1,464 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "5c291475-8c7c-461c-9b12-545a887b2432",
"metadata": {},
"source": [
"# Intermediate Level Python\n",
"\n",
"## Getting you up to speed\n",
"\n",
"This course assumes that you're at an intermediate level of python. For example, you should have a decent idea what something like this might do:\n",
"\n",
"`yield from {book.get(\"author\") for book in books if book.get(\"author\")}`\n",
"\n",
"If not - then you've come to the right place! Welcome to the crash course in intermediate level python. The best way to learn is by doing!\n"
]
},
{
"cell_type": "markdown",
"id": "542f0577-a826-4613-a5d7-4170e9666d04",
"metadata": {},
"source": [
"## First: if you need a refresher on the foundations\n",
"\n",
"I'm going to defer to an AI friend for this, because these explanations are so well written with great examples. Copy and paste the code examples into a new cell to give them a try.\n",
"\n",
"**Python imports:** \n",
"https://chatgpt.com/share/672f9f31-8114-8012-be09-29ef0d0140fb\n",
"\n",
"**Python functions** including default arguments: \n",
"https://chatgpt.com/share/672f9f99-7060-8012-bfec-46d4cf77d672\n",
"\n",
"**Python strings**, including slicing, split/join, replace and literals: \n",
"https://chatgpt.com/share/672fb526-0aa0-8012-9e00-ad1687c04518\n",
"\n",
"**Python f-strings** including number and date formatting: \n",
"https://chatgpt.com/share/672fa125-0de0-8012-8e35-27918cbb481c\n",
"\n",
"**Python lists, dicts and sets**, including the `get()` method: \n",
"https://chatgpt.com/share/672fa225-3f04-8012-91af-f9c95287da8d\n",
"\n",
"**Python classes:** \n",
"https://chatgpt.com/share/672fa07a-1014-8012-b2ea-6dc679552715"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5802e2f0-0ea0-4237-bbb7-f375a34260f0",
"metadata": {},
"outputs": [],
"source": [
"# Next let's create some things:\n",
"\n",
"fruits = [\"Apples\", \"Bananas\", \"Pears\"]\n",
"\n",
"book1 = {\"title\": \"Great Expectations\", \"author\": \"Charles Dickens\"}\n",
"book2 = {\"title\": \"Bleak House\", \"author\": \"Charles Dickens\"}\n",
"book3 = {\"title\": \"An Book By No Author\"}\n",
"book4 = {\"title\": \"Moby Dick\", \"author\": \"Herman Melville\"}\n",
"\n",
"books = [book1, book2, book3, book4]"
]
},
{
"cell_type": "markdown",
"id": "9b941e6a-3658-4144-a8d4-72f5e72f3707",
"metadata": {},
"source": [
"# Part 1: List and dict comprehensions"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "61992bb8-735d-4dad-8747-8c10b63aec82",
"metadata": {},
"outputs": [],
"source": [
"# Simple enough to start\n",
"\n",
"for fruit in fruits:\n",
" print(fruit)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c89c3842-9b74-47fa-8424-0fcb08e4177c",
"metadata": {},
"outputs": [],
"source": [
"# Let's make a new version of fruits\n",
"\n",
"fruits_shouted = []\n",
"for fruit in fruits:\n",
" fruits_shouted.append(fruit.upper())\n",
"\n",
"fruits_shouted"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4ec13b3a-9545-44f1-874a-2910a0663560",
"metadata": {},
"outputs": [],
"source": [
"# You probably already know this\n",
"# There's a nice Python construct called \"list comprehension\" that does this:\n",
"\n",
"fruits_shouted2 = [fruit.upper() for fruit in fruits]\n",
"fruits_shouted2"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ecc08c3c-181d-4b64-a3e1-b0ccffc6c0cd",
"metadata": {},
"outputs": [],
"source": [
"# But you may not know that you can do this to create dictionaries, too:\n",
"\n",
"fruit_mapping = {fruit:fruit.upper() for fruit in fruits}\n",
"fruit_mapping"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "500c2406-00d2-4793-b57b-f49b612760c8",
"metadata": {},
"outputs": [],
"source": [
"# you can also use the if statement to filter the results\n",
"\n",
"fruits_with_longer_names_shouted = [fruit.upper() for fruit in fruits if len(fruit)>5]\n",
"fruits_with_longer_names_shouted"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38c11c34-d71e-45ba-945b-a3d37dc29793",
"metadata": {},
"outputs": [],
"source": [
"fruit_mapping_unless_starts_with_a = {fruit:fruit.upper() for fruit in fruits if not fruit.startswith('A')}\n",
"fruit_mapping_unless_starts_with_a"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5c97d8e8-31de-4afa-973e-28d8e5cab749",
"metadata": {},
"outputs": [],
"source": [
"# Another comprehension\n",
"\n",
"[book['title'] for book in books]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "50be0edc-a4cd-493f-a680-06080bb497b4",
"metadata": {},
"outputs": [],
"source": [
"# This code will fail with an error because one of our books doesn't have an author\n",
"\n",
"[book['author'] for book in books]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53794083-cc09-4edb-b448-2ffb7e8495c2",
"metadata": {},
"outputs": [],
"source": [
"# But this will work, because get() returns None\n",
"\n",
"[book.get('author') for book in books]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b8e4b859-24f8-4016-8d74-c2cef226d049",
"metadata": {},
"outputs": [],
"source": [
"# And this variation will filter out the None\n",
"\n",
"[book.get('author') for book in books if book.get('author')]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c44bb999-52b4-4dee-810b-8a400db8f25f",
"metadata": {},
"outputs": [],
"source": [
"# And this version will convert it into a set, removing duplicates\n",
"\n",
"set([book.get('author') for book in books if book.get('author')])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "80a65156-6192-4bb4-b4e6-df3fdc933891",
"metadata": {},
"outputs": [],
"source": [
"# And finally, this version is even nicer\n",
"# curly braces creates a set, so this is a set comprehension\n",
"\n",
"{book.get('author') for book in books if book.get('author')}"
]
},
{
"cell_type": "markdown",
"id": "c100e5db-5438-4715-921c-3f7152f83f4a",
"metadata": {},
"source": [
"# Part 2: Generators\n",
"\n",
"We use Generators in the course because AI models can stream back results.\n",
"\n",
"If you've not used Generators before, please start with this excellent intro from ChatGPT:\n",
"\n",
"https://chatgpt.com/share/672faa6e-7dd0-8012-aae5-44fc0d0ec218\n",
"\n",
"Try pasting some of its examples into a cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1efc26fa-9144-4352-9a17-dfec1d246aad",
"metadata": {},
"outputs": [],
"source": [
"# First define a generator; it looks like a function, but it has yield instead of return\n",
"\n",
"import time\n",
"\n",
"def come_up_with_fruit_names():\n",
" for fruit in fruits:\n",
" time.sleep(1) # thinking of a fruit\n",
" yield fruit"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "eac338bb-285c-45c8-8a3e-dbfc41409ca3",
"metadata": {},
"outputs": [],
"source": [
"# Then use it\n",
"\n",
"for fruit in come_up_with_fruit_names():\n",
" print(fruit)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f6880578-a3de-4502-952a-4572b95eb9ff",
"metadata": {},
"outputs": [],
"source": [
"# Here's another one\n",
"\n",
"def authors_generator():\n",
" for book in books:\n",
" if book.get(\"author\"):\n",
" yield book.get(\"author\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9e316f02-f87f-441d-a01f-024ade949607",
"metadata": {},
"outputs": [],
"source": [
"# Use it\n",
"\n",
"for author in authors_generator():\n",
" print(author)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7535c9d0-410e-4e56-a86c-ae6c0e16053f",
"metadata": {},
"outputs": [],
"source": [
"# Here's the same thing written with list comprehension\n",
"\n",
"def authors_generator():\n",
" for author in [book.get(\"author\") for book in books if book.get(\"author\")]:\n",
" yield author"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dad34494-0f6c-4edb-b03f-b8d49ee186f2",
"metadata": {},
"outputs": [],
"source": [
"# Use it\n",
"\n",
"for author in authors_generator():\n",
" print(author)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "abeb7e61-d8aa-4af0-b05a-ae17323e678c",
"metadata": {},
"outputs": [],
"source": [
"# Here's a nice shortcut\n",
"# You can use \"yield from\" to yield each item of an iterable\n",
"\n",
"def authors_generator():\n",
" yield from [book.get(\"author\") for book in books if book.get(\"author\")]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "05b0cb43-aa83-4762-a797-d3beb0f22c44",
"metadata": {},
"outputs": [],
"source": [
"# Use it\n",
"\n",
"for author in authors_generator():\n",
" print(author)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fdfea58e-d809-4dd4-b7b0-c26427f8be55",
"metadata": {},
"outputs": [],
"source": [
"# And finally - we can replace the list comprehension with a set comprehension\n",
"\n",
"def unique_authors_generator():\n",
" yield from {book.get(\"author\") for book in books if book.get(\"author\")}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3e821d08-97be-4db9-9a5b-ce5dced3eff8",
"metadata": {},
"outputs": [],
"source": [
"# Use it\n",
"\n",
"for author in unique_authors_generator():\n",
" print(author)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "905ba603-15d8-4d01-9a79-60ec293d7ca1",
"metadata": {},
"outputs": [],
"source": [
"# And for some fun - press the stop button in the toolbar when bored!\n",
"# It's like we've made our own Large Language Model... although not particularly large..\n",
"# See if you understand why it prints a letter at a time, instead of a word at a time. If you're unsure, try removing the keyword \"from\" everywhere in the code.\n",
"\n",
"import random\n",
"import time\n",
"\n",
"pronouns = [\"I\", \"You\", \"We\", \"They\"]\n",
"verbs = [\"eat\", \"detest\", \"bathe in\", \"deny the existence of\", \"resent\", \"pontificate about\", \"juggle\", \"impersonate\", \"worship\", \"misplace\", \"conspire with\", \"philosophize about\", \"tap dance on\", \"dramatically renounce\", \"secretly collect\"]\n",
"adjectives = [\"turqoise\", \"smelly\", \"arrogant\", \"festering\", \"pleasing\", \"whimsical\", \"disheveled\", \"pretentious\", \"wobbly\", \"melodramatic\", \"pompous\", \"fluorescent\", \"bewildered\", \"suspicious\", \"overripe\"]\n",
"nouns = [\"turnips\", \"rodents\", \"eels\", \"walruses\", \"kumquats\", \"monocles\", \"spreadsheets\", \"bagpipes\", \"wombats\", \"accordions\", \"mustaches\", \"calculators\", \"jellyfish\", \"thermostats\"]\n",
"\n",
"def infinite_random_sentences():\n",
" while True:\n",
" yield from random.choice(pronouns)\n",
" yield \" \"\n",
" yield from random.choice(verbs)\n",
" yield \" \"\n",
" yield from random.choice(adjectives)\n",
" yield \" \"\n",
" yield from random.choice(nouns)\n",
" yield \". \"\n",
"\n",
"for letter in infinite_random_sentences():\n",
" print(letter, end=\"\", flush=True)\n",
" time.sleep(0.02)"
]
},
{
"cell_type": "markdown",
"id": "04832ea2-2447-4473-a449-104f80e24d85",
"metadata": {},
"source": [
"# Exercise\n",
"\n",
"Write some python classes for the books example.\n",
"\n",
"Write a Book class with a title and author. Include a method has_author()\n",
"\n",
"Write a BookShelf class with a list of books. Include a generator method unique_authors()"
]
},
{
"cell_type": "markdown",
"id": "35760406-fe6c-41f9-b0c0-3e8cf73aafd0",
"metadata": {},
"source": [
"# Finally\n",
"\n",
"Here are some intermediate level details of Classes from our AI friend, including use of type hints, inheritance and class methods. This includes a Book example.\n",
"\n",
"https://chatgpt.com/share/67348aca-65fc-8012-a4a9-fd1b8f04ba59"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

73
week1/day1.ipynb

@ -5,7 +5,9 @@
"id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9",
"metadata": {},
"source": [
"# Instant Gratification!\n",
"# Instant Gratification\n",
"\n",
"## Your first Frontier LLM Project!\n",
"\n",
"Let's build a useful LLM solution - in a matter of minutes.\n",
"\n",
@ -13,26 +15,29 @@
"\n",
"Our goal is to code a new kind of Web Browser. Give it a URL, and it will respond with a summary. The Reader's Digest of the internet!!\n",
"\n",
"Before starting, be sure to have followed the instructions in the \"README\" file, including creating your API key with OpenAI and adding it to the `.env` file.\n",
"Before starting, you should have completed the setup for [PC](../SETUP-PC.md) or [Mac](../SETUP-mac.md) and you hopefully launched this jupyter lab from within the project root directory, with your environment activated.\n",
"\n",
"## If you're new to Jupyter Lab\n",
"\n",
"Welcome to the wonderful world of Data Science experimentation! Once you've used Jupyter Lab, you'll wonder how you ever lived without it. Simply click in each \"cell\" with code in it, such as the cell immediately below this text, and hit Shift+Return to execute that cell. As you wish, you can add a cell with the + button in the toolbar, and print values of variables, or try out variations. \n",
"\n",
"If you need to start a 'notebook' again, go to Kernel menu >> Restart kernel. \n",
"\n",
"If you want to become a pro at Jupyter Lab, you can read their tutorial [here](https://jupyterlab.readthedocs.io/en/latest/). But this isn't required for our course; just a good technique for hitting Shift + Return and enjoying the result!\n",
"I've written a notebook called [Guide to Jupyter](Guide%20to%20Jupyter.ipynb) to help you get more familiar with Jupyter Labs, including adding Markdown comments, using `!` to run shell commands, and `tqdm` to show progress.\n",
"\n",
"If you prefer to work in IDEs like VSCode or Pycharm, they both work great with these lab notebooks too. \n",
"\n",
"## If you'd like to brush up your Python\n",
"\n",
"I've added a notebook called [Intermediate Python](Intermediate%20Python.ipynb) to get you up to speed. But you should give it a miss if you already have a good idea what this code does: \n",
"`yield from {book.get(\"author\") for book in books if book.get(\"author\")}`\n",
"\n",
"## I am here to help\n",
"\n",
"If you have any problems at all, please do reach out. \n",
"I'm available through the platform, or at ed@edwarddonner.com, or at https://www.linkedin.com/in/eddonner/ if you'd like to connect.\n",
"I'm available through the platform, or at ed@edwarddonner.com, or at https://www.linkedin.com/in/eddonner/ if you'd like to connect (and I love connecting!)\n",
"\n",
"## More troubleshooting\n",
"\n",
"Please see the [troubleshooting](troubleshooting.ipynb) notebook in this folder for more ideas!\n",
"Please see the [troubleshooting](troubleshooting.ipynb) notebook in this folder to diagnose and fix common problems.\n",
"\n",
"## If this is old hat!\n",
"\n",
@ -59,7 +64,7 @@
"from IPython.display import Markdown, display\n",
"from openai import OpenAI\n",
"\n",
"# If you get an error like \"NameError\" running this cell, then please head over to the troubleshooting notebook!"
"# If you get an error running this cell, then please head over to the troubleshooting notebook!"
]
},
{
@ -75,19 +80,11 @@
"\n",
"Head over to the [troubleshooting](troubleshooting.ipynb) notebook in this folder for step by step code to identify the root cause and fix it!\n",
"\n",
"A summary of some points:\n",
"If you make a change, try restarting the \"Kernel\" (the python process sitting behind this notebook) by Kernel menu >> Restart Kernel and Clear Outputs of All Cells. Then try this notebook again, starting at the top.\n",
"\n",
"1. OpenAI takes a few minutes to register after you set up an account. If you receive an error about being over quota, try waiting a few minutes and try again.\n",
"2. You'll need to set up billing and add the minimum amount of credit at this page [here](https://platform.openai.com/settings/organization/billing/overview). OpenAI requires a minimum of $5 to get started in the U.S. right now - this might be different for your region. You'll only need to use a fraction for this course. In my view, this is well worth the investment for your education and future projects - but if you have any concerns, you can skip this and watch me using OpenAI instead. In week 3 we will start to use free open-source models!\n",
"3. Also, double check you have the right kind of API token with the right permissions. You should find it on [this webpage](https://platform.openai.com/api-keys) and it should show with Permissions of \"All\". If not, try creating another key by:\n",
"- Pressing \"Create new secret key\" on the top right\n",
"- Select **Owned by:** you, **Project:** Default project, **Permissions:** All\n",
"- Click Create secret key, and use that new key in the code and the `.env` file (it might take a few minutes to activate)\n",
"- Do a Kernel >> Restart kernel, and execute the cells in this Jupyter lab starting at the top\n",
"4. As a fallback, replace the line `openai = OpenAI()` with `openai = OpenAI(api_key=\"your-key-here\")` - while it's not recommended to hard code tokens in Jupyter lab, because then you can't share your lab with others, it's a workaround for now\n",
"5. Contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n",
"Or, contact me! Message me or email ed@edwarddonner.com and we will get this to work.\n",
"\n",
"Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point."
"Any concerns about API costs? See my notes in the README - costs should be minimal, and you can control it at every point. You can also use Ollama as a free alternative, which we discuss during Day 2."
]
},
{
@ -106,10 +103,10 @@
"\n",
"if not api_key:\n",
" print(\"No API key was found - please head over to the troubleshooting notebook in this folder to identify & fix!\")\n",
"elif api_key[:8]!=\"sk-proj-\":\n",
" print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key\")\n",
"elif not api_key.startswith(\"sk-proj-\"):\n",
" print(\"An API key was found, but it doesn't start sk-proj-; please check you're using the right key - see troubleshooting notebook\")\n",
"elif api_key.strip() != api_key:\n",
" print(\"An API key was found, but it looks like it might have space or tab characters at the start or end - please remove them\")\n",
" print(\"An API key was found, but it looks like it might have space or tab characters at the start or end - please remove them - see troubleshooting notebook\")\n",
"else:\n",
" print(\"API key found and looks good so far!\")\n"
]
@ -124,8 +121,8 @@
"openai = OpenAI()\n",
"\n",
"# If this doesn't work, try Kernel menu >> Restart Kernel and Clear Outputs Of All Cells, then run the cells from the top of this notebook down.\n",
"# If it STILL doesn't work (horrors!) then please see the troubleshooting notebook, ot try the below line instead:\n",
"# openai = OpenAI(api_key=\"your-key-here\")"
"# If it STILL doesn't work (horrors!) then please see the troubleshooting notebook, or try the below line instead:\n",
"# openai = OpenAI(api_key=\"your-key-here-starting-sk-proj-\")"
]
},
{
@ -136,14 +133,12 @@
"outputs": [],
"source": [
"# A class to represent a Webpage\n",
"# If you're not familiar with Classes, check out the \"Intermediate Python\" notebook\n",
"\n",
"class Website:\n",
" \"\"\"\n",
" A utility class to represent a Website that we have scraped\n",
" \"\"\"\n",
" url: str\n",
" title: str\n",
" text: str\n",
"\n",
" def __init__(self, url):\n",
" \"\"\"\n",
@ -215,13 +210,23 @@
"\n",
"def user_prompt_for(website):\n",
" user_prompt = f\"You are looking at a website titled {website.title}\"\n",
" user_prompt += \"The contents of this website is as follows; \\\n",
" user_prompt += \"\\nThe contents of this website is as follows; \\\n",
"please provide a short summary of this website in markdown. \\\n",
"If it includes news or announcements, then summarize these too.\\n\\n\"\n",
" user_prompt += website.text\n",
" return user_prompt"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "26448ec4-5c00-4204-baec-7df91d11ff2e",
"metadata": {},
"outputs": [],
"source": [
"print(user_prompt_for(ed))"
]
},
{
"cell_type": "markdown",
"id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc",
@ -255,6 +260,16 @@
" ]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36478464-39ee-485c-9f3f-6a4e458dbc9c",
"metadata": {},
"outputs": [],
"source": [
"messages_for(ed)"
]
},
{
"cell_type": "markdown",
"id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0",
@ -370,7 +385,7 @@
"source": [
"## An extra exercise for those who enjoy web scraping\n",
"\n",
"You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them."
"You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. In the community-contributions folder, you'll find an example Selenium solution from a student (thank you!)"
]
},
{

167
week1/day2 EXERCISE.ipynb

@ -0,0 +1,167 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9",
"metadata": {},
"source": [
"# HOMEWORK EXERCISE ASSIGNMENT\n",
"\n",
"Upgrade the day 1 project to summarize a webpage to use an Open Source model running locally via Ollama rather than OpenAI\n",
"\n",
"You'll be able to use this technique for all subsequent projects if you'd prefer not to use paid APIs.\n",
"\n",
"**Benefits:**\n",
"1. No API charges - open-source\n",
"2. Data doesn't leave your box\n",
"\n",
"**Disadvantages:**\n",
"1. Significantly less power than Frontier Model\n",
"\n",
"## Recap on installation of Ollama\n",
"\n",
"Simply visit [ollama.com](https://ollama.com) and install!\n",
"\n",
"Once complete, the ollama server should already be running locally. \n",
"If you visit: \n",
"[http://localhost:11434/](http://localhost:11434/)\n",
"\n",
"You should see the message `Ollama is running`. \n",
"\n",
"If not, bring up a new Terminal (Mac) or Powershell (Windows) and enter `ollama serve` \n",
"Then try [http://localhost:11434/](http://localhost:11434/) again."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4e2a9393-7767-488e-a8bf-27c12dca35bd",
"metadata": {},
"outputs": [],
"source": [
"# imports\n",
"\n",
"import requests\n",
"from bs4 import BeautifulSoup\n",
"from IPython.display import Markdown, display"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29ddd15d-a3c5-4f4e-a678-873f56162724",
"metadata": {},
"outputs": [],
"source": [
"# Constants\n",
"\n",
"OLLAMA_API = \"http://localhost:11434/api/chat\"\n",
"HEADERS = {\"Content-Type\": \"application/json\"}\n",
"MODEL = \"llama3.2\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dac0a679-599c-441f-9bf2-ddc73d35b940",
"metadata": {},
"outputs": [],
"source": [
"# Create a messages list using the same format that we used for OpenAI\n",
"\n",
"messages = [\n",
" {\"role\": \"user\", \"content\": \"Describe some of the business applications of Generative AI\"}\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7bb9c624-14f0-4945-a719-8ddb64f66f47",
"metadata": {},
"outputs": [],
"source": [
"payload = {\n",
" \"model\": MODEL,\n",
" \"messages\": messages,\n",
" \"stream\": False\n",
" }"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42b9f644-522d-4e05-a691-56e7658c0ea9",
"metadata": {},
"outputs": [],
"source": [
"response = requests.post(OLLAMA_API, json=payload, headers=HEADERS)\n",
"print(response.json()['message']['content'])"
]
},
{
"cell_type": "markdown",
"id": "6a021f13-d6a1-4b96-8e18-4eae49d876fe",
"metadata": {},
"source": [
"# Introducing the ollama package\n",
"\n",
"And now we'll do the same thing, but using the elegant ollama python package instead of a direct HTTP call.\n",
"\n",
"Under the hood, it's making the same call as above to the ollama server running at localhost:11434"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7745b9c4-57dc-4867-9180-61fa5db55eb8",
"metadata": {},
"outputs": [],
"source": [
"import ollama\n",
"\n",
"response = ollama.chat(model=MODEL, messages=messages)\n",
"print(response['message']['content'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9a611b05-b5b0-4c83-b82d-b3a39ffb917d",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "1622d9bb-5c68-4d4e-9ca4-b492c751f898",
"metadata": {},
"source": [
"# NOW the exercise for you\n",
"\n",
"Take the code from day1 and incorporate it here, to build a website summarizer that uses Llama 3.2 running locally instead of OpenAI"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

59
week1/day5.ipynb

@ -28,6 +28,7 @@
"outputs": [],
"source": [
"# imports\n",
"# If these fail, please check you're running from an 'activated' environment with (llms) in the command prompt\n",
"\n",
"import os\n",
"import requests\n",
@ -49,7 +50,13 @@
"# Initialize and constants\n",
"\n",
"load_dotenv()\n",
"os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
"api_key = os.getenv('OPENAI_API_KEY')\n",
"\n",
"if api_key and api_key[:8]=='sk-proj-':\n",
" print(\"API key looks good so far\")\n",
"else:\n",
" print(\"There might be a problem with your API key? Please visit the troubleshooting notebook!\")\n",
" \n",
"MODEL = 'gpt-4o-mini'\n",
"openai = OpenAI()"
]
@ -67,11 +74,6 @@
" \"\"\"\n",
" A utility class to represent a Website that we have scraped, now with links\n",
" \"\"\"\n",
" url: str\n",
" title: str\n",
" body: str\n",
" links: List[str]\n",
" text: str\n",
"\n",
" def __init__(self, url):\n",
" self.url = url\n",
@ -100,7 +102,7 @@
"outputs": [],
"source": [
"ed = Website(\"https://edwarddonner.com\")\n",
"print(ed.get_contents())"
"ed.links"
]
},
{
@ -140,6 +142,16 @@
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b97e4068-97ed-4120-beae-c42105e4d59a",
"metadata": {},
"outputs": [],
"source": [
"print(link_system_prompt)"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -175,7 +187,7 @@
"source": [
"def get_links(url):\n",
" website = Website(url)\n",
" completion = openai.chat.completions.create(\n",
" response = openai.chat.completions.create(\n",
" model=MODEL,\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": link_system_prompt},\n",
@ -183,10 +195,21 @@
" ],\n",
" response_format={\"type\": \"json_object\"}\n",
" )\n",
" result = completion.choices[0].message.content\n",
" result = response.choices[0].message.content\n",
" return json.loads(result)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "74a827a0-2782-4ae5-b210-4a242a8b4cc2",
"metadata": {},
"outputs": [],
"source": [
"anthropic = Website(\"https://anthropic.com\")\n",
"anthropic.links"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -268,6 +291,16 @@
" return user_prompt"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cd909e0b-1312-4ce2-a553-821e795d7572",
"metadata": {},
"outputs": [],
"source": [
"get_brochure_user_prompt(\"Anthropic\", \"https://anthropic.com\")"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -308,14 +341,6 @@
"with the familiar typewriter animation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bcb358a4-aa7f-47ec-b2bc-67768783dfe1",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,

463
week1/solutions/day2 SOLUTION.ipynb

@ -0,0 +1,463 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d15d8294-3328-4e07-ad16-8a03e9bbfdb9",
"metadata": {},
"source": [
"# EXERCISE SOLUTION\n",
"\n",
"Upgrade the day 1 project to summarize a webpage to use an Open Source model running locally via Ollama rather than OpenAI\n",
"\n",
"You'll be able to use this technique for all subsequent projects if you'd prefer not to use paid APIs.\n",
"\n",
"**Benefits:**\n",
"1. No API charges - open-source\n",
"2. Data doesn't leave your box\n",
"\n",
"**Disadvantages:**\n",
"1. Significantly less power than Frontier Model\n",
"\n",
"## Recap on installation of Ollama\n",
"\n",
"Simply visit [ollama.com](https://ollama.com) and install!\n",
"\n",
"Once complete, the ollama server should already be running locally. \n",
"If you visit: \n",
"[http://localhost:11434/](http://localhost:11434/)\n",
"\n",
"You should see the message `Ollama is running`. \n",
"\n",
"If not, bring up a new Terminal (Mac) or Powershell (Windows) and enter `ollama serve` \n",
"Then try [http://localhost:11434/](http://localhost:11434/) again."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "4e2a9393-7767-488e-a8bf-27c12dca35bd",
"metadata": {},
"outputs": [],
"source": [
"# imports\n",
"\n",
"import requests\n",
"from bs4 import BeautifulSoup\n",
"from IPython.display import Markdown, display\n",
"import ollama"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "29ddd15d-a3c5-4f4e-a678-873f56162724",
"metadata": {},
"outputs": [],
"source": [
"# Constants\n",
"\n",
"MODEL = \"llama3.2\""
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "c5e793b2-6775-426a-a139-4848291d0463",
"metadata": {},
"outputs": [],
"source": [
"# A class to represent a Webpage\n",
"\n",
"class Website:\n",
" \"\"\"\n",
" A utility class to represent a Website that we have scraped\n",
" \"\"\"\n",
" url: str\n",
" title: str\n",
" text: str\n",
"\n",
" def __init__(self, url):\n",
" \"\"\"\n",
" Create this Website object from the given url using the BeautifulSoup library\n",
" \"\"\"\n",
" self.url = url\n",
" response = requests.get(url)\n",
" soup = BeautifulSoup(response.content, 'html.parser')\n",
" self.title = soup.title.string if soup.title else \"No title found\"\n",
" for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n",
" irrelevant.decompose()\n",
" self.text = soup.body.get_text(separator=\"\\n\", strip=True)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Home - Edward Donner\n",
"Home\n",
"Outsmart\n",
"An arena that pits LLMs against each other in a battle of diplomacy and deviousness\n",
"About\n",
"Posts\n",
"Well, hi there.\n",
"I’m Ed. I like writing code and experimenting with LLMs, and hopefully you’re here because you do too. I also enjoy DJing (but I’m badly out of practice), amateur electronic music production (\n",
"very\n",
"amateur) and losing myself in\n",
"Hacker News\n",
", nodding my head sagely to things I only half understand.\n",
"I’m the co-founder and CTO of\n",
"Nebula.io\n",
". We’re applying AI to a field where it can make a massive, positive impact: helping people discover their potential and pursue their reason for being. Recruiters use our product today to source, understand, engage and manage talent. I’m previously the founder and CEO of AI startup untapt,\n",
"acquired in 2021\n",
".\n",
"We work with groundbreaking, proprietary LLMs verticalized for talent, we’ve\n",
"patented\n",
"our matching model, and our award-winning platform has happy customers and tons of press coverage.\n",
"Connect\n",
"with me for more!\n",
"October 16, 2024\n",
"From Software Engineer to AI Data Scientist – resources\n",
"August 6, 2024\n",
"Outsmart LLM Arena – a battle of diplomacy and deviousness\n",
"June 26, 2024\n",
"Choosing the Right LLM: Toolkit and Resources\n",
"February 7, 2024\n",
"Fine-tuning an LLM on your texts: a simulation of you\n",
"Navigation\n",
"Home\n",
"Outsmart\n",
"An arena that pits LLMs against each other in a battle of diplomacy and deviousness\n",
"About\n",
"Posts\n",
"Get in touch\n",
"ed [at] edwarddonner [dot] com\n",
"www.edwarddonner.com\n",
"Follow me\n",
"LinkedIn\n",
"Twitter\n",
"Facebook\n",
"Subscribe to newsletter\n",
"Type your email…\n",
"Subscribe\n"
]
}
],
"source": [
"# Let's try one out\n",
"\n",
"ed = Website(\"https://edwarddonner.com\")\n",
"print(ed.title)\n",
"print(ed.text)"
]
},
{
"cell_type": "markdown",
"id": "6a478a0c-2c53-48ff-869c-4d08199931e1",
"metadata": {},
"source": [
"## Types of prompts\n",
"\n",
"You may know this already - but if not, you will get very familiar with it!\n",
"\n",
"Models like GPT4o have been trained to receive instructions in a particular way.\n",
"\n",
"They expect to receive:\n",
"\n",
"**A system prompt** that tells them what task they are performing and what tone they should use\n",
"\n",
"**A user prompt** -- the conversation starter that they should reply to"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "abdb8417-c5dc-44bc-9bee-2e059d162699",
"metadata": {},
"outputs": [],
"source": [
"# Define our system prompt - you can experiment with this later, changing the last sentence to 'Respond in markdown in Spanish.\"\n",
"\n",
"system_prompt = \"You are an assistant that analyzes the contents of a website \\\n",
"and provides a short summary, ignoring text that might be navigation related. \\\n",
"Respond in markdown.\""
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c",
"metadata": {},
"outputs": [],
"source": [
"# A function that writes a User Prompt that asks for summaries of websites:\n",
"\n",
"def user_prompt_for(website):\n",
" user_prompt = f\"You are looking at a website titled {website.title}\"\n",
" user_prompt += \"The contents of this website is as follows; \\\n",
"please provide a short summary of this website in markdown. \\\n",
"If it includes news or announcements, then summarize these too.\\n\\n\"\n",
" user_prompt += website.text\n",
" return user_prompt"
]
},
{
"cell_type": "markdown",
"id": "ea211b5f-28e1-4a86-8e52-c0b7677cadcc",
"metadata": {},
"source": [
"## Messages\n",
"\n",
"The API from Ollama expects the same message format as OpenAI:\n",
"\n",
"```\n",
"[\n",
" {\"role\": \"system\", \"content\": \"system message goes here\"},\n",
" {\"role\": \"user\", \"content\": \"user message goes here\"}\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "0134dfa4-8299-48b5-b444-f2a8c3403c88",
"metadata": {},
"outputs": [],
"source": [
"# See how this function creates exactly the format above\n",
"\n",
"def messages_for(website):\n",
" return [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt_for(website)}\n",
" ]"
]
},
{
"cell_type": "markdown",
"id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0",
"metadata": {},
"source": [
"## Time to bring it together - now with Ollama instead of OpenAI"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "905b9919-aba7-45b5-ae65-81b3d1d78e34",
"metadata": {},
"outputs": [],
"source": [
"# And now: call the Ollama function instead of OpenAI\n",
"\n",
"def summarize(url):\n",
" website = Website(url)\n",
" messages = messages_for(website)\n",
" response = ollama.chat(model=MODEL, messages=messages)\n",
" return response['message']['content']"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "05e38d41-dfa4-4b20-9c96-c46ea75d9fb5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'**Summary**\\n\\n* Website belongs to Edward Donner, a co-founder and CTO of Nebula.io.\\n* He is the founder and CEO of AI startup untapt, which was acquired in 2021.\\n\\n**News/Announcements**\\n\\n* October 16, 2024: \"From Software Engineer to AI Data Scientist – resources\" (resource list for career advancement)\\n* August 6, 2024: \"Outsmart LLM Arena – a battle of diplomacy and deviousness\" (introducing the Outsmart arena, a competition between LLMs)\\n* June 26, 2024: \"Choosing the Right LLM: Toolkit and Resources\" (resource list for selecting the right LLM)\\n* February 7, 2024: \"Fine-tuning an LLM on your texts: a simulation of you\" (blog post about simulating human-like conversations with LLMs)'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"summarize(\"https://edwarddonner.com\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "3d926d59-450e-4609-92ba-2d6f244f1342",
"metadata": {},
"outputs": [],
"source": [
"# A function to display this nicely in the Jupyter output, using markdown\n",
"\n",
"def display_summary(url):\n",
" summary = summarize(url)\n",
" display(Markdown(summary))"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "3018853a-445f-41ff-9560-d925d1774b2f",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Summary of Edward Donner's Website\n",
"\n",
"## About the Creator\n",
"Edward Donner is a writer, code enthusiast, and co-founder/CTO of Nebula.io, an AI company that applies AI to help people discover their potential.\n",
"\n",
"## Recent Announcements and News\n",
"\n",
"* October 16, 2024: \"From Software Engineer to AI Data Scientist – resources\" - a resource list for those transitioning into AI data science.\n",
"* August 6, 2024: \"Outsmart LLM Arena – a battle of diplomacy and deviousness\" - an introduction to the Outsmart arena where LLMs compete against each other in diplomacy and strategy.\n",
"* June 26, 2024: \"Choosing the Right LLM: Toolkit and Resources\" - a resource list for choosing the right Large Language Model (LLM) for specific use cases.\n",
"\n",
"## Miscellaneous\n",
"\n",
"* A section about Ed's personal interests, including DJing and amateur electronic music production.\n",
"* Links to his professional profiles on LinkedIn, Twitter, Facebook, and a contact email."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display_summary(\"https://edwarddonner.com\")"
]
},
{
"cell_type": "markdown",
"id": "b3bcf6f4-adce-45e9-97ad-d9a5d7a3a624",
"metadata": {},
"source": [
"# Let's try more websites\n",
"\n",
"Note that this will only work on websites that can be scraped using this simplistic approach.\n",
"\n",
"Websites that are rendered with Javascript, like React apps, won't show up. See the community-contributions folder for a Selenium implementation that gets around this. You'll need to read up on installing Selenium (ask ChatGPT!)\n",
"\n",
"Also Websites protected with CloudFront (and similar) may give 403 errors - many thanks Andy J for pointing this out.\n",
"\n",
"But many websites will work just fine!"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "45d83403-a24c-44b5-84ac-961449b4008f",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"I can't provide information on that topic."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display_summary(\"https://cnn.com\")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "75e9fd40-b354-4341-991e-863ef2e59db7",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Website Summary: Anthropic\n",
"## Overview\n",
"\n",
"Anthropic is an AI safety and research company based in San Francisco. Their interdisciplinary team has experience across ML, physics, policy, and product.\n",
"\n",
"### News and Announcements\n",
"\n",
"* **Claude 3.5 Sonnet** is now available, featuring the most intelligent AI model.\n",
"* **Announcement**: Introducing computer use, a new Claude 3.5 Sonnet, and Claude 3.5 Haiku (October 22, 2024)\n",
"* **Research Update**: Constitutional AI: Harmlessness from AI Feedback (December 15, 2022) and Core Views on AI Safety: When, Why, What, and How (March 8, 2023)\n",
"\n",
"### Products and Services\n",
"\n",
"* Claude for Enterprise\n",
"* Research and development of AI systems with a focus on safety and reliability.\n",
"\n",
"### Company Information\n",
"\n",
"* Founded in San Francisco\n",
"* Interdisciplinary team with experience across ML, physics, policy, and product.\n",
"* Provides reliable and beneficial AI systems."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display_summary(\"https://anthropic.com\")"
]
},
{
"cell_type": "markdown",
"id": "eeab24dc-5f90-4570-b542-b0585aca3eb6",
"metadata": {},
"source": [
"# Sharing your code\n",
"\n",
"I'd love it if you share your code afterwards so I can share it with others! You'll notice that some students have already made changes (including a Selenium implementation) which you will find in the community-contributions folder. If you'd like add your changes to that folder, submit a Pull Request with your new versions in that folder and I'll merge your changes.\n",
"\n",
"If you're not an expert with git (and I am not!) then GPT has given some nice instructions on how to submit a Pull Request. It's a bit of an involved process, but once you've done it once it's pretty clear. As a pro-tip: it's best if you clear the outputs of your Jupyter notebooks (Edit >> Clean outputs of all cells, and then Save) for clean notebooks.\n",
"\n",
"PR instructions courtesy of an AI friend: https://chatgpt.com/share/670145d5-e8a8-8012-8f93-39ee4e248b4c"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "682eff74-55c4-4d4b-b267-703edbc293c7",
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

176
week1/solutions/week1 SOLUTION.ipynb

@ -0,0 +1,176 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "fe12c203-e6a6-452c-a655-afb8a03a4ff5",
"metadata": {},
"source": [
"# End of week 1 solution\n",
"\n",
"To demonstrate your familiarity with OpenAI API, and also Ollama, build a tool that takes a technical question, \n",
"and responds with an explanation. This is a tool that you will be able to use yourself during the course!\n",
"\n",
"After week 2 you'll be able to add a User Interface to this tool, giving you a valuable application."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c1070317-3ed9-4659-abe3-828943230e03",
"metadata": {},
"outputs": [],
"source": [
"# imports\n",
"\n",
"from dotenv import load_dotenv\n",
"from IPython.display import Markdown, display, update_display\n",
"from openai import OpenAI\n",
"import ollama"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4a456906-915a-4bfd-bb9d-57e505c5093f",
"metadata": {},
"outputs": [],
"source": [
"# constants\n",
"\n",
"MODEL_GPT = 'gpt-4o-mini'\n",
"MODEL_LLAMA = 'llama3.2'"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a8d7923c-5f28-4c30-8556-342d7c8497c1",
"metadata": {},
"outputs": [],
"source": [
"# set up environment\n",
"\n",
"load_dotenv()\n",
"openai = OpenAI()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3f0d0137-52b0-47a8-81a8-11a90a010798",
"metadata": {},
"outputs": [],
"source": [
"# here is the question; type over this to ask something new\n",
"\n",
"question = \"\"\"\n",
"Please explain what this code does and why:\n",
"yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8595807b-8ae2-4e1b-95d9-e8532142e8bb",
"metadata": {},
"outputs": [],
"source": [
"# prompts\n",
"\n",
"system_prompt = \"You are a helpful technical tutor who answers questions about python code, software engineering, data science and LLMs\"\n",
"user_prompt = \"Please give a detailed explanation to the following question: \" + question"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9605cbb6-3d3f-4969-b420-7f4cae0b9328",
"metadata": {},
"outputs": [],
"source": [
"# messages\n",
"\n",
"messages = [\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60ce7000-a4a5-4cce-a261-e75ef45063b4",
"metadata": {},
"outputs": [],
"source": [
"# Get gpt-4o-mini to answer, with streaming\n",
"\n",
"stream = openai.chat.completions.create(model=MODEL_GPT, messages=messages,stream=True)\n",
" \n",
"response = \"\"\n",
"display_handle = display(Markdown(\"\"), display_id=True)\n",
"for chunk in stream:\n",
" response += chunk.choices[0].delta.content or ''\n",
" response = response.replace(\"```\",\"\").replace(\"markdown\", \"\")\n",
" update_display(Markdown(response), display_id=display_handle.display_id)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f7c8ea8-4082-4ad0-8751-3301adcf6538",
"metadata": {},
"outputs": [],
"source": [
"# Get Llama 3.2 to answer\n",
"\n",
"response = ollama.chat(model=MODEL_LLAMA, messages=messages)\n",
"reply = response['message']['content']\n",
"display(Markdown(reply))"
]
},
{
"cell_type": "markdown",
"id": "7e14bcdb-b928-4b14-961e-9f7d8c7335bf",
"metadata": {},
"source": [
"# Congratulations!\n",
"\n",
"You could make it better by taking in the question using \n",
"`my_question = input(\"Please enter your question:\")`\n",
"\n",
"And then creating the prompts and making the calls interactively."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "da663d73-dd2a-4fff-84df-2209cf2b330b",
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

20
week1/troubleshooting.ipynb

@ -23,11 +23,18 @@
"\n",
"Try running the next cell (click in the cell under this one and hit shift+return).\n",
"\n",
"If this doesn't work, then you're likely not running in an \"activated\" environment. Please check back in the [README](../README.md) for setting up the Anaconda (or virtualenv) environment and activating it, before running `jupyter lab`.\n",
"If this gives an error, then you're likely not running in an \"activated\" environment. Please check back in Part 5 of the SETUP guide for [PC](../SETUP-PC.md) or [Mac](../SETUP-mac.md) for setting up the Anaconda (or virtualenv) environment and activating it, before running `jupyter lab`.\n",
"\n",
"If you look in the Anaconda window (on PC) or the Terminal window (on Mac), you should see `(llms)` in your prompt where you launch `jupyter lab` - that's your clue that the llms environment is activated.\n",
"If you look in the Anaconda prompt (PC) or the Terminal (Mac), you should see `(llms)` in your prompt where you launch `jupyter lab` - that's your clue that the llms environment is activated.\n",
"\n",
"You might also need to restart the \"Kernel\" (the python process used to run this notebook). To do that, go to the Kernel menu and select \"Restart Kernel and Clear Outputs Of All Cells..\""
"If you are in an activated environment, the next thing to try is to restart everything:\n",
"1. Close down all Jupyter windows, like this\n",
"2. Exit all command prompts / Terminals / Anaconda\n",
"3. Repeat Part 5 from the SETUP instructions to begin a new activated environment and launch jupyter lab\n",
"4. Kernel menu >> Restart Kernel and Clear Outputs of All Cells\n",
"5. Come back to this notebook and try the cell below again.\n",
"\n",
"If **that** doesn't work, then please contact me! I'll respond quickly, and we'll figure it out."
]
},
{
@ -37,7 +44,8 @@
"metadata": {},
"outputs": [],
"source": [
"# This should run with no output - no import errors:\n",
"# This should run with no output - no import errors.\n",
"# Import errors might indicate that you started jupyter lab without your environment activated? See SETUP part 5.\n",
"\n",
"from openai import OpenAI"
]
@ -200,7 +208,7 @@
"Then there's something up with your API key!\n",
"\n",
"First check this webpage to make sure you have a positive credit balance.\n",
"OpenAI requires that you have a positive credit balance and it has minimums. My salespitch for OpenAI is that this is well worth it for your education: for less than the price of a music album, you will build so much valuable commercial experience. But it's not required for this course at all; you can watch me running OpenAI code, and then wait until we get to open source models in week 3.\n",
"OpenAI requires that you have a positive credit balance and it has minimums. My salespitch for OpenAI is that this is well worth it for your education: for less than the price of a music album, you will build so much valuable commercial experience. But it's not required for this course at all; you can watch me running OpenAI code, and then wait until we get to open source models in week 3. Also, I'll show you how to use Ollama to run open-source models locally.\n",
"\n",
"https://platform.openai.com/settings/organization/billing/overview\n",
"\n",
@ -208,7 +216,7 @@
"\n",
"https://platform.openai.com/api-keys\n",
"\n",
"And note that sometimes OpenAI seems to take a few minutes to give you access after you try.\n",
"Sometimes OpenAI may take a few minutes to give you access after you try.\n",
"\n",
"## If all else fails:\n",
"\n",

104
week1/week1 EXERCISE.ipynb

@ -0,0 +1,104 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "fe12c203-e6a6-452c-a655-afb8a03a4ff5",
"metadata": {},
"source": [
"# End of week 1 exercise\n",
"\n",
"To demonstrate your familiarity with OpenAI API, and also Ollama, build a tool that takes a technical question, \n",
"and responds with an explanation. This is a tool that you will be able to use yourself during the course!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c1070317-3ed9-4659-abe3-828943230e03",
"metadata": {},
"outputs": [],
"source": [
"# imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4a456906-915a-4bfd-bb9d-57e505c5093f",
"metadata": {},
"outputs": [],
"source": [
"# constants\n",
"\n",
"MODEL_GPT = 'gpt-4o-mini'\n",
"MODEL_LLAMA = 'llama3.2'"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a8d7923c-5f28-4c30-8556-342d7c8497c1",
"metadata": {},
"outputs": [],
"source": [
"# set up environment"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3f0d0137-52b0-47a8-81a8-11a90a010798",
"metadata": {},
"outputs": [],
"source": [
"# here is the question; type over this to ask something new\n",
"\n",
"question = \"\"\"\n",
"Please explain what this code does and why:\n",
"yield from {book.get(\"author\") for book in books if book.get(\"author\")}\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60ce7000-a4a5-4cce-a261-e75ef45063b4",
"metadata": {},
"outputs": [],
"source": [
"# Get gpt-4o-mini to answer, with streaming"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f7c8ea8-4082-4ad0-8751-3301adcf6538",
"metadata": {},
"outputs": [],
"source": [
"# Get Llama 3.2 to answer"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

61
week2/day1.ipynb

@ -21,17 +21,15 @@
"source": [
"## Setting up your keys\n",
"\n",
"If you haven't done so already, you'll need to create API keys from OpenAI, Anthropic and Google.\n",
"If you haven't done so already, you could now create API keys for Anthropic and Google in addition to OpenAI.\n",
"\n",
"**Please note:** if you'd prefer to avoid extra API costs, feel free to skip setting up Anthopic and Google! You can see me do it, and focus on OpenAI for the course.\n",
"**Please note:** if you'd prefer to avoid extra API costs, feel free to skip setting up Anthopic and Google! You can see me do it, and focus on OpenAI for the course. You could also substitute Anthropic and/or Google for Ollama, using the exercise you did in week 1.\n",
"\n",
"For OpenAI, visit https://openai.com/api/ \n",
"For Anthropic, visit https://console.anthropic.com/ \n",
"For Google, visit https://ai.google.dev/gemini-api \n",
"\n",
"When you get your API keys, you need to set them as environment variables.\n",
"\n",
"EITHER (recommended) create a file called `.env` in this project root directory, and set your keys there:\n",
"When you get your API keys, you need to set them as environment variables by adding them to your `.env` file.\n",
"\n",
"```\n",
"OPENAI_API_KEY=xxxx\n",
@ -39,9 +37,7 @@
"GOOGLE_API_KEY=xxxx\n",
"```\n",
"\n",
"OR enter the keys directly in the cells below.\n",
"\n",
"You may need to restart the Jupyter Notebook Kernel (the Python process) via the Kernel menu."
"Afterwards, you may need to restart the Jupyter Lab Kernel (the Python process that sits behind this notebook) via the Kernel menu, and then rerun the cells from the top."
]
},
{
@ -56,11 +52,24 @@
"import os\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
"import google.generativeai\n",
"import anthropic\n",
"from IPython.display import Markdown, display, update_display"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f0a8ab2b-6134-4104-a1bc-c3cd7ea4cd36",
"metadata": {},
"outputs": [],
"source": [
"# import for google\n",
"# in rare cases, this seems to give an error on some systems. Please reach out to me if this happens,\n",
"# or you can feel free to skip Gemini - it's the lowest priority of the frontier models that we use\n",
"\n",
"import google.generativeai"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -69,11 +78,27 @@
"outputs": [],
"source": [
"# Load environment variables in a file called .env\n",
"# Print the key prefixes to help with any debugging\n",
"\n",
"load_dotenv()\n",
"os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
"os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY', 'your-key-if-not-using-env')\n",
"os.environ['GOOGLE_API_KEY'] = os.getenv('GOOGLE_API_KEY', 'your-key-if-not-using-env')"
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
"\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"if anthropic_api_key:\n",
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
"else:\n",
" print(\"Anthropic API Key not set\")\n",
"\n",
"if google_api_key:\n",
" print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
"else:\n",
" print(\"Google API Key not set\")"
]
},
{
@ -447,7 +472,17 @@
"source": [
"# See the community-contributions folder\n",
"\n",
"For a great variation with a 3-way bringing Gemini into the conversation!"
"For a great variation with a 3-way bringing Gemini into the conversation!\n",
"\n",
"Try doing this yourself before you look in the folder.\n",
"\n",
"## Additional exercise\n",
"\n",
"Try adding in an Ollama model in to the conversation.\n",
"\n",
"## Business relevance\n",
"\n",
"This structure of a conversation, as a list of messages, is fundamental to the way we build conversational AI assistants and how they are able to keep the context during a conversation. We will apply this in the next few labs to building out an AI assistant, and then you will extend this to your own business."
]
},
{

28
week2/day2.ipynb

@ -9,7 +9,9 @@
"\n",
"Today we will build User Interfaces using the outrageously simple Gradio framework.\n",
"\n",
"Prepare for joy!"
"Prepare for joy!\n",
"\n",
"Please note: your Gradio screens may appear in 'dark mode' or 'light mode' depending on your computer settings."
]
},
{
@ -49,11 +51,27 @@
"outputs": [],
"source": [
"# Load environment variables in a file called .env\n",
"# Print the key prefixes to help with any debugging\n",
"\n",
"load_dotenv()\n",
"os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
"os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY', 'your-key-if-not-using-env')\n",
"os.environ['GOOGLE_API_KEY'] = os.getenv('GOOGLE_API_KEY', 'your-key-if-not-using-env')"
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
"\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"if anthropic_api_key:\n",
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
"else:\n",
" print(\"Anthropic API Key not set\")\n",
"\n",
"if google_api_key:\n",
" print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
"else:\n",
" print(\"Google API Key not set\")"
]
},
{
@ -63,7 +81,7 @@
"metadata": {},
"outputs": [],
"source": [
"# Connect to OpenAI, Anthropic and Google\n",
"# Connect to OpenAI, Anthropic and Google; comment out the Claude or Google lines if you're not using them\n",
"\n",
"openai = OpenAI()\n",
"\n",

26
week2/day3.ipynb

@ -31,11 +31,27 @@
"outputs": [],
"source": [
"# Load environment variables in a file called .env\n",
"# Print the key prefixes to help with any debugging\n",
"\n",
"load_dotenv()\n",
"os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
"os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY', 'your-key-if-not-using-env')\n",
"os.environ['GOOGLE_API_KEY'] = os.getenv('GOOGLE_API_KEY', 'your-key-if-not-using-env')"
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
"\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"if anthropic_api_key:\n",
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
"else:\n",
" print(\"Anthropic API Key not set\")\n",
"\n",
"if google_api_key:\n",
" print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
"else:\n",
" print(\"Google API Key not set\")"
]
},
{
@ -72,7 +88,7 @@
"\n",
"`chat(message, history)`\n",
"\n",
"Which expects to receive `history` in a particular format, which we need to map to the OpenAO format before we call OpenAI:\n",
"Which expects to receive `history` in a particular format, which we need to map to the OpenAI format before we call OpenAI:\n",
"\n",
"```\n",
"[\n",
@ -102,7 +118,7 @@
"outputs": [],
"source": [
"# Simpler than in my video - we can easily create this function that calls OpenAI\n",
"# It's just 1 line of code to prepare the input to OpenAI!\n",
"# It's now just 1 line of code to prepare the input to OpenAI!\n",
"\n",
"def chat(message, history):\n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",

8
week2/day4.ipynb

@ -36,7 +36,13 @@
"# Initialization\n",
"\n",
"load_dotenv()\n",
"os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
"\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"MODEL = \"gpt-4o-mini\"\n",
"openai = OpenAI()"
]

14
week2/day5.ipynb

@ -36,7 +36,13 @@
"# Initialization\n",
"\n",
"load_dotenv()\n",
"os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')\n",
"\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"MODEL = \"gpt-4o-mini\"\n",
"openai = OpenAI()"
]
@ -362,7 +368,7 @@
"\n",
"This version should work fine for you. It might work for Windows users too, but you might get a Permissions error writing to a temp file. If so, see the next section!\n",
"\n",
"As always, if you have problems, please contact me! (You could also comment out the audio talker() in the later code if you're less interested in audio generation - "
"As always, if you have problems, please contact me! (You could also comment out the audio talker() in the later code if you're less interested in audio generation)"
]
},
{
@ -431,7 +437,7 @@
" temp_path = os.path.join(temp_dir, \"temp_audio.wav\")\n",
" try:\n",
" audio_segment.export(temp_path, format=\"wav\")\n",
" time.sleep(3) # Dominic found that this was needed. You could also try commenting out to see if not needed on your PC\n",
" time.sleep(3) # Student Dominic found that this was needed. You could also try commenting out to see if not needed on your PC\n",
" subprocess.call([\n",
" \"ffplay\",\n",
" \"-nodisp\",\n",
@ -657,7 +663,7 @@
"id": "226643d2-73e4-4252-935d-86b8019e278a",
"metadata": {},
"source": [
"# Business Applications\n",
"# Exercises and Business Applications\n",
"\n",
"Add in more tools - perhaps to simulate actually booking a flight. A student has done this and provided their example in the community contributions folder.\n",
"\n",

4
week3/day1.ipynb

@ -7,6 +7,10 @@
"source": [
"# Introducing Colab\n",
"\n",
"Learn about Google Colab and set up a Google account (if you don't already have one) [here](https://colab.research.google.com/)\n",
"\n",
"You should be able to use the free tier or minimal spend to complete all the projects in the class. I personally signed up for Colab Pro+ and I'm loving it - but it's not required.\n",
"\n",
"To see some of what Colab can do, please follow the link below!\n",
"\n",
"https://colab.research.google.com/drive/1DjcrYDZldAXKJ08x1uYIVCtItoLPk1Wr?usp=sharing"

8
week5/day1.ipynb

@ -199,11 +199,7 @@
"outputs": [],
"source": [
"def chat(message, history):\n",
" messages = [{\"role\": \"system\", \"content\": system_message}]\n",
" for user_message, assistant_message in history:\n",
" messages.append({\"role\": \"user\", \"content\": user_message})\n",
" messages.append({\"role\": \"assistant\", \"content\": assistant_message})\n",
" \n",
" messages = [{\"role\": \"system\", \"content\": system_message}] + history\n",
" message = add_context(message)\n",
" messages.append({\"role\": \"user\", \"content\": message})\n",
"\n",
@ -232,7 +228,7 @@
"metadata": {},
"outputs": [],
"source": [
"view = gr.ChatInterface(chat).launch()"
"view = gr.ChatInterface(chat, type=\"messages\").launch()"
]
},
{

17
week5/day3.ipynb

@ -101,6 +101,23 @@
" documents.append(doc)"
]
},
{
"cell_type": "markdown",
"id": "f065d4b1-80b7-4e15-abd4-60a83e752ea8",
"metadata": {},
"source": [
"# Please note:\n",
"\n",
"In the next cell, we split the text into chunks.\n",
"\n",
"2 students let me know that the next cell crashed their computer. \n",
"They were able to fix it by changing the chunk_size from 1,000 to 2,000 and the chunk_overlap from 200 to 400. \n",
"This shouldn't be required; but if it happens to you, please make that change! \n",
"(Note that LangChain may give a warning about a chunk being larger than 1,000 - this can be safely ignored).\n",
"\n",
"_With much thanks to Steven W and Nir P for this valuable contribution._"
]
},
{
"cell_type": "code",
"execution_count": null,

20
week5/day4.ipynb

@ -313,7 +313,7 @@
"# the retriever is an abstraction over the VectorStore that will be used during RAG\n",
"retriever = vectorstore.as_retriever()\n",
"\n",
"# putting it together: set up the conversation chain with the GPT 3.5 LLM, the vector store and memory\n",
"# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n",
"conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)"
]
},
@ -329,6 +329,20 @@
"print(result[\"answer\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e6eb99fb-33ec-4025-ab92-b634ede03647",
"metadata": {},
"outputs": [],
"source": [
"# set up a new conversation memory for the chat\n",
"memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n",
"\n",
"# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n",
"conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)"
]
},
{
"cell_type": "markdown",
"id": "bbbcb659-13ce-47ab-8a5e-01b930494964",
@ -346,7 +360,7 @@
"metadata": {},
"outputs": [],
"source": [
"# Wrapping that in a function\n",
"# Wrapping in a function - note that history isn't used, as the memory is in the conversation_chain\n",
"\n",
"def chat(message, history):\n",
" result = conversation_chain.invoke({\"question\": message})\n",
@ -362,7 +376,7 @@
"source": [
"# And in Gradio:\n",
"\n",
"view = gr.ChatInterface(chat).launch()"
"view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)"
]
},
{

16
week5/day5.ipynb

@ -313,6 +313,20 @@
"print(result[\"answer\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5b5a9013-d5d4-4e25-9e7c-cdbb4f33e319",
"metadata": {},
"outputs": [],
"source": [
"# set up a new conversation memory for the chat\n",
"memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)\n",
"\n",
"# putting it together: set up the conversation chain with the GPT 4o-mini LLM, the vector store and memory\n",
"conversation_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, memory=memory)"
]
},
{
"cell_type": "markdown",
"id": "bbbcb659-13ce-47ab-8a5e-01b930494964",
@ -346,7 +360,7 @@
"source": [
"# And in Gradio:\n",
"\n",
"view = gr.ChatInterface(chat).launch()"
"view = gr.ChatInterface(chat, type=\"messages\").launch(inbrowser=True)"
]
},
{

17
week6/day1.ipynb

@ -259,7 +259,22 @@
"\n",
"And will create a prompt to be used during Training.\n",
"\n",
"Items will be rejected if they don't have sufficient characters."
"Items will be rejected if they don't have sufficient characters.\n",
"\n",
"## But why 180 tokens??\n",
"\n",
"A student asked me a great question - why are we truncating to 180 tokens? How did we determine that number? (Thank you Moataz A. for the excellent question).\n",
"\n",
"The answer: this is an example of a \"hyper-parameter\". In other words, it's basically trial and error! We want a sufficiently large number of tokens so that we have enough useful information to gauge the price. But we also want to keep the number low so that we can train efficiently. You'll see this in action in Week 7.\n",
"\n",
"I started with a number that seemed reasonable, and experimented with a few variations before settling on 180. If you have time, you should do the same! You might find that you can beat my results by finding a better balance. This kind of trial-and-error might sound a bit unsatisfactory, but it's a crucial part of the data science R&D process.\n",
"\n",
"There's another interesting reason why we might favor a lower number of tokens in the training data. When we eventually get to use our model at inference time, we'll want to provide new products and have it estimate a price. And we'll be using short descriptions of products - like 1-2 sentences. For best performance, we should size our training data to be similar to the inputs we will provide at inference time.\n",
"\n",
"## But I see in items.py it constrains inputs to 160 tokens?\n",
"\n",
"Another great question from Moataz A.! The description of the products is limited to 160 tokens because we add some more text before and after the description to turn it into a prompt. That brings it to around 180 tokens in total.\n",
"\n"
]
},
{

2
week6/day3.ipynb

@ -155,8 +155,6 @@
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"with open('train.pkl', 'rb') as file:\n",
" train = pickle.load(file)\n",
"\n",

71
week6/day5.ipynb

@ -529,77 +529,6 @@
"source": [
"Tester.test(gpt_fine_tuned, test)"
]
},
{
"cell_type": "code",
"execution_count": 320,
"id": "03ff4b48-3788-4370-9e34-6592f23d1bce",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"DNS resolution for api.gradio.app: 54.68.118.249\n",
"Gradio API Status: 500\n",
"Gradio API Response: Internal Server Error\n",
"HuggingFace CDN Status: 403\n"
]
}
],
"source": [
"import requests\n",
"import socket\n",
"\n",
"def check_connectivity():\n",
" try:\n",
" # Check DNS resolution\n",
" ip = socket.gethostbyname('api.gradio.app')\n",
" print(f\"DNS resolution for api.gradio.app: {ip}\")\n",
"\n",
" # Check connection to Gradio API\n",
" response = requests.get(\"https://api.gradio.app/v2/tunnel/\", timeout=5)\n",
" print(f\"Gradio API Status: {response.status_code}\")\n",
" print(f\"Gradio API Response: {response.text}\")\n",
"\n",
" # Check connection to HuggingFace CDN\n",
" cdn_response = requests.get(\"https://cdn-media.huggingface.co/frpc-gradio-0.2/frpc_linux_aarch64\", timeout=5)\n",
" print(f\"HuggingFace CDN Status: {cdn_response.status_code}\")\n",
" except Exception as e:\n",
" print(f\"Error in connectivity check: {e}\")\n",
"\n",
"check_connectivity()"
]
},
{
"cell_type": "code",
"execution_count": 323,
"id": "f7d4eec4-da5e-4fbf-ba3e-fbbcfb399d6c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'4.44.0'"
]
},
"execution_count": 323,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import gradio\n",
"gradio.__version__"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cad08a54-912b-43d2-9280-f00b5a7775a6",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {

6
week6/items.py

@ -3,8 +3,10 @@ from transformers import AutoTokenizer
import re
BASE_MODEL = "meta-llama/Meta-Llama-3.1-8B"
MIN_TOKENS = 150
MAX_TOKENS = 160
MIN_TOKENS = 150 # Any less than this, and we don't have enough useful content
MAX_TOKENS = 160 # Truncate after this many tokens. Then after adding in prompt text, we will get to around 180 tokens
MIN_CHARS = 300
CEILING_CHARS = MAX_TOKENS * 7

20
week8/day1.ipynb

@ -31,6 +31,21 @@
"import modal"
]
},
{
"cell_type": "markdown",
"id": "ab5c8533-9f66-448f-b9b2-133d1ff50639",
"metadata": {},
"source": [
"# Setting up the modal tokens\n",
"\n",
"The first time you run this, please uncomment the next line and execute it. \n",
"This is the same as running `modal setup` from the command line. It connects with Modal and installs your tokens.\n",
"\n",
"A student on Windows mentioned that on Windows, you might also need to run this command from a command prompt afterwards: \n",
"`modal token new` \n",
"(Thank you Ed B. for that!)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -38,6 +53,7 @@
"metadata": {},
"outputs": [],
"source": [
"# Remove the '# ' from the next line and run the cell\n",
"# !modal setup"
]
},
@ -86,7 +102,7 @@
"\n",
"1. Go to modal.com, sign in and go to your dashboard\n",
"2. Click on Secrets in the nav bar\n",
"3. Create new secret, click on Hugging Face\n",
"3. Create new secret, click on Hugging Face, this new secret needs to be called **hf-secret** because that's how we refer to it in the code\n",
"4. Fill in your HF_TOKEN where it prompts you\n",
"\n",
"### And now back to business: time to work with Llama"
@ -219,7 +235,7 @@
"\n",
"I've added a utility called `keep_warm.py` that will keep our Modal warm by pinging it every 30 seconds.\n",
"\n",
"To use the utliity, bring up a new Terminal (Mac) or Anaconda prompt (Windows), ensure the environment is activated with `conda activate llms\\\n",
"To use the utliity, bring up a new Terminal (Mac) or Anaconda prompt (Windows), ensure the environment is activated with `conda activate llms`\n",
"\n",
"Then run: `python keep_warm.py` from within the week8 drectory.\n",
"\n",

12
week8/day2.1.ipynb

@ -59,7 +59,7 @@
"# It is very fun turning this up to 400_000 and seeing the full dataset visualized,\n",
"# but it almost crashes my box every time so do that at your own risk!! 10_000 is safe!\n",
"\n",
"MAXIMUM_DATAPOINTS = 10_000"
"MAXIMUM_DATAPOINTS = 30_000"
]
},
{
@ -135,7 +135,7 @@
" x=reduced_vectors[:, 0],\n",
" y=reduced_vectors[:, 1],\n",
" mode='markers',\n",
" marker=dict(size=2, color=colors, opacity=0.7),\n",
" marker=dict(size=3, color=colors, opacity=0.7),\n",
")])\n",
"\n",
"fig.update_layout(\n",
@ -148,6 +148,14 @@
"\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5e4ae088-3d29-45d3-87a2-fea805fe2c65",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {

2
week8/day2.2.ipynb

@ -58,7 +58,7 @@
"source": [
"# Turn this up at your own risk! 10_000 is safe..\n",
"\n",
"MAXIMUM_DATAPOINTS = 10_000"
"MAXIMUM_DATAPOINTS = 20_000"
]
},
{

Loading…
Cancel
Save