Overview
확인해볼 예시 코드는 ResNet imageNet 데이터를 사전학습한 신경망 모델에 gradCAM을 붙인 코드이다.
gradCAM은 CNN 모델 맨 마지막 컨볼루션 층에 연결하여 해당 데이터의 가중치를 토대로 이미지에 덧씌우는 기술이다. 그러나 LIME/SHAP은 가능한 모든 변수들을 제거한 뒤 변수의 중요도를 측정하며 진정한 의미의 설명 가능 인공지능이라고 말할 수 있다.
model=ResNet50(weights='imagenet')
model.summary()
- 파인 튜닝 없이 이미지넷에 있는 가중치를 그대로 쓰겠다.
input layer
layeroutput | shape | param | connect to |
input_1 (InputLayer) | (None, 224, 224, 3) | 0 | [] |
... | ... | ... | ... |
conv1_bn (BatchNormalization) | (None, 14, 14, 256) | 1024 | 'conv4_block1_1_conv[0][0]' |
... | ... | ... | ... |
avg_pool (GlobalAveragePooling2D) | (None, 2048) | 0 | 'conv5_block3_out[0][0]' |
- 학습시킬 이미지 개수를 지정하지 않음2/224 x 224로 resize / rgb colors
- gradiant 문제 해결하기 위해 Batch size만큼 모델을 돌릴 때 Normalization를 한다. drop out을 넣어 overfitting을 했듯 모델 중간중간 BatchNormalization layer을 쌓아준다.
Code Review
지정된 영상을 불러와 크기를 조정하고 화면에 디스플레이한다.
image_path='/content/drive/MyDrive/gradcam/hummingbird.jpg'
img=image.load_img(image_path,target_size=(224,224))
plt.matshow(img)

- 테스트 하고자 하는 이미지
이미지/영상을 신경망 입력 형태로 변환한다.
x=image.img_to_array(img)
x=np.expand_dims(x,axis=0)
x=resnet50.preprocess_input(x)
x=resnet50.preprocess_input(x)
- resNet은 모든 이미지를 255로 나누어 정규화하는 대신 데이터 별로 분산, 평균을 구하여 그 값으로 정규화하는 preprocess한다.
이미지 x를 predict함수로 예측한다.
preds=model.predict(x)
print("예측 결과:", resnet50.decode_predictions(preds,top=5)[0])
print("예측 결과:", resnet50.decode_predictions(preds,top=5)[0])
imageNet은 천 개의 카테고리로 분류하므로, 천 개 카데고리 별로 가능성을 보여준다. 그렇기 때문에 가장 가능성이 높은 5개의 카테고리만 표시한다.
gradiant를 구하기 위해 모델을 두 가지로 나눈다.
last_conv_layer=model.get_layer("conv5_block3_out")
model_1=keras.Model(model.inputs,last_conv_layer.output)
input_2=keras.Input(shape=last_conv_layer.output.shape[1:])
x_2=model.get_layer("avg_pool")(input_2)
x_2=model.get_layer("predictions")(x_2)
model_2=keras.Model(input_2,x_2)
특징 추출 부분만으로 구성된 모델 model_1을 만들고, 미분한 값들의 합을 구하기 위해 분류(전역 평균 풀링 또는 완전 연결층) 부분으로만 구성된 모델 model_2를 구한다.
last_conv_layer=model.get_layer("conv5_block3_out")
- 맨 마지막 컨볼루션 층을 구한다.
- summary를 찍어봤을 때 avg_pool층 바로 위가 마지막 컨볼루션 층이라는 걸 알 수 있다.
model_1=keras.Model(model.inputs,last_conv_layer.output)
- 특징 추출 부분으로만 이루어져있다.
input_2=keras.Input(shape=last_conv_layer.output.shape[1:])
- last_conv 이후 layer를 input2에 담는다.
x_2=model.get_layer("avg_pool")(input_2)
x_2=model.get_layer("predictions")(x_2)
model_2=keras.Model(input_2,x_2)
- 분류(전역평균 풀링 또는 완전연결층) 부분만으로 구성된 모델 model_2 만든다.
model_1과 model_2를 이용하여 gradiant를 계산한다.
with tf.GradientTape() as tape:
output_1=model_1(x)
tape.watch(output_1)
preds=model_2(output_1)
class_id=tf.argmax(preds[0])
output_2=preds[:,class_id]
모델1을 모델2로 미분하는 함수이다.
tape.watch(output_1)
- 마지막 층으로 미분하기 위한 준비
grads=tape.gradient(output_2,output_1) # 그레이디언트 계산
pooled_grads=tf.reduce_mean(grads,axis=(0,1,2)) # 식 (12.5) 적용
그래디언트를 계산한다.
(편미분 값 x 특징맵)을 계산하여 최종 heap맵을 만들고 이미지에 덧씌운다.
output_1=output_1.numpy()[0]
pooled_grads=pooled_grads.numpy()
for i in range(pooled_grads.shape[-1]): # 식 (12.6) 적용
output_1[:,:,i]*=pooled_grads[i]
heatmap=np.mean(output_1,axis=-1)
- 편미분 값을 구해 특징맵과 곱하여 heapmap을 만든다.
heatmap=np.maximum(heatmap,0)/np.max(heatmap)
plt.matshow(heatmap)
- [0,1]로 정규화한다.
- heap맵이 여러장이 생긴다.
img=image.load_img(image_path)
- 입력 영상을 다시 불러온다.
img=image.img_to_array(img)
heatmap=np.uint8(255*heatmap)
- 정규화된 이미지 데이터를 다시 원본데이터로 변환한다.
jet=cm.get_cmap("jet")
color=jet(np.arange(256))[:,:3]
color_heatmap=color[heatmap]
- [0,255] 열지도를 jet 컬러맵으로 표시한다.
color_heatmap=keras.preprocessing.image.array_to_img(color_heatmap)
color_heatmap=color_heatmap.resize((img.shape[1],img.shape[0]))
color_heatmap=keras.preprocessing.image.img_to_array(color_heatmap)
- 원본 이미지를 heapmap으로 변환함.
overlay_img=color_heatmap*0.4+img
overlay_img=keras.preprocessing.image.array_to_img(overlay_img)
plt.matshow(overlay_img)
- heap맵을 원본 이미지에 덧씌운다.
'AI' 카테고리의 다른 글
Bert CODE (0) | 2024.06.14 |
---|---|
설명가능 인공지능 (1) | 2024.06.14 |
[빅데이터] 하둡 기본 세팅 (0) | 2024.06.14 |
[빅데이터] Hadoop (1) | 2024.06.14 |
[머신러닝] YOLO ver.3 code (0) | 2024.06.14 |
댓글