Conv1D 기반 DNA 분석 #4 RNAi 효율 예측 #
#2026-02-27
#1 RNA 간섭(RNAi)이란?
세포 안에서 유전자가 단백질을 만드는 과정은 DNA에서 mRNA라는 복사본이 만들어지고, 이 mRNA를 리보솜이라는 기계가 읽어서 단백질을 찍어낸다. 유전자 → mRNA → 단백질, 이 흐름이 생명의 기본 공정이다.
그런데 세포 안에 짧은 RNA 조각을 집어넣으면, 그 RNA가 특정 mRNA를 찾아가서 분해한다. mRNA가 사라지면 리보솜이 읽을 게 없으니 단백질도 안 만들어진다 즉 특정 유전자를 “조용히 시키는” 것이다. 이걸 RNA 간섭, RNAi라고 한다.
이때 집어넣는 짧은 RNA를 siRNA(small interfering RNA)라고 하는데, 길이가 딱 21개 염기다. 21글자짜리 문자열 하나가 특정 유전자를 꺼버리는 스위치 역할을 하는 셈이다. 이게 왜 중요하냐면, 약으로 쓸 수 있기 때문이다. 질병을 일으키는 유전자가 있으면, 그 유전자의 mRNA를 겨냥하는 siRNA를 설계해서 넣으면 된다. 실제로 RNAi 기반 치료제가 이미 시판되고 있다.
siRNA: 21개 염기 서열
목표: 유전자 침묵 효율 (0~1 사이 연속값, 높을수록 좋음)
→ 회귀 문제
문제는 아무 21글자 서열이나 잘 작동하는 게 아니라는 것이다. 같은 유전자를 겨냥하더라도 어떤 siRNA 서열은 mRNA를 90% 넘게 분해하고, 어떤 서열은 10%밖에 분해하지 못하는 등 서열의 구성에 따라 효율이 다르다. 이유는 여러가지가 있는데 siRNA의 특정 위치에 어떤 염기가 오느냐에 따라 RISC라는 단백질 복합체와의 결합 효율이 달라지고, 서열의 열역학적 안정성(얼마나 단단하게 결합하는가)도 영향을 미치고, mRNA의 표적 부위가 접근 가능한 구조인지도 관계된다. 이러한 siRNA를 하나하나 실험으로 테스트하는 건 시간과 돈이 많이 든다. 이에 분석 목적은 서열만 보고 “이 siRNA는 효율이 높을 거야"라고 미리 예측할 수 있는 모델을 만드는것이다.
이전의 전사인자 결합 예측과 겉모습은 비슷한데, DNA(또는 RNA) 서열을 넣으면 뭔가를 예측한다. 하지만 본질적으로 다른 점이 하나 있는데 전사인자 문제에서는 “붙는다” 또는 “안 붙는다”, 즉 0 아니면 1인 분류 문제였다. 하지만 RNAi 효율은 0.12일 수도 있고 0.47일 수도 있고 0.93일 수도 있다. 0과 1 사이의 어떤 값이든 될 수 있는 연속적인 숫자이므로 회귀 문제이다. 이에 모델의 손실 함수, 평가 지표가 바뀐다.
#
#2 모델 구조
features = tf.keras.Input(shape=(21, 4))
이전에는 입력이 길이 101짜리 DNA 조각이었는데, 이번에는 길이 21짜리 siRNA다. 원-핫 인코딩은 동일하게 적용해서 (21, 4) 형태의 행렬이 된다.
101에서 21로 줄었다는 건 단순히 숫자가 작아진 것 이상의 의미가 있다. 서열이 짧다는 건 그 안에 담긴 패턴의 복잡도도 낮다는 뜻이다. 101글자 안에는 여러 모티프가 복잡하게 조합될 수 있지만, 21글자 안에서는 그럴 여지가 훨씬 적다. 그래서 모델도 더 단순해야 한다.
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)
Conv1D 레이어가 3개에서 2개로 줄었고 필터 수도 15개에서 10개로 줄었다. 이건 과적합 방지와 직결된다. 데이터가 담고 있는 정보량에 비해 모델이 너무 크면, 모델이 훈련 데이터의 잡음까지 외워버린다. 21글자짜리 서열에 15개 필터 3겹은 과분하다. 10개 필터 2겹이면 21글자 안의 패턴을 충분히 포착할 수 있다.
Dropout 비율도 0.5에서 0.3으로 내려갔다. 이전에는 뉴런의 절반을 껐는데, 이번에는 30%만 끈다. 모델 자체가 작아졌으니 너무 많이 끄면 학습할 용량이 부족해지기 때문이다. 큰 팀에서는 절반을 빼도 나머지가 커버할 수 있지만, 작은 팀에서 절반을 빼면 일이 안 돌아가는 것과 같은 원리다.
Conv1D의 kernel_size는 여전히 10이다. 21글자 서열에서 10글자씩 보는 창이면 서열의 거의 절반을 한 번에 보는 셈이다. 이 정도면 siRNA 효율에 영향을 미치는 위치별 염기 선호도를 충분히 잡아낼 수 있다.
2겹의 Conv1D를 통과하면 (21, 10) 형태의 특징 맵이 나온다. 21개 위치 각각에 대해 10개 필터가 값을 내놓은 것이다. Flatten이 이걸 210개짜리 1차원 벡터로 펼친다. 이전의 1,515개에 비하면 훨씬 작다.
tfbinding 대비 차이점:
| tfbinding | rnai | |
|---|---|---|
| 입력 길이 | 101 bp | 21 bp |
| Conv 레이어 수 | 3 | 2 |
| 필터 수 | 15 | 10 |
| Dropout 비율 | 0.5 | 0.3 |
| 출력 | 이진 분류 | 회귀 |
즉 서열이 짧고(21bp) 문제가 단순하므로 더 작은 모델을 사용한다.
output = layers.Dense(units=1, activation=tf.math.sigmoid)(layers.Flatten()(prev))
Dense(units=1, activation=sigmoid)가 210개의 특징을 숫자 하나로 압축하고 sigmoid를 통과시킨다.
이전 모델에서도 sigmoid를 썼고, 이번에도 sigmoid를 썼지만 의미가 다르다. 이전 모델에서 sigmoid의 출력은 “결합할 확률"이었다. 확률이니까 0-1 사이인 게 자연스럽다. 이번 모델에서 sigmoid의 출력은 “유전자 침묵 효율"이다. 이것도 0-1 사이 값이다. 0이면 전혀 효과 없음, 1이면 완벽한 침묵. 출력 범위가 마침 0~1이니까 sigmoid가 잘 맞는 것이다. 만약 예측해야 하는 값의 범위가 0-1이 아니라 임의의 실수였다면 sigmoid를 쓸 수 없었을 거다. 그때는 활성화 함수 없이 raw 출력을 그대로 내보내거나 다른 방법을 써야 한다. 하지만 RNAi 효율은 운 좋게도 0-1 범위에 딱 들어맞으므로 sigmoid가 자연스러운 선택이다.
그리고 한 가지 중요한 구조적 차이가 있다. 이전 분류 모델에서는 출력을 두 개(sigmoid 적용한 확률과 적용 전 logit) 내보냈다. 수치 안정성을 위해 손실 함수에 logit을 직접 넣어야 했기 때문이다. 이번 모델에서는 출력이 하나뿐이다. Dense 레이어에 sigmoid가 바로 붙어 있고, 이 값이 예측에도 쓰이고 손실 계산에도 쓰인다. 이게 가능한 이유는 손실 함수가 바뀌었기 때문이다.
model = dc.models.KerasModel(
keras_model,
loss=dc.models.losses.L2Loss(), # ← 회귀 손실!
batch_size=1000,
model_dir='rnai')
이전 모델은 SigmoidCrossEntropy를 썼다. 그건 “맞다/틀리다"라는 이진 판단에 최적화된 손실 함수다. 이번에는 분류가 아니라 연속값 예측이므로 L2Loss, 즉 평균 제곱 오차(MSE)를 쓴다.
Loss = (예측값 - 실제값)²
실제값이 0.7인데 모델이 0.8이라고 예측했다면, 손실은 (0.8 - 0.7)² = 0.01이다. 꽤 가까우니 벌점이 작다. 실제값이 0.7인데 0.2라고 예측했다면, 손실은 (0.2 - 0.7)² = 0.25다. 많이 틀렸으니 벌점이 크다.
제곱을 하는 이유가 두 가지 있다. 첫째, 오차의 방향(높게 틀렸든 낮게 틀렸든)을 무시하고 크기만 본다. 0.1 차이든 -0.1 차이든 똑같이 0.01의 손실이다. 둘째, 큰 오차에 불균형적으로 큰 벌점을 준다. 0.1 차이의 손실은 0.01인데, 0.5 차이의 손실은 0.25로 25배나 크다. 이 성질 덕분에 모델은 크게 틀리는 걸 특히 싫어하게 되고, 극단적인 오류를 줄이는 방향으로 학습한다.
왜 이진 교차 엔트로피 대신 L2를 쓰느냐? 이진 교차 엔트로피는 본질적으로 “두 확률 분포가 얼마나 다른가"를 재는 것이다. 정답이 0 아니면 1인 상황에 맞게 설계되어 있다. 정답이 0.43 같은 중간값인 회귀 문제에서는 의미가 없다. L2Loss는 “두 숫자가 얼마나 떨어져 있는가"를 직접 재니까 연속값 예측에 자연스럽다.
metric = dc.metrics.Metric(dc.metrics.pearsonr, mode='regression')
분류에서는 ROC-AUC로 평가했다. 회귀에서는 피어슨 상관계수 r을 쓴다.
피어슨 상관계수가 측정하는 건 “모델의 예측값과 실제값이 함께 움직이는 정도"다. 실제 효율이 높은 siRNA에 대해 모델도 높은 값을 예측하고, 실제 효율이 낮은 siRNA에 대해 모델도 낮은 값을 예측한다면, 두 값 사이에 강한 양의 상관관계가 있는 것이다.
r이 1이면 완벽한 양의 상관이다. 예측값과 실제값을 그래프에 점으로 찍으면 모든 점이 하나의 직선 위에 올라간다. r이 0이면 아무 관계가 없다. 점들이 사방에 흩어져 있어서 예측이 무의미하다는 뜻이다. r이 -1이면 완벽한 음의 상관, 즉 모델이 체계적으로 반대로 예측하고 있다는 뜻이다.
피어슨 상관계수의 좋은 점은 스케일에 민감하지 않다는 것이다. 모델이 실제값보다 전체적으로 0.1씩 높게 예측하더라도, 높고 낮음의 순서가 맞으면 r은 여전히 높다. 이건 “예측의 절대적 정확도"보다 “상대적 순위를 얼마나 잘 잡는가"에 더 관심이 있을 때 유용하다. siRNA를 설계할 때도 정확한 효율 수치보다는 “어떤 서열이 더 효과적인가"라는 순위가 더 중요한 경우가 많으므로, 이 지표가 실용적으로 의미 있다.
#
#4 정리
21글자짜리 siRNA 서열을 원-핫 인코딩으로 (21, 4) 행렬로 바꾸고, 두 겹의 Conv1D가 서열을 훑으며 효율에 영향을 미치는 패턴을 추출하고, Flatten과 Dense가 그 패턴들을 종합해서 0~1 사이의 효율 예측값 하나를 내놓는다. L2Loss가 예측과 실제의 차이를 재서 모델을 교정하고, 피어슨 상관계수가 전반적인 예측 품질을 평가한다.
이전 모델들과 뼈대는 같다 Conv1D로 서열 패턴을 찾고, Dense로 최종 판단을 내리는 구조인데, 바뀐 건 문제의 성격(분류에서 회귀로)에 맞춰 모델 크기, 손실 함수, 평가 지표를 조정하였다. 같은 도구를 다른 작업에 맞게 튜닝하는 것이 딥러닝 실무의 핵심이다.