Chest X-Ray Medical Diagnosis with Deep Learning - ③ Model Development
start
BioinformaticsAndMe
Chest X-Ray Medical Diagnosis with Deep Learning
① Import Packages and Function
② Load the Datasets
③ Model Development
④ Training
⑤ Prediction and Evaluation
③ Model Development
: 이제 Model 교육 및 개발을 수행
: 하지만 실제로 신경망을 훈련하기 전에, class 불균형을 해소해야 함
plt.xticks(rotation=90)
plt.bar(x=labels, height=np.mean(train_generator.labels, axis=0))
plt.title("Frequency of Each Class")
plt.show()
: 위 그림에서 여러 병리에 따라 양성 사례의 유병률이 크게 다르다는 것을 알 수 있음
→이러한 경향은 전체 데이터셋의 경향도 반영함
: 이상적으로는 균형 잡힌 데이터셋으로 모델을 훈련시켜, positive 및 negative 사례가 손실에 동등하게 기여하도록 함
Exercise 2 - Computing Class Frequencies
: 아래 함수를 통해, 각 데이터셋의 라벨에 대한 빈도를 계산
def compute_class_freqs(labels):
"""
Compute positive and negative frequences for each class.
Args:
labels (np.array): matrix of labels, size (num_examples, num_classes)
Returns:
positive_frequencies (np.array): array of positive frequences for each
class, size (num_classes)
negative_frequencies (np.array): array of negative frequences for each
class, size (num_classes)
"""
# total number of patients (rows)
N = labels.shape[0]
positive_frequencies = np.sum(labels, axis=0) / labels.shape[0]
negative_frequencies = 1 - positive_frequencies
return positive_frequencies, negative_frequencies
: 예제 테스트
labels_matrix = np.array(
[[1, 0, 0],
[0, 1, 1],
[1, 0, 1],
[1, 1, 1],
[1, 0, 1]]
)
print("labels:")
print(labels_matrix)
test_pos_freqs, test_neg_freqs = compute_class_freqs(labels_matrix)
print(f"pos freqs: {test_pos_freqs}")
print(f"neg freqs: {test_neg_freqs}")
: 결과 출력
# Expected output
labels:
[[1 0 0]
[0 1 1]
[1 0 1]
[1 1 1]
[1 0 1]]
pos freqs: [0.8 0.4 0.8]
neg freqs: [0.2 0.6 0.2]
: 이제 training 데이터셋에 대한 빈도를 계산
freq_pos, freq_neg = compute_class_freqs(train_generator.labels)
freq_pos
# Expected output
array([0.02 , 0.013, 0.128, 0.002, 0.175, 0.045, 0.054, 0.106, 0.038,
0.021, 0.01 , 0.014, 0.016, 0.033])
: 각 병리에 대하여, positive 또는 negative의 기여 비율을 나란히 시각화
data = pd.DataFrame({"Class": labels, "Label": "Positive", "Value": freq_pos})
data = data.append([{"Class": labels[l], "Label": "Negative", "Value": v} for l,v in enumerate(freq_neg)], ignore_index=True)
plt.xticks(rotation=90)
f = sns.barplot(x="Class", y="Value", hue="Label" ,data=data)
: 위 그림에서 보듯이, 양성 사례의 기여도는 음성 사례의 기여도보다 현저히 낮음
: 기여도가 동일하도록 수행하는 방법은 각 클래스별 가중치인 Wpos 및 Wneg를 곱하여, 전체 기여도가 동일하게함
pos_weights = freq_neg
neg_weights = freq_pos
pos_contribution = freq_pos * pos_weights
neg_contribution = freq_neg * neg_weights
: positive, negative 기여도를 다시 그래프로 확인
data = pd.DataFrame({"Class": labels, "Label": "Positive", "Value": pos_contribution})
data = data.append([{"Class": labels[l], "Label": "Negative", "Value": v}
for l,v in enumerate(neg_contribution)], ignore_index=True)
plt.xticks(rotation=90)
sns.barplot(x="Class", y="Value", hue="Label" ,data=data);
: 위 그림에서처럼 가중치를 적용되어, 각 클래스의 양수/음수 레이블이 손실 함수에 대해 동일한 기여도를 갖게됨
Exercise 3 - Weighted Loss
: 아래 weighted_loss 함수를 작성하여 각 배치의 가중 손실을 계산하는 손실 함수를 반환
: 다중 클래스 손실의 경우 각 개별 클래스의 평균 손실을 합산
def get_weighted_loss(pos_weights, neg_weights, epsilon=1e-7):
"""
Return weighted loss function given negative weights and positive weights.
Args:
pos_weights (np.array): array of positive weights for each class, size (num_classes)
neg_weights (np.array): array of negative weights for each class, size (num_classes)
Returns:
weighted_loss (function): weighted loss function
"""
def weighted_loss(y_true, y_pred):
"""
Return weighted loss value.
Args:
y_true (Tensor): Tensor of true labels, size is (num_examples, num_classes)
y_pred (Tensor): Tensor of predicted labels, size is (num_examples, num_classes)
Returns:
loss (Tensor): overall scalar loss summed across all classes
"""
# initialize loss to zero
loss = 0.0
for i in range(len(pos_weights)):
# for each class, add average weighted loss for that class
loss += -(K.mean( pos_weights[i] * y_true[:,i] * K.log(y_pred[:,i] + epsilon) + \
neg_weights[i] * (1 - y_true[:,i]) * K.log(1 - y_pred[:,i] + epsilon), axis = 0))
return loss
return weighted_loss
: 예제 테스트
sess = K.get_session()
with sess.as_default() as sess:
print("Test example:\n")
y_true = K.constant(np.array(
[[1, 1, 1],
[1, 1, 0],
[0, 1, 0],
[1, 0, 1]]
))
print("y_true:\n")
print(y_true.eval())
w_p = np.array([0.25, 0.25, 0.5])
w_n = np.array([0.75, 0.75, 0.5])
print("\nw_p:\n")
print(w_p)
print("\nw_n:\n")
print(w_n)
y_pred_1 = K.constant(0.7*np.ones(y_true.shape))
print("\ny_pred_1:\n")
print(y_pred_1.eval())
y_pred_2 = K.constant(0.3*np.ones(y_true.shape))
print("\ny_pred_2:\n")
print(y_pred_2.eval())
# test with a large epsilon in order to catch errors
L = get_weighted_loss(w_p, w_n, epsilon=1)
print("\nIf we weighted them correctly, we expect the two losses to be the same.")
L1 = L(y_true, y_pred_1).eval()
L2 = L(y_true, y_pred_2).eval()
print(f"\nL(y_pred_1)= {L1:.4f}, L(y_pred_2)= {L2:.4f}")
print(f"Difference is L1 - L2 = {L1 - L2:.4f}")
# Expected output
Test example:
y_true:
[[1. 1. 1.]
[1. 1. 0.]
[0. 1. 0.]
[1. 0. 1.]]
w_p:
[0.25 0.25 0.5 ]
w_n:
[0.75 0.75 0.5 ]
y_pred_1:
[[0.7 0.7 0.7]
[0.7 0.7 0.7]
[0.7 0.7 0.7]
[0.7 0.7 0.7]]
y_pred_2:
[[0.3 0.3 0.3]
[0.3 0.3 0.3]
[0.3 0.3 0.3]
[0.3 0.3 0.3]]
If we weighted them correctly, we expect the two losses to be the same.
L(y_pred_1)= -0.4956, L(y_pred_2)= -0.4956
Difference is L1 - L2 = 0.0000
3.3 DenseNet121
: 다음으로 Keras에서 로드한 후, 두 개의 레이어를 추가 할 수 있는 DenseNet121 모델을 사용
*GlobalAveragePooling2D - DenseNet121에서 마지막 convolution 레이어의 평균을 얻음
*Dense - 각 클래스에 대한 예측 logit을 얻기 위한 sigmoid 기능이 있는 layer
: compile 함수에서 loss 매개 변수를 지정하여, 모델에 대한 사용자 정의 손실 함수를 설정할 수 있음
# create the base pre-trained model
base_model = DenseNet121(weights='drive/MyDrive/nih/densenet.hdf5', include_top=False)
x = base_model.output
# add a global spatial average pooling layer
x = GlobalAveragePooling2D()(x)
# and a logistic layer
predictions = Dense(len(labels), activation="sigmoid")(x)
model = Model(inputs=base_model.input, outputs=predictions)
model.compile(optimizer='adam', loss=get_weighted_loss(pos_weights, neg_weights))
다음 분석
Chest X-Ray Medical Diagnosis with Deep Learning
④ Training
#Reference
1) www.coursera.org/learn/ai-for-medical-diagnosis
2) github.com/vishrutskaushik/Chest-X-Ray-Medical-Diagnosis
Chest X-Ray Medical Diagnosis with Deep Learning - ③ Model Development
end
BioinformaticsAndMe
'Machine Learning' 카테고리의 다른 글
Chest X-Ray Medical Diagnosis with Deep Learning - ⑤ Prediction and Evaluation (0) | 2021.02.21 |
---|---|
Chest X-Ray Medical Diagnosis with Deep Learning - ④ Training (0) | 2021.02.21 |
Chest X-Ray Medical Diagnosis with Deep Learning - ② Load the Datasets (0) | 2021.02.15 |
Chest X-Ray Medical Diagnosis with Deep Learning - ① Import Packages and Function (0) | 2021.02.15 |
AUC-ROC 커브 (3) | 2020.08.04 |