Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added 23%_accuracy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 3%_accuracy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 3.3_loss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
653 changes: 653 additions & 0 deletions Capstone.ipynb

Large diffs are not rendered by default.

Binary file added Design Document.docx
Binary file not shown.
Binary file added Ethical Consideration.pdf
Binary file not shown.
Binary file added KARPresentation.pptx
Binary file not shown.
Binary file added KARcapstonePresentation.pptx
Binary file not shown.
509 changes: 509 additions & 0 deletions Notebook.ipynb

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@
<!--
Name of your teams' final project
-->
# final-project
## [National Action Council for Minorities in Engineering(NACME)](https://www.nacme.org) Google Applied Machine Learning Intensive (AMLI) at the `PARTICIPATING_UNIVERSITY`
# Artist classification by painting
## [National Action Council for Minorities in Engineering(NACME)](https://www.nacme.org) Google Applied Machine Learning Intensive (AMLI) at the `University of Arkansas`

<!--
List all of the members who developed the project and
link to each members respective GitHub profile
-->
Developed by:
- [member1](https://github.com/cbaker6) - `STUDENTS_UNIVERSITY`
- [member2](https://github.com/cbaker6) - `STUDENTS_UNIVERSITY`
- [member3](https://github.com/cbaker6) - `STUDENTS_UNIVERSITY`
- [member4](https://github.com/cbaker6) - `STUDENTS_UNIVERSITY`
- [member1](https://github.com/anhtran09) - `Anh Tran - Uark`
- [member2](https://github.com/rjmouron01) - `Rodrigo Mouron - Uark`
- [member3](https://github.com/kaveon19) - `Kaveon Ware - UAPB`

## Description
<!--
Give a short description on what your project accomplishes and what tools is uses. In addition, you can drop screenshots directly into your README file to add them to your README. Take these from your presentations.
-->

We created a model that will predict the name of the Artist who's painting we analyze. We used the knowledge we gained from the colabs we have worked on to make our model more accurate. We used our own model which we developed.


## Usage instructions
<!--
Give details on how to install fork and install your project. You can get all of the python dependencies for your project by typing `pip3 freeze requirements.txt` on the system that runs your project. Add the generated `requirements.txt` to this repo.
-->
1. Fork this repo
2. Change directories into your project
3. On the command line, type `pip3 install requirements.txt`
4. ....

To run our project there are a couple of things needed to get started.

1. The user must download the dataset from Kaggle at: https://www.kaggle.com/competitions/painter-by-numbers/data?select=train_1.zip. This will download the training dataset. The entire library of photos is 90gb so we decided to download a portion of it. This file should be around 5gb in size.
2. Download all our code and place the file of photos in a folder with our code
3. Download all the libraries. We used the pycharm IDE to code, the modules the user must install are: pillow, tensorflow, keras, sklearn, os, and tqdm.

Once the user has completed these 3 steps, the program should run.
Binary file added after_filter_with_count_greater_than_10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added count_artists.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added first_run_bad_epochs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
348 changes: 348 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
# Artist classification by painting
import tensorflow.python.keras.preprocessing.image
from PIL import Image
import tensorflow as tf
import tensorflow.keras as tfk
from tensorflow.keras.preprocessing import image
import matplotlib.pyplot as plt
import pandas as pd
import os
from sklearn.model_selection import train_test_split
from tqdm import tqdm
import numpy as np
from PIL import ImageFile
import tensorflow.keras as keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.utils import to_categorical

from sklearn import tree
import io
import pydotplus

from IPython.display import Image




ImageDir = 'C:/Users/14794/Documents/NACME_capstone/train_1/train_1/'
# ending = '.jpg'
CSVDir = 'C:/Users/14794/Documents/NACME_capstone/all_data_info.csv/all_data_info.csv'

def data_preprocessing():

# Load all_data_info.csv
labels = pd.read_csv(CSVDir)

# Creating dataframe from Image directory
list_dir = os.listdir('train_1/train_1/')
list_df = pd.DataFrame(list_dir, columns = ['new_filename'])
for i in list_df['new_filename']:
list_df['path'] = ImageDir + i




# List df has 11025 rows

# Joining dataframes drop non matching
new_df = pd.merge(labels, list_df, on ="new_filename")


# new_df = new_df.dropna()

# x_train, x_test, y_train, y_test = train_test_split(FEATURES, TARGET, test_size = 0.15, random_state = 42, shuffle =True)
# print( x_train.shape, x_test.shape, y_train.shape, y_test.shape)

# You can see after the 90th image it gives you an error IOError: image file truncated (80 bytes not processed)
# This happens when the file is too big. Lets print out the image
# print(list_dir[90])
# This prints out image 100102.jpg

# To fix this jsut add this statement above your call stack

ImageFile.LOAD_TRUNCATED_IMAGES = True


# Turning it into a byte array
painting_images = []
for i in tqdm(range(list_df.shape[0])):

img = image.load_img('train_1/train_1/'+ new_df['new_filename'][i], target_size=(224, 224, 3))
img = image.img_to_array(img)

img = image.load_img('train_1/train_1/'+ new_df['new_filename'][i], target_size=(100, 100, 3))
img = image.img_to_array(img)
# img = keras.preprocessing.image.smart_resize(img, (100, 100))

img = img/255
painting_images.append(img)
# print('train_1/train_1/'+ new_df['new_filename'][i])
# print(img)
X = np.array(painting_images)


# Looking at other features
d = []
for a, b in new_df.iterrows():
array = []
g = str(b['genre'])
s = str(b['style'])
array.append(g)
array.append(s)
print(array)
d.append(array)

y = np.array(new_df['artist'])



return X, y, d



def cleaning_data(x_array, y_array, features):

# Create dataframe
dataframe_1 = pd.DataFrame(x_array.reshape((y_array.shape[0], -1)), columns=list(range(150528)))
dataframe_2 = pd.DataFrame(y_array, columns=["filename"])
dataframe_3 = pd.DataFrame(features, columns= ["genre", "style"])
df = pd.merge(dataframe_1, dataframe_3, left_index=True, right_index=True)
df = pd.merge(df, dataframe_2, left_index = True, right_index = True)
df = df.dropna()


# drop columns where there are less than 10 paintings
dataframe = df[df['count'] >= 10]
print(dataframe.head(10))

# see how many artists
labels = [x for x in dataframe["filename"].unique()]
num_artists = len(labels)
print(num_artists)

# turn back into arrays
X_array = dataframe.iloc[:,:150528].to_numpy()
Y_array = dataframe['filename'].to_numpy()
artists = list(np.unique(Y_array))
num_classes = len(artists)
Y_array = np.array([artists.index(i) for i in Y_array])
Y_array = to_categorical(Y_array)

# train test split
x_train, x_test, y_train, y_test = train_test_split(X_array, Y_array, random_state=42, test_size=0.15, shuffle=True)
print(x_train.shape, y_train.shape, y_train.shape, y_test.shape)


# reshape to correct dimensions
x_train = x_train.reshape((y_train.shape[0], 224, 224, 3))
x_test = x_test.reshape((y_test.shape[0], 224, 224, 3))

print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)

return x_train, x_test, y_train, y_test, num_artists, dataframe


# CNN method
def create_model(num_classes):
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=(5, 5), activation="relu", input_shape=(224, 224, 3)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters=32, kernel_size=(5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters=64, kernel_size=(5, 5), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters=64, kernel_size=(5, 5), activation='relu'))

# print(plt.imshow(X[2]))


# print(new_df.columns)
# print(new_df[0])

# FEATURES = [new_df[['date', 'genre','style' ]], X]
# # print(FEATURES)
# TARGET = new_df[['artist']]
# # print(TARGET)

# YYYYYYYYYEEEETTTTT
y = np.array(new_df['artist'])
# y = np.array(new_df['date', 'genre', 'style'], X)

# x = []
# for a, b in new_df.iterrows():
# array = []
# for paintings in np.nditer(X):
# p = X(paintings)
#
# d = str(b['date'])
# g = str(b['genre'])
# s = str(b['style'])
# array.append(d)
# array.append(g)
# array.append(s)
# array.append(p)
# print(array)
# x.append(array)

labels = [x for x in new_df["artist"].unique()]
num_artists = len(labels)

# x_train, x_test, y_train, y_test = train_test_split(X, y, test_size = 0.15, random_state = 42, shuffle =True)

return X, y, num_artists

# return x_train, x_test, y_train, y_test, num_artists

def create_model(num_classes):
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=(5, 5), activation="relu", input_shape=(100,100,3)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters=32, kernel_size=(5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters=64, kernel_size=(5, 5), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters=64, kernel_size=(5, 5), activation='relu'))

model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.summary()

return model


# RESNET50 method
def RESNET50(num_classes):
resnet = Sequential()

pretrained = tensorflow.keras.applications.ResNet50(include_top = False,
input_shape = (100, 100, 3),
pooling = 'avg',
classes = 5,
weights = 'imagenet')
for layer in pretrained.layers:
layer.trainable = False

resnet.add(pretrained)
resnet.add(Flatten())
resnet.add(Dense(128, activation='relu'))
resnet.add(Dropout(0.5))
resnet.add(Dense(64, activation='relu'))

resnet.add(Dense(32, activation='relu'))
resnet.add(Dropout(0.5))


resnet.add(Dropout(0.25))
resnet.add(Dense(num_classes, activation='softmax'))

return resnet



if __name__ == "__main__":


x_array, y_array, feature_array = data_preprocessing()
x_train, x_test, y_train, y_test, num_classes, data = cleaning_data(x_array, y_array, feature_array)
print(data)
print(data.columns)

# Run CNN model
model = create_model(num_classes)
model.summary()
model.compile(optimizer = 'adam', loss = "categorical_crossentropy", metrics = ['accuracy'])
history = model.fit(x_train, y_train, epochs=250, batch_size = 18)

# Plot CNN model
epochs = range(250)
plt.plot(epochs, history.history['accuracy'])
plt.show()
plt.plot(epochs, history.history['loss'])
plt.show()



model.save('./ckpts/Model_1')

evaluate = model.evaluate(x_test, y_test)
print(evaluate)

# Run RESNET50
ResNet = RESNET50(num_classes)
ResNet.compile(optimizer = 'adam', loss = "categorical_crossentropy", metrics = ['accuracy'])
ResHistory = ResNet.fit(x_train, y_train, epochs = 100, batch_size = 15)
ResNet.save('.ckpts/ResNet')

# Plot RESNET
ResNet.evaluate(x_test, y_test)
plt.plot(epochs, ResHistory.history['accuracy'])
plt.show()
plt.plot(epochs, ResHistory.history['loss'])
plt.show()




if __name__ == "__main__":

x_array, y_array, num_classes = data_preprocessing()
print(x_array.shape)
print(y_array.shape)
# dataframe = pd.DataFrame(x_array.reshape((y_array.shape[0], -1)), y_array, columns=['image_bytes', 'filename'])
dataframe_1 = pd.DataFrame(x_array.reshape((y_array.shape[0], -1)), columns=list(range(30000)))
dataframe_2 = pd.DataFrame(y_array, columns=["filename"])
dataframe = pd.merge(dataframe_1, dataframe_2, left_index=True, right_index=True)
dataframe = dataframe.dropna()

# labels = [x for x in dataframe["artist"].unique()]

print(dataframe.isna().sum())

X_array = dataframe[list(range(30000))].to_numpy()
Y_array = dataframe['filename'].to_numpy()
artists = list(np.unique(Y_array))
num_classes = len(artists)
Y_array = np.array([artists.index(i) for i in Y_array])
Y_array = to_categorical(Y_array)

# for painters in y_array:
# if painters = naN


# print(x_array[0])
# print(y_array[0])

x_train, x_test, y_train, y_test = train_test_split(X_array, Y_array, random_state = 42, test_size = 0.15, shuffle = True)
x_train = x_train.reshape((y_train.shape[0], 100, 100, 3))
x_test = x_test.reshape((y_test.shape[0], 100, 100, 3))
# print(x_train, y_test, y_train, y_test)
print(x_train.shape, y_test.shape, y_train.shape, y_test.shape)

# x_train, x_test, y_train, y_test, num_classes = data_preprocessing()
model = create_model(num_classes)
model.summary()
model.compile(optimizer = 'adam', loss = "categorical_crossentropy", metrics = ['accuracy'])
#
history = model.fit(x_train, y_train, epochs=10, batch_size = 24, validation_split = 0.15)
model.save('./ckpts/epoch10')
#
# print(x_train.shape)
#
# model.fit(x_train, y_train, epochs = 10, batch_size= 64)


Loading