안녕하세요, 여행벌입니다.

오늘은 자주 사용하는 브라우저 '크롬' 을 조금 더 예쁘게 바꿔보는 법을 배워보겠습니다!


1. 크롬 우측 상단에 있는 메뉴바를 눌러줍니다.

2. 메뉴바에서 설정을 눌러줍니다.

3. 설정에 들어가셔서 모양을 선택한 후, 테마를 누릅니다.

4. 짜잔 여러가지 예쁜 테마들이 여러분을 기다리고 있습니다! 저는 봄 시즌이라 벚꽃에 어울리는 분홍분홍한 'Rose' 테마를 골랐습니다. 'Just Black' 이 이용자 분들이 정말 많이 사용하는 다크모드입니다!

5. Chrome에 추가하기만 누르신다면 쉽고 간단하게 예쁜 테마의 크롬을 이용하실 수 있습니다.


 

안녕하세요, 여행벌입니다.

저번 포스팅에 이어서

"혈청 Micro-RNA 데이터와 기계학습을 통한 암종의 다중 분류"

준비 과정에 대해서 포스팅해보겠습니다.


[원본데이터 학습진행]

먼저, 원본데이터를 가지고 학습을 진행했습니다. 학습 과정은 다음과 같습니다.

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%의 정확도를 얻었습니다.

# 데이터 나누기
train_data, test_data, train_target, test_target = train_test_split(data, target, test_size = 0.3)
train_data, validation_data, train_target, validation_target = train_test_split(train_data, train_target, test_size = 0.1)
#신경망구현
class Net(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)
        
    def forward(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 in range(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 데이터와 제안된 모델로 암을 진단하여 암의 오진율 및 사망률 감소를 기대합니다.


학습을 진행하는 과정은 밤새 연구실 서버에서 돌렸기 때문에 오히려 어렵지 않았습니다.

하지만 더 좋은 신경망을 찾기 위해서 층도 늘려보고 구조를 바꿔보고 하는 과정이 어려웠던 것 같습니다.

다음 포스팅에서는 학술 대회에서 교수님들께 받은 질문과 한계점에 대해서 포스팅해보도록 하겠습니다.

안녕하세요, 여행벌입니다.

이번 포스팅에서는 인생 처음으로 써 본 소논문

"혈청 Micro-RNA 데이터와 기계학습을 통한 암종의 다중 분류"

준비 과정에 대해서 자세히 다뤄보려고 합니다.


[시작 배경]

올 4월에 처음으로 인공지능 공부를 시작해, 3달 정도 '모두를 위한 딥러닝' 책으로 공부를 했습니다.

7월에는 꾸준히 Pytorch 공부를 했지만 책에 있는 예시를 따라 하는데서 더 나아가지 못했습니다.

지도교수님께서 책을 따라 하기보다는 직접 데이터를 찾고, 결과를 내보라고 조언해주셨고, 

여러 가지 암에 대해서 정확하게 분류해주는 신경망 학습 + 추계 학술대회 투고를 목적으로 

약 두 달가량 데이터를 찾고, 전처리하고 신경망을 학습시키고, 결과를 정리하는 과정을 가졌습니다.

 

[데이터 찾기]

목표는 인공지능(딥러닝)을 이용해서 여러 가지 암에 대해서 정확하게 분류하는 것입니다.

여러 가지 암과 건강한 사람에 대한 데이터가 필요했고, GEO 사이트를 이용해서 데이터를 구할 수 있었습니다.

https://www.ncbi.nlm.nih.gov/geo/

사이트에 들어가 보시면 다음과 같은 문구가 나옵니다.

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 사이트는 실험 데이터들을 공공 데이터베이스에 표준화된 포맷으로 저장하고자 하는 취지로 만들어졌습니다.

자세한 소개는 아래 링크를 타고 들어가시면 됩니다.

http://www.incodom.kr/%EC%9C%A0%EC%A0%84%EC%9E%90_%EB%B0%9C%ED%98%84_%EB%B6%84%EC%84%9D

 

GEO 사이트를 알아내긴 했지만, 여기서 내가 원하는 데이터를 찾는 일은 또 다른 일이었습니다.

Cancer 키워드로 사이트를 1~2주 정도 뒤졌고 최종적으로 여러 가지 암에 대한 데이터셋을 4개 얻을 수 있었습니다.

처음에는 데이터셋 4개를 합춰보려고했습니다. 하지만, 정규화한 방법도 다르고 결정적으로 4개의 데이터셋이 2200개 정도는 같은 유전자에 대해서 값을 저장하고 있었으나, 약 4~500개의 서로 다른 유전자에 대해서 값을 저장하고 있기 때문에 데이터셋 4개를 합치려면 각 데이터셋의 20% 정도의 유전자 값들을 날려줘야 했습니다.

 

4개의 데이터셋을 합쳐도 되는지 안되는지 확인하기 위해, PCB 방법도 써보고 각 데이터셋 별로 데이터 분포도 확인해봤지만 결과가 다 애매하게 나와서 결국 제일 큰 데이터셋 하나만 가지고 학습을 진행했습니다.

4046명의 여성에 대한 혈청 MicroRNA 데이터로 총 2565개의 유전자에 대한 값들을 저장하고 있는 데이터입니다.

 

[데이터 전처리]

원본 데이터는 총 13개 클래스에 대한 데이터입니다.

하지만, 원본 데이터를 가지고 학습을 진행한 결과 '악성 난소 질환', '경계 난소 종양', '난소 관련 기타'가 모두 난소암으로 판단되는 것을 확인했고 '난소 질환' 이라는 하나의 클래스로 묶어주기 위해 난소암 클래스와 다른 모든 클래스에 대해서 SVM(서포트 벡터머신)을 이용해 이진 분류를 진행했습니다.

그 결과 다음과 같이 난소암은 다른 암들과는 90% 이상으로 분류가 되지만 '악성 난소 질환', '경계 난소 종양'만 이진 분류가 되지 않는 것을 확인했습니다.

따라서, 하나의 클래스로 모두 묶었고 최종적으로 다음과 같은 데이터를 얻었습니다.


오늘은 여기까지만 포스팅하고 다음 시간에 학습 진행과 최종 결과에 대해서 다뤄보겠습니다.

데이터를 찾고, 전처리하는데 정말정말 많은 시간을 소모했는데....

글로 정리해보니 굉장히 짧네요,,,,

 

좋은 데이터를 찾고 전처리하는게 제일 중요하고 오래걸리는 작업이라는 생각이 듭니다.

안녕하세요, 여행벌입니다.

오늘은 Pytorch 기본 연산들에 대해서 배워보도록 하겠습니다.

Pytorch library를 설치하지 못하신 분은 아래 포스팅을 먼저 읽어주세요!

https://travelbeeee.tistory.com/75

이 포스팅을 읽으시는 분들이 Pytorch 라이브러리를 이용해서

손쉽게 딥러닝을 구현할 수 있도록 최대한 세세하게 포스팅을 해보도록 하겠습니다!


1. Tensor 기본 연산 명령어

파이토치는 데이터를 추상화하는 Tensor와 Variable을 제공합니다.

그중 Tensor는 numpy 배열과 유사해서 유용하게 사용할 수 있습니다.

Tensor와 Variable 타입 모두 GPU에서 동작해 'GPU의 빠른 연산력을 사용할 수 있다.'는 장점이 있다고 합니다!

그러면 여러 함수들을 익혀볼까요?

● torch.Tensor() : tensor 배열을 생성한다. numpy 배열을 input으로 받으면 tensor 배열로 변환해준다.

● 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 배열인

y를 tensor 배열로 쉽게 변환할 수 있는 것을 확인할 수 있습니다.

출력 :
tensor([[0.0000, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0000]])
[[0.67086163 0.55784783 0.62186057]
 [0.99621408 0.86104033 0.17540402]
 [0.22081897 0.53235119 0.6920162 ]
 [0.02901596 0.3410925  0.69009763]
 [0.62706006 0.16814722 0.5602715 ]]
tensor([[0.6709, 0.5578, 0.6219],
        [0.9962, 0.8610, 0.1754],
        [0.2208, 0.5324, 0.6920],
        [0.0290, 0.3411, 0.6901],
        [0.6271, 0.1681, 0.5603]])
<class 'torch.Tensor'>

z에 numpy 배열이 tensor 배열로 바뀐 후 저장된 것을 확인할 수 있습니다.

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 함수를 이용할 수도 있습니다.

torch.add 함수는 특이하게 결과값을 out을 통해 변수에 저장할 수도 있습니다.

출력 :
# print(x)
tensor([[0.1405, 0.4824, 0.5622],
        [0.4702, 0.0449, 0.5176],
        [0.8134, 0.2111, 0.0923],
        [0.9565, 0.9365, 0.7615],
        [0.1268, 0.6055, 0.6063]])
# print(y)
tensor([[0.8514, 0.3682, 0.6901],
        [0.9142, 0.6101, 0.8050],
        [0.0158, 0.1671, 0.3655],
        [0.9922, 0.4498, 0.1291],
        [0.3218, 0.4852, 0.7165]])
# print(x+y)
tensor([[0.9919, 0.8506, 1.2523],
        [1.3843, 0.6550, 1.3226],
        [0.8291, 0.3782, 0.4578],
        [1.9488, 1.3863, 0.8907],
        [0.4486, 1.0906, 1.3228]])
# print(tensor.add(x,y))
tensor([[0.9919, 0.8506, 1.2523],
        [1.3843, 0.6550, 1.3226],
        [0.8291, 0.3782, 0.4578],
        [1.9488, 1.3863, 0.8907],
        [0.4486, 1.0906, 1.3228]])
# print(result)
tensor([[0.9919, 0.8506, 1.2523],
        [1.3843, 0.6550, 1.3226],
        [0.8291, 0.3782, 0.4578],
        [1.9488, 1.3863, 0.8907],
        [0.4486, 1.0906, 1.3228]])

또, 다음과 같이 in_place하게 덧셈을 진행할 수도 있습니다.

y.add(x) #  y 배열에 x 배열을 더해서 y 배열에 다시 저장.
print(y)
출력 :
# print(y)
tensor([[0.9919, 0.8506, 1.2523],
        [1.3843, 0.6550, 1.3226],
        [0.8291, 0.3782, 0.4578],
        [1.9488, 1.3863, 0.8907],
        [0.4486, 1.0906, 1.3228]])

배열의 크기를 알아볼 수도 있습니다.

print(x.size())
print(y.size())
출력 :
torch.Size([5, 3])
torch.Size([5, 3])

오늘은 여기까지만 다뤄보고,

다음 포스팅 때 다른 명령어들을 알아보겠습니다!

+ Recent posts