Wednesday, January 31, 2024

ML: SVM vs. Random Forest for image segmentation

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# https://github.com/bnsreenu/python_for_microscopists/blob/master/068b-ML_06_04_TRAIN_ML_segmentation_All_filters_RForest_SVM.py


import numpy as np
import cv2
import pandas as pd

img=cv2.imread("D://Mask//IMG_0686.JPG")
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

img2=img.reshape(-1)
df=pd.DataFrame()
df['Original Image']=img2

# Generate Gabor features
# To count numbers up in order to give Gabor features a label in the data frame
num=1
kernels=[]

for theta in range(2):  # Define number of thetas
    theta=theta/4.*np.pi
    for sigma in (1, 3):
        for lamda in np.arange(0, np.pi, np.pi/4):
            for gamma in (0.05, 0.5):
                gabor_label='Gabor'+str(num)
                ksize=9
                kernel=cv2.getGaborKernel((ksize, ksize),sigma,theta,lamda,gamma, 0, ktype=cv2.CV_32F)
                kernels.append(kernel)
                fimg=cv2.filter2D(img2, cv2.CV_8UC3, kernel)
                filtered_img=fimg.reshape(-1)
                df[gabor_label]=filtered_img
                print(gabor_label, ': theta=', theta, ': sigma, ', sigma, ': lamda=', lamda, ':gamma=', gamma)
                num=num+1


# Canny Edge
edges=cv2.Canny(img, 100, 200)  # Image, min and max values
edges1=edges.reshape(-1)
df['Canny Edge']=edges1

from skimage.filters import roberts, sobel, scharr, prewitt


# Robert Edge
edge_roberts=roberts(img)
edge_roberts1=edge_roberts.reshape(-1)
df['Roberts']=edge_roberts1


# Sobel
edge_sobel=sobel(img)
edge_sobel1=edge_sobel.reshape(-1)
df['Sobel']=edge_sobel1

# Scharr
edge_scharr=scharr(img)
edge_scharr1=edge_scharr.reshape(-1)
df['Scharr']=edge_scharr1

# Prewitt
edge_prewitt=prewitt(img)
edge_prewitt1=edge_prewitt.reshape(-1)
df['Prewitt']=edge_prewitt1

# Gaussian with sigma=3
from scipy import ndimage as nd
gaussian_img=nd.gaussian_filter(img, sigma=3)
gaussian_img1=gaussian_img.reshape(-1)
df['Gaussian s3']=gaussian_img1

# Gaussian with sigma=7
gaussian_img2=nd.gaussian_filter(img, sigma=7)
gaussian_img3=gaussian_img2.reshape(-1)
df['Gaussian s7']=gaussian_img3

# Median with sigma=3
median_img=nd.median_filter(img, size=3)
median_img1=median_img.reshape(-1)
df['Median s3']=median_img1


# Variance with size=3
variance_img=nd.generic_filter(img, np.var, size=3)
variance_img1=variance_img.reshape(-1)
df['Variance s3']=variance_img1

# Now, add a column in the data frame for the labels
# For this, we need to import the labeled image
labeled_img=cv2.imread("D://Mask//mask.tif")
# Remember that you can load an image with partial labels
# But, drop the rows with unlabeled data

labeled_img=cv2.cvtColor(labeled_img, cv2.COLOR_BGR2GRAY)
labeled_img1=labeled_img.reshape(-1)
df['Labels']=labeled_img1

print(df.head())



# Define the dependent variable that needs to be predicted (labels)
Y=df["Labels"].values
# Define the independent variables
X=df.drop(labels=["Labels"], axis=1)

# Split data into train and test to verify accuracy after fitting the model
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.4, random_state=20)

# Import the model we are using
# RandomForestRegressor is for regression type of problems
# For classification we use RandomForestClassifier
# Both yield similar results except for regressor the result is float
# and for classifier it is an integer

from sklearn.ensemble import RandomForestClassifier
model=RandomForestClassifier(n_estimators=100, random_state=42)


# Train the model on training data
model.fit(X_train, y_train)


# Testing the model by predicting on test data
# and Calculate the accuracy score
# First test predication on the training data itself. Should be good
prediction_test_train=model.predict(X_train)

# Test prediction on testing data
prediction_test=model.predict(X_test)


# Let us check the accuracy on test data
from sklearn import metrics

# First check the accuracy on training data. This will be higher than test data predication accuracy
print("Accuracy on training data= ", metrics.accuracy_score(y_train, prediction_test_train))
print("Accuracy= ", metrics.accuracy_score(y_test, prediction_test))

Monday, January 29, 2024

ML: Auto segmentation using multi-otsu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Auto segmentation using multi-otsu, https://www.youtube.com/watch?v=YdhhiXDQDl4&list=PLZsOBAyNTZwYx-7GylDo3LSYpSompzsqW&index=36
# https://github.com/bnsreenu/python_for_microscopists/blob/master/115_auto_segmentation_using_multiotsu.py
import matplotlib.pyplot as plt
import numpy as np


from skimage import data, io, img_as_ubyte
from skimage.filters import threshold_multiotsu
from skimage.color import rgb2gray

# Read an image
image=io.imread("D:/Mask/IMG_0252.JPG")
image=rgb2gray(image)


# image=Image.open("D:/Mask/IMG_0252.JPG").convert('L')
# Apply multi-Otsu threshold
thresholds=threshold_multiotsu(image, classes=2)

# Digitize (segment) original image into multiple classes
# np.digitize assign values 0, 1, 2, 3, ... to pixels in each class
regions=np.digitize(image, bins=thresholds)
output=img_as_ubyte(regions)

plt.imsave("D:/Mask/otsu_segment.jpg", output)

Wednesday, January 24, 2024

ML: Image classification using Sklearn (RandomForest)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# https://www.kaggle.com/code/kkhandekar/image-classification-using-sklearn-randomforest/notebook

import numpy as np
import pandas as pd
import warnings
warnings.simplefilter('ignore')

import matplotlib.pyplot as plt
#%matplotlib inline
import os
import pprint
from collections import Counter
import joblib
from pprint import pprint
import cv2

from skimage.io import imread
from skimage.transform import resize
from skimage.transform import rescale


from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV

def resize_all(src, pklname, include, width=150, height=None):
    height=height if  height is not None else width

    data=dict()
    data['description']='resized ({0}*{1}) mini dog images in rgb'.format(int(width), int(height))
    data['label']=[]
    data['filename']=[]
    data['data']=[]

    pklname=f"{pklname}_{width}x{height}px.pkl"

    for subdir in os.listdir(src):
        if subdir in include:
            print(f"Reading images for {subdir} ...")
            current_path=os.path.join(src, subdir)
            for file in os.listdir(current_path):
                if file[-3:] in {'jpg', 'png'}:
                    im=imread(os.path.join(current_path, file))
                    im=resize(im, (width, height))
                    data['label'].append(subdir[:])
                    data['filename'].append(file)
                    data['data'].append(im)
        joblib.dump(data, pklname)




IMAGE_PATH='D:\A\Dat\AnoPyTest\kkk\MiniDogBreedData'
CLASSES=os.listdir(IMAGE_PATH)
BASE_NAME='mini_dog_breeds'
WIDTH=90

# Load & resize the images
resize_all(src=IMAGE_PATH, pklname=BASE_NAME, width=WIDTH, include=CLASSES)

data=joblib.load(f'{BASE_NAME}_{WIDTH}x{WIDTH}px.pkl')

print('number of samples: ', len(data['data']))
print('keys: ', list(data.keys()))
print('description: ', data['description'])
print('image shape: ', data['data'][0].shape)
print('labels: ', np.unique(data['label']))

print(Counter(data['label']))

labels=np.unique(data['label'])
# fig, axes=plt.subplot(1,  len(labels))
fig, axes = plt.subplots(1, len(labels))
fig.set_size_inches(15, 4)
fig.tight_layout()



for ax, label in zip(axes, labels):
    idx=data['label'].index(label)
    ax.imshow(data['data'][idx])
    #plt.show()
    ax.axis('off')
    ax.set_title(label)


x=np.array(data['data'])
y=np.array(data['label'])

SIZE=0.1
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=SIZE, shuffle=True, random_state=np.random.randint(1,50))

print(f"Training Size: {x_train.shape[0]}\n Validation Size: {x_test.shape[0]}")



x_train=x_train/255.0
x_test=x_test/255.0



nsamples, nx, ny, nrgb=x_train.shape
x_train2=x_train.reshape((nsamples, nx*ny*nrgb))


nsamples, nx, ny,nrgb=x_test.shape
x_test2=x_test.reshape((nsamples, nx*ny*nrgb))


rfc=RandomForestClassifier()
rfc.fit(x_train2, y_train)

y_pred=rfc.predict(x_test2)

from sklearn.metrics import accuracy_score
acc='{:.2%}'.format(accuracy_score(y_test, y_pred))
print(f"Accuracy for Random Forrest: {acc}")


n_estimators=[int(x) for x in np.linspace(start=200, stop=1000, num=3)]
criterion=['gini', 'entropy']
max_depth=[int(x) for x in np.linspace(10, 110, num=3)]
max_depth.append(None)


min_samples_split=[2, 5, 10]
min_samples_leaf=[1, 2, 4]

bootstrap=[True, False]

class_weight=['balanced', 'balanced_subsample', None]

param_grid={'n_estimators': n_estimators,
            'criterion': criterion,
            'max_depth': max_depth,
            'min_samples_split': min_samples_split,
            'min_samples_leaf': min_samples_leaf, 'bootstrap': bootstrap,
            'class_weight': class_weight}


pprint(param_grid)


rfc_t=RandomForestClassifier()

rf_random=RandomizedSearchCV(
    estimator=rfc_t,
    param_distributions=param_grid,
    n_iter=10,
    cv=3,
    verbose=0,
    random_state=42,
    n_jobs=-1
)


rf_random.fit(x_train2, y_train)
rf_random.best_params_


rfc=RandomForestClassifier()
rfc.fit(x_train2, y_train)
y_pred=rfc.predict(x_test2)

# accuracy score
acc = '{:.1%}'.format(accuracy_score(y_test, y_pred))
print(f"Accuracy for Random Forrest: {acc}")

ML: Image Classification Using Machine Learning-Support Vector Machine(SVM)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# https://medium.com/analytics-vidhya/image-classification-using-machine-learning-support-vector-machine-svm-dc7a0ec92e01

import pandas as pd
import os
from skimage.transform import resize
from skimage.io import imread
import numpy as np
import matplotlib.pyplot as plt

Categories=['Cat', 'Dog']
flat_data_arr=[]
target_arr=[]


datadir=f'D:\PyTest\PetImages\\tkt'
for i in Categories:
    print(f'loading ... category: {i}')
    path=os.path.join(datadir,i)
    for img in os.listdir(path):
        img_array=imread(os.path.join(path, img))
        img_resized=resize(img_array, (150,150,3))
        flat_data_arr.append(img_resized.flatten())
        target_arr.append(Categories.index(i))
        #print(Categories.index(i))
        #print(os.path.join(path, img))
    print(f'loaded category: {i} successfully!')

flat_data=np.array(flat_data_arr)
target=np.array(target_arr)
df=pd.DataFrame(flat_data)
df['Target']=target
x=df.iloc[:,:-1]
y=df.iloc[:,-1]

from sklearn import svm
from sklearn.model_selection import GridSearchCV
param_grid={'C':[0.1, 1, 10, 100], 'gamma': [0.0001, 0.001, 0.1, 1], 'kernel': ['rbf', 'poly']}
svc=svm.SVC(probability=True)
model=GridSearchCV(svc, param_grid)


from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test=train_test_split(x, y, test_size=0.20, random_state=77, stratify=y)
print('Splitted Successfully!')
model.fit(x_train, y_train)
print('The model is trained successfully with the given images!')


from sklearn.metrics import accuracy_score

y_pred=model.predict(x_test)
print('The predicted Data is:')
print(y_pred)
print('The actual data is:')
print(np.array(y_test))
print(f"The model is {accuracy_score(y_test, y_pred)*100}% accurate.")

Tuesday, January 23, 2024

ML: Image segmentation with a U-Net-like architecture

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# https://keras.io/examples/vision/oxford_pets_image_segmentation/
import os

input_dir="images/"
target_dir="annotations/trimaps/"
img_size=(160, 160)
num_classes=3
batch_size=32

input_img_paths=sorted(
    [
        os.path.join(input_dir, fname)
        for fname in os.listdir(input_dir)
        if fname.endswith(".jpg")
    ]
)

target_img_paths=sorted(
    [
        os.path.join(target_dir, fname)
        for fname in os.listdir(target_dir)
        if fname.endswith(".png") and not fname.startswith(".")
    ]
)

print("Number of samples:", len(input_img_paths))

for input_path, target_path in zip(input_img_paths[:10], target_img_paths[:10]):
    print(input_path, "|", target_path)


from IPython.display import Image, display
from keras.utils import load_img
from PIL import ImageOps
import matplotlib.pyplot as plt

# Display input image #10
display(Image(filename=input_img_paths[9]))

# Display auto-contrast version of corresponding target (per-pixel categories)
img=ImageOps.autocontrast(load_img(target_img_paths[9]))
display(img)


import keras
import numpy as np
from tensorflow import data as tf_data
from tensorflow import image as tf_image
from tensorflow import io as tf_io

def get_dataset(
        batch_size,
        img_size,
        input_img_paths,
        target_img_paths,
        max_dataset_len=None,
):
    def load_img_masks(input_img_path, target_img_path):
        input_img=tf_io.read_file(input_img_path)  # Reads the contents of file.
        input_img=tf_io.decode_png(input_img, channels=3)  # Decode a PNG-encoded image to a uint8 or uint16 tensor.
        input_img=tf_image.resize(input_img, img_size)
        input_img=tf_image.convert_image_dtype(input_img, "float32")

        target_img=tf_io.read_file(target_img_path)
        target_img=tf_io.decode_png(target_img, channels=1)
        target_img=tf_image.resize(target_img, img_size, method="nearest")
        target_img=tf_image.convert_image_dtype(target_img, "uint8")

        # Ground truth labels are 1, 2, 3. Subtract one to make them 0, 1, 2:
        target_img=target_img-1
        return input_img, target_img

    # For faster debugging, limit the size of data
    if max_dataset_len:  # checks if max_dataset_len has a truthy value. If max_dataset_len is None, 0, or even an empty container like [] or '', the condition will be False
        input_img_paths=input_img_paths[: max_dataset_len]
        target_img_paths=target_img_paths[:max_dataset_len]
    dataset=tf_data.Dataset.from_tensor_slices((input_img_paths, target_img_paths))  # Represents a potentially large set of elements
    dataset=dataset.map(load_img_masks, num_parallel_calls=tf_data.AUTOTUNE)
    return dataset.batch(batch_size)

from keras import layers

def get_model(img_size, num_classes):
    inputs=keras.Input(shape=img_size+(3, ))

    # Entry block
    x=layers.Conv2D(32, 3, strides=2, padding="same")(inputs)  # 2D convolution layer
    x=layers.BatchNormalization()(x)
    x=layers.Activation("relu")(x)

    previous_block_activation=x

    # Block 1, 2, 3 are identical apart from the feature depth
    for filters in [64, 128, 256]:
        x=layers.Activation("relu")(x)
        x=layers.SeparableConv2D(filters, 3, padding="same")(x)
        x=layers.BatchNormalization()(x)

        x=layers.Activation("relu")(x)
        x=layers.SeparableConv2D(filters, 3, padding="same")(x)
        x=layers.BatchNormalization()(x)

        x=layers.MaxPooling2D(3, strides=2, padding="same")(x)


        # Project residual
        residual=layers.Conv2D(filters, 1, strides=2, padding="same")(
            previous_block_activation
        )
        x=layers.add([x, residual])
        previous_block_activation=x

    for filters in [256, 128, 64,32]:
        x=layers.Activation("relu")(x)
        x=layers.Conv2DTranspose(filters, 3, padding="same")(x)
        x=layers.BatchNormalization()(x)

        x=layers.Activation("relu")(x)
        x=layers.Conv2DTranspose(filters, 3, padding="same")(x)
        x=layers.BatchNormalization()(x)

        x=layers.UpSampling2D(2)(x)

        # Project residual
        residual=layers.UpSampling2D(2)(previous_block_activation)
        residual=layers.Conv2D(filters, 1, padding="same")(residual)
        x=layers.add([x, residual])
        previous_block_activation=x

    # Add a per-pixel classification layer
    outputs=layers.Conv2D(num_classes,3, activation="softmax", padding="same")(x)


    model=keras.Model(inputs, outputs)
    return model

# Build model
model = get_model(img_size, num_classes)
# model=ComputeSumModel(get_model(img_size, num_classes))
model.summary()

import random

# Split our img paths into a training and a validation set
val_samples=1000
random.Random(1337).shuffle(input_img_paths)
random.Random(1337).shuffle(target_img_paths)

train_input_img_paths=input_img_paths[:-val_samples]
train_target_img_paths=target_img_paths[:-val_samples]
val_input_img_paths=input_img_paths[-val_samples:]
val_target_img_paths=target_img_paths[-val_samples:]


# Instantiate dataset for each split
# Limit input files in 'max_dataset_len' for faster epoch training time
# Remove the 'max_dataset_len' arg when running with full dataset
train_dataset=get_dataset(
    batch_size,
    img_size,
    train_input_img_paths,
    train_target_img_paths,
    max_dataset_len=1000,
)
valid_dataset=get_dataset(
    batch_size, img_size, val_input_img_paths, val_target_img_paths
)

# Configure the model for training.
# We use the "sparse" version of categorical_crossentropy
# because our target data is integers
model.compile(
    optimizer=keras.optimizers.Adam(1e-4), loss="sparse_categorical_crossentropy"
)

callbacks=[
    keras.callbacks.ModelCheckpoint("oxford_segmentation.keras", save_best_only=True)
]

# Train the model, doing validation at the end of each epoch
epochs=1

model.fit(
    train_dataset,
    epochs=epochs,
    validation_data=valid_dataset,
    callbacks=callbacks,
    verbose=2,
)

# Generate predictions for all images in the validation set
val_dataset=get_dataset(
    batch_size, img_size, val_input_img_paths, val_target_img_paths
)
val_preds=model.predict(val_dataset)


def display_img(i):
    mask=np.argmax(val_preds[i], axis=-1)
    mask=np.expand_dims(mask, axis=-1)
    img=ImageOps.autocontrast(keras.utils.array_to_img(mask))
    display(img)



# Display results for validation image #10
i=10

# Display input image
display(Image(filename=val_input_img_paths[i]))

# Display ground-truth target mask
img=ImageOps.autocontrast(load_img(val_target_img_paths[i]))
display(img)

# Display mask predicted by our model
display_img(i)

Grex: Tips

1
2
3
4
virtualenv --no-download ENV
source ENV/bin/activate
pip install --upgrade pip
deactivate #to exit the virtual environment, simply enter the command deactivate
You can now use the same virtual environment over and over again. Each time: Load the same environment modules that you loaded when you created the virtual environment, e.g. module load python
Activate the environment, source ENV/bin/activate

Monday, January 22, 2024

ML: Image classification via fine-tuning with EfficientNet

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
# https://keras.io/examples/vision/image_classification_efficientnet_fine_tuning/

import numpy as np
import tensorflow_datasets as tfds
import tensorflow as tf
import matplotlib.pyplot as plt
import keras
from keras import layers
from keras.applications import EfficientNetB0

IMG_SIZE=224 # IMG_SIZE is determined by EfficientNet Model choice
BATCH_SIZE=64

# Loading data
dataset_name="stanford_dogs"
(ds_train, ds_test), ds_info=tfds.load(
dataset_name, split=["train", "test"], with_info=True, as_supervised=True
)
NUM_CLASSES=ds_info.features["label"].num_classes


# When the dataset include images with various size, we need to resize them into a shared size. The Stanford Dogs dataset includes only images at least 200x200 pixels in size. Here we resize the images to the input size needed for EfficientNet.
size=(IMG_SIZE, IMG_SIZE)
ds_train=ds_train.map(lambda image, label:(tf.image.resize(image, size), label))
ds_test=ds_test.map(lambda image, label:(tf.image.resize(image, size), label))

def format_label(label):
    string_label=label_info.int2str(label)
    return string_label.split("-")[1]

label_info=ds_info.features["label"]
for i, (image, label) in enumerate(ds_train.take(9)):
    ax=plt.subplot(3, 3, i+1)
    plt.imshow(image.numpy().astype("uint8"))
    plt.title("{}".format(format_label(label)))
    plt.axis('off')


% Data augmentation
img_augmentation_layers=[
    layers.RandomRotation(factor=0.15),
    layers.RandomTranslation(height_factor=0.1, width_factor=0.1),  # A preprocessing layer which randomly translates images during training. 
    layers.RandomFlip(),  # A preprocessing layer which randomly flips images during training.
    layers.RandomContrast(factor=0.1),  # A preprocessing layer which randomly adjusts contrast during training.
]


def img_augmentation(images):
    for layer in img_augmentation_layers:
        images=layer(images)
    return images

# Here we plot 9 examples of augmentation result of a given figure.
for image, label in ds_train.take(1):
    for i in range(9):
        ax=plt.subplot(3, 3, i+1)
        aug_img=img_augmentation(np.expand_dims(image.numpy(), axis=0))
        aug_img=np.array(aug_img)
        plt.imshow(aug_img[0].astype("uint8"))
        plt.title("{}".format(format_label(label)))
        plt.axis('off')



def input_preprocess_train(image, label):  # One-hot/categorical encoding
    image=img_augmentation(image)
    label=tf.one_hot(label, NUM_CLASSES)  # Returns a one-hot tensor.
    return image, label


def input_preprocess_test(image, label):
    label=tf.one_hot(label, NUM_CLASSES)  # Returns a one-hot tensor.
    return image, label

ds_train=ds_train.map(input_preprocess_train, num_parallel_calls=tf.data.AUTOTUNE)
ds_train=ds_train.batch(batch_size=BATCH_SIZE, drop_remainder=True)
ds_train=ds_train.prefetch(tf.data.AUTOTUNE)

ds_test=ds_test.map(input_preprocess_test, num_parallel_calls=tf.data.AUTOTUNE)
ds_test=ds_test.batch(batch_size=BATCH_SIZE, drop_remainder=True)

# Training a model from scratch
model=EfficientNetB0(
    include_top=True,
    weights=None,
    classes=NUM_CLASSES,
    input_shape=(IMG_SIZE, IMG_SIZE, 3),
)

model.compile(optimizer='adam', loss="categorical_crossentropy", metrics=["accuracy"])
model.summary()

# all model.summary() to print a useful summary of the model, which includes:
# Name and type of all layers in the model.
# Output shape for each layer.
# Number of weight parameters of each layer.
# If the model has general topology (discussed below), the inputs each layer receives
# The total number of trainable and non-trainable parameters of the model.

epochs=20

hist=model.fit(ds_train, epochs=epochs, validation_data=ds_test)

Friday, January 19, 2024

ML: Training an image classifier from scratch on the Kaggle Cats vs Dogs dataset

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# https://keras.io/examples/vision/image_classification_from_scratch/

import os
import numpy as np
import keras
from keras import layers
from tensorflow import data as tf_data
import matplotlib.pyplot as plt

num_skipped=0; # the number of photos deleted
for folder_name in ("Cat", "Dog"):
    folder_path=os.path.join("D:\PyTest\PetImages", folder_name)
    for fname in os.listdir(folder_path):
        fpath=os.path.join(folder_path, fname)
        try:
            fobj=open(fpath, "rb") # "r" - Read & "b" - Binary - Binary mode
            is_jfif=b"JFIF" in fobj.peek(10)
        finally:
            fobj.close()

        if not is_jfif:
            num_skipped= num_skipped+1
            os.remove(fpath)

print(f"Deleted {num_skipped} images.")

image_size=(180, 180) # width, height
batch_size=128

train_ds, val_ds=keras.utils.image_dataset_from_directory(
    "D:\PyTest\PetImages",
    validation_split=0.2,  # fraction of data to reserve for validation
    subset="both",
    seed=1337, # Optional random seed for shuffling and transformations.
    image_size=image_size,
    batch_size=batch_size,
)

plt.figure(figsize=(10, 10))  # plot the images

for images, labels in train_ds.take(1):
    for i in range(9):
        ax=plt.subplot(3, 3, i+1)

        plt.imshow(np.array(images[i]).astype("uint8"))
        # plt.show()
        plt.title(int(labels[i]))
        plt.axis("off")

data_augmentation_layers=[
    layers.RandomFlip("horizontal"), # which flip mode to use. Can be "horizontal", "vertical", or "horizontal_and_vertical". "horizontal" is a left-right flip and "vertical" is a top-bottom flip. Defaults to "horizontal_and_vertical"
    layers.RandomRotation(0.1), # a float represented as fraction of 2 Pi, or a tuple of size 2 representing lower and upper bound for rotating clockwise and counter-clockwise.
]

def data_augmentation(images):   # a function is defined, all input images will be augmented and return.
    for layer in data_augmentation_layers:
        images=layer(images)

    return images

plt.figure(figsize=(10, 10))   # plot the images

for images, _ in train_ds.take(1):
    for i in range(9):
        augmented_images=data_augmentation(images)
        ax=plt.subplot(3, 3, i+1)

        plt.imshow(np.array(augmented_images[0]).astype("uint8"))

        plt.axis("off")

inputs=keras.Input(shape=image_size)
x=data_augmentation(inputs) # Call a function, we defined above.
x=layers.Rescaling(1./255)(x) # To rescale an input in the [0, 255] range to be in the [0, 1] range, you would pass scale=1./255.


# Apply 'data_augmentation' to the training images.
train_ds=train_ds.map(
    lambda img, label: (data_augmentation(img), label),
    num_parallel_calls=tf_data.AUTOTUNE,
)
# Prefetching samples in GPU memory helps maximize GPU utilization.
train_ds=train_ds.prefetch(tf_data.AUTOTUNE)
val_ds=val_ds.prefetch(tf_data.AUTOTUNE)

def make_model(input_shape, num_classes):  # Define a function
    inputs=keras.Input(shape=input_shape)

    #Entry block
    x=layers.Rescaling(1.0/255)(inputs) # To rescale an input in the [0, 255] range to be in the [0, 1] range, you would pass scale=1./255.
    x=layers.Conv2D(128,3,strides=2, padding="same")(x) # int, the dimension of the output space (the number of filters in the convolution).
    x=layers.BatchNormalization()(x)  # Layer that normalizes its inputs.
    x=layers.Activation("relu")(x)

    previous_block_activation=x

    for size in [256, 512, 728]:
        x=layers.Activation("relu")(x)
        x=layers.SeparableConv2D(size, 3, padding="same")(x)  # Depthwise separable 2D convolution
        x=layers.BatchNormalization()(x)  # Layer that normalizes its inputs.
        x=layers.Activation("relu")(x)
        x=layers.SeparableConv2D(size, 3,padding="same")(x)
        x=layers.BatchNormalization()(x)



        x=layers.MaxPooling2D(3, strides=2, padding="same")(x) # Max pooling operation for 2D spatial data.

        residual=layers.Conv2D(size, 1, strides=2, padding="same")(
            previous_block_activation
        )
        x=layers.add([x,residual])
        previous_block_activation=x

    x=layers.SeparableConv2D(1024, 3, padding="same")(x)
    x=layers.BatchNormalization()(x)
    x=layers.Activation("relu")(x)


    x=layers.GlobalAveragePooling2D()(x)
    if num_classes==2:
        units=1
    else:
        units=num_classes



    x=layers.Dropout(0.25)(x)

    # We specify activation=None so as to return logits
    outputs=layers.Dense(units, activation=None)(x)
    return keras.Model(inputs, outputs)

img=keras.utils.load_img("D:\weed\PyTest\PetImages\Cat\6779.jpg", target_size=image_size)

img_array=keras.utils.img_to_array(img)
img_array=keras.ops.expand_dims(img_array, 0)


predictions=model.predict(img_array)
score=float(keras.ops.sigmoid(predictions[0][0]))
print(f"This image is {100*(1-score):.2f}% cat and {100*score:.2f}% dog.")