Commit 1862a70d authored by Lafnoune Imane's avatar Lafnoune Imane
Browse files

CNN transfer learning * 4

parent d60a3d60
%% Cell type:markdown id: tags:
# CNN superposition + MLP
%% Cell type:markdown id: tags:
https://www.pyimagesearch.com/2019/02/04/keras-multiple-inputs-and-mixed-data/
%% Cell type:code id: tags:
``` python
import numpy as np
import pandas as pd
import os
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
```
%% Cell type:markdown id: tags:
## A - Preprocessing : Reading Data
%% Cell type:code id: tags:
``` python
os.chdir('../')
```
%% Cell type:code id: tags:
``` python
from preprocessing.read_load_data import read_data
input_directory='../osic-pulmonary-fibrosis-progression'
train_df, test_df, sample_df = read_data(input_directory)
train_df.head()
```
%%%% Output: execute_result
Patient Weeks FVC Percent Age Sex SmokingStatus
0 ID00007637202177411956430 -4 2315 58.253649 79 Male Ex-smoker
1 ID00007637202177411956430 5 2214 55.712129 79 Male Ex-smoker
2 ID00007637202177411956430 7 2061 51.862104 79 Male Ex-smoker
3 ID00007637202177411956430 9 2144 53.950679 79 Male Ex-smoker
4 ID00007637202177411956430 11 2069 52.063412 79 Male Ex-smoker
%% Cell type:markdown id: tags:
## B - Preprocessing : Loading Data
%% Cell type:code id: tags:
``` python
patients_train_ids= train_df.Patient.unique()
patient_test_list= test_df.Patient.unique()
patients_train_ids = [pat for pat in patients_train_ids]
```
%% Cell type:code id: tags:
``` python
from preprocessing.read_load_data import load_images
logging.info("loading attributes...")
df = pd.read_csv(f'{input_directory}/train.csv')
df = df.drop_duplicates(subset = 'Patient', keep='first')
patients_train_ids= df.Patient.unique().tolist()
df = df[df['Patient'].isin(patients_train_ids)]
logging.info("loading images...")
images = load_images(input_directory,
'train',
patients_train_ids,
option='superposition',
outputH = 240,
outputW = 240)
print("Array shape: ", images.shape)
#check value between -1,1
print('min value: ', np.amin(images))
print('max value: ', np.amax(images))
```
%%%% Output: stream
INFO:loading attributes...
INFO:loading images...
%%%% Output: stream
Array shape: (176, 240, 240, 4)
min value: -0.1251496147096971
max value: 0.16921848376183674
%% Cell type:markdown id: tags:
## C - Preprocessing : shuffle
%% Cell type:code id: tags:
``` python
from sklearn.model_selection import train_test_split
split = train_test_split(df, images, test_size=0.2, random_state=42)
(trainAttrX, testAttrX, trainImagesX, testImagesX) = split
```
%% Cell type:markdown id: tags:
## D - Preprocessing : Scaling + Encoding
%% Cell type:code id: tags:
``` python
from preprocessing.scale_data import scale_variable
sc, trainAttrX, testAttrX = scale_variable(trainAttrX, testAttrX,'FVC')
trainY = trainAttrX.loc[:,'FVC_scaled']
testY = testAttrX.loc[:,'FVC_scaled']
```
%% Cell type:code id: tags:
``` python
from preprocessing.scale_data import encode_variable
trainAttrX, testAttrX = encode_variable(trainAttrX, testAttrX,'Sex')
trainAttrX, testAttrX = encode_variable(trainAttrX, testAttrX,'SmokingStatus')
trainAttrX.drop(columns = ['Sex','SmokingStatus','FVC','FVC_scaled','Patient'], inplace = True)
testAttrX.drop(columns = ['Sex','SmokingStatus','FVC','FVC_scaled','Patient'], inplace = True)
```
%% Cell type:markdown id: tags:
## E - Processing : Create models
%% Cell type:code id: tags:
``` python
from processing.models import create_hybrid
from keras.optimizers import Adam
model = create_hybrid(trainAttrX.shape[1], shape = (240,240,4))
opt = Adam(lr=1e-3, decay=1e-3 / 200)
model.compile(loss="mean_absolute_percentage_error", optimizer=opt)
```
%% Cell type:code id: tags:
``` python
model.summary()
```
%%%% Output: stream
Model: "model_1"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_1 (InputLayer) [(None, 240, 240, 4) 0
__________________________________________________________________________________________________
conv2d (Conv2D) (None, 240, 240, 32) 1184 input_1[0][0]
__________________________________________________________________________________________________
activation (Activation) (None, 240, 240, 32) 0 conv2d[0][0]
__________________________________________________________________________________________________
batch_normalization (BatchNorma (None, 240, 240, 32) 128 activation[0][0]
__________________________________________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 120, 120, 32) 0 batch_normalization[0][0]
__________________________________________________________________________________________________
conv2d_1 (Conv2D) (None, 120, 120, 64) 18496 max_pooling2d[0][0]
__________________________________________________________________________________________________
activation_1 (Activation) (None, 120, 120, 64) 0 conv2d_1[0][0]
__________________________________________________________________________________________________
batch_normalization_1 (BatchNor (None, 120, 120, 64) 256 activation_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D) (None, 60, 60, 64) 0 batch_normalization_1[0][0]
__________________________________________________________________________________________________
conv2d_2 (Conv2D) (None, 60, 60, 128) 73856 max_pooling2d_1[0][0]
__________________________________________________________________________________________________
activation_2 (Activation) (None, 60, 60, 128) 0 conv2d_2[0][0]
__________________________________________________________________________________________________
batch_normalization_2 (BatchNor (None, 60, 60, 128) 512 activation_2[0][0]
__________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D) (None, 30, 30, 128) 0 batch_normalization_2[0][0]
__________________________________________________________________________________________________
flatten (Flatten) (None, 115200) 0 max_pooling2d_2[0][0]
__________________________________________________________________________________________________
dense_3 (Dense) (None, 16) 1843216 flatten[0][0]
__________________________________________________________________________________________________
activation_3 (Activation) (None, 16) 0 dense_3[0][0]
__________________________________________________________________________________________________
dense_input (InputLayer) [(None, 5)] 0
__________________________________________________________________________________________________
batch_normalization_3 (BatchNor (None, 16) 64 activation_3[0][0]
__________________________________________________________________________________________________
dense (Dense) (None, 8) 48 dense_input[0][0]
__________________________________________________________________________________________________
dropout (Dropout) (None, 16) 0 batch_normalization_3[0][0]
__________________________________________________________________________________________________
dense_1 (Dense) (None, 4) 36 dense[0][0]
__________________________________________________________________________________________________
dense_4 (Dense) (None, 4) 68 dropout[0][0]
__________________________________________________________________________________________________
dense_2 (Dense) (None, 1) 5 dense_1[0][0]
__________________________________________________________________________________________________
activation_4 (Activation) (None, 4) 0 dense_4[0][0]
__________________________________________________________________________________________________
concatenate (Concatenate) (None, 5) 0 dense_2[0][0]
activation_4[0][0]
__________________________________________________________________________________________________
dense_5 (Dense) (None, 4) 24 concatenate[0][0]
__________________________________________________________________________________________________
dense_6 (Dense) (None, 1) 5 dense_5[0][0]
==================================================================================================
Total params: 1,937,898
Trainable params: 1,937,418
Non-trainable params: 480
__________________________________________________________________________________________________
%% Cell type:code id: tags:
``` python
%%time
hist = model.fit(
x=[trainAttrX, trainImagesX], y=trainY,
validation_data=([testAttrX, testImagesX], testY),
epochs=10, batch_size=8)
```
%%%% Output: stream
Epoch 1/10
18/18 [==============================] - 17s 962ms/step - loss: 17297.2285 - val_loss: 8773.3945
Epoch 2/10
18/18 [==============================] - 17s 937ms/step - loss: 14543.4473 - val_loss: 7628.3647
Epoch 3/10
18/18 [==============================] - 17s 932ms/step - loss: 12521.3574 - val_loss: 6439.5806
Epoch 4/10
18/18 [==============================] - 17s 923ms/step - loss: 10621.5508 - val_loss: 5404.7344
Epoch 5/10
18/18 [==============================] - 18s 1s/step - loss: 9031.5049 - val_loss: 4566.3062
Epoch 6/10
18/18 [==============================] - 17s 929ms/step - loss: 7397.2144 - val_loss: 3876.5049
Epoch 7/10
18/18 [==============================] - 12s 646ms/step - loss: 6170.1357 - val_loss: 3202.0596
Epoch 8/10
18/18 [==============================] - 9s 505ms/step - loss: 5047.9321 - val_loss: 2654.9036
Epoch 9/10
18/18 [==============================] - 9s 526ms/step - loss: 4015.9482 - val_loss: 2034.9280
Epoch 10/10
18/18 [==============================] - 9s 527ms/step - loss: 3207.2871 - val_loss: 1467.7925
CPU times: user 10min 8s, sys: 34.7 s, total: 10min 42s
Wall time: 2min 33s
%% Cell type:code id: tags:
``` python
from postprocessing.plot_history import plot_history
plot_history(hist)
```
%%%% Output: display_data
![](data:image/png;base64,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)
%% Cell type:markdown id: tags:
# F - Evaluation
%% Cell type:markdown id: tags:
### Training set
%% Cell type:code id: tags:
``` python
from postprocessing.evaluate import evaluate_hybrid, compute_score
```
%% Cell type:code id: tags:
``` python
preds = evaluate_hybrid(model, df, trainAttrX, trainImagesX, trainY, sc)
conf, score = compute_score(trainY,preds.flatten())
print('competition score :', score)
```
%%%% Output: stream
INFO:predicting ...
INFO:NumExpr defaulting to 8 threads.
%%%% Output: stream
avg. FVC: 2771.744318181818, std FVC 835.5745106360505
mean difference : 202.32%, std: 86.26%
competition score : -4.720542265507132
%% Cell type:code id: tags:
``` python
model.evaluate([trainAttrX, trainImagesX], trainY)
from postprocessing.evaluate import evaluate_hybrid, compute_scoremodel.evaluate([trainAttrX, trainImagesX], trainY)
```
%%%% Output: stream
5/5 [==============================] - 1s 295ms/step - loss: 2697.1895
%%%% Output: execute_result
2697.189453125
%% Cell type:markdown id: tags:
### Test set
%% Cell type:code id: tags:
``` python
preds = evaluate_hybrid(model, df, testAttrX, testImagesX, testY, sc)
conf, score = compute_score(testY,preds.flatten())
print('competition score :', score)
```
%%%% Output: stream
INFO:predicting ...
%%%% Output: stream
avg. FVC: 2771.744318181818, std FVC 835.5745106360505
mean difference : 215.41%, std: 88.26%
competition score : -4.714108713977412
%% Cell type:code id: tags:
``` python
model.evaluate([testAttrX, testImagesX], testY)
```
%%%% Output: stream
2/2 [==============================] - 0s 21ms/step - loss: 1467.7925
%%%% Output: execute_result
1467.79248046875
%% Cell type:markdown id: tags:
# G - Sample submission file
%% Cell type:code id: tags:
``` python
```
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,11 @@ from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import GlobalAveragePooling2D
from tensorflow.keras.layers import concatenate
from tensorflow import TensorShape
import numpy as np
......@@ -69,4 +73,75 @@ def create_hybrid(nb_attributes,shape=(240,240,1)):
x = Dense(4, activation="relu")(combinedInput)
x = Dense(1, activation="linear")(x)
model = Model(inputs=[mlp.input, cnn.input], outputs=x)
return model
def multify_weights(kernel, out_channels):
# Expand weights dimension to match new input channels
mean_1d = np.mean(kernel, axis=-2).reshape(kernel[:,:,-1:,:].shape)
tiled = np.tile(mean_1d, (out_channels, 1))
return(tiled)
def weightify(model_orig, custom_model, layer_modify,input_channel):
# Loop through layers of both original model
# and custom model and copy over weights
# layer_modify refers to first convolutional layer
layer_to_modify = [layer_modify]
conf = custom_model.get_config()
layer_names = [conf['layers'][x]['name'] for x in range(len(conf['layers']))]
for layer in model_orig.layers:
if layer.name in layer_names:
if layer.get_weights() != []:
target_layer = custom_model.get_layer(layer.name)
#print(len(layer.get_weights()))
if layer.name in layer_to_modify:
kernels = layer.get_weights()[0]
#biases = layer.get_weights()[1]
kernels_extra_channel = np.concatenate((kernels,
multify_weights(kernels, input_channel - 3)),
axis=-2)
target_layer= Conv2D(32, (3, 3), activation='relu', padding='valid',use_bias=False)
input_shape = TensorShape([None, 240, 240, 4]) # to define h, w, c based on shape of layer input
target_layer.build(input_shape)
target_layer.set_weights([kernels_extra_channel])
#target_layer.set_weights([kernels_extra_channel, biases])
#target_layer.set_weights(kernels)
#target_layer.trainable = False
else:
target_layer.set_weights(layer.get_weights())
target_layer.trainable = False
return custom_model
def create_transfer_learning(new_model, custom_model, modify_name,input_channel = 4):
# create cnn with transfer learning
new = weightify(new_model,custom_model,modify_name,input_channel)
x = new.output
x = GlobalAveragePooling2D()(x)
x = Dropout(0.5)(x)
x = Dense(1)(x)
model = Model(new.input, x)
for layer in new.layers:
layer.trainable = False
return model
def create_hybrid_transfer(nb_attributes,new_model, custom_model, modify_name,input_channel):
# create cnn and mlp models
mlp = create_mlp(nb_attributes)
cnn = create_transfer_learning(new_model, custom_model, modify_name,input_channel)
combinedInput = concatenate([mlp.output, cnn.output])
x = Dense(4, activation="relu")(combinedInput)
x = Dense(1, activation="linear")(x)
model = Model(inputs=[mlp.input, cnn.input], outputs=x)
return model
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment