CNN #1 RNA interference 효율 예측 모델 #
#2026-02-27
개요 #
siRNA 서열을 입력받아서 RNA interference 효율을 예측하는 회귀 모델
- siRNA 길이: 21bp
- 위치당 염기 종류: 4
- -> input shape: (21,4)
#
모델 구조
features = tf.keras.Input(shape=(21, 4))
prev = features
for i in range(2):
prev = layers.Conv1D(
filters=10,
kernel_size=10,
activation=tf.nn.relu,
padding='same'
)(prev)
prev = layers.Dropout(rate=0.3)(prev)
output = layers.Dense(
units=1,
activation=tf.math.sigmoid
)(layers.Flatten()(prev))
keras_model = tf.keras.Model(inputs=features, outputs=output)
keras_model.summary()
- 21bp siRNA sequence를 입력받고
- 두 개의 Conv1D layer로 RNAi 효율 관련 염기 패턴을 학습하고
- 0~1 사이의 효율값을 예측.
요약하면 이렇다.
21bp siRNA one-hot sequence
→ Conv1D
→ Dropout
→ Conv1D
→ Dropout
→ Flatten
→ Dense(sigmoid)
→ RNAi efficiency prediction
#
첫번째 Conv1D layer #
prev = layers.Conv1D(
filters=10,
kernel_size=10,
activation=tf.nn.relu,
padding='same'
)(prev)
Conv1D 필터가 siRNA 서열을 왼쪽에서 오른쪽으로 훑으면서 염기 조합 패턴을 찾는다
- kernel_size=10: 필터 한 번에 10개 염기
- filters=10: 이런 패턴 탐지기를 10개 만든다
- activation=tf.nn.relu: Conv1D 결과를 비선형적으로 바꾼다 즉 음수 값은 0으로 만들고, 양수 값은 그대로 통과시킨다.
- padding=‘same’: convolution을 해도 sequence 길이를 유지한다. 입력 길이가 21이면 출력도 길이 21로 유지된다.
conv1d (Conv1D) (None, 21, 10) 410
첫번째 Conv1D 결과
- 입력은 (None, 21, 4)이고 출력은 (None, 21, 10)이다.
- 각 siRNA 샘플마다 21개 위치에 대해 10개의 필터 반응값을 갖는다.
- 첫 번째 Conv1D의 parameter 수는 410
- 첫 번째 Conv1D는 one-hot encoding 차원이 4이기 때문에 입력 채널이 4개이다
- 필터 하나는 kernel_size=10만큼의 위치를 보고, 각 위치마다 4개 채널을 본다.
- 그래서 필터 하나의 weight 수는 10 × 4 = 40
- 그리고 필터마다 bias가 1개 있어서 40 + 1 = 41
- 필터가 총 10개이므로 전체 parameter 수는 41 × 10 = 410
#
Dropout layer #
prev = layers.Dropout(rate=0.3)(prev)
- Dropout: 학습 중에 일부 뉴런 출력을 랜덤하게 꺼버리는 정규화 기법
- rate=0.3: 학습할 때 약 30%의 값을 임시로 0으로 만든다.
dropout (Dropout) (None, 21, 10) 0
Dropout 결과
- Dropout은 parameter가 없다
- Dropout은 학습되는 weight가 있는 layer가 아니라, 학습 중 일부 값을 꺼주는 동작만 하기 때문에 parameter 수가 0이다.
#
두번째 Conv1D layer #
prev = layers.Conv1D(
filters=10,
kernel_size=10,
activation=tf.nn.relu,
padding='same'
)(prev)
코드는 같음.
- 첫 번째 Conv1D가 찾은 저수준 sequence pattern들을 다시 조합해서 더 복합적인 패턴을 찾는다.
- 첫 번째 Conv1D가 이런 수준이라면
- 특정 10bp 구간에 G/C-rich 패턴이 있는가?
- 특정 위치 조합이 있는가?
- 특정 motif 비슷한 신호가 있는가?
- 두 번째 Conv1D는 이런 식이다.
- 앞 layer에서 감지한 여러 motif 조합이 특정 위치 관계로 나타나는가?
- 여러 부분 패턴이 함께 나타날 때 RNAi 효율이 높아지는가?
conv1d_1 (Conv1D) (None, 21, 10) 1010
두번째 Conv1D 결과
- 입력 shape는 (None, 21, 4)가 아니라 (None, 21, 10)
- 출력 shape은 그대로 (None, 21, 10)
- padding=‘same’이므로 길이 21은 유지
- filters=10이므로 채널 수도 10
- parameter 수는 1010
- 첫 번째 Conv1D가 10개의 filter 출력을 만들었기 때문에 두 번째 Conv1D의 입력 채널 수는 4 -> 10으로 바뀜
- 필터 하나의 weight 수는 kernel_size × input_channels = 10 × 10 = 100
- bias 1개를 더하면 필터 하나당 101
- 필터가 10개이므로 전체 parameter 수는 101 × 10 = 1010
#
Flatten layer #
layers.Flatten()(prev)
- Conv1D를 거친 후 데이터 shape은 (None, 21, 10)
- Dense layer는 1차원 벡터를 입력으로 받기 때문에 2차원 feature map을 한 줄로 펼쳐서 (None, 21, 10) -> (None, 210)로 만든다.
- 한 샘플당
- 21개 위치마다 10개의 feature -> 210개의 feature가 된다.
flatten (Flatten) (None, 210) 0
Flatten 결과
- Flatten은 단순히 모양만 바꾸는 layer라서 parameter가 없다.
#
Dense output layer #
output = layers.Dense(
units=1,
activation=tf.math.sigmoid
)(layers.Flatten()(prev))
- 210개의 feature를 받아서 최종 예측값 1개를 출력
dense (Dense) (None, 1) 211
Dense 결과
- parameter 수는 211
- 입력 feature가 210개이고, 출력 unit이 1개
- weight = 210 × 1 = 210 / bias = 1 / total = 211
Activation으로 sigmoid를 사용
- 출력값은 0과 1 사이로 제한된다.
- 0에 가까움 -> RNAi 효율 낮음
- 1에 가까움 -> RNAi 효율 높음
- 결과: siRNA sequence를 보고 RNAi 효율 score를 예측하는 회귀 모델
#
모델 Summary #
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 21, 4)] 0
conv1d (Conv1D) (None, 21, 10) 410
dropout (Dropout) (None, 21, 10) 0
conv1d_1 (Conv1D) (None, 21, 10) 1010
dropout_1 (Dropout) (None, 21, 10) 0
flatten (Flatten) (None, 210) 0
dense (Dense) (None, 1) 211
=================================================================
Total params: 1631 (6.37 KB)
Trainable params: 1631 (6.37 KB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
전체 parameter 수
- 첫 번째 Conv1D: 410
- 두 번째 Conv1D: 1010
- Dense: 211
- 총합: 410 + 1010 + 211 = 1631
-> 총 1,631개의 학습 가능한 parameter를 가진 작은 CNN 모델. 길이 21의 짧은 siRNA sequence를 다루기 때문에, Conv1D 두 층만으로도 sequence pattern을 어느 정도 학습할 수 있다.
#
학습 #
rnai_model = dc.models.KerasModel(
keras_model,
loss=dc.models.losses.L2Loss(),
batch_size=1000,
model_dir='rnai'
)
- 손실함수: L2 loss
- RNAi 효율 예측은 classification이 아니라 연속값 예측에 가깝다 따라서 binary cross entropy가 아니라 예측 RNAi 효율값과 실제 RNAi 효율값의 차이를 줄이는 회귀 손실을 사용한다.
- batch_size=1000: 한 번에 최대 1000개 샘플씩 묶어서 학습.
metric_rnai = dc.metrics.Metric(dc.metrics.pearsonr, mode='regression')
평가 metric: Pearson correlation
- 예측값과 실제값이 얼마나 선형적으로 잘 같이 움직이는지.
- +1에 가까움: 예측값과 실제값이 매우 잘 일치하는 방향으로 움직임
- 0에 가까움: 거의 관계 없음
- -1에 가까움: 반대로 움직임
- RNAi 효율 예측에서는 정확히 값이 완전히 같냐보다 효율이 높은 siRNA는 높게 예측하고 효율이 낮은 siRNA는 낮게 예측하는가가 중요해서 Pearson r이 적절함.
for i in range(20):
rnai_model.fit(train_rnai, nb_epoch=10)
train_score = rnai_model.evaluate(
train_rnai,
[metric_rnai]
)['pearsonr']
valid_score = rnai_model.evaluate(
valid_rnai,
[metric_rnai]
)['pearsonr']
print(
f'[RNAi] epoch {(i+1)*10:3d} | '
f'train pearsonr: {train_score:.4f} | '
f'valid pearsonr: {valid_score:.4f}'
)
학습 loop
- 20번 반복, 한 번 반복할 때마다 nb_epoch=10으로 학습
- 전체 학습 epoch 수는 20번 반복 × 10 epoch = 총 200 epoch.
- Epoch마다
- train_rnai 데이터로 10 epoch 학습
- train_rnai에서 Pearson r 계산
- valid_rnai에서 Pearson r 계산
- 현재 epoch, train score, valid score 출력
#
결과 #
[RNAi] epoch 10 | train pearsonr: 0.0863 | valid pearsonr: 0.1463
[RNAi] epoch 20 | train pearsonr: 0.3657 | valid pearsonr: 0.3439
[RNAi] epoch 30 | train pearsonr: 0.4876 | valid pearsonr: 0.4309
[RNAi] epoch 40 | train pearsonr: 0.5318 | valid pearsonr: 0.4699
[RNAi] epoch 50 | train pearsonr: 0.5669 | valid pearsonr: 0.4991
[RNAi] epoch 60 | train pearsonr: 0.6044 | valid pearsonr: 0.5267
[RNAi] epoch 70 | train pearsonr: 0.6275 | valid pearsonr: 0.5464
[RNAi] epoch 80 | train pearsonr: 0.6438 | valid pearsonr: 0.5598
[RNAi] epoch 90 | train pearsonr: 0.6559 | valid pearsonr: 0.5693
[RNAi] epoch 100 | train pearsonr: 0.6666 | valid pearsonr: 0.5780
[RNAi] epoch 110 | train pearsonr: 0.6750 | valid pearsonr: 0.5875
[RNAi] epoch 120 | train pearsonr: 0.6816 | valid pearsonr: 0.5925
[RNAi] epoch 130 | train pearsonr: 0.6887 | valid pearsonr: 0.6027
[RNAi] epoch 140 | train pearsonr: 0.6942 | valid pearsonr: 0.6079
[RNAi] epoch 150 | train pearsonr: 0.6988 | valid pearsonr: 0.6111
[RNAi] epoch 160 | train pearsonr: 0.7038 | valid pearsonr: 0.6148
[RNAi] epoch 170 | train pearsonr: 0.7071 | valid pearsonr: 0.6183
[RNAi] epoch 180 | train pearsonr: 0.7125 | valid pearsonr: 0.6210
[RNAi] epoch 190 | train pearsonr: 0.7151 | valid pearsonr: 0.6220
[RNAi] epoch 200 | train pearsonr: 0.7191 | valid pearsonr: 0.6261
train Pearson r과 valid Pearson r이 모두 꾸준히 증가
- 10 epoch: train pearsonr: 0.0863 / valid pearsonr: 0.1463
- 20 epoch: train pearsonr: 0.3657 / valid pearsonr: 0.3439
- 30 epoch: train pearsonr: 0.4876 / valid pearsonr: 0.4309
- -> 처음에는 랜덤한 필터에 가까웠던 Conv1D filter들이 학습을 거치면서 RNAi 효율과 관련된 sequence pattern을 점점 잡아가고 있다.
train과 valid 성능 차이
- 최종 200 epoch 결과: train pearsonr: 0.7191 / valid pearsonr: 0.6261
- train 성능이 valid 성능보다 높지만 valid Pearson r이 마지막까지 대체로 증가중이므로 검증 데이터에 대해서도 일반화 성능이 개선되고 있음.
최종 valid Pearson r = 0.6261
- 예측값과 실제 RNAi 효율 사이에 중간 이상 정도의 양의 상관관계.
- 모델이 완벽하게 맞히는 것은 아니지만, 효율이 높은 siRNA와 낮은 siRNA를 어느 정도 구분할 수 있다
- RNAi 효율은 sequence만으로 100% 결정되는 것이 아닐 수 있다. 실제 생물학적 환경에서는 target accessibility, RNA secondary structure, GC content, off-target 가능성, 세포 상태, 실험 noise 같은 다양한 요인이 영향을 줄 수 있다.
- 따라서 단순히 21bp one-hot sequence만 사용한 작은 CNN 모델이 validation Pearson r 0.626 정도를 냈다면, sequence 자체에 RNAi 효율을 설명하는 정보가 꽤 들어 있다는 뜻으로 볼 수 있다.