PyTorch에서 TabNet 구현

https://unsplash.com/photos/Wpnoqo2plFA

딥 러닝은 비전, 자연어 처리, 음성 인식 및 기타 많은 분야를 장악하여 놀라운 결과를 달성하고 일부에서는 초인적 인 성능을 달성했습니다. 그러나 테이블 형식 데이터를 모델링하기 위해 딥 러닝을 사용하는 것은 상대적으로 제한적입니다.

테이블 형식 데이터의 경우 가장 일반적인 접근 방식은 트리 기반 모델과 해당 앙상블을 사용하는 것입니다. 트리 기반 모델은 전체적으로 엔트로피를 가장 많이 줄이는 기능을 선택합니다. 배깅, 부스팅과 같은 앙상블 방법은 모델 분산을 줄임으로써 이러한 트리 기반 방법을 더욱 향상시킵니다. XGBoost 및 LightGBM과 같은 최근 트리 기반 앙상블이 Kaggle 대회를 지배했습니다.

TabNet은 Google Cloud AI의 연구팀에서 개발 한 신경 아키텍처입니다. 회귀 및 분류 문제 모두에서 여러 데이터 세트에 대한 최신 결과를 얻을 수있었습니다. 매우 복잡한 기능과 트리 기반 알고리즘 의 기능 선택 속성에 맞게 신경망의 기능을 결합합니다 . 즉, 모델은 학습 과정에서 관련 기능 만 선택하는 방법을 학습합니다. 또한 전 세계적으로 만 기능을 선택할 수있는 트리 기반 모델과 달리 TabNet의 기능 선택 프로세스는 인스턴스 방식입니다. TabNet의 또 다른 바람직한 기능은 해석 가능성 입니다. 신경망이 블랙 박스처럼 작동하는 대부분의 딥 러닝과 달리 TabNet의 경우 모델이 선택하는 기능을 해석 할 수 있습니다.

이 블로그에서는 PyTorch에서 TabNet을 단계별로 초보자에게 친숙하게 구현하는 방법을 설명합니다. 시작하자!!

TabNet 아키텍처.

1) 출처 : https : //arxiv.org/pdf/1908.07442v1.pdf

그림 (1)은 원래 TabNet 논문에서 발췌 한 것입니다. 이미지의 각 구성 요소를 개별적으로 빌드하고 결국 조립합니다. 먼저,이 모델에 사용 된 두 가지 필수 개념 인 GBN (Ghost Batch Normalization)Sparsemax를 살펴 보겠습니다 .

고스트 배치 정규화 (GBN) :
GBN을 사용하면 대량의 데이터 배치를 훈련하고 동시에 더 잘 일반화 할 수 있습니다. 간단히 말해, 입력 배치를 동일한 크기의 하위 배치 (가상 배치 크기)로 분할하고 동일한 배치 정규화 레이어를 적용합니다. 입력 특성에 적용된 첫 번째 일괄 정규화 계층을 제외하고 모델에서 사용되는 모든 일괄 정규화 계층은 GBN 계층입니다. 다음과 같이 PyTorch에서 구현할 수 있습니다.

class GBN(nn.Module):
    def __init__(self,inp,vbs=128,momentum=0.01):
        super().__init__()
        self.bn = nn.BatchNorm1d(inp,momentum=momentum)
        self.vbs = vbs
    def forward(self,x):
        chunk = torch.chunk(x,x.size(0)//self.vbs,0)
        res = [self.bn(y) for y in chunk]
        return torch.cat(res,0)

Sparsemax는 softmax와 같은 비선형 정규화 함수이지만 이름에서 알 수 있듯이 분포는 'sparser'입니다. 즉, 소프트 맥스에 비해 출력 확률 분포의 일부 숫자는 1에 훨씬 더 가깝고 다른 숫자는 0에 훨씬 더 가깝습니다.이를 통해 모델은 각 결정 단계에서 관련 기능을보다 효과적으로 선택할 수 있습니다. sparsemax를 사용하여 특징 선택 단계의 마스크를 희소 공간에 투영합니다. sparsemax의 구현은 https://github.com/gokceneraslan/SparseMax.torch 에서 찾을 수 있습니다.

마스크의 희소성을 더욱 높이기 위해 희소성 정규화 기술을 추가하여 덜 희박한 마스크에 페널티를줍니다. 이는 다음과 같이 각 결정 단계에서 구현할 수 있습니다.

(mask*torch.log(mask+1e-10)).mean() #F(x)= -∑xlog(x+eps)

주의 변환기 :
모델이 관련 기능 간의 관계를 학습하고 현재 결정 단계의 기능 변환기에 전달할 기능을 결정하는 곳입니다. 각 Attention Transformer는 완전히 연결된 계층, Ghost Batch Normalization Layer 및 Sparsemax 계층으로 구성됩니다. 각 결정 단계의주의 변환기는 입력 기능, 이전 단계에서 처리 된 기능 및 사용 된 기능에 대한 이전 정보를 수신합니다. 이전 정보는 batch_size x input_features 크기의 행렬로 표시됩니다. 1로 초기화되고 모든 결정 단계의주의 변환기로 전달되고 업데이트됩니다. 정방향 패스에서 특정 기능을 사용할 수있는 횟수를 제한하는 완화 매개 변수도 있습니다. 더 큰 값은 모델이 동일한 기능을 여러 번 재사용 할 수 있음을 의미합니다. 코드가 모든 것을 명확하게한다고 생각합니다.

class AttentionTransformer(nn.Module):
    def __init__(self,d_a,inp_dim,relax,vbs=128):
        super().__init__()
        self.fc = nn.Linear(d_a,inp_dim)
        self.bn = GBN(out_dim,vbs=vbs)
        self.smax = Sparsemax()
        self.r = relax
#a:feature from previous decision step
    def forward(self,a,priors): 
        a = self.bn(self.fc(a)) 
        mask = self.smax(a*priors) 
        priors =priors*(self.r-mask)  #updating the prior
        return mask

기능 변압기 :

기능 변환기는 선택한 모든 기능이 처리되어 최종 출력을 생성하는 곳입니다. 각 기능 변압기는 여러 개의 게이트 선형 단위 블록으로 구성됩니다. GLU는 네트워크를 통해 추가 흐름을 허용해야하는 정보를 제어합니다. GLU 블록을 구현하려면 먼저 완전 연결 계층을 사용하여 입력 기능의 차원을 GLU에 두 배로 늘 립니다. GBN Layer를 사용하여 결과 행렬을 정규화합니다. 그런 다음 결과 특성의 후반부시그 모이 드를 적용 하고 결과를 전반부에 곱합니다 . 결과는 배율 인수 (이 경우에는 sqrt (0.5))와 곱해지며 입력에 추가됩니다. 이 합산 결과는 시퀀스의 다음 GLU 블록에 대한 입력입니다.

모델 용량과 효율성을 높이기 위해 모든 결정 단계에서 일정 수의 GLU 블록을 공유합니다 ( 선택 사항 ). 첫 번째 공유 GLU 블록 (또는 블록이 공유되지 않는 경우 첫 번째 독립 블록)은 입력 특성의 차원을 n_a + n_d와 같은 차원으로 줄이므로 고유합니다. n_a는 다음 단계의주의 변환기에 입력되는 특성의 차원이고 n_d는 최종 결과를 계산하는 데 사용되는 특성의 차원입니다. 이러한 기능은 분할기에 도달 할 때까지 함께 처리됩니다. ReLU 활성화는 n_d 차원 벡터에 적용됩니다. 모든 결정 단계의 출력은 합산되어 완전히 연결된 계층을 통과하여 출력 차원에 매핑됩니다.

class GLU(nn.Module):
    def __init__(self,inp_dim,out_dim,fc=None,vbs=128):
        super().__init__()
        if fc:
            self.fc = fc
        else:
            self.fc = nn.Linear(inp_dim,out_dim*2)
        self.bn = GBN(out_dim*2,vbs=vbs) 
        self.od = out_dim
    def forward(self,x):
        x = self.bn(self.fc(x))
        return x[:,:self.od]*torch.sigmoid(x[:,self.od:])
class FeatureTransformer(nn.Module):
    def __init__(self,inp_dim,out_dim,shared,n_ind,vbs=128):
        super().__init__()
        first = True
        self.shared = nn.ModuleList()
        if shared:
            self.shared.append(GLU(inp_dim,out_dim,shared[0],vbs=vbs))
            first= False    
            for fc in shared[1:]:
                self.shared.append(GLU(out_dim,out_dim,fc,vbs=vbs))
        else:
            self.shared = None
        self.independ = nn.ModuleList()
        if first:
            self.independ.append(GLU(inp,out_dim,vbs=vbs))
        for x in range(first, n_ind):
            self.independ.append(GLU(out_dim,out_dim,vbs=vbs))
        self.scale = torch.sqrt(torch.tensor([.5],device=device))
    def forward(self,x):
        if self.shared:
            x = self.shared[0](x)
            for glu in self.shared[1:]:
                x = torch.add(x, glu(x))
                x = x*self.scale
        for glu in self.independ:
            x = torch.add(x, glu(x))
            x = x*self.scale
        return x

class DecisionStep(nn.Module):
    def __init__(self,inp_dim,n_d,n_a,shared,n_ind,relax,vbs=128):
        super().__init__()
        self.fea_tran = FeatureTransformer(inp_dim,n_d+n_a,shared,n_ind,vbs)
        self.atten_tran =  AttentionTransformer(n_a,inp_dim,relax,vbs)
    def forward(self,x,a,priors):
        mask = self.atten_tran(a,priors)
        sparse_loss = ((-1)*mask*torch.log(mask+1e-10)).mean()
        x = self.fea_tran(x*mask)
        return x,sparse_loss

class TabNet(nn.Module):
    def __init__(self,inp_dim,final_out_dim,n_d=64,n_a=64,
n_shared=2,n_ind=2,n_steps=5,relax=1.2,vbs=128):
        super().__init__()
        if n_shared>0:
            self.shared = nn.ModuleList()
            self.shared.append(nn.Linear(inp_dim,2*(n_d+n_a)))
            for x in range(n_shared-1):
                self.shared.append(nn.Linear(n_d+n_a,2*(n_d+n_a)))
        else:
            self.shared=None
        self.first_step = FeatureTransformer(inp_dim,n_d+n_a,self.shared,n_ind) 
        self.steps = nn.ModuleList()
        for x in range(n_steps-1):
            self.steps.append(DecisionStep(inp_dim,n_d,n_a,self.shared,n_ind,relax,vbs))
        self.fc = nn.Linear(n_d,final_out_dim)
        self.bn = nn.BatchNorm1d(inp_dim)
        self.n_d = n_d
    def forward(self,x):
        x = self.bn(x)
        x_a = self.first_step(x)[:,self.n_d:]
        sparse_loss = torch.zeros(1).to(x.device)
        out = torch.zeros(x.size(0),self.n_d).to(x.device)
        priors = torch.ones(x.shape).to(x.device)
        for step in self.steps:
            x_te,l = step(x,x_a,priors)
            out += F.relu(x_te[:,:self.n_d])
            x_a = x_te[:,self.n_d:]
            sparse_loss += l
        return self.fc(out),sparse_loss

이 TabNet 모듈은 분류 및 회귀 작업을 위해 확장 할 수 있습니다. 범주 형 변수에 대한 임베딩을 추가하고 출력에 Sigmoid 또는 Softmax 함수를 적용하는 등의 작업을 수행 할 수 있습니다. 실험하고 자신에게 가장 적합한 것을 확인하십시오. 예제 노트북에서 Sparsemax를 Sigmoid로 교체해 보았고 약간 더 나은 정확도를 얻을 수있었습니다.

Mechanisms of Actions (MoA) Prediction 데이터 세트 에 대한 사용 사례 예제는 https://www.kaggle.com/samratthapa/drug-prediction에서 내 노트북을 찾을 수 있습니다 . 현재 Kaggle에서 개최되는 대회의 데이터 세트입니다.

TabNet의 구현은 DreamQuark의 관대 한 사람들의 작업을 짧게 수정 한 것입니다. TabNet의 전체 구현은
https://github.com/dreamquark-ai/tabnet/tree/develop/pytorch_tabnet 에서 찾을 수 있습니다 .
당신은 읽기 고려해야 용지를 TabNet에 대한 자세한 설명.

읽어 주셔서 감사합니다. 도움이 되었기를 바랍니다.

참고 문헌 :
1) Sercan O. Arık, Tomas Pfister. 2020. TabNet : 세심한 해석 가능한 테이블 형식 학습 https://arxiv.org/abs/1908.07442v4
2) Yann N. Dauphin, Angela Fan, Michael Auli 및 David Grangier. 2016. Gated Convolutional Networks를 사용한 언어 모델링.
https://arxiv.org/pdf/1612.08083.pdf
3) Elad Hoffer, Itay Hubara 및 Daniel Soudry. 2017. 더 오래 훈련하고 더 잘 일반화 : 신경망의 대규모 배치 훈련에서 일반화 격차를 좁 힙니다.
https://arxiv.org/pdf/1705.08741.pdf
4) Andre FT Martins 및 Ramon Fernandez Astudillo. 2016. Softmax에서 Sparsemax로 :주의 및 다중 레이블 분류의 희소 모델.
https://arxiv.org/abs/1602.02068
5) Sparsemax 구현 https://github.com/gokceneraslan/SparseMax.torch
6) PyTorch TabNet 구현 완료
https://github.com/dreamquark-ai/tabnet/tree/ 개발 / pytorch_tabnet

Suggested posts

PyTorch를 사용하여 CIFAR_10 데이터 세트를 학습하고 예측하는 방법

PyTorch를 사용하여 CIFAR_10 데이터 세트를 학습하고 예측하는 방법

두 개의 이전 포스트에서 PyTorch를 사용하여 MNist 데이터 세트에 대한 예측을 수행하는 방법에 대해 논의했으며 PyTorch 및 skorch 라이브러리를 모두 사용하여 매우 높은 정확도 점수를 달성하게되어 매우 기뻤습니다. 주제에 대한 가장 최근 게시물에 대한 링크는 다음에서 찾을 수 있습니다.-PyTorch 및 skorch를 사용하여 Kaggle의 MNIST 경쟁에서 정확도를 2 % 증가시킨 방법 | 작성자 Tracyrenee | MLearning.

PyTorch 및 skorch를 사용하여 Kaggle의 MNIST 경쟁에서 정확도를 2 % 높이는 방법

PyTorch 및 skorch를 사용하여 Kaggle의 MNIST 경쟁에서 정확도를 2 % 높이는 방법

이전 게시물에서 PyTorch와 skorch라는 새 라이브러리를 사용하여 openml의 MNIST 데이터 세트에 대한 솔루션의 코드 검토를 수행했습니다. 해당 게시물에 대한 링크는 여기에서 찾을 수 있습니다.-코드 검토 : sklearn 및 skorch를 사용한 Google Colab MNIST 예측 | 작성자 Tracyrenee | 2021 년 4 월 | Medium이 게시물에서는 이전 게시물에서 사용했던 알고리즘을 사용하고 코드를 약간 수정하여 Kaggle의 Digit Recognizer 경쟁을 해결하는 데 사용하려고합니다.

Related posts

"실용적인 프로그래머"의 5 가지 필수 사항

역대 베스트셀러 코딩 북의 요점

"실용적인 프로그래머"의 5 가지 필수 사항

Pragmatic Programmer는 1999 년에 처음 출판되었으며 이후 역대 최고의 프로그래밍 책으로 선정되었습니다. 저자 Andy Hunt와 David Thomas는 Agile Manifesto의 원저자 중 하나였으며 몇 가지 심각한 자격을 가지고 있습니다.

대규모 GraphQL 쿼리 공격으로부터 보호

공격자가 공개적으로 사용 가능한 GraphQL 인터페이스를 사용하여 사이트를 스크랩하거나 서비스 거부 공격을 실행하는 방법에 대해 알아보십시오. 이들은 4 가지 방법 중 하나로이를 수행 할 수 있습니다. 단일 대형 쿼리를 신중하게 구성하여 실행하고, 관련 데이터를 가져올 수있는 병렬 쿼리를 많이 작성하고, 일괄 요청을 사용하여 많은 쿼리를 연속적으로 실행하고, 마지막으로 많은 요청을 보냅니다.

기술 인터뷰의 사회적 구성 요소

코딩 문제는 스트레스가 많지만 스트레스에 대한 당신의 반응은 당신의 기술적 능력보다 더 크게 말합니다.

기술 인터뷰의 사회적 구성 요소

기술 업계의 직책을 위해 인터뷰 할 때 일반적으로 제안을 고려하기 전에 최소한 3 차례의 인터뷰를 거치게됩니다. 라운드는 일반적으로 다음과 같습니다. 그렇게 생각하면 잘못된 것입니다.

훌륭한 개발자의 3 가지 행동 특성

훌륭한 개발자의 3 가지 행동 특성

훌륭한 개발자를 만드는 비 기술적 인 것들 나는이 기사를 작성하는 것을 한동안 미루고 있습니다. 나는 그것을 작성할 자격이 있다고 생각하지 못했습니다. 오늘은 쓸 때라고 생각했습니다.