상세 컨텐츠

본문 제목

머신러닝과 딥러닝(17)_전이학습

카테고리 없음

by teminam 2023. 6. 21. 10:13

본문

1. 에일리언 vs 프레데터 데이터셋

 

2. 이미지 증강 기법(Image Augmentation)

 

    이미지 증강(Image Augmentation)은 기계 학습과 컴퓨터 비전 분야에서 사용되는
    중요한 기술 중 하나입니다. 이미지 증강은 기존의 훈련 데이터셋을 다양한
    방법으로 변형하여 데이터의 다양성을 높이고, 모델의 일반화 능력을 향상시키는
    데 사용됩니다.

    이미지 증강은 다양한 변형 기법을 사용하여 원본 이미지를 변형시키는
    과정입니다. 이러한 변형은 회전, 확대/축소, 이동, 대칭, 밝기 조정, 색상 변환
    등과 같은 다양한 변형을 포함할 수 있습니다. 이 변형들은 실제로 일어날 수
    있는 환경 변동을 모방하거나, 데이터의 다양성을 향상시키는 데 도움을 줍니다.

    이미지 증강은 다음과 같은 몇 가지 기법을 포함할 수 있습니다:

    1. 회전 (Rotation): 이미지를 일정한 각도로 회전시킵니다. 이는 이미지의
    방향에 대한 불변성을 향상시키고, 객체의 다양한 각도에서의 특징을 학습할 수
    있도록 도와줍니다.

    2. 확대/축소 (Scaling): 이미지를 확대하거나 축소하여 크기를 조정합니다.
    이를 통해 객체의 크기에 대한 불변성을 향상시킬 수 있습니다.

    3. 이동 (Translation): 이미지를 수평 또는 수직으로 이동시킵니다. 객체의
    위치에 대한 불변성을 향상시키고, 모델이 객체를 잘 인식할 수 있도록 도움을
    줍니다.

    4. 대칭 (Mirroring): 이미지를 수평 또는 수직으로 반전시킵니다. 이를 통해
    이미지에 대한 다양성을 높이고, 대칭된 객체의 인식을 향상시킬 수 있습니다.

    5. 밝기 조정 (Brightness Adjustment): 이미지의 밝기를 조정합니다. 이를 통해
    다양한 조명 조건에서의 객체 인식 능력을 개선할 수 있습니다.

    6. 색상 변환 (Color Transformation): 이미지의 색상을 변환합니다. 이를 통해
    다양한 색상 조건에서의 객체 인식 능력을 향상시킬 수 있습니다.

    이 외에도 더 다양한 이미지 증강 기법들이 존재하며, 이들을 조합하여 데이터의
    다양성을 증가시킬 수 있습니다.

    이미지 증강은 데이터셋이 작거나 한정적인 경우에 특히 유용하며, 모델의
    일반화 능력을 향상시켜 성능을 향상시킬 수 있습니다.

 

 

    Compose 함수는 함수형 프로그래밍에서 자주 사용되는 개념입니다. Compose
    함수는 여러 개의 함수를 합성하여 새로운 함수를 생성하는 데 사용됩니다. 이는
    함수들을 순차적으로 실행하는 것과 동일한 효과를 가지지만, 코드의 가독성과
    재사용성을 향상시킬 수 있습니다.

    보통 Compose 함수는 두 개 이상의 함수를 인자로 받고, 이들 함수를 오른쪽에서
    왼쪽으로 연속적으로 적용합니다. 예를 들어, `f`, `g`, `h`라는 세 개의 함수가
    있다고 가정해봅시다. `compose` 함수를 사용하여 이들 함수를 합성할 수
    있습니다.

    수식으로 표현하면 다음과 같습니다:

      ```
      compose(f, g, h) = f(g(h(x)))
      ```

    여기서 `x`는 입력값입니다. Compose 함수는 `h` 함수를 `x`에 적용한 결과를
    `g` 함수에 전달하고, 다시 그 결과를 `f` 함수에 전달하여 최종 결과를
    생성합니다.

    Compose 함수를 사용하면 여러 함수를 한 줄로 연결하여 코드를 작성할 수
    있습니다. 이를 통해 함수들 간의 의존성을 명확하게 표현하고, 재사용 가능한
    함수 체인을 생성할 수 있습니다. 또한, Compose 함수를 사용하면 중첩 함수
    호출을 피할 수 있어 코드를 간결하고 가독성이 높게 유지할 수 있습니다.

    다양한 프로그래밍 언어와 라이브러리에서 Compose 함수 또는 유사한 함수를
    제공하고 있으며, 함수형 프로그래밍에서 일반적으로 사용되는 개념입니다.

 

 

    위의 코드는 PyTorch의 torchvision.transforms 모듈을 사용하여 데이터 전처리
    과정을 정의한 예시입니다. 코드에서는 'train'과 'validation' 두 가지
    데이터셋에 대한 전처리 방식을 정의하고 있습니다. 각 데이터셋은 Compose
    함수를 사용하여 여러 전처리 단계를 순차적으로 적용합니다.

    1. `'train'` 데이터셋 전처리:
      - `transforms.Resize((224, 224))`: 이미지 크기를 (224, 224)로 조정합니다.
      - `transforms.RandomAffine(0, shear=10, scale=(0.8, 1.2))`: 무작위로
      이미지를 변형합니다. Affine 변환 중에서 shear(전단), scale(확대/축소)
      변환을 무작위로 적용합니다.
      - `transforms.RandomHorizontalFlip()`: 이미지를 무작위로 수평으로
      뒤집습니다.
      - `transforms.ToTensor()`: 이미지를 텐서로 변환합니다. 이미지를 0과 1
      사이의 값으로 정규화합니다.

    2. `'validation'` 데이터셋 전처리:
      - `transforms.Resize((224, 224))`: 이미지 크기를 (224, 224)로 조정합니다.
      - `transforms.ToTensor()`: 이미지를 텐서로 변환합니다. 이미지를 0과 1
      사이의 값으로 정규화합니다.

    이렇게 정의된 `data_transforms` 딕셔너리는 주로 PyTorch의 데이터 로더
    (Dataloader)와 함께 사용됩니다. 데이터 로더는 데이터셋을 배치 단위로 불러올
    수 있게 해주는 기능을 제공합니다. 데이터 로더에 전달되는 데이터셋에
    `transform` 인자로 위에서 정의한 전처리 방식을 지정하여 데이터가 로드되는
    동안 실시간으로 전처리가 적용될 수 있습니다.

 

 

 

imgs, labels = next(iter(dataloaders['train']))

fig, axes = plt.subplots(4, 8, figsize=(20, 10))

for img, label, ax in zip(imgs, labels, axes.flatten()):
  ax.set_title(label.item())
  ax.imshow(img.permute(1, 2, 0))
  ax.axis('off')

 

 

    위의 코드는 데이터 로더(`dataloaders['train']`)에서 배치 단위로 이미지와
    레이블을 가져와서 시각화하는 과정을 나타내고 있습니다. 코드의 세부 내용은
    다음과 같습니다:

    1. `imgs, labels = next(iter(dataloaders['train']))`: `dataloaders['train']
    ` 데이터 로더로부터 다음 배치의 이미지와 레이블을 가져옵니다. `next(iter())
    `를 사용하여 첫 번째 배치를 가져옵니다. `imgs`는 이미지 배치를, `labels`는
    해당 이미지들에 대한 레이블을 나타내는 텐서입니다.

    2. `fig, axes = plt.subplots(4, 8, figsize=(20, 10))`: 4행 8열의 서브플롯
    (subplot)을 가진 Figure 객체 `fig`와 이를 구성하는 Axes 객체 배열 `axes`를
    생성합니다. 이 서브플롯은 이미지와 해당 레이블을 시각화하기 위해 사용될
    예정입니다. `figsize=(20, 10)`는 Figure 객체의 크기를 지정하는 매개변수로,
    가로로 20인치, 세로로 10인치 크기로 설정되었습니다.

    3. `for img, label, ax in zip(imgs, labels, axes.flatten()):`: `imgs`
    `labels`에서 이미지와 레이블을 순회하면서 시각화를 수행합니다. `axes.flatten
    ()`는 `axes` 배열을 1차원으로 평탄화시켜 순회하도록 합니다. `img`, `label`,
    `ax`는 각각 이미지, 레이블, 그리고 서브플롯 객체(`Axes`)를 나타냅니다.

    4. `ax.set_title(label.item())`: `ax`에 해당하는 서브플롯의 제목을 레이블
    값으로 설정합니다. `label.item()`을 사용하여 레이블 텐서를 정수로
    변환합니다.

    5. `ax.imshow(img.permute(1, 2, 0))`: `ax`에 해당하는 서브플롯에 이미지를
    표시합니다. `img.permute(1, 2, 0)`는 이미지의 차원을 변경하여 RGB 이미지로
    표시하기 위한 작업입니다. 이미지 텐서의 차원 순서를 (채널, 높이, 너비)에서
    (높이, 너비, 채널)로 변경합니다.

    6. `ax.axis('off')`: 서브플롯의 축을 숨깁니다. 이를 통해 이미지 주변에 축이
    표시되지 않습니다.

    위의 코드는 훈련 데이터셋에서 한 배치의 이미지와 레이블을 시각화하여
    보여주는 예시입니다. 4행 8열의 서브플롯으로 구성된 그리드에 이미지와
    레이블이 표시되며, 각 서브플롯의 제목은 해당 이미지의 레이블 값을
    나타냅니다. 이미지는 RGB 형식으로 변환되어 표시되며, 축은 숨겨져 있어
    이미지 주변에 표시되지 않습니다.

 

 

3. 전이학습(Transfer Learning)

  • 하나의 작업을 위해 훈련된 모델을 유사 작업수행 모델의 시작점으로 활용하는 딥러닝 접근법
  • 신경망은 처음부터 새로 학습하는 것보다 전이 학습을 통해 업데이트 하고 재학습하는 편이 더 빠르고 간편함
  • 전이학습은 여러 응용 분야 중에서도 특히 검출, 영상 인식, 음성 인식, 검색 분야에 많이 사용
 

3-1. 전이 학습의 고려할 점

  • 크기: 모델 크기의 중요성은 모델을 배포할 위치와 방법에 따라 달라짐
  • 정확도: 재훈련 전의 모델 성능은 어느 정도인지 확인이 필요
  • 예측속도: 하드웨어 및 배치 크기와 같은 다른 딥러닝 요소는 물론 선택된 모델의 아키텍쳐와 모델 크기에 따라서도 달라짐

 

 

Q. 전이학습이란?

    전이학습(Transfer Learning)은 기존에 학습된 신경망 모델의 지식을 다른
    문제에 적용하는 기법입니다. 이미지 분류를 예로 들면, 전이학습은 이미지
    데이터셋을 사용하여 학습된 신경망 모델을 가져와서 새로운 이미지 분류 문제에
    적용하는 것을 의미합니다.

    일반적으로 전이학습은 다음과 같은 절차를 따릅니다:

    1. 기존에 학습된 신경망 모델 가져오기: 전이학습을 위해 일반적으로 이미지
    분류 등의 공통 작업에 널리 사용되는 사전 학습된 신경망 모델을 선택합니다.
    대표적으로 VGG, ResNet, Inception, MobileNet 등이 있습니다. 이러한 모델들은
    대규모 이미지 데이터셋(예: ImageNet)에서 사전에 학습된 상태로 제공됩니다.

    2. 신경망 아키텍처 변경 및 초기화: 가져온 모델의 최종 분류 계층을 제외한
    나머지 부분을 고정합니다. 그리고 새로운 분류 작업에 맞게 모델의 아키텍처를
    수정하고, 분류 계층을 초기화합니다. 이렇게 함으로써 모델은 새로운
    데이터셋에 맞게 특징을 추출할 수 있도록 준비됩니다.

    3. 새로운 데이터셋으로 학습: 수정된 신경망 모델을 새로운 데이터셋에 대해
    학습시킵니다. 대부분의 경우, 사전 학습된 모델의 일부 파라미터는 고정되어
    있기 때문에 학습할 파라미터의 수가 상대적으로 적습니다. 이로 인해 새로운
    데이터셋에 대한 학습이 빠르고 적은 데이터로도 좋은 성능을 얻을 수 있습니다.

    4. 성능 평가 및 예측: 학습된 모델을 사용하여 새로운 데이터에 대한 예측을
    수행하고, 해당 문제에 대한 성능을 평가합니다. 이를 통해 모델의 성능을
    개선하거나 추가적인 조정이 필요한 경우 모델을 수정하고 다시 학습시킬 수
    있습니다.

    전이학습은 다음과 같은 장점을 가지고 있습니다:

    - 데이터 부족 문제 해결: 전이학습은 작은 규모의 데이터셋에서도 좋은 성능을
    제공할 수 있습니다. 사전 학습된 모델은 대규모 데이터셋에서 학습되었으며,

    이를 이용하여 모델이 이미지의 일반적인 특징을 학습하고 새로운 데이터셋에
    적용할 수 있습니다.

    - 계산 효율성: 사전 학습된 모델을 기반으로 하기 때문에 학습하는 데 필요한
    시간과 컴퓨팅 자원을 절약할 수 있습니다.

    - 최적화의 용이성: 사전 학습된 모델은 이미 많은 파라미터를 조정하고
    최적화했기 때문에 초기 가중치 설정에 대한 부담이 줄어듭니다.

    전이학습은 컴퓨터 비전 분야를 넘어 자연어 처리, 음성 처리 등 다른
    분야에서도 널리 사용되고 있으며, 기존의 학습된 모델을 활용하여 새로운
    문제에 대한 해결에 큰 도움을 줍니다.

 

 

4. 사전 학습된 ResNet50 모델


4-1. 이미지넷(ImageNet)

  • 이미지 데이터베이스
  • 1000개의 동물과 사물 이미지를 포함

 

    해당 코드는 torchvision 패키지에서 제공하는 ResNet-50 모델을 불러오는
    과정입니다. ResNet-50은 컴퓨터 비전 분야에서 널리 사용되는 심층 신경망
    아키텍처 중 하나입니다.

    설명을 좀 더 자세히 하자면:

    1. `models.resnet50(weights='IMAGENET1K_V1')`: `models` 모듈은
    torchvision에서 제공하는 다양한 모델 구조를 포함하고 있습니다. 여기서는
    `resnet50`을 호출하여 ResNet-50 모델을 가져옵니다. `weights` 매개변수는
    사전 학습된 가중치를 지정하는 것으로, `'IMAGENET1K_V1'`은 ImageNet
    데이터셋에 대해 사전 학습된 가중치를 사용한다는 의미입니다. 즉, ImageNet
    데이터셋으로 사전 학습된 ResNet-50 모델을 가져오게 됩니다.

    2. `.to(device)`: `.to()` 함수를 사용하여 모델을 지정한 디바이스(GPU 또는
    CPU)로 이동합니다. `device` 변수는 모델이 실행될 디바이스를 나타내며, GPU를
    사용하기 위해 미리 정의된 GPU 디바이스를 지정할 수 있습니다.

    3. `print(model)`: 모델의 구조와 파라미터 정보를 출력합니다. 이를 통해
    ResNet-50 모델의 아키텍처를 확인할 수 있습니다. 모델의 출력 결과는 신경망의
    계층 구조와 각 계층의 파라미터 수 등을 보여줍니다.

    ResNet-50은 딥러닝에서 이미지 분류와 관련된 다양한 작업에 널리 사용되며,
    사전 학습된 가중치를 사용하여 고성능의 모델을 쉽게 구성할 수 있습니다. 해당
    코드를 실행하면 ResNet-50 모델이 생성되고, 모델의 구조와 파라미터 정보가
    출력됩니다.

 

4-2. Freeze Layers

  • 특징을 뽑아내는 CNN의 앞쪽 컨볼루션 레이어들은 학습을 하지 않도록 설정
  • 출력 부분의 레이어(fc)를 다시 설정하여 분류에 맞게 설정

 

    Freeze Layers는 전이학습에서 사용되는 개념으로, 사전 학습된 모델의 일부
    계층의 가중치를 고정하여 학습 과정에서 업데이트되지 않도록 하는 것을
    의미합니다. 이를 통해 고정된 계층은 이전에 다른 데이터셋에서 학습한 특징을
    유지하면서 새로운 작업에 맞게 모델을 세밀하게 조정할 수 있습니다.

    Freeze Layers를 사용하는 이유는 다음과 같습니다:

    1. 파라미터 수의 감소: 모델의 일부 계층을 고정함으로써 학습할 파라미터 수를
    줄일 수 있습니다. 이는 학습 과정에서 필요한 계산 자원과 메모리 사용량을
    줄여줍니다.

    2. 오버피팅 방지: 고정된 계층은 이전에 학습한 특징을 유지하므로, 새로운
    데이터셋에 대해 학습할 때 오버피팅을 방지할 수 있습니다. 특히, 작은 규모의
    데이터셋을 가지고 작업할 때 유용합니다.

    Freeze Layers를 적용하는 방법은 다음과 같습니다:

    1. 모든 계층을 고정하지 않고 원하는 계층을 선택합니다. 일반적으로 사전
    학습된 모델의 초기 계층은 이미지의 저수준 특징을 학습하는데 사용되므로
    고정하지 않습니다. 대신, 더 깊은 계층이나 분류 계층을 고정하는 것이
    일반적입니다.

    2. 선택한 계층의 `requires_grad` 속성을 False로 설정합니다. 이렇게 함으로써
    해당 계층의 가중치 업데이트를 막을 수 있습니다.

    3. 고정된 계층을 제외한 나머지 계층을 새로운 데이터셋에 맞게 학습시킵니다.
    이를 위해 새로운 데이터셋에 대해 오차를 계산하고, 역전파를 통해 가중치를
    업데이트합니다.

    Freeze Layers를 적절하게 사용하면 전이학습에서 모델의 성능을 향상시킬 수
    있습니다. 고정할 계층의 선택은 주어진 작업과 데이터셋에 따라 달라질 수
    있으며, 실험과 조정을 통해 최적의 설정을 찾을 수 있습니다.

 

for param in model.parameters():
  param.requires_grad = False # 가져온 파라미터(W=Weight, b=bias)를 업데이트 하지 않음

model.fc = nn.Sequential(
    nn.Linear(2048, 128),
    nn.ReLU(),
    nn.Linear(128, 1),
    nn.Sigmoid()
).to(device)

print(model)

 

 

# 학습: fc 부분만 학습하므로 속도가 빠름
optimizer = optim.Adam(model.fc.parameters(), lr=0.001)

epochs = 10

for epoch in range(epochs):
    for phase in ['train', 'validation']:
        if phase == 'train':
            model.train()
        else:
            model.eval()

        sum_losses = 0
        sum_accs = 0

        for x_batch, y_batch in dataloaders[phase]:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            y_pred = model(x_batch)

            loss = nn.BCELoss()(y_pred, y_batch)

            if phase == 'train':
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            sum_losses = sum_losses + loss.item()

            y_bool = (y_pred >= 0.5).float()
            acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
            sum_accs = sum_accs + acc.item()

        avg_loss = sum_losses / len(dataloaders[phase])
        avg_acc = sum_accs / len(dataloaders[phase])

        print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs}, Loss: {avg_loss:.4f}, Accuracy: {avg_acc:.2f}%')

    위의 코드는 주어진 데이터셋으로 모델을 학습하고, 학습 과정에서의 손실과
    정확도를 출력하는 과정을 나타내고 있습니다. 코드를 상세히
    설명해드리겠습니다:

    1. `optimizer = optim.Adam(model.fc.parameters(), lr=0.001)`: Adam
    옵티마이저를 사용하여 모델의 분류 계층 (`model.fc`)의 파라미터를
    학습합니다. 학습률은 0.001로 설정됩니다.

    2. `epochs = 10`: 전체 데이터셋을 사용하여 학습할 에폭 수를 지정합니다. 각
    에폭은 전체 데이터셋을 한 번씩 순회하는 것을 의미합니다.

    3. `for epoch in range(epochs):`: 주어진 에폭 수에 따라 반복합니다.

    4. `for phase in ['train', 'validation']:`: 학습과 검증 단계를 나타내는
    'train'과 'validation'을 순회합니다.

    5. `if phase == 'train': model.train() else: model.eval()`: 현재 단계가
    학습 단계인지 검증 단계인지 확인합니다. `model.train()`은 모델을 학습
    모드로 설정하고, `model.eval()`은 모델을 평가 모드로 설정합니다. 평가
    모드에서는 드롭아웃과 배치 정규화와 같은 학습 과정에서 사용되지 않는
    기능들이 비활성화됩니다.

    6. `sum_losses = 0``sum_accs = 0`: 손실과 정확도를 계산하기 위한 변수를
    초기화합니다.

    7. `for x_batch, y_batch in dataloaders[phase]:`: 데이터로더에서 미니배치
    데이터를 가져옵니다. `x_batch`는 입력 이미지 배치이고, `y_batch`는 해당
    이미지들의 정답 레이블 배치입니다.

    8. `x_batch = x_batch.to(device)``y_batch = y_batch.to(device)`:
    데이터를 GPU로 이동합니다. `to(device)`는 주어진 디바이스(GPU 또는 CPU)로
    데이터를 이동하는 역할을 합니다.

    9. `y_pred = model(x_batch)`: 입력 배치에 대한 모델의 예측을 계산합니다.
    이전에 설정한 분류 계층을 통과한 결과를 반환합니다.

    10. `loss = nn.BCELoss()(y_pred, y_batch)`: 이진 분류 작업을 위한 이진 교차
    엔트로피 손실을 계산합니다. `nn.BCELoss()`는 이진 교차 엔트로피 손실 함수를
    나타냅니다. `y_pred`는 예측값, `y_batch`는 실제 레이블입니다.

    11. `if phase == 'train': optimizer.zero_grad()`, `loss.backward()`,
    `optimizer.step()`:

    학습 단계에서는 옵티마이저의 그래디언트를 0으로 초기화한 후, 손실을
    역전파하여 그래디언트를 계산하고, 옵티마이저의 `step()` 메서드를 호출하여
    파라미터를 업데이트합니다.

    12. `sum_losses = sum_losses + loss.item()`, `sum_accs = sum_accs + acc.item
    ()`: 현재 미니배치의 손실과 정확도를 누적합니다.

    13. `avg_loss = sum_losses / len(dataloaders[phase])`, `avg_acc =
    sum_accs / len(dataloaders[phase])`: 현재 단계(학습 또는 검증)에서의 평균
    손실과 정확도를 계산합니다.

    14. `print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs}, Loss: {avg_loss:.
    4f}, Accuracy: {avg_acc:.2f}%')`: 현재 단계(학습 또는 검증)의 에폭, 평균
    손실 및 정확도를 출력합니다. 출력 결과는 주어진 형식에 따라 나타납니다.

    위의 코드는 주어진 데이터셋으로 모델을 학습하고, 각 에폭에서 학습과 검증의
    손실과 정확도를 출력합니다. 학습 단계에서는 손실을 역전파하여 모델의
    파라미터를 업데이트하고, 검증 단계에서는 모델의 평가를 수행합니다.

 

 

 

    위의 코드는 ResNet-50 모델을 생성하고, 마지막 레이어를 변경하여 이진 분류를
    수행하는 모델을 만드는 과정입니다.

    1. `model = models.resnet50().to(device)`: torchvision의 `models` 모듈을
    사용하여 ResNet-50 아키텍처의 사전 학습된 모델을 불러옵니다. 모델을
    `device`로 이동시킵니다. 기존의 사전 학습된 가중치를 사용하여 초기화된
    모델이 생성됩니다.

    2. `model.fc = nn.Sequential(...)`: ResNet-50 모델의 마지막 fully connected
    레이어인 `model.fc`를 변경합니다. 기존의 마지막 레이어를 새로운 fully
    connected 레이어로 대체합니다.

    3. `nn.Linear(2048, 128)`: 입력 차원이 2048이고 출력 차원이 128인 선형
    레이어를 추가합니다.

    4. `nn.ReLU()`: ReLU 활성화 함수를 적용합니다.

    5. `nn.Linear(128, 1)`: 입력 차원이 128이고 출력 차원이 1인 선형 레이어를
    추가합니다. 이는 이진 분류를 위한 출력 레이어입니다.

    6. `nn.Sigmoid()`: Sigmoid 활성화 함수를 적용하여 출력을 0과 1 사이의
    확률로 변환합니다.

    7. `.to(device)`: 모델을 `device`로 이동시킵니다.

    이렇게 변경된 모델은 이진 분류 작업에 적합하도록 마지막 레이어가 재구성된
    ResNet-50 모델입니다. 이 모델은 입력 이미지를 특징 추출을 위해 ResNet-50의
    합성곱 레이어를 통과시킨 후, 새로운 fully connected 레이어를 통과시켜 이진
    분류를 수행합니다.

 

optimizer = optim.Adam(model.fc.parameters(), lr=0.001)

epochs = 10

for epoch in range(epochs):
    for phase in ['train', 'validation']:
        if phase == 'train':
            model.train()
        else:
            model.eval()

        sum_losses = 0
        sum_accs = 0

        for x_batch, y_batch in dataloaders[phase]:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            y_pred = model(x_batch)

            loss = nn.BCELoss()(y_pred, y_batch)

            if phase == 'train':
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            sum_losses = sum_losses + loss.item()

            y_bool = (y_pred >= 0.5).float()
            acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
            sum_accs = sum_accs + acc.item()

        avg_loss = sum_losses / len(dataloaders[phase])
        avg_acc = sum_accs / len(dataloaders[phase])

        print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs}, Loss: {avg_loss:.4f}, Accuracy: {avg_acc:.2f}%')

optimizer = optim.Adam(model.fc.parameters(), lr=0.001)

epochs = 10

for epoch in range(epochs):
    for phase in ['train', 'validation']:
        if phase == 'train':
            model.train()
        else:
            model.eval()

        sum_losses = 0
        sum_accs = 0

        for x_batch, y_batch in dataloaders[phase]:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            y_pred = model(x_batch)

            loss = nn.BCELoss()(y_pred, y_batch)

            if phase == 'train':
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            sum_losses = sum_losses + loss.item()

            y_bool = (y_pred >= 0.5).float()
            acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
            sum_accs = sum_accs + acc.item()

        avg_loss = sum_losses / len(dataloaders[phase])
        avg_acc = sum_accs / len(dataloaders[phase])

        print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs}, Loss: {avg_loss:.4f}, Accuracy: {avg_acc:.2f}%')

    주어진 코드는 다음과 같은 기능을 수행합니다:

    1. `optimizer = optim.Adam(model.fc.parameters(), lr=0.001)`:
    Adam 옵티마이저를 생성합니다. 모델의 `fc` 레이어의
    파라미터만을 최적화 대상으로 선택하고, 학습률을 0.001로
    설정합니다. Adam은 경사 하강법 최적화 알고리즘 중 하나로,
    학습 속도를 조정하면서 모델의 파라미터를 업데이트합니다.

    2. `epochs = 10`: 학습할 에포크(epoch)의 수를 설정합니다.
    에포크는 전체 데이터셋을 한 번씩 훑는 것을 의미합니다.

    3. `for epoch in range(epochs):`: 주어진 에포크 수만큼
    반복합니다. 각 에포크는 전체 학습 과정을 의미합니다.

    4. `for phase in ['train', 'validation']:`: 학습과 검증
    (validation) 두 가지 단계에 대해 반복합니다. 이 코드는
    데이터셋을 학습용과 검증용으로 나누어 모델을 학습하고
    평가하는 과정을 수행합니다.

    5. `if phase == 'train': model.train()`: 현재 단계가
    'train'인 경우 모델을 학습 모드로 설정합니다. 이는 모델이
    학습 중에는 가중치를 업데이트해야 하며, 역전파를 통해
    그라디언트를 계산하고 가중치를 조정해야 함을 의미합니다.

    6. `else: model.eval()`: 현재 단계가 'train'이 아닌 경우, 즉
    'validation'인 경우 모델을 평가 모드로 설정합니다. 이는
    모델이 평가 중에는 가중치를 업데이트하지 않으며, 그라디언트를
    계산하지 않아도 됨을 의미합니다.

    7. `sum_losses = 0``sum_accs = 0`: 손실(loss)과 정확도
    (accuracy)의 합을 저장하기 위한 변수를 초기화합니다.

    8. `for x_batch, y_batch in dataloaders[phase]:`: 현재 단계
    (phase)에 대한 데이터로더에서 미니 배치를 순회합니다. 미니
    배치는 입력 데이터(`x_batch`)와 해당하는 정답 데이터
    (`y_batch`)로 구성됩니다.

    9. `x_batch = x_batch.to(device)` 및 `y_batch = y_batch.to
    (device)`: 데이터를 GPU로 전송합니다. `to(device)`를 사용하여
    데이터를 GPU 메모리로 이동시킵니다. `device`는 이전에 지정한
    디바이스(GPU 또는 CPU)를 나타냅니다.

    10. `y_pred = model(x_batch)`: 모델에 입력 데이터를 전달하여
    예측값(`y_pred`)을 얻습니다. 모델은 입력 데이터를 기반으로
    클래스에 대한 예측 확률을 출력합니다.

    11. `loss = nn.BCELoss()(y_pred, y_batch)`: 이진 교차
    엔트로피 손실 함수(`nn.BCELoss()`)를 사용하여 예측값과 정답
    데이터 간의 손실을 계산합니다. 이 손실은 예측과 정답 간의
    차이를 측정하는데 사용됩니다.

    12. `if phase == 'train': optimizer.zero_grad()`, `loss.
    backward()`, `optimizer.step()`: 현재 단계가 'train'인 경우,
    옵티마이저를 사용하여 역전파를 수행하고 모델의 가중치를
    업데이트합니다. `zero_grad()`는 그라디언트를 초기화하고,
    `backward()`는 그라디언트를 계산하고, `step()`은 가중치를
    업데이트합니다.

    13. `sum_losses = sum_losses + loss.item()`: 현재 배치의
    손실을 `sum_losses`에 더합니다. `.item()`을 사용하여 손실
    텐서를 스칼라 값으로 변환합니다.

    14. `y_bool = (y_pred >= 0.5).float()`, `acc = (y_batch ==
    y_bool).float().sum() / len(y_batch) * 100`: 예측값과 정답
    데이터를 비교하여 정확도를 계산합니다. 이 코드는 예측값이 0.
    5보다 크거나 같은 경우에는 1, 작은 경우에는 0으로 변환한 후,
    정답과 비교합니다. 정확도는 맞은 예측의 개수를 전체 데이터
    개수로 나눈 비율로 계산됩니다.

    15. `sum_accs = sum_accs + acc.item()`: 현재 배치의 정확도를
    `sum_accs`에 더합니다.

    16. `avg_loss = sum_losses / len(dataloaders[phase])`
    `avg_acc = sum_accs / len(dataloaders[phase])`: 현재 단계
    (phase)에 대한 평균 손실과 평균 정확도를 계산합니다. `len
    (dataloaders[phase])`는 배치의 개수를 나타냅니다.

    17. `print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs}, Loss:
    {avg_loss:.4f}, Accuracy: {avg_acc:.2f}%')`: 현재 단계(phase)
    의 에포크, 평균 손실 및 평균 정확도를 출력합니다. 이를 통해
    각 에포크의 학습과 검증 단계에서의 손실과 정확도를 확인할 수
    있습니다.

    주어진 결과는 10개의 에포크 동안 학습과 검증 단계에서의
    손실과 정확도를 보여줍니다. 첫 번째 열은 단계(train 또는
    validation)를 나타내며, 두 번째 열은 현재 에포크 수와 총
    에포크 수를 나타냅니다. 세 번째 열은 평균 손실을, 네 번째
    열은 평균 정확도를 표시합니다. 이를 통해 학습 과정에서 손실이
    감소하고 정확도가 향상되는지 확인할 수 있습니다.

    주어진 코드는 다음과 같은 일련의 과정을 거칩니다:

    1. `from PIL import Image`: PIL (Python Imaging
    Library) 패키지에서 Image 모듈을 가져옵니다. 이 모듈은
    이미지 파일을 열고 조작하는 기능을 제공합니다.

    2. `img1 = Image.open('data/validation/alien/32.jpg')
    `: 주어진 경로에 있는 '32.jpg' 파일을 엽니다. 이
    파일은 'alien' 클래스에 속하는 이미지입니다. `Image.
    open()` 함수를 사용하여 이미지 파일을 열고, 반환된
    이미지 객체를 `img1` 변수에 할당합니다.

    3. `img2 = Image.open('data/validation/predator/45.
    jpg')`: 주어진 경로에 있는 '45.jpg' 파일을 엽니다. 이
    파일은 'predator' 클래스에 속하는 이미지입니다. `Image.
    open()` 함수를 사용하여 이미지 파일을 열고, 반환된
    이미지 객체를 `img2` 변수에 할당합니다.

    4. `fig, axes = plt.subplots(1, 2, figsize=(12, 6))`:
    `subplots()` 함수를 사용하여 1행 2열의 그래프 영역을
    생성합니다. 이 그래프는 두 개의 이미지를 나란히 표시할
    것입니다. `fig` 변수는 전체 그림을 나타내는 Figure
    객체를, `axes` 변수는 두 개의 축 객체를 포함하는
    배열을 반환합니다.

    5. `axes[0].imshow(img1)`: 첫 번째 축에 `imshow()`
    함수를 사용하여 `img1` 이미지를 표시합니다. `imshow()`
    함수는 이미지 데이터를 시각화하는 데 사용됩니다. 이
    경우, `img1` 이미지가 첫 번째 축에 표시됩니다.

    6. `axes[0].axis('off')`: 첫 번째 축의 축 표시를
    끕니다. 이렇게 하면 이미지 주위에 축과 눈금이 표시되지
    않습니다.

    7. `axes[1].imshow(img2)`: 두 번째 축에 `imshow()`
    함수를 사용하여 `img2` 이미지를 표시합니다. `img2`
    이미지가 두 번째 축에 표시됩니다.

    8. `axes[1].axis('off')`: 두 번째 축의 축 표시를
    끕니다. 이렇게 하면 이미지 주위에 축과 눈금이 표시되지
    않습니다.

    9. `plt.show()`: 앞에서 생성한 그래프를 보여줍니다.
    `show()` 함수를 호출하여 그래프를 표시하고, 이를 통해
    두 개의 이미지가 나란히 표시되는 결과를 확인할 수
    있습니다.

    이 코드는 'alien' 및 'predator' 클래스에 속하는 두
    개의 이미지를 로드하고, 이를 나란히 표시하여
    시각적으로 확인할 수 있는 기능을 제공합니다.

 

 

    주어진 코드는 이미지와 예측 결과를 시각화하는 부분입니다.

    1. `fig, axes = plt.subplots(1, 2, figsize=(12, 6))`: 1행
    2열의 subplot을 생성하여 두 개의 이미지와 예측 결과를 나란히
    표시하기 위한 그림을 생성합니다.

    2. `axes[0].set_title(f'{(1-y_pred[0, 0]) * 100:.2f}% Alien,
    {y_pred[0, 0] * 100:.2f}% Predator')`: 왼쪽 subplot에 제목을
    설정합니다. 제목은 첫 번째 이미지의 예측 결과에 대한 정보를
    포함하고 있습니다. 예측 결과를 확률 형태로 표시하며,
    'Alien'과 'Predator'의 예측 확률을 백분율로 표시합니다.

    3. `axes[0].imshow(img1)`: 왼쪽 subplot에 첫 번째 이미지를
    표시합니다.

    4. `axes[0].axis('off')`: 왼쪽 subplot의 축을 숨깁니다.

    5. `axes[1].set_title(f'{(1-y_pred[1, 0]) * 100:.2f}% Alien,
    {y_pred[1, 0] * 100:.2f}% Predator')`: 오른쪽 subplot에
    제목을 설정합니다. 제목은 두 번째 이미지의 예측 결과에 대한
    정보를 포함하고 있습니다. 예측 결과를 확률 형태로 표시하며,
    'Alien'과 'Predator'의 예측 확률을 백분율로 표시합니다.

    6. `axes[1].imshow(img2)`: 오른쪽 subplot에 두 번째 이미지를
    표시합니다.

    7. `axes[1].axis('off')`: 오른쪽 subplot의 축을 숨깁니다.

    8. `plt.show()`: 그림을 표시합니다.

    따라서 왼쪽 그림은 79.27%의 확률로 'Alien'으로 예측되었고, 20.
    73%의 확률로 'Predator'로 예측되었습니다. 오른쪽 그림은 21.
    12%의 확률로 'Alien'으로 예측되었고, 78.88%의 확률로
    'Predator'로 예측되었습니다.

 

 

# 학습: fc 부분만 학습하므로 속도가 빠름

optimizer = optim.Adam(model.fc.parameters(), lr=0.001)
epochs = 10
for epoch in range(epochs):
    for phase in ['train', 'validation']:
        if phase == 'train':
            model.train()
        else:
            model.eval()
        sum_losses = 0
        sum_accs = 0
        for x_batch, y_batch in dataloaders[phase]:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            y_pred = model(x_batch)
            loss = nn.BCELoss()(y_pred, y_batch)

            if phase == 'train':
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            sum_losses = sum_losses + loss.item()

            y_bool = (y_pred >= 0.5).float()
            acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
            sum_accs = sum_accs + acc.item()

        avg_loss = sum_losses / len(dataloaders[phase])
        avg_acc = sum_accs / len(dataloaders[phase])

        print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs}, Loss: {avg_loss:.4f}, Accuracy: {avg_acc:.2f}%')