ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 데이터 분석_파이토치 : Pytorch1
    DATA_STUDY 2024. 1. 19. 20:15

     

    해당 자료는 이수안 컴퓨터 연구소의 유튜브에 올라와있는 자료입니다. ! 

    유튜브에 이수안 컴퓨터 연구소 검색하고 보세요!. 자료 좋아요!!

    문제가 있을 시에 알려주시면,  빛 삭제 혹은 수정하겠습니다.


    https://www.youtube.com/watch?v=k60oT_8lyFw&list=PL7ZVZgsnLwEEIC4-KQIchiPda_EjxX61r&index=


     

    1.파이토치(PyTorch)

    • 페이스북이 초기 루아(Lua) 언어로 개발된 토치(Torch)를 파이썬 버전으로 개발하여 2017년도에 공개
    • 초기에 (프레임워크) 토치(Torch)는 넘파이(NumPy) 라이브러리처럼 과학 연산을 위한 라이브러리로 공개
    • 이후 (텐서병렬처리를위한) GPU를 이용한 텐서 조작 및 동적 신경망 구축이 가능하도록 딥러닝 프레임워크로 발전시킴
    • 파이썬답게 만들어졌고, 유연하면서도 가속화된 계산 속도를 제공

    1.파이토치의 구성요소

    • torch: 메인 네임스페이스, 텐서 등의 다양한 수학 함수가 포함
    • torch.autograd: 자동 미분 기능을 제공하는 라이브러리
    • torch.nn: 신경망 구축을 위한 데이터 구조나 레이어 등의 라이브러리
    • torch.multiprocessing: 병럴처리 기능을 제공하는 라이브러리
    • torch.optim: SGD(Stochastic Gradient Descent)를 중심으로 한 파라미터 최적화 알고리즘 제공
    • torch.utils: 데이터 조작 등 유틸리티 기능 제공
    • torch.onnx: ONNX(Open Neural Network Exchange), 서로 다른 프레임워크 간의 모델을 공유할 때 사용

    2.텐서(Tensors)

    • 다차원에 대한 데이터 표현 방법
    • 데이터 표현을 위한 기본 구조로 텐서(tensor)를 사용
    • 텐서는 데이터를 담기위한 컨테이너(container)로서 일반적으로 수치형 데이터를 저장
    • 넘파이(NumPy)의 ndarray와 유사
    • GPU를 사용한 연산 가속 가능
    # Tensor는 다차원 데이터 구조를 가지고 있다
    import torch
    
    #쿠다 버전 확인 
    torch.__version__ # 버전 2.1.0 쿠다 121

    3.텐서 초기화와 데이터 타입

     

    ## 초기화 되지 않은 텐서
    x = torch.empty(4,2) #4행 2열짜리 torch를 만들어
    #tensor([[2.1707e-18, 7.0952e+22],
    #        [1.7748e+28, 1.8176e+31],
    #        [7.2708e+31, 5.0778e+31],
    #        [3.2608e-12, 1.7728e+28]])
    
    ## 무작위로 초기화된 텐서
    x = torch.rand(4,2) #초기화가 랜덤을 기준으로
    print(x)
    #tensor([[0.5978, 0.0850],
    #        [0.9591, 0.3563],
    #        [0.2373, 0.3342],
    #        [0.0166, 0.6169]])
    
    ## 데이터 타입(dtype)이 long이고, 0으로 채워진 텐서
    x = torch.zeros(4,2, dtype=torch.long) #long = 정수
    
    ## 사용자가 입력한 값으로 텐서 초기화
    x = torch.tensor([3, 2.3]) #기본적으로 실수형 타입으로 들어감
    
    ## 2 x 4 크기, double 타입, 1로 채워진 텐서
    x = x.new_ones(2,4, dtype=torch.double) 
    # 데이터 타입의 최소단위인 텐서를 자유자제로 다룰수 있어야합니다.
    
    ## x와 같은 크기, float 타입, 무작위로 채워진 텐서
    x = torch.randn_like(x, dtype=torch.float ) # _like 뜻 기존의 tensor와 같은 것으로 만들어줘
    
    ## 텐서의 크기 계산
    print(x.size())

    4. 데이터 타입(Data Type)

    # float.tensor
    ft = torch.FloatTensor([1,2,3])
    print(ft)
    print(ft.dtype) #기본이 32bit float 다
    
    #타입 캐스팅 => 데이터타입을 바꿔주는 역할
    print(ft.short()) # 기존 tensor를 short으로 타입 캐스팅을 합니다
    print (ft.int()) # short 은 int16짜리/ int는 32bit, long 64bit의 정수임
    print(ft.long())
    
    it = torch.IntTensor([1,2,3])
    print(it)
    print(it.dtype)
    
    print(it.float()) # 실수 기본형 32bit
    print(it.double()) # 실수 64 bit
    print(it.half()) # 실수 16 bit

    5. CUDA Tensors 

    • .to 메소드를 사용하여 텐서를 어떠한 장치(cpu, gpu)로도 옮길 수 있음
    • 쿠다 : 엔비디아의 대표 GPU 라이브러리
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu' ) #조건을 걸어서 gpu가 안되면 자동으로 cpu로 넘어가게
    # torch.device('cuda') 또는 ('cpu')로 동작함
    print(device)
    
    y = torch.ones_like(x, device=device)
    print(y)
    
    x = x.to(device)
    print(x)
    
    z = x + y
    print(z)
    print(z.to('cpu', torch.double)) # 계산된 결과를 cpu로 double타입으로 옮겼음

    6.다차원 텐서 표현

    0D Tensor(Scalar)

    • 하나의 숫자를 담고 있는 텐서(tensor)
    • 축과 형상이 없음
    t0 = torch.tensor(0)
    print( t0.ndim ) #차원 없음
    print(t0.shape) #형태 없음
    print(t0) # 값은 그냥 0

    1D Tensor(Vector)

    • 값들을 저장한 리스트와 유사한 텐서
    • 하나의 축이 존재
    t1 = torch.tensor([1,2,3])
    print( t1.ndim ) # 1차원
    print(t1.shape) # 형태 한줄
    print(t1) # 값은 1 2 3

    2D Tensor(Matrix)

    • 행렬과 같은 모양으로 두개의 축이 존재
    • 일반적인 수치, 통계 데이터셋이 해당
    • 주로 샘플(samples)과 특성(features)을 가진 구조로 사용
    t2 = torch.tensor([[1,2,3],
                       [4,5,6],
                       [7,8,9]])
    print( t2.ndim ) # 2차원
    print(t2.shape) # 형태 행렬/수치모양
    print(t2) # 값은 1 2 3 ,   4 5 6 ,   78 9  3*3행

    3D Tensor

    • 큐브(cube)와 같은 모양으로 세개의 축이 존재
    • 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당
    • 주식 가격 데이터셋, 시간에 따른 질병 발병 데이터 등이 존재
    • 주로 샘플(samples), 타임스텝(timesteps), 특성(features)을 가진 구조로 사용
    t3 = torch.tensor([ [[1,2,3], # t2가 여러개인 형태로 들어감
                        [4,5,6],
                        [7,8,9]],
                        [[1,2,3],
                        [4,5,6],
                        [7,8,9]],
                        [[1,2,3],
                        [4,5,6],
                         [7,8,9]] ] )
    print( t3.ndim ) # 3차원 큐브모양
    print(t3.shape) # 형태 행렬/수치모양
    print(t3)

    4D Tensor

    • 4개의 축
    • 컬러 이미지 데이터가 대표적인 사례
    • 흑백 이미지 데이터는 3D Tensor로 가능
    • 흑백은 채널 정보가 빠짐
    • 주로 샘플(samples), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용

    5D Tensor

    • 5개의 축
    • 비디오 데이터가 대표적인 사례
    • 주로 샘플(samples), 프레임(frames), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용
    • 이미지가 연달아 시퀀스로 있는 것이 비디오
    • 초당 몇개의 이미지가 있냐 ; 프레임

    7. 텐서의 연산(Operations)

    • 텐서에 대한 수학 연산, 삼각함수, 비트 연산, 비교 연산, 집계 등 제공
    import math
    a = torch.rand(1,2) * 2 - 1
    print(a)
    print(torch.abs(a))
    print(torch.ceil(a))
    print(torch.floor(a))
    print(torch.clamp(a, -0.5, 0.5)) #범위 지정해서 값을 찝음? 최솟값이 -0.5 최대값이 0.5까지
    print(a)
    print(torch.min(a)) # 최소
    print(torch.max(a)) #최대
    print(torch.mean(a)) # 평균
    print(torch.std(a)) #표준편차
    print(torch.prod(a)) #곱
    print(torch.unique(torch.tensor([1,2,3, 1,2,2]))) # 중복제외 유닉크

    max와 min은 dim 인자를 줄 경우 argmax와 argmin도 함께 리턴

    • argmax: 최대값을 가진 인덱스
    • argmin: 최소값을 가진 인덱스
    x = torch.rand(2,2)
    print(x)
    print(x.max(dim=0))   # 위아래로 묶어서 누가 더 큰값인지 비교했음  values=tensor([0.8898, 0.8613]),
    print(x.max(dim=1))   #  좌우로 묶어서 비교했음 # 인덱스로 하면 [0 , 1], [0, 1]   values=tensor([0.8613, 0.8898]),
    
    print(x.min(dim=0))
    print(x.min(dim=1))

     

    torch.add: 덧셈

    print(x + y)
    print( torch.add(x,y))

    결과 텐서를 인자로 제공

    result = torch.empty(2, 4 )
    torch.add(x,y, out=result)
    print(result)

    in-place 방식

    • in-place방식으로 텐서의 값을 변경하는 연산 뒤에는 _''가 붙음
    • x.copy_(y), x.t_()
    print(x )
    print(y)
    y.add_(x) # x에 더한 값을 y에 저장해줘 라는 뜻
    print(y)

    torch.sub: 뺄셈

    print(x)
    print(y)
    print( x- y)
    print(torch.sub(x,y))
    print(x.sub(y))

    torch.mul: 곱셉

    print(x)
    print(y)
    print( x * y)
    print(torch.mul(x,y))
    print(x.mul(y))

    torch.div: 나눗셈

    print(x)
    print(y)
    print( x / y)
    print(torch.div(x,y))
    print(x.div(y))

    torch.mm: 내적(dot product)

    print(x)
    print(y)
    print(torch.matmul(x,y)) #메트릭스 멀티뮬리?
    
    z = torch.mm(x,y) #줄여서 mm 이라고  #행렬곱
    print(z)
    
    print(torch.svd(z))# singular value decomposition #분해

    8. 텐서의 조작(Manipulations)

    인덱싱(Indexing): NumPy처럼 인덱싱 형태로 사용가능

    x = torch.Tensor([[1,2],
                       [3,4]])
    print(x)
    
    #인덱스
    print(x[0,0])
    print(x[0,1])
    print(x[1,0])
    print(x[1,1])
    
    #슬라이싱
    print(x[:, 0]) # 행은 다 선택하면서 0번째 컬럼을 선택
    print(x[:, 1])
    print(x[0, :]) # 행은 0번째 선택, 컬럼은 다 선택
    print(x[1, :])

    view: 텐서의 크기(size)나 모양(shape)을 변경

    • 기본적으로 변경 전과 후에 텐서 안의 원소 개수가 유지되어야 함
    • -1로 설정되면 계산을 통해 해당 크기값을 유추
    x = torch.randn(4,5)
    print(x)
    y = x.view(20) # 4by5 구조가 없어지고 flat한 형태로 바뀜
    print(y)
    
    z = x.view(5, -1) # -1은 알아서 하라는 뜻
    print(z) # 결과는 5,4

    item: 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음

    • tensor 안의 값을 가져오는 것
    x = torch.randn(1)
    print(x)
    print(x.item())
    print(x.dtype)

    주의!! 스칼라값 하나만 존재해야 item() 사용 가능

    squeeze: 차원을 축소(제거)

    tensor = torch.rand(1,3,3)
    print(tensor)
    print(tensor.shape)
    
    t = tensor.squeeze()
    print(t.shape)

    unsqueeze: 차원을 증가(생성)

    t = torch.rand(3,3)
    print(t)
    print(t.shape)
    
    tensor = t.unsqueeze(dim=0) #0은 첫번째 차원을 기준으로 늘려줘
    print(tensor)
    print(tensor.shape)
    
    tensor = t.unsqueeze(dim=2) #2은 세번째 차원을 기준으로 늘려줘
    print(tensor)
    print(tensor.shape)

    stack: 텐서간 결합

    • stack = 쌓는다
    x = torch.FloatTensor([1,4])
    print(x)
    
    y = torch.FloatTensor([2,5])
    print(y)
    
    z = torch.FloatTensor([3,6])
    print(z)
    
    print(torch.stack([x,y,z]) )

    cat: 텐서를 결합하는 메소드(concatenate)

    • 넘파이의 stack과 유사하지만, 쌓을 dim이 존재해야함
    • 해당 차원을 늘려준 후 결합
    a = torch.randn( 1,3, 3)
    print(a)
    b = torch.randn(1,3,3)
    print(b)
    
    c = torch.cat((a,b), dim=0)
    print(c)
    print(c.size())
    
    c = torch.cat((a,b), dim=1)
    print(c)
    print(c.size())
    
    c = torch.cat((a,b), dim=2)
    print(c)
    print(c.size())

    chunk: 텐서를 여러 개로 나눌 때 사용

    • (몇 개로 나눌 것인가?)
    tensor = torch.rand(3,6)
    print(tensor)
    
    t1, t2, t3 = torch.chunk(tensor, 3, dim=1)

    split: chunk와 동일한 기능이지만 조금 다름

    • (텐서의 크기는 몇인가?)라고 물어보는 것
    tensor = torch.rand(3,6)
    t1, t2 = torch.split( tensor, 3, dim=1) # tensor 3크기/ 기준차원은
    print(tensor )
    
    print(t1)
    print(t2)

    torch ↔ numpy

    • Torch Tensor(텐서)를 NumPy array(배열)로 변환 가능
      • numpy()
      • from_numpy()
    • Tensor가 CPU상에 있다면 NumPy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함
    a = torch.ones(7)
    print(a)
    
    a.add_(1) # 언더바는 inplace 반영값을 넣기
    print(a)
    print(b) #  NumPy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함
    
    import numpy as np
    a = np.ones(7)
    b = torch.from_numpy(a) # torch형태로 바뀐 numpy
    np.add(a, 1, out=a) #out 출력은 a로 해줘 ( add_ 와 같은 기능 )
    print(a)
    print(b) # torch 와 numpy 가 메모리를 공유한다!!

    9.Autograd(자동미분)

    • torch.autograd 패키지는 Tensor의 모든 연산에 대해 자동 미분 제공
    • 이는 코드를 어떻게 작성하여 실행하느냐에 따라 역전파가 정의된다는 뜻
    • backprop를 위해 미분값을 자동으로 계산
      • 역전파 : BackPropagation이 되어야지 우리가 미분값을 backprop(미세조정)을 위해 신경망에서 ?? 에?
    • requires_grad 속성을 True로 설정하면, 해당 텐서에서 이루어지는 모든 연산들을 추적하기 시작
    • 기록을 추적하는 것을 중단하게 하려면, .detach()를 호출하여 연산기록으로부터 분리
    a = torch.rand(3,3)
    a = a * 3
    print(a)
    print(a.requires_grad)

    requires_grad_(...)는 기존 텐서의 requires_grad 값을 바꿔치기(in-place)하여 변경

    grad_fn: 미분값을 계산한 함수에 대한 정보 저장 (어떤 함수에 대해서 backprop 했는지)

    a.requires_grad_(True) #언더바 inplace 바꾼값을 바로 적용해서 연산
    print(a.requires_grad )
    
    b = (a * a).sum() # 연산을 한것을 기록으로 남김 : =<SumBackward0>)
    print(b)
    print(b.grad_fn)# gradient function

    10.기울기(Gradient)

    import torch
    import  math
    x = torch.ones(3,3, requires_grad=True)
    print(x)
    y = x + 5
    print(y)
    
    z = y * y       # grad_fn=<MulBackward0>
    out = z.mean()  # grad_fn=<MeanBackward0>
    print(z, out)

    계산이 완료된 후, .backward() 호출하면 자동으로 역전파 계산이 가능하고, .grad 속성에 누적됨

    print(out)
    out.backward()   #tensor(36., grad_fn=<MeanBackward0>)

    grad: data가 거쳐온 layer에 대한 미분값 저장

    print(x)
    print(x.grad) # 실제 미분값을 알려줘
    
    x = torch.randn(3, requires_grad=True)
    y = x * 2
    while y.data.norm() < 1000: # normalistion
        y = y * 2
    print(y)     # tensor([ 839.1677, -426.3043, 1344.2209], grad_fn=<MulBackward0>)
    
    v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
    y.backward(v)
    print(x.grad) #tensor([2.0480e+02, 2.0480e+03, 2.0480e-01])

    with torch.no_grad()를 사용하여 기울기의 업데이트를 하지 않음

    • 기록을 추적하는 것을 방지하기 위해 코드 블럭을 with torch.no_grad()로 감싸면 기울기 계산은 필요없지만,
    • requires_grad=True로 설정되어 학습 가능한 매개변수를 갖는 모델을 평가(evaluate)할 때 유용
    • 모델을 평가시에는 모델을 새로 고치거나/업데이트 하지 않기 때문에 기울기 계산이 딱히 필요없음
    print(x.requires_grad)
    print(( x ** 2).requires_grad )
    
    with torch.no_grad() :
        print((x ** 2).requires_grad)

    detach(): 내용물(content)은 같지만 require_grad가 다른 새로운 Tensor를 가져올 때

    print(x.requires_grad) # 기울기 True
    y = x.detach()         # 기울기빼기?
    print(y.requires_grad) # 기울기 False
    print(x.eq(y).all()) # x와 y가 equal 인지 확인

    자동 미분 흐름 예제

    • 계산 흐름 abcout

    out / a = ?

    • -> (미분값을 의미)
    • backward()를 통해 abcout을 계산하면 outa값이 a.grad에 채워짐
    a = torch.ones(2,2)
    a = torch.ones(2,2, requires_grad=True)
    # tensor([[1., 1.],
    #        [1., 1.]], requires_grad=True)
    
    print(a.data)
    print(a.grad)
    print(a.grad_fn) # 현재 tensor 대한 연산이 들어간 것이 없음 => gradient 값이 없음 = None

    b = a + 2

    b = a + 2
    print(b)

    c = b^2

    c = b ** 2
    out = c.sum()
    print(out) #tensor(36., grad_fn=<SumBackward0>)
    
    out.backward() #역전파를 해보자?? #tensor(36., grad_fn=<SumBackward0>)

    a의 grad_fn이 None인 이유는 직접적으로 계산한 부분이 없었기 때문

    print(a.data)
    print(a.grad)
    print(a.grad_fn) #None #a의 값을 활용했을뿐 직접적인 계산은 없었음
    
    print(b.data) #실제값 #tensor([[3., 3.],
           							 [3., 3.]])
    print(b.grad) #None
    print(b.grad_fn) #<AddBackward0 object at 0x7f9212ec0f10>
    
    print(c.data) #실제값 #tensor([[9., 9.],
            						[9., 9.]])
    print(c.grad) #None
    print(c.grad_fn) #<PowBackward0 object at 0x7f9212ec0b50>
    
    print(out.data) #최종결과 #tensor(36.)
    print(out.grad) #None
    print(out.grad_fn) #<SumBackward0 object at 0x7f9212ec0910>


    파이토치 활용 딥러닝 

    데이터 준비 -mnist

    파이토치에서는 데이터 준비를 위해 torch.utils.data의 Dataset과 DataLoader 사용 가능

    라이브러리 import 

    import torch, math, numpy as np, pandas as pd
    from torch.utils.data import Dataset, DataLoader

    토치비전(torchvision)은 파이토치에서 제공하는 데이터셋들이 모여있는 패키지

    import torchvision.transforms as transforms
    from torchvision import datasets
    • DataLoader의 인자로 들어갈 transform을 미리 정의할 수 있고, Compose를 통해 리스트 안에 순서대로 전처리 진행
    • ToTensor()를 하는 이유는 torchvision이 PIL Image 형태로만 입력을 받기 때문에 데이터 처리를 위해서 Tensor형으로 변환 필요
    # Tensor 형태로 미리 전환
    mnist_transform = transforms.Compose([transforms.ToTensor(), #Tensor 형태로 바꿔줌
                                          transforms.Normalize(mean=(0.5, ), std=(1.0, ))])
    #모델의 train set, test set
    
    trainset = datasets.MNIST(root='/content/',
                              train=True, download=True,
                              transform=mnist_transform )
    testset = datasets.MNIST(root='/content/',
                              train=False, download=True,
                              transform=mnist_transform )
    • DataLoader는 데이터 전체를 보관했다가 실제 모델 학습을 할 때 batch_size 크기만큼 데이터를 가져옴
    train_loader = DataLoader(trainset, batch_size=8, shuffle=True, num_workers=2)
    test_loader = DataLoader(testset, batch_size=8, shuffle=True, num_workers=2)
    # python 3.6 version
    # dataiter = iter(train_loader)
    # images, labels = dataiter.next()
    # images.shape, labels.shape
    
    # python 3.7 version부터는
    dataiter = iter(train_loader)
    images, labels = next(dataiter)
    images.shape, labels.shape
    
    # (torch.Size([8, 1, 28, 28]), torch.Size([8]))
    # 28*28짜리 이미지, 1이면 흑백, 8개  => 8개의 흑백 사진이라는
    # 왜 8개인가 batch_size가 8이라서
    torch_image = torch.squeeze(images[0]) # 차원 축소, 첫번째 이미지 기준으로
    torch_image.shape

    ## 이미지 시각화 하기

    import matplotlib.pyplot as plt
    
    figure = plt.figure(figsize=(12,6))
    cols, rows = 4,2
    for i in range(1, cols * rows +1): # 1-9까지 반복
        sample_idx = torch.randint(len(trainset), size=(1, ) ).item() #len기준으로 size를 가오는데, 랜덤값의 item =실제값을 인덱스로 가져오기
        img, label = trainset[sample_idx]
        figure.add_subplot(rows, cols, i)
        plt.title(label) #실제 숫자가 label 몇인지 뜸
        plt.axis('off')
        plt.imshow(img.squeeze(), cmap='gray' )
    plt.show()

    신경망 구성

    • 레이어(layer): 신경망의 핵심 데이터 구조로 하나 이상의 텐서를 입력받아 하나 이상의 텐서를 출력
    • 모듈(module): 한 개 이상의 계층이 모여서 구성
    • 모델(model): 한 개 이상의 모듈이 모여서 구성

    torch.nn 패키지 = neural network

    주로 가중치(weights), 편향(bias)값들이 내부에서 자동으로 생성되는 레이어들을 사용할 때 사용 (weight값들을 직접 선언 안함)  https://pytorch.org/docs/stable/nn.html

    import torch.nn as nn

    nn.Linear 계층 예제

    input = torch.randn(128, 20)
    print(input)
    
    m = nn.Linear(20, 30)
    print(m)
    
    output = m(input)
    print(output)
    print(output.size())

    nn.Conv2d 계층 예시

    input = torch.randn(20,16,50,100)
    print(input.size())
    
    m = nn.Conv2d(16, 33, 3, stride=2 )
    
    m = nn.Conv2d(16, 33, (3,5), stride=(2,1), padding=(4,2) )
    m = nn.Conv2d(16, 33, kernel_size=(3,5), stride=(2,1), padding=(4,2), dilation=(3,1) )
    print(m) #Conv2d(16, 33, kernel_size=(3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
    
    output = m(input)
    print(output.size())

    컨볼루션 레이어(Convolution Layers)

    nn.Conv2d 예제

    • in_channels: channel의 갯수
    • out_channels: 출력 채널의 갯수
    • kernel_size: 커널(필터) 사이즈
    nn.Conv2d(in_channels=1, out_channels=20, kernel_size=5, stride=1 )
    layer = nn.Conv2d(1,20,5,1).to(torch.device('cpu')) # in, out, 커널, 보폭
    layer  #Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))

    weight 확인

    weight = layer.weight
    weight.shape

    weight detach()를 통해 꺼내줘야 numpy()변환이 가능

    weight = weight.detach()
    weight = weight.numpy()
    weight.shape

    시각화하기

    import matplotlib.pyplot as plt
    plt.imshow(weight[0,0, :, :, ],'jet') #'gray'
    plt.colorbar()
    plt.show()
    print(images.shape) #torch.Size([8, 1, 28, 28])
    print(images[0].size()) #torch.Size([1, 28, 28])
    
    input_image = torch.squeeze(images[0])
    print(input_image.size())#torch.Size([28, 28])
    input_data = torch.unsqueeze(images[0], dim=0)
    print(input_data.size()) #torch.Size([1, 1, 28, 28]) 흑백사진 1장
    
    output_data = layer(input_data) #레이어를 통과시키고
    output = output_data.data  # 통과한 것의 데이터만 뽑아서
    output_arr = output.numpy() #array, 즉 numpy로 바꾼후에
    output_arr.shape  #즉 레이어 통과후의 모양은 =>  (1, 20, 24, 24)

    ## 레이어 통과 후의 시각화 

    # 레이어 통과후의 시각화
    plt.figure(figsize=(30,15))
    
    plt.subplot(131)
    plt.title('input')
    plt.imshow(input_image, 'gray')
    
    plt.subplot(132)
    plt.title('Weight')
    plt.imshow(weight[0,0, :,:], 'jet')
    
    plt.subplot(133)
    plt.title('Output')
    plt.imshow(output_arr[0, 0, :, :], 'gray')
    
    plt.show()

    풀링 레이어(Pooling layers)

    • F.max_pool2d
      • stride
      • kernel_size
    • torch.nn.MaxPool2d 도 많이 사용
    import torch.nn.functional as F
    
    pool = F.max_pool2d(output, 2, 2)
    pool.shape
    • MaxPool Layer는 weight가 없기 때문에 바로 numpy()변환 가능
    pool_arr = pool.numpy()
    pool_arr.shape

    # 풀링 이후 시각화 : 풀링 레이어를 통과하면 , 해상도가  떨어진다

    # 풀링 이후 시각화 : 풀링 레이어를 통과하면 , 해상도가 절반?으로 떨어진다
    # 2 by 2 짜리중에 최대값을 가지는 것으로 결과가 나옴
    plt.figure(figsize=(10,15))
    
    plt.subplot(121)
    plt.title('Input')
    plt.imshow(input_image, 'gray')
    
    plt.subplot(122)
    plt.title('Output')
    plt.imshow(pool_arr[0,0, :,:], 'gray')
    
    plt.show()

    선형 레이어(Linear layers)

    1d만 가능하므로 .view()를 통해 1d로 펼쳐줘야함

    • 쭉 펼치는 flatten과정이 필요
    flatten  = input_image.view(1,28*28)
    flatten.shape
    
    lin = nn.Linear(784, 10)(flatten)#in_features=784, out_features=10   # 784 -> 10짜리로 줄이는 것
    lin.shape
    
    #tensor 확인
    lin

    시각

    plt.imshow(lin.detach().numpy(), cmap='jet')
    plt.colorbar()
    plt.show()

    비선형 활성화 (Non-linear Activations)

    F.softmax와 같은 활성화 함수 등

    with torch.no_grad():
        flatten = input_image.view(1, 28 * 28)
        lin = nn.Linear(784,10)(flatten) # input이 리니어를 거쳐서 softmax까지
        softmax = F.softmax(lin, dim=1)
    
    softmax
    
    np.sum(softmax.numpy()) # 결과는 모든 10개의 합이 100% /  다중 분류

    F.relu

    • ReLU 활성화함수를 적용하는 레이어
    • nn.ReLU로도 사용 가능
    inputs = torch.randn(4,3 , 28, 28).to(device)
    inputs.shape
    
    layer = nn.Conv2d(3, 20, 5,1).to(device)
    output = F.relu(layer(inputs))
    output.shape
Designed by Tistory.