7 : 3 의 비율로 Training Data와 Test Data를 나누고 다시 Training Data를 9 : 1의 비율로 Training Data와 Validation Data로 나눴습니다. 그 후, 학습률 0.01 로 500 epoch, 학습률을 0.001로 낮춰 500 epoch 총 1000 epoch 동안 학습을 진행했습니다. Output Layer는 log softmax를 활성화 함수로 사용하고, 나머지 layer에서는 ReLU 활성화 함수를 이용했습니다. 완전 연결 계층의 경우는 드랍아웃을 추가적으로 사용했고, 손실함수는 Cross entropy 함수를 이용했습니다. 최종적으로 평균 90.38%의 정확도를 얻었습니다.
#신경망구현classNet(nn.Module):def__init__(self):super(Net, self).__init__()
self.fc1 = nn.Linear(2565,1280)
self.fc2 = nn.Linear(1280,640)
self.fc3 = nn.Linear(640,320)
self.fc4 = nn.Linear(320,12)
defforward(self, x):
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = F.relu(self.fc3(x))
x = F.dropout(x, training=self.training)
x = self.fc4(x)
return F.log_softmax(x)
여러 번의 학습 중 하나의 예시에 대한 정답 테이블과 그래프입니다.
Training Data / Validataion Data 의 손실값에 대한 그래프입니다. (빨간색 : Validation 파란색 : Training Data)
Training Data / Validataion Data 의 정확도에 대한 그래프입니다. (빨간색 : Validation 파란색 : Training Data)
위의 그래프를 통해 학습이 제대로 이루어지지 않고 있는 것을 알 수 있고, 이는 비암환자 클래스가 압도적으로 많은 데이터 수를 가지고 있기 때문에 오버피팅된 것으로 판단했습니다.
따라서, SMOTE 알고리즘을 통해 오버샘플링을 진행했고 각 클래스 별로 500개의 Data로 균일하게 크기를 맞춰 학습을 진행해봤습니다. 하지만 오히려 정확도가 60%까지 떨어지는 결과가 나왔고, 언더샘플링을 통해 크기가 100개 이상인 클래스를 모두 크기를 100으로 맞춰주고 학습을 진행한 경우에도 정확도가 7~ 80%까지 떨어지는 결과가 나왔습니다.
최종적으로 랜덤추출 오버샘플링을 통해 클래스 별로 Data 크기를 맞춰서학습을 진행했습니다.
랜덤추출 오버샘플링 코드는 다음과 같습니다.
ninput = 301
dummy_data = pd.DataFrame()
for i inrange(1,ninput):
row = random.randrange(0,115)
dummy_data = dummy_data.append(data1.iloc[row])
dummy_data.shape
data1은 유방암으로 원본 데이터는 115명에 대한 데이터입니다. 데이터를 300개로 키우기 위해 랜덤하게 데이터를 계속 추출합니다. 다음과 같은 과정을 모든 클래스에 대해서 진행하면 랜덤추출 오버샘플링을 통해 클래스 별로 Data 크기를 맞춘 데이터를 얻을 수 있습니다.
[시뮬레이션 결과]
각 암종별 데이터 수를 동일하게 300(G3), 500(G5), 700(G7), 1000(G10)으로 데이터를 각 2번 반복 생성하였습니다. 생성 방법은 무작위 추출을 통한 오버샘플링 기법을 활용하였습니다. 그 후 데이터별로 10번의 학습을 진행했습니다. 원본 데이터로 학습시킨 결과는 최대 91.65%, 평균 90.38% 정확도인데 반해서 오버샘플링 기법을 활용한 결과, 최대 99.50%의 정확도를 얻었습니다.
[결론]
제안된 모델은 9종류의 암종과 건강한 사람을 100%에 가까운 정확도로 구분합니다. 한 가지 우려되는 제한사항은 데이터에 대한 접근성으로 RNA 데이터가 세포 속에 있기 때문에 다른 데이터에 비해 비교적 채취하기가 어렵습니다. 하지만 microRNA가 암과 연관이 있음이 밝혀지고 이를 빠르고 효과적으로 얻기 위한 연구가 진행되고 있습니다. 현재는 microRNA가 혈청과 혈장을 타고 순환하는 사실이 밝혀지면서 혈중 microRNA 연구가 가속화되고 있습니다. 가까운 시일 내에 mircoRNA 데이터와 제안된 모델로 암을 진단하여 암의 오진율 및 사망률 감소를 기대합니다.
학습을 진행하는 과정은 밤새 연구실 서버에서 돌렸기 때문에 오히려 어렵지 않았습니다.
하지만 더 좋은 신경망을 찾기 위해서 층도 늘려보고 구조를 바꿔보고 하는 과정이 어려웠던 것 같습니다.
다음 포스팅에서는 학술 대회에서 교수님들께 받은 질문과 한계점에 대해서 포스팅해보도록 하겠습니다.
GEO is a public functional genomics data repository supporting MIAME-compliant data submissions. Array- and sequence-based data are accepted. Tools are provided to help users query and download experiments and curated gene expression profiles.
간단하게 요악하면 GEO 사이트는 실험 데이터들을 공공 데이터베이스에 표준화된 포맷으로 저장하고자 하는 취지로 만들어졌습니다.
GEO 사이트를 알아내긴 했지만, 여기서 내가 원하는 데이터를 찾는 일은 또 다른 일이었습니다.
Cancer 키워드로 사이트를 1~2주 정도 뒤졌고 최종적으로 여러 가지 암에 대한 데이터셋을 4개 얻을 수 있었습니다.
처음에는 데이터셋 4개를 합춰보려고했습니다. 하지만, 정규화한 방법도 다르고 결정적으로 4개의 데이터셋이 2200개 정도는 같은 유전자에 대해서 값을 저장하고 있었으나, 약 4~500개의 서로 다른 유전자에 대해서 값을 저장하고 있기 때문에 데이터셋 4개를 합치려면 각 데이터셋의 20% 정도의 유전자 값들을 날려줘야 했습니다.
4개의 데이터셋을 합쳐도 되는지 안되는지 확인하기 위해, PCB 방법도 써보고 각 데이터셋 별로 데이터 분포도 확인해봤지만 결과가 다 애매하게 나와서 결국 제일 큰 데이터셋 하나만 가지고 학습을 진행했습니다.
4046명의 여성에 대한 혈청 MicroRNA 데이터로 총 2565개의 유전자에 대한 값들을 저장하고 있는 데이터입니다.
[데이터 전처리]
원본 데이터는 총 13개 클래스에 대한 데이터입니다.
하지만, 원본 데이터를 가지고 학습을 진행한 결과 '악성 난소 질환', '경계 난소 종양', '난소 관련 기타'가 모두 난소암으로 판단되는 것을 확인했고 '난소 질환' 이라는 하나의 클래스로 묶어주기 위해 난소암 클래스와 다른 모든 클래스에 대해서 SVM(서포트 벡터머신)을 이용해 이진 분류를 진행했습니다.
그 결과 다음과 같이 난소암은 다른 암들과는 90% 이상으로 분류가 되지만 '악성 난소 질환', '경계 난소 종양'만 이진 분류가 되지 않는 것을 확인했습니다.
● torch.randn() : 평균 0, 분산 1인 정규 분포를 따라서 tensor 배열을 생성한다.
● torch.add(x,y) : tensor 배열 x, y를 더해준다.
● torch.add(x, y, out = result) : tensor 배열 x, y를 더해 result tensor 배열에 저장한다.
● y.add(x) : tensor 배열 y 에 x를 더한 값을 y에 in_place 하게 저장한다.
● x + y : numpy 배열처럼 tensor 배열 x, y를 더한다.
● x - y : numpy 배열처럼 tensor 배열 x, y를 뺀다.
● x * y : numpy 배열처럼 tensor 배열 x, y를 행렬 곱을 한다.
● .size() : tensor 배열의 크기를 알려준다.
import numpy as np
import torch
# 1번 코드
x = torch.Tensor(5,3) # 5 x 3 tensor 배열을 만든다.
print(x)
# 2번 코드
y = np.random.rand(5,3) # 5 x 3 numpy 배열을 만든다.
print(y)
# 3번 코드 중요!
z = torch.Tensor(y) # numpy 배열 y를 tensor 배열로 바꿔 저장한다.print(z)
print(type(z))
먼저 numpy 와 torch library를 import 하겠습니다. 1번 코드를 보시면, numpy 배열과 비슷하게 tensor 배열을 만들 수 있습니다. 위에서 tensor 타입은 numpy와 비슷하다고 했는데, 3번 코드를 보시면 numpy 배열인
import torch
x = torch.rand(5,3)
print(x)
y = torch.rand(5,3)
print(y)
print(x+y)
print(torch.add(x,y))
result = torch.Tensor(5,3) # 결과를 담아줄 배열을 만든다.
torch.add(x,y, out = result)
print(result)
다음으로는 여러 가지 덧셈 문법에 대해서 알아보도록 하겠습니다.
numpy 배열처럼 직접 x + y를 할 수도 있고, torch.add 함수를 이용할 수도 있습니다.