Christopher Capobianco commited on
Commit
d8d58f7
1 Parent(s): 7234ab5

Add project pages and move intro page

Browse files
Home.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+
4
+ # Page title
5
+ st.title("Chris Capobianco's ML Portfolio")
6
+
7
+ st.markdown('Hello, welcome to my ML portfolio.')
8
+ st.markdown('Please have a look at the descriptions below, and select a project from the sidebar.')
9
+
10
+ st.header('Projects', divider='red')
11
+
12
+ mv = Image.open("assets/movie.jpg")
13
+ # wp = Image.open("assets/weather.png")
14
+ sm = Image.open("assets/stock-market.png")
15
+ mu = Image.open("assets/music.jpg")
16
+ llm = Image.open("assets/llm.png")
17
+
18
+ with st.container():
19
+ text_column, image_column = st.columns((3,1))
20
+ with text_column:
21
+ st.subheader("Movie Recommendation", divider="green")
22
+ st.markdown("""
23
+ - Created a content based recommendation system using cosine similarity
24
+ - Trained on almost 5k movies and credits from the TMDB dataset available at Kaggle
25
+ """)
26
+ with image_column:
27
+ st.image(mv)
28
+
29
+ # with st.container():
30
+ # text_column, image_column = st.columns((3,1))
31
+ # with text_column:
32
+ # st.subheader("Weather Classification", divider="green")
33
+ # st.markdown("""
34
+ # - Created a Random Forest classification model to predict the weather
35
+ # - Trained on three years of data for the city of Seattle, Washington
36
+ # """)
37
+ # with image_column:
38
+ # st.image(wp)
39
+
40
+ with st.container():
41
+ text_column, image_column = st.columns((3,1))
42
+ with text_column:
43
+ st.subheader("Stock Market Forecast", divider="green")
44
+ st.markdown("""
45
+ - Created a two layer GRU model to forecast of stock prices
46
+ - Trained on 2006-2018 closing prices of four well known stocks
47
+ """)
48
+ with image_column:
49
+ st.image(sm)
50
+
51
+ with st.container():
52
+ text_column, image_column = st.columns((3,1))
53
+ with text_column:
54
+ st.subheader("Generative Music", divider="green")
55
+ st.markdown("""
56
+ - Created a LSTM model to generate music
57
+ - Trained on MIDI files from Final Fantasy series
58
+ """)
59
+ with image_column:
60
+ st.image(mu)
61
+
62
+ with st.container():
63
+ text_column, image_column = st.columns((3,1))
64
+ with text_column:
65
+ st.subheader("Fine Tuned LLM", divider="green")
66
+ st.warning("**Work In Progress**")
67
+ st.markdown("""
68
+ - Fine tuned a LLM to act like math assistant
69
+ - The base model is Meta's Llama 3.1 (8B) Instruct
70
+ """)
71
+ with image_column:
72
+ st.image(llm)
app.py CHANGED
@@ -1,72 +1,29 @@
1
  import streamlit as st
2
- from PIL import Image
3
 
4
  # Page title
5
- st.title("Chris Capobianco's ML Portfolio")
6
-
7
- st.markdown('Hello, welcome to my ML portfolio.')
8
- st.markdown('Please have a look at the descriptions below, and select a project from the sidebar.')
9
-
10
- st.header('Projects', divider='red')
11
-
12
- mv = Image.open("assets/movie.jpg")
13
- # wp = Image.open("assets/weather.png")
14
- sm = Image.open("assets/stock-market.png")
15
- mu = Image.open("assets/music.jpg")
16
- llm = Image.open("assets/llm.png")
17
-
18
- with st.container():
19
- text_column, image_column = st.columns((3,1))
20
- with text_column:
21
- st.subheader("Movie Recommendation", divider="green")
22
- st.markdown("""
23
- - Created a content based recommendation system using cosine similarity
24
- - Trained on almost 5k movies and credits from the TMDB dataset available at Kaggle
25
- """)
26
- with image_column:
27
- st.image(mv)
28
-
29
- # with st.container():
30
- # text_column, image_column = st.columns((3,1))
31
- # with text_column:
32
- # st.subheader("Weather Classification", divider="green")
33
- # st.markdown("""
34
- # - Created a Random Forest classification model to predict the weather
35
- # - Trained on three years of data for the city of Seattle, Washington
36
- # """)
37
- # with image_column:
38
- # st.image(wp)
39
-
40
- with st.container():
41
- text_column, image_column = st.columns((3,1))
42
- with text_column:
43
- st.subheader("Stock Market Forecast", divider="green")
44
- st.markdown("""
45
- - Created a two layer GRU model to forecast of stock prices
46
- - Trained on 2006-2018 closing prices of four well known stocks
47
- """)
48
- with image_column:
49
- st.image(sm)
50
-
51
- with st.container():
52
- text_column, image_column = st.columns((3,1))
53
- with text_column:
54
- st.subheader("Generative Music", divider="green")
55
- st.markdown("""
56
- - Created a LSTM model to generate music
57
- - Trained on MIDI files from Final Fantasy series
58
- """)
59
- with image_column:
60
- st.image(mu)
61
-
62
- with st.container():
63
- text_column, image_column = st.columns((3,1))
64
- with text_column:
65
- st.subheader("Fine Tuned LLM", divider="green")
66
- st.warning("**Work In Progress**")
67
- st.markdown("""
68
- - Fine tuned a LLM to act like math assistant
69
- - The base model is Meta's Llama 3.1 (8B) Instruct
70
- """)
71
- with image_column:
72
- st.image(llm)
 
1
  import streamlit as st
 
2
 
3
  # Page title
4
+ st.set_page_config(page_title="Chris Capobianco's Profile", page_icon=':rocket:', layout='wide')
5
+
6
+ home = st.Page('Intro.py', title = 'Home')
7
+
8
+ movie_recommendation = st.Page('projects/02_Movie_Recommendation.py', title='Movie Recommendation')
9
+ # weather_classification = st.Page('projects/04_Weather_Classification.py', title='Weather Classification')
10
+ stock_market = st.Page('projects/05_Stock_Market.py', title='Stock Market Forecast')
11
+ generative_music = st.Page('projects/06_Generative_Music.py', title='Generative Music')
12
+ llm_fine_tune = st.Page('projects/07_LLM_Fine_Tuned.py', title='Fine Tuned LLM')
13
+
14
+ pg = st.navigation(
15
+ {
16
+ 'Home': [
17
+ home
18
+ ],
19
+ 'Projects': [
20
+ movie_recommendation,
21
+ # weather_classification,
22
+ stock_market,
23
+ generative_music,
24
+ llm_fine_tune
25
+ ]
26
+ }
27
+ )
28
+
29
+ pg.run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
projects/02_Movie_Recommendation.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pickle
3
+
4
+ st.header('Movie Recommendation', divider='green')
5
+
6
+ @st.cache_resource
7
+ def load_model():
8
+ model_file = open('./models/movie_recommendation_model.pkl', 'rb')
9
+ movies_df = pickle.load(model_file)
10
+ cosine_sim = pickle.load(model_file)
11
+ indices = pickle.load(model_file)
12
+ model_file.close()
13
+ return movies_df, cosine_sim, indices
14
+
15
+ # Load the Model
16
+ movies_df, cosine_sim, indices = load_model()
17
+
18
+ @st.cache_data
19
+ def get_recommendations(title, cosine_sim = cosine_sim):
20
+ if title in indices:
21
+ idx = indices[title]
22
+ else:
23
+ print(f"Unable to find a matching movie title: {title}")
24
+ return []
25
+ similarity_scores = list(enumerate(cosine_sim[idx]))
26
+ similarity_scores = sorted(similarity_scores, key = lambda x: x[1], reverse = True)
27
+ similarity_scores = similarity_scores[1:11]
28
+ # (a, b) where a is id of movie, b is similarity_scores
29
+ movies_indices = [ind[0] for ind in similarity_scores]
30
+ movies = movies_df["title"].iloc[movies_indices]
31
+ return movies
32
+
33
+ # Get movie recommendations
34
+ st.markdown("#### What is a Recommendation System?")
35
+ st.markdown("Recommendation systems suggest recommendations to users depending on a variety of criteria.")
36
+ st.markdown('''There are 3 types of recommendation systems:
37
+ 1. Demographic Filtering: The recommendations are the same for every user. They are generalized, not personalized. These types of systems are behind sections like *Top Trending*.
38
+ 2. Content-based Filtering: These suggest recommendations based on the item metadata (movie, product, song, etc). Here, the main idea is if a user likes an item, then the user will also like items similar to it.
39
+ 3. Collaboration-based Filtering: These systems make recommendations by grouping the users with similar interests. For this system, metadata of the item is not required.
40
+ ''')
41
+ st.markdown("In this project, we are building a **Content-based** recommendation engine for movies titles.")
42
+ tmdb_data_url = "https://www.kaggle.com/datasets/tmdb/tmdb-movie-metadata"
43
+ st.markdown("To build this recommendation system, we will be using almost 5k movies and credits from the TMDB dataset available at [Kaggle](%s)" % tmdb_data_url)
44
+
45
+ st.divider()
46
+
47
+ st.markdown("Enter the title of a movie to see a list of 10 recommendations (e.g. The Dark Knight Rises, The Avengers, etc)")
48
+ title = st.text_input("Movie Title")
49
+ if title != "":
50
+ movies = get_recommendations(title)
51
+ if len(movies) > 0:
52
+ output = ''
53
+ count = 1
54
+ for m in movies:
55
+ output += f"{count}. {m}\n"
56
+ count += 1
57
+ st.markdown(output)
58
+ else:
59
+ st.warning(f"Unable to find a movie matching title: {title}")
projects/04_Weather_Classification.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import pickle
4
+ import sklearn
5
+ from PIL import Image
6
+
7
+ @st.cache_resource
8
+ def load_model():
9
+ model_file = open('./models/weather_prediction_model.pkl', 'rb')
10
+ rfc = pickle.load(model_file)
11
+ oe = pickle.load(model_file)
12
+ sc = pickle.load(model_file)
13
+ images = pickle.load(model_file)
14
+ model_file.close()
15
+ return rfc, oe, sc, images
16
+
17
+ @st.cache_data
18
+ def load_icons():
19
+ dz = Image.open("assets/drizzle.png")
20
+ rn = Image.open("assets/rain.png")
21
+ sn = Image.open("assets/sun.png")
22
+ sw = Image.open("assets/snow.png")
23
+ fg = Image.open("assets/fog.png")
24
+ return dz, rn, sn, sw, fg
25
+
26
+ @st.cache_data
27
+ def get_prediction(input):
28
+ if len(input) != 4:
29
+ return None
30
+ input = pd.DataFrame([input], columns = ['precipitation', 'temp_max', 'temp_min', 'wind'])
31
+ X_predict = sc.transform(input)
32
+ y_predict = [rfc.predict(X_predict)]
33
+ weather_predict = oe.inverse_transform(y_predict)[0]
34
+ return weather_predict[0]
35
+
36
+ # Load the Model
37
+ rfc, oe, sc, images = load_model()
38
+
39
+ # Load the Icons
40
+ dz, rn, sn, sw, fg = load_icons()
41
+
42
+ st.header('Weather Classification', divider='green')
43
+
44
+ st.markdown("Change the sliders below to see the classification")
45
+
46
+ # Get input parameters
47
+ precipitation = st.slider('Precipitation (mm)', 0.0, 100.0, 0.0, 1.0)
48
+ temp_min = st.slider('Minimum Temperature (C)', -10.0, 20.0, 8.0, 1.0)
49
+ temp_max = st.slider('Maximum Temperature (C)', -2.0, 40.0, 15.0, 1.0)
50
+ wind = st.slider('Wind Speed (m/s)', 0.0, 10.0, 3.0, 1.0)
51
+
52
+ # Get weather prediction
53
+ weather = get_prediction([precipitation, temp_min, temp_max, wind])
54
+ if weather == None:
55
+ st.warning("Unknown Weather Classification")
56
+ else:
57
+ icon = Image.open(images[weather])
58
+
59
+ st.info("Weather Classification:")
60
+ st.image(icon, caption = weather, width = 250)
projects/05_Stock_Market.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pickle
3
+ import plotly.graph_objects as go
4
+ from PIL import Image
5
+
6
+ @st.cache_resource
7
+ def load_model():
8
+ model_file = open('./models/stock_market_model.pkl', 'rb')
9
+ amazon_predictions = pickle.load(model_file)
10
+ amazon_scores = pickle.load(model_file)
11
+ google_predictions = pickle.load(model_file)
12
+ google_scores = pickle.load(model_file)
13
+ ibm_predictions = pickle.load(model_file)
14
+ ibm_scores = pickle.load(model_file)
15
+ microsoft_predictions = pickle.load(model_file)
16
+ microsoft_scores = pickle.load(model_file)
17
+ model_file.close()
18
+ return amazon_predictions, amazon_scores, google_predictions, google_scores, ibm_predictions, ibm_scores, microsoft_predictions, microsoft_scores
19
+
20
+ # Load Image
21
+ gru = Image.open("assets/gru.png")
22
+ nn = Image.open("assets/nn.png")
23
+
24
+ # Load the Model
25
+ amazon_predictions, amazon_scores, google_predictions, google_scores, ibm_predictions, ibm_scores, microsoft_predictions, microsoft_scores = load_model()
26
+
27
+ st.header('Stock Market Forecast', divider='green')
28
+
29
+ st.markdown("#### Time Series Forecasting")
30
+ st.markdown("Time series forecasting uses information regarding historical values and associated patterns to predict future activity. Most often, this relates to trend analysis, cyclical fluctuation analysis, and issues of seasonality. As with all forecasting methods, success is not guaranteed.")
31
+
32
+ st.markdown("#### GRU Model")
33
+ st.markdown("Gated recurrent unit is essentially a simplified LSTM. It has the exact same role in the network. The main difference is in the number of gates and weights — GRU is somewhat simpler. It has 2 gates. Since it does not have an output gate, there is no control over the memory content. The update gate controls the information flow from the previous activation, and the addition of new information as well, while the reset gate is inserted into the candidate activation.")
34
+
35
+ st.image(gru, caption = "Gated Recurrent Unit (GRU)")
36
+
37
+ st.markdown("Below are the analyses of four stocks using a GRU-based model: *Amazon*, *Google*, *IBM* and *Microsoft*")
38
+ st.markdown("The model consists of the following: A single input and output dimension (i.e. Closing Price) and two hidden layers, with 32 GRU nodes per layer. These models were trained for 105 epochs each.")
39
+ st.image(nn, caption = "GRU-based Model")
40
+
41
+ st.divider()
42
+
43
+ st.markdown("Below each graph is the mean square error (MSE) for the train and test sets, where the test set consists of the last 20 days.")
44
+
45
+ fig1 = go.Figure()
46
+ fig1.add_trace(go.Scatter(go.Scatter(x=amazon_predictions['Date'], y=amazon_predictions['Train Prediction'],
47
+ mode='lines',
48
+ name='Train Prediction')))
49
+ fig1.add_trace(go.Scatter(x=amazon_predictions['Date'], y=amazon_predictions['Test Prediction'],
50
+ mode='lines',
51
+ name='Test Prediction'))
52
+ fig1.add_trace(go.Scatter(go.Scatter(x=amazon_predictions['Date'], y=amazon_predictions['Actual Value'],
53
+ mode='lines',
54
+ name='Actual Value')))
55
+ fig1.update_layout(
56
+ title="Amazon Stock Prediction",
57
+ xaxis_title="Date",
58
+ yaxis_title="Close (USD)",
59
+ showlegend=True,
60
+ template = 'plotly_dark'
61
+ )
62
+
63
+ annotations = []
64
+ annotations.append(dict(xref='paper', yref='paper', x=0.0, y=1.05,
65
+ xanchor='left', yanchor='bottom',
66
+ text='',
67
+ showarrow=False))
68
+ fig1.update_layout(annotations=annotations)
69
+ st.plotly_chart(fig1, use_container_width=True)
70
+
71
+ # MSE on train and test sets
72
+ st.markdown(f"Train MSE: {amazon_scores[0]:.3f}, Test MSE: {amazon_scores[1]:.3f}")
73
+
74
+ fig2 = go.Figure()
75
+ fig2.add_trace(go.Scatter(go.Scatter(x=google_predictions['Date'], y=google_predictions['Train Prediction'],
76
+ mode='lines',
77
+ name='Train Prediction')))
78
+ fig2.add_trace(go.Scatter(x=google_predictions['Date'], y=google_predictions['Test Prediction'],
79
+ mode='lines',
80
+ name='Test Prediction'))
81
+ fig2.add_trace(go.Scatter(go.Scatter(x=google_predictions['Date'], y=google_predictions['Actual Value'],
82
+ mode='lines',
83
+ name='Actual Value')))
84
+ fig2.update_layout(
85
+ title="Google Stock Prediction",
86
+ xaxis_title="Date",
87
+ yaxis_title="Close (USD)",
88
+ showlegend=True,
89
+ template = 'plotly_dark'
90
+ )
91
+
92
+ annotations = []
93
+ annotations.append(dict(xref='paper', yref='paper', x=0.0, y=1.05,
94
+ xanchor='left', yanchor='bottom',
95
+ text='',
96
+ showarrow=False))
97
+ fig2.update_layout(annotations=annotations)
98
+ st.plotly_chart(fig2, use_container_width=True)
99
+
100
+ # MSE on train and test sets
101
+ st.markdown(f"Train MSE: {google_scores[0]:.3f}, Test MSE: {google_scores[1]:.3f}")
102
+
103
+ fig3 = go.Figure()
104
+ fig3.add_trace(go.Scatter(go.Scatter(x=ibm_predictions['Date'], y=ibm_predictions['Train Prediction'],
105
+ mode='lines',
106
+ name='Train Prediction')))
107
+ fig3.add_trace(go.Scatter(x=ibm_predictions['Date'], y=ibm_predictions['Test Prediction'],
108
+ mode='lines',
109
+ name='Test Prediction'))
110
+ fig3.add_trace(go.Scatter(go.Scatter(x=ibm_predictions['Date'], y=ibm_predictions['Actual Value'],
111
+ mode='lines',
112
+ name='Actual Value')))
113
+ fig3.update_layout(
114
+ title="IBM Stock Prediction",
115
+ xaxis_title="Date",
116
+ yaxis_title="Close (USD)",
117
+ showlegend=True,
118
+ template = 'plotly_dark'
119
+ )
120
+
121
+ annotations = []
122
+ annotations.append(dict(xref='paper', yref='paper', x=0.0, y=1.05,
123
+ xanchor='left', yanchor='bottom',
124
+ text='',
125
+ showarrow=False))
126
+ fig3.update_layout(annotations=annotations)
127
+ st.plotly_chart(fig3, use_container_width=True)
128
+
129
+ # MSE on train and test sets
130
+ st.markdown(f"Train MSE: {ibm_scores[0]:.3f}, Test MSE: {ibm_scores[1]:.3f}")
131
+
132
+ fig4 = go.Figure()
133
+ fig4.add_trace(go.Scatter(go.Scatter(x=microsoft_predictions['Date'], y=microsoft_predictions['Train Prediction'],
134
+ mode='lines',
135
+ name='Train Prediction')))
136
+ fig4.add_trace(go.Scatter(x=microsoft_predictions['Date'], y=microsoft_predictions['Test Prediction'],
137
+ mode='lines',
138
+ name='Test Prediction'))
139
+ fig4.add_trace(go.Scatter(go.Scatter(x=microsoft_predictions['Date'], y=microsoft_predictions['Actual Value'],
140
+ mode='lines',
141
+ name='Actual Value')))
142
+ fig4.update_layout(
143
+ title="Microsoft Stock Prediction",
144
+ xaxis_title="Date",
145
+ yaxis_title="Close (USD)",
146
+ showlegend=True,
147
+ template = 'plotly_dark'
148
+ )
149
+
150
+ annotations = []
151
+ annotations.append(dict(xref='paper', yref='paper', x=0.0, y=1.05,
152
+ xanchor='left', yanchor='bottom',
153
+ text='',
154
+ showarrow=False))
155
+ fig4.update_layout(annotations=annotations)
156
+ st.plotly_chart(fig4, use_container_width=True)
157
+
158
+ # MSE on train and test sets
159
+ st.markdown(f"Train MSE: {microsoft_scores[0]:.3f}, Test MSE: {microsoft_scores[1]:.3f}")
projects/06_Generative_Music.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import io
3
+ import pickle
4
+ import pretty_midi
5
+ import numpy as np
6
+ from music21 import instrument, note, stream, chord
7
+ from keras.saving import load_model
8
+ from scipy.io import wavfile
9
+
10
+ @st.cache_resource
11
+ def load_notes():
12
+ notes_filepath = 'models/music_notes.pkl'
13
+ with open(notes_filepath, 'rb') as filepath:
14
+ notes = pickle.load(filepath)
15
+ pitchnames = pickle.load(filepath)
16
+ n_vocab = pickle.load(filepath)
17
+ return (notes, pitchnames, n_vocab)
18
+
19
+ @st.cache_resource
20
+ def model_load():
21
+ model_filepath = 'models/music_model.keras'
22
+ model = load_model(model_filepath)
23
+ return model
24
+
25
+ @st.cache_data
26
+ def prepare_sequences(notes, pitchnames, n_vocab, sequence_length=100):
27
+ note_to_int = dict((note, number) for number, note in enumerate(pitchnames))
28
+
29
+ network_input = []
30
+ for i in range(0, len(notes) - sequence_length, 1):
31
+ sequence_in = notes[i:i + sequence_length]
32
+ sequence_out = notes[i + sequence_length]
33
+ network_input.append([note_to_int[char] for char in sequence_in])
34
+
35
+ return network_input
36
+
37
+ def generate_notes(model, network_input, pitchnames, n_vocab, nlength, istart=-1):
38
+ # pick a random sequence from the input as a starting point for the prediction
39
+ if istart < 0 or istart > len(network_input) - 1:
40
+ start = np.random.randint(0, len(network_input) - 1)
41
+ print(f"Starting Position = {start}")
42
+ else:
43
+ start = istart
44
+
45
+ int_to_note = dict((number, note) for number, note in enumerate(pitchnames))
46
+
47
+ pattern = network_input[start]
48
+ prediction_output = []
49
+
50
+ # generate nlength notes
51
+ for note_index in range(nlength):
52
+ prediction_input = np.reshape(pattern, (1, len(pattern), 1))
53
+ prediction_input = prediction_input / float(n_vocab)
54
+
55
+ prediction = model.predict(prediction_input, verbose=0)
56
+
57
+ index = np.argmax(prediction)
58
+ result = int_to_note[index]
59
+ prediction_output.append(result)
60
+
61
+ pattern.append(index)
62
+ pattern = pattern[1:len(pattern)]
63
+
64
+ return prediction_output
65
+
66
+ def create_midi(prediction_output, output_filepath):
67
+ offset = 0
68
+ output_notes = []
69
+
70
+ # create note and chord objects based on the values generated by the model
71
+ for pattern in prediction_output:
72
+ # pattern is a chord
73
+ if ('.' in pattern) or pattern.isdigit():
74
+ notes_in_chord = pattern.split('.')
75
+ notes = []
76
+ for current_note in notes_in_chord:
77
+ new_note = note.Note(int(current_note))
78
+ new_note.storedInstrument = instrument.Piano()
79
+ notes.append(new_note)
80
+ new_chord = chord.Chord(notes)
81
+ new_chord.offset = offset
82
+ output_notes.append(new_chord)
83
+ # pattern is a note
84
+ else:
85
+ new_note = note.Note(pattern)
86
+ new_note.offset = offset
87
+ new_note.storedInstrument = instrument.Piano()
88
+ output_notes.append(new_note)
89
+
90
+ # increase offset each iteration so that notes do not stack
91
+ offset += 0.5
92
+
93
+ # Write notes to a MIDI file
94
+ midi_stream = stream.Stream(output_notes)
95
+ midi_stream.write('midi', fp='output.mid')
96
+
97
+ def generate(model, network_input, pitchnames, n_vocab, nlength=500, istart=-1):
98
+ output_filepath = 'output.mid'
99
+ if nlength < 1:
100
+ print(f"Song length must be at least one note, defaulting to 250 notes")
101
+ nlength = 500
102
+ if nlength > 500:
103
+ print(f"Cannot exceed 500 notes for song length")
104
+ nlength = 500
105
+
106
+ prediction_output = generate_notes(model, network_input, pitchnames, n_vocab, nlength, istart)
107
+ create_midi(prediction_output, output_filepath)
108
+ return output_filepath
109
+
110
+ st.header('Generative Music', divider='green')
111
+
112
+ # Load notes
113
+ notes, pitchnames, n_vocab = load_notes()
114
+
115
+ # Prepare note sequences
116
+ network_input = prepare_sequences(notes, pitchnames, n_vocab)
117
+
118
+ # Load model
119
+ model = model_load()
120
+
121
+ st.markdown("#### What are Recurrent Neural Networks?")
122
+ st.markdown("A recurrent neural network is a class of artificial neural networks that make use of sequential information. They are called recurrent because they perform the same function for every single element of a sequence, with the result being dependent on previous computations. Whereas outputs are independent of previous computations in traditional neural networks.")
123
+ st.markdown("In this project we will use a **Long Short-Term Memory** (LSTM) network. They are a type of Recurrent Neural Network that can efficiently learn via gradient descent. Using a gating mechanism, LSTMs are able to recognise and encode long-term patterns. LSTMs are extremely useful to solve problems where the network has to remember information for a long period of time as is the case in music and text generation.")
124
+ st.markdown("#### Data")
125
+ st.markdown("The data that our model will be trained on will consist of piano MIDI files of Final Fantasy soundtracks, but any set of MIDI files consisting of a single instrument would work.")
126
+ st.markdown("The sequence of notes and chords from the MIDI files are broken down into increments of 100, which are used to predict the next note or chord.")
127
+ st.markdown("#### Model")
128
+ st.markdown("For this project we will use a network consisting of three LSTM layers, three Dropout layers, two Dense layers and one activation layer.")
129
+ st.markdown("It may be possible to improve this model by playing around with the the structure of the network, or adding new categories (e.g. varying note duration, rest periods between notes, etc). However, to achieve satisfying results with more classes we would also have to increase the depth of the LSTM network.")
130
+ st.markdown("*This is based off the tutorial by Sigurður Skúli [How to Generate Music using a LSTM Neural Network in Keras](https://towardsdatascience.com/how-to-generate-music-using-a-lstm-neural-network-in-keras-68786834d4c5)*")
131
+ st.divider()
132
+
133
+ midi_file = None
134
+ generated_midi = None
135
+ sample_midi = None
136
+
137
+ st.markdown("You can select one of the samples below")
138
+
139
+ sample_midi = st.selectbox(
140
+ 'Select a sample MIDI file to play',
141
+ ('assets/sample_01.mid', 'assets/sample_02.mid', 'assets/sample_03.mid'),
142
+ index=None,
143
+ placeholder="Please select a sample...",
144
+ )
145
+
146
+ st.markdown("Or generate a new sample by clicking the generate button")
147
+
148
+ n_notes = st.slider("How many notes do you want?", 1, 500, 250)
149
+ start_pos = st.slider("Where do you want to start? Negative will start at a random position.", -1, len(network_input) - 1, -1)
150
+
151
+ if st.button('Generate'):
152
+ with st.spinner(f"Generating a new MIDI file"):
153
+ generated_midi = generate(model, network_input, pitchnames, n_vocab, n_notes, start_pos)
154
+
155
+ st.divider()
156
+
157
+ if generated_midi:
158
+ midi_file = generated_midi
159
+ sample_midi = None
160
+ elif sample_midi:
161
+ midi_file = sample_midi
162
+
163
+ if midi_file:
164
+ with st.spinner(f"Transcribing to FluidSynth"):
165
+ midi_data = pretty_midi.PrettyMIDI(midi_file)
166
+ audio_data = midi_data.fluidsynth()
167
+ audio_data = np.int16(
168
+ audio_data / np.max(np.abs(audio_data)) * 32767 * 0.9
169
+ ) # -- Normalize for 16 bit audio https://github.com/jkanner/streamlit-audio/blob/main/helper.py
170
+
171
+ virtualfile = io.BytesIO()
172
+ wavfile.write(virtualfile, 44100, audio_data)
173
+
174
+ st.audio(virtualfile)
175
+ st.markdown("Download the audio by right-clicking on the media player")
176
+ else:
177
+ st.markdown("Either generate a new MIDI file, or select one of the samples")
projects/07_LLM_Fine_Tuned.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ # from llama_cpp import Llama
3
+ import re
4
+
5
+ st.header('Fine Tuned LLM', divider='green')
6
+
7
+ st.markdown("#### What is a LLM?")
8
+ st.markdown("LLM stands for Large Language Model, which are mathematical models trained to predict the next set of words based on the prompt provided to it.")
9
+ st.markdown("In this case we are using [Meta's LLama 3.1 (8B) Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct) as our base model.")
10
+ st.markdown("#### What is a fine tuning?")
11
+ st.markdown("Fine tuning is the processes of tweaking the response of the LLM to particular subset of prompts. Most LLMs are trained on a large corpus of generic data, fine tuning just guides the LLM to a specific use case.")
12
+ st.markdown("In this case I have fine tuned the base model on [Microsoft's Orca Math Word Problems](https://huggingface.co/datasets/microsoft/orca-math-word-problems-200k), so the chatbot below is more of math assistant. Though it occasionally gets the wrong answer, it is willing to try again. I only fine tuned on 1000 math word problems, but I could try to train on the entire dataset in the future.")
13
+ st.markdown("#### What is quantization?")
14
+ st.markdown("Most LLM are quite large, often too large to fit into a computer's memory. So ML developers employ Graphic Processing Units (GPUs) with large amounts of memory to train or make use of such LLMs.")
15
+ st.markdown("However not everyone has access to such resources, so quantization is the process of decreasing the size of a model so that it can fit into memory (GPU or CPU). The process of quantization decreases the precision used to store the models parameters, at the cost of the model's accuracy.")
16
+ st.markdown("In this case after I fine tuned the LLama 3.1 (8B) base model, it was quantized to 4 bits which offers reasonable model accuracy at 25% the base model size.")
17
+ st.markdown("*This is based off the tutorial by Abid Ali Awan [Fine-Tuning Llama 3 and Using It Locally: A Step-by-Step Guide](https://www.datacamp.com/tutorial/llama3-fine-tuning-locally)*")
18
+ st.divider()
19
+
20
+ st.warning("**Work In Progress**")
21
+
22
+ if "messages" not in st.session_state:
23
+ st.session_state["messages"] = [{"role": "system", "content": "You are a helpful math assistant."}, {"role": "assistant", "content": "What math problem can I help you with today?"}]
24
+
25
+ def chat_action(prompt):
26
+ if len(st.session_state.messages) > 6:
27
+ st.session_state.messages.pop(2)
28
+ st.session_state.messages.pop(2)
29
+ st.session_state["messages"].append({"role": "user", "content": prompt})
30
+ st.chat_message("user").write(prompt)
31
+
32
+ # with st.spinner(f"Generating response"):
33
+ # response = llm.create_chat_completion(
34
+ # messages=st.session_state.messages,
35
+ # temperature = 0.7,
36
+ # repeat_penalty = 1.1,
37
+ # stop = "[/INST]"
38
+ # )
39
+ # msg = response['choices'][0]['message']['content']
40
+ # msg = re.sub(r'(<<|\[)*(INST|SYS)(>>|\])*', '', msg)
41
+ # st.session_state["messages"].append({"role": "assistant", "content": msg})
42
+ # st.chat_message("assistant").write(msg)
43
+
44
+ # @st.cache_resource
45
+ # def load_llm():
46
+ # #### Import Model from Huggingface
47
+ # llm = Llama.from_pretrained(
48
+ # repo_id="ccapo/llama-3.1-8b-chat-math-teacher-GGUF",
49
+ # filename="*Q4_K_M.gguf",
50
+ # verbose=False,
51
+ # n_ctx=2048
52
+ # )
53
+ # return llm
54
+
55
+ for msg in st.session_state.messages:
56
+ if msg["role"] != "system":
57
+ with st.chat_message(name=msg["role"]):
58
+ st.write(msg["content"])
59
+
60
+ # with st.spinner(f"Loading LLM"):
61
+ # llm = load_llm()
62
+
63
+ if prompt := st.chat_input():
64
+ chat_action(prompt)