kimosabe777/OpenAI-FineTuning-NLP
0
1import pandas as pd2import json3import re4import openai5from dotenv import load_dotenv6import os7import streamlit as st8import time9import logging10 11 12def createValidationData():13 # Load the dataset14 csvfile = "./datasets/test_dataset.csv"15 df = pd.read_csv(csvfile)16 df = df.dropna() ## Added this line so that the dataframe does not contain any null values, otherwise it will throw an error in OpenAI fine-tuning17 df_valid = createTrainData(df)18 df_valid["Mood"] = df["Mood"].apply(map_mood)19 return df_valid20 21def loadData(data_file):22 # Load the dataset23 df = pd.read_csv(data_file)24 df = df.dropna() ## Added this line so that the dataframe does not contain any null values, otherwise it will throw an error in OpenAI fine-tuning25 df_train = createTrainData(df)26 df_train["Mood"] = df["Mood"].apply(map_mood)27 return df_train28 29def createTrainData(df):30 # Create the training data31 df_neu = df[df['Mood']== 0]32 df_pos = df[df['Mood']== 1]33 df_neg = df[df['Mood']== 2]34 35 ## This sampling is based on the distribution of the dataset, required to do this for OpenAI fine-tuning36 df_sample_neu = df_neu.sample(frac=0.01)37 df_sample_pos = df_pos.sample(frac=0.01)38 df_sample_neg = df_neg.sample(frac=0.01)39 40 ## Logging to check the sample sizes are balanced between classes, this can be commented out later on41 logging.error(f"Sample Neutral {df_sample_neu.shape}")42 logging.error(f"Sample Positive {df_sample_pos.shape}")43 logging.error(f"Sample Negative {df_sample_neg.shape}")44 45 ## Combine the samples46 df_sample_sets = pd.concat([df_sample_neu, df_sample_pos, df_sample_neg])47 return df_sample_sets48 49 50def map_mood(senti_score):51 if senti_score == 1:52 return "Positive"53 elif senti_score == 2:54 return "Negative"55 else:56 return "Neutral"57 58 59## Coverting DF to JSON format60def dfToJSON(df, JSONfile):61 # Convert the DataFrame to the required format62 fine_tune_data = df[['translated_text', 'Mood']].rename(columns={'translated_text': 'prompt', 'Mood': 'completion'})63 64 # Save the dataset to a JSONL file65 #with open('fine_tune_data.jsonl', 'w') as f:66 with open(JSONfile, 'w') as f:67 for i, row in fine_tune_data.iterrows():68 json.dump({"prompt": row['prompt'], "completion": row['completion']}, f)69 f.write('\n')70 71 #fine_tune_data.head()72 73## Fine Tune OpenAI74def fineTune_OpenAI(client, JSONfile):75 # * Upload the training JSON data file for fine tuning76 # * Check the status of the upload job process 77 # * Run the fine tuning based on our training data78 # * Check the status of the fine tuning job process79 80 ## Upload the training data JON file to OpenAI (we have limit it to 200 for now see the "nrows" when the CSV data is loaded)81 response = client.files.create(file=open(JSONfile, 'rb'),82 purpose='fine-tune')83 84 return response.id, response.status85 86def createJob_OpenAI(client, responseID, valid_respID):87 ## Creata a job to fine-tune the model. It might take a while depending on the size of the file that is being processed88 ## So, ideally we only use a small subset of training data89 finetune_response = client.fine_tuning.jobs.create(90 training_file=responseID,91 validation_file=valid_respID,92 model="davinci-002"93 )94 return finetune_response.id95 96def checkJob_OpenAI(client, responseID):97 ## Print the results/status information of the fine-tune job after submission98 #print(f"Fine tuning Job ID : {finetune_response.id}")99 #print(finetune_response)100 #for key, value in finetune_response:101 # print(f"{key} : {value}")102 103 ## Print the current results/status information of the fine-tuning job, make sure it is finished/successful104 ## before running the model, otherwise it will fail105 #client.fine_tuning.jobs.list(limit=1)106 jobStatus = client.fine_tuning.jobs.retrieve(responseID)107 #for key, value in jobStatus:108 # print(f"{key} : {value}")109 110 ## Once the fine tuning is successful, we will get/used the "fine_tuned_model" from JobStatus object,111 ## otherwise, it will return "None"112 fineTunedModel = jobStatus.fine_tuned_model113 status = jobStatus.status114 return fineTunedModel, status115 116def listJobEvents(client, responseID):117 ## To list all the events for the fine-tuning job ##118 response = client.fine_tuning.jobs.list_events(responseID, limit=5)119 events = response.data120 events.reverse()121 122 #for event in events:123 # print(event.message)124 return events125 126def getlastModel(client):127 # List 10 fine-tuning jobs128 response = client.fine_tuning.jobs.list(limit=1)129 #response130 for i in enumerate(response):131 #print(f"Job ID: {i[1].id}, Fine tuned Model: {i[1].fine_tuned_model}, Status: {i[1].status}")132 ft_jobid = i[1].id133 ft_model = i[1].fine_tuned_model134 ft_status = i[1].status135 break136 return ft_model, ft_status137 138 139def AnalyzeSentiment(client, model, tweet):140 response = client.completions.create(141 model=model,142 prompt=tweet,143 max_tokens=1144 #temperature=0,145 #top_p=1,146 #frequency_penalty=0,147 #presence_penalty=0,148 #stop=["\n"]149 )150 return response151 152 153def uiTweets():154 user_tweet = st.text_input("Tweet: ")155 return user_tweet156 157 158def testTweet(client, fineTunedModel, tweet):159 TestResponse = AnalyzeSentiment(client, fineTunedModel, tweet)160 161 #print(TestResponse.choices[0].text)162 st.write(TestResponse.choices[0].text)163 164 165def main():166 # Set up logging configuration167 logging.basicConfig(filename='tweetLLM_errors.log', level=logging.ERROR, 168 format='%(asctime)s:%(levelname)s:%(message)s')169 170 ## Load your API key from an environment variable or a configuration file171 load_dotenv()172 openai.api_key = os.getenv("OPENAI_API_KEY", "<your OpenAI API key if not set as env var>")173 client = openai.OpenAI(api_key=openai.api_key)174 175 st.header("NLP with OpenAI : :panda_face:")176 177 user_tweet = st.text_input("Enter Tweet to analyze: ")178 #print(user_tweet)179 #st.write(user_tweet)180 181 button_label = "Evaluate sentiment"182 train_new = 0183 job_status = ""184 opt_rad1 = st.radio("Option", ["Train and fine-tune new model", "Use last Fine-tuned model"], captions = ["Train and fine-tune new model in OpenAI", "Use last Fine-tuned model from OpenAI"])185 if opt_rad1 == "Train and fine-tune new model":186 button_label = "Train new model"187 uploaded_file = st.file_uploader("Choose a file")188 train_new = 1189 else:190 ft_model, ft_status = getlastModel(client)191 job_status = ft_status192 ft_msg = f"Last trained model was *{ft_model}* with status of *{ft_status}*"193 st.write(ft_msg)194 195 196 if st.button(button_label): 197 msg_placeholder = st.empty()198 msg_list = []199 if train_new: ## Train new model 200 if uploaded_file: ## This will allow you to upload the datasets to be used to train new model201 dataset = loadData(uploaded_file)202 dataset_v = createValidationData()203 finetune_JSON = "fine_tune_data.jsonl"204 validation_JSON = "validation_data.jsonl"205 dfToJSON(dataset, finetune_JSON)206 dfToJSON(dataset_v, validation_JSON)207 responseID, responseStatus = fineTune_OpenAI(client, finetune_JSON) ## This line for the training data208 valid_respID, valid_respStatus = fineTune_OpenAI(client, validation_JSON) ## This line for the validation data209 msg_list.append(f"Response ID: {responseID}, Status : {responseStatus}")210 msg_list.append(f"Response ID: {valid_respID}, Status : {valid_respStatus}")211 msg_placeholder.text_area("Processing", "\n".join(msg_list), height=200)212 responseID = createJob_OpenAI(client, responseID, valid_respID)213 214 with st.spinner("Fine tuning new model in OpenAI..."):215 while True:216 fineTunedModel, job_status = checkJob_OpenAI(client, responseID)217 ##fineTunedModel = "Test tune Model"218 #msg2 = f"Fine Tune Model : {fineTunedModel} - {type(fineTunedModel)}"219 msg_list.append(f"Fine Tune Model : {fineTunedModel} - {type(fineTunedModel)}")220 msg_list.append(f"Job Status : {job_status}")221 msg_placeholder.text_area("Processing", "\n".join(msg_list), height=200)222 if job_status == "failed":223 break224 else:225 if fineTunedModel is not None:226 break227 else:228 time.sleep(20)229 events = listJobEvents(client, responseID)230 #events = ["Processing...1", "Processing...2", "Processing...3", "Processing...4"]231 for event in events:232 msg_list.append(event.message)233 msg_placeholder.text_area("Processing", "\n".join(msg_list), height=200)234 continue235 else:236 msg_list.append("Training failed! Please upload a file to train new model and try again")237 msg_placeholder.text_area("", "\n".join(msg_list), height=200)238 else: ## Use the last good model239 st.write(user_tweet)240 if ft_model is not None:241 fineTunedModel = ft_model242 243 if job_status == "failed":244 st.write("Fine-tuning failed. Check your data and please try again.")245 else:246 if job_status == "succeeded":247 TestResponse = AnalyzeSentiment(client, fineTunedModel, user_tweet)248 #TestResponse = "Test response"249 st.write(TestResponse)250 sentiResults = TestResponse.choices[0].text 251 st.write(sentiResults)252 253 254 255if __name__ == "__main__":256 main()