본문 바로가기

Upstage AI Lab 2기

Upstage AI Lab 2기 [Day060] 수강생 TODO #02 - Pytorch Data Loading - 수정작업 #2

Upstage AI Lab 2기

2024년 3월 8일 (목) Day_060

수강생 TODO

https://hyj89han.tistory.com/133

https://hyj89han.tistory.com/134

 

1차 피드백 중 애매하게 해결된 것 

  1. normalization 반드시 하기
  2. 모듈화 해서 합치는 과정에서 무언가 오류가 생김 (실행에는 문제가 없음) 왜 extend를 썼을때는 오류가 생겼었을까?
  3. feature extraction layer와 classification layer 분리하는 과정에서 softmax 레이어를 어디로 옮겼는지 기억이 안남.

해결하지 못한 1 차 질문 :

  • 왜 8:2로 train val 나눴는가 -> cifar 10은 정제가 잘 된 data라 val이 10000개까지 필요 없을 수도 있다.
  • 왜 LeakyReLU 를 썼는지, 음수 값을 보존하는 게 목적이었다면 더 좋은 대안 들이 있었을 텐데?
  • 시그모이드 함수는 선형인가요 비선형인가요~?
  • 손실함수와 활성화 함수 왜 쓰는지 알고 쓸 것!

숙제 :

  • 왜 pixel의 value를 normalize 해서 0~1 range로 scaling 하면 성능이 오르는지
  • 왜 Normalization 을 하면 성능이 올라갈까? - 가우시안 분포와 관련이 있음 (딥러닝에서 가우시안 분포 매우매우 중요)
  • kernel size 를 3*3를 쓰는 이유가 있다. 이미지 인풋이 큰 모델에서도 3*3을 많이 씀. 왜 그럴까요~? -> 논문 읽어보기

가능한 추가 작업 :

  • K-fold validations
  • data normalization

 

TODO

  1. 다른 조원들 코드 보기
  2. CNN 모듈에 softmax 레이어 합치기
  3. wandb 쓰는 법 익히기 - 일단 강의부터 듣기
  4. 3-5 강의 - VGG 모델 구현하기, GoogLeNet 구현하기, ResNet 모델 구현하기
  5. 프로젝트 디렉토리 구성 및 파일명 작성하는 방식 익히기 
    참고 : https://github.com/DimensionSTP/multimodal-transformer
  6. 손실함수와 optimizer 복습
  7. kernel size 를 3*3를 쓰는 이유 -> 파라미터 계산해보기 & VGG 논문 읽어보기 
    Simonyan, Karen, and Andrew Zisserman. "Very deep convolutional networks for large-scale image recognition." arXiv preprint arXiv:1409.1556 (2014).
  8. extend를 썼을 때 어느 지점에서 연산적 이상이 발생한 것인지, reshape을 좀 더 효율적으로 적용하는 코드를 확인하기.
  9. 어제 본 데이터 특성 정리하기

 

 

cifar10 - 원본 데이터의 구성 형태

train data : data_batch 파일 5개 ( data_batch 랜덤한 이미지 10000개씩)

test data : test_batch (10000개 이미지, 10개 클래스에 대해 1000개씩)

 

def unpickle(file):
    import pickle
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding ='bytes')
    return dict

 

input data의 형태를 확인하기 위해 train_dataset1 를 세부적으로 뜯어봄

train_dataset1 = unpickle('./data/cifar-10-python/cifar-10-batches-py/data_batch_1')

 

unpickle 하면 dict 형태로 반환

dict keys는 [b'batch_label', b'labels', b'data', b'filenames']

print(train_dataset1.keys())
# dict_keys([b'batch_label', b'labels', b'data', b'filenames'])
print(len(train_dataset1[b'labels']))
# 10000

print(len(train_dataset1[b'data']))
# 10000

print(type(train_dataset1[b'data']))
# numpy.ndarray

print(train_dataset1[b'data'].shape)
# (10000, 3072)

print(train_dataset1[b'data'][0].shape)
# (3072,)

 

한 개의 이미지에 대한 데이터는 (3072,) ndarray로 들어가 있음

원문 : Each row of the array stores a 32x32 colour image.

The first 1024 entries contain the red channel values,
the next 1024 the green, and the final 1024 the blue.
The image is stored in row-major order,
so that the first 32 entries of the array are
the red channel values of the first row of the image.

 

 

 

a = torch.arange(1, 3073)
a.shape
# torch.Size([3072])
a.reshape(3, 32, 32)

 

 

 


우리 조 질문 취합

이승현
  22시간 전
@정호인_멘토
안녕하십니까 멘토님! 현재 Upstage AI Lab 2기를 수강하고 있는 수강생 이승현이라고 합니다!
다름이 아니라 공부하던 중에 궁금하던 것이 있어서 질문 남깁니다!
물론 직접 찾아보면 좋지만 훌륭한 멘토님들이 계신데 잘 활용해 보고 싶어서 질문 남겨요!
*오전 스터디 중 질문이 하나 추가됐습니다.
질문은 총 세가지 입니다!
  1. CNN에서 레이어를 통과하면서 feature map들의 크기는 줄어들고 channel의 수는 늘어나는 것을 확인했습니다!
     그런데 이게 왜 성능이 더 좋은지 궁금하더라고요. 제가 알기로는 앞서 연구하셨던 연구자 분들이 feature map의
     크기는 작고, 채널은 길게 만든다고 알고 있었는데, 제가 알고있는게 맞는지, 아니면 다른 이유가 있는지 궁금해졌습니다!
  2. CNN에서 커널의 크기를 5x5보다 3x3 혹은 1x1 크기를 사용하는게 더 좋다고 알고 있습니다.
     이것도 그냥 좋다고 알고는 있었는데 이게 왜 좋은지 궁금해졌습니다!
  3. CNN에서 pooling을 할 때 정보의 손실이 생긴다고 생각되는데 이유가 있을까요?
     제가 알기로는 손실이 생기지만 연산 효율성이 높아져서 pooling을 하는 것으로 알고 있는데
     제가 알고 있는게 맞는지? 궁금합니다! 틀렸다면 혹시 다른 이유가 있을까요?|
제 질문은 이 세가지 이고, 질문을 읽어주셔서 감사합니다! (편집됨) 

 

멘토님 답변

정호인_멘토
  21시간 전

  1. Feature map 크기를 작게 만드는 것은 이미지의 정보를 압축함으로써 한 개의 feature가 가지는 정보의 양이 많아지게 하기 위해서입니다. 예를들어 첫번째 layer에서 3x3 커널을 사용했다면, 각 feature map 이미지의 3x3 크기의 픽셀 정보밖에 담고있지 않습니다. 하지만 이러한 layer를 더 깊게 쌓으면 한 feature map이 커버하는 전체 이미지의 크기가 늘어나기 때문에, 이미지 안에 큰 물체가 있어도 그 정보를 모두 담을 수 있게 됩니다. Channel 수가 늘어나는 것은, feature map 크기만 작아지고 channel 수가 그대로라면 가질 수 있는 정보가 제한적일 것입니다. 이미지를 압축하는 동시에 많은 정보를 갖기 위해서 feature map 크기는 작아지게, channel수는 늘어나게 설계합니다.
  2. 위에서 말씀하신 것처럼, 5x5커널 1개와 3x3 커널 2개는 같은 receptive field를 가집니다. 같은 receptive field에 더 적은 파라미터를 쓸 수 있기 때문에 계산면에서 더 효율적이고, 3x3 필터 사이에 activation function을 넣음으로써 nonlinearity를 더할 수 있습니다. 두개의 3x3 커널이 계산적으로 효율적이기도 하고, non linearity를 더하는 것도 좋지만 성능 개선을 무조건 보장하는 것은 아니니 이 부분을 주의하셔야 합니다.
  3. Pooling은 정보의 손실이 생기는 것이 맞습니다. 하지만 네트워크를 깊게 쌓지 않고도 이미지 크기를 빠르게 줄일 수 있고,  또한 pooling 단계에서는 parameter가 필요 없기 때문에 연산 면에서 매우 효율적입니다. 정보 손실을 최소화 하면서도 이미지를 줄이기 위해 사용되는 다른 방법으로는 dilated convolution이나 spatial pyramid pooling 등이 있습니다.

 


VGG 참고 자료

[8] Simonyan, Karen, and Andrew Zisserman. "Very Deep Convolutional Networks for Large-Scale Image Recognition." arXiv preprint arXiv:1409.1556, 2014. 9
[9] https://towardsdatascience.com/understanding-and-coding-a-resnet-in-keras-446d7ff84d33
[10] https://wikidocs.net/164796

 

 

 


 

다음주 수요일까지 숙제 : 공식 코드 안 보고, figure만 보고 ResNet 5가지 구현

(ResNet-18, ResNet-34, ResNet-50, ResNet-101, ResNet-152)

 

Residual Block

 

 

 

 

 

https://www.mygreatlearning.com/blog/resnet/#sh1

2015 by Kaiming He, Xiangyu Zhang, Shaoqing Ren and Jian Sun in their paper “Deep Residual Learning for Image Recognition”.

 

 


softmax를 넣었는데 왜 성능이 더 떨어지지?

Epoch [65 / 100], Train Loss : 1.9537, Train Acc : 0.5061

Epoch [65 / 100], Valid Loss : 1.9581, Valid Acc : 0.4991

Epoch [65 / 100], Train Acc : 0.5061, Valid Acc : 0.4991

 

Epoch [66 / 100], Train Loss : 1.9539, Train Acc : 0.5054

Epoch [66 / 100], Valid Loss : 1.9628, Valid Acc : 0.4938

Epoch [66 / 100], Train Acc : 0.5054, Valid Acc : 0.4938

 

Epoch [67 / 100], Train Loss : 1.9542, Train Acc : 0.5068

Epoch [67 / 100], Valid Loss : 1.9647, Valid Acc : 0.4917

Epoch [67 / 100], Train Acc : 0.5068, Valid Acc : 0.4917

 

Epoch [68 / 100], Train Loss : 1.9509, Train Acc : 0.5108

Epoch [68 / 100], Valid Loss : 1.9670, Valid Acc : 0.4878

 

Early stopping at epoch 68

Valid max accuracy : 0.4991

Custom CNN test accuracy : 0.4979

엥?

 


class CrossEntropyLoss(_WeightedLoss):
    r"""This criterion computes the cross entropy loss between input logits
    and target.

    It is useful when training a classification problem with `C` classes.
    If provided, the optional argument :attr:`weight` should be a 1D `Tensor`
    assigning weight to each of the classes.
    This is particularly useful when you have an unbalanced training set.

    The `input` is expected to contain the unnormalized logits for each class (which do `not` need
    to be positive or sum to 1, in general).
    `input` has to be a Tensor of size :math:`(C)` for unbatched input,
    :math:`(minibatch, C)` or :math:`(minibatch, C, d_1, d_2, ..., d_K)` with :math:`K \geq 1` for the
    `K`-dimensional case. The last being useful for higher dimension inputs, such
    as computing cross entropy loss per-pixel for 2D images.

    The `target` that this criterion expects should contain either:

    - Class indices in the range :math:`[0, C)` where :math:`C` is the number of classes; if
      `ignore_index` is specified, this loss also accepts this class index (this index
      may not necessarily be in the class range). The unreduced (i.e. with :attr:`reduction`
      set to ``'none'``) loss for this case can be described as:

      .. math::
          \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad
          l_n = - w_{y_n} \log \frac{\exp(x_{n,y_n})}{\sum_{c=1}^C \exp(x_{n,c})}
          \cdot \mathbb{1}\{y_n \not= \text{ignore\_index}\}

      where :math:`x` is the input, :math:`y` is the target, :math:`w` is the weight,
      :math:`C` is the number of classes, and :math:`N` spans the minibatch dimension as well as
      :math:`d_1, ..., d_k` for the `K`-dimensional case. If
      :attr:`reduction` is not ``'none'`` (default ``'mean'``), then

      .. math::
          \ell(x, y) = \begin{cases}
              \sum_{n=1}^N \frac{1}{\sum_{n=1}^N w_{y_n} \cdot \mathbb{1}\{y_n \not= \text{ignore\_index}\}} l_n, &
               \text{if reduction} = \text{`mean';}\\
                \sum_{n=1}^N l_n,  &
                \text{if reduction} = \text{`sum'.}
            \end{cases}

      Note that this case is equivalent to the combination of :class:`~torch.nn.LogSoftmax` and
      :class:`~torch.nn.NLLLoss`.

    - Probabilities for each class; useful when labels beyond a single class per minibatch item
      are required, such as for blended labels, label smoothing, etc. The unreduced (i.e. with
      :attr:`reduction` set to ``'none'``) loss for this case can be described as:

      .. math::
          \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad
          l_n = - \sum_{c=1}^C w_c \log \frac{\exp(x_{n,c})}{\sum_{i=1}^C \exp(x_{n,i})} y_{n,c}

      where :math:`x` is the input, :math:`y` is the target, :math:`w` is the weight,
      :math:`C` is the number of classes, and :math:`N` spans the minibatch dimension as well as
      :math:`d_1, ..., d_k` for the `K`-dimensional case. If
      :attr:`reduction` is not ``'none'`` (default ``'mean'``), then

      .. math::
          \ell(x, y) = \begin{cases}
              \frac{\sum_{n=1}^N l_n}{N}, &
               \text{if reduction} = \text{`mean';}\\
                \sum_{n=1}^N l_n,  &
                \text{if reduction} = \text{`sum'.}
            \end{cases}

    .. note::
        The performance of this criterion is generally better when `target` contains class
        indices, as this allows for optimized computation. Consider providing `target` as
        class probabilities only when a single class label per minibatch item is too restrictive.

    Args:
        weight (Tensor, optional): a manual rescaling weight given to each class.
            If given, has to be a Tensor of size `C`
        size_average (bool, optional): Deprecated (see :attr:`reduction`). By default,
            the losses are averaged over each loss element in the batch. Note that for
            some losses, there are multiple elements per sample. If the field :attr:`size_average`
            is set to ``False``, the losses are instead summed for each minibatch. Ignored
            when :attr:`reduce` is ``False``. Default: ``True``
        ignore_index (int, optional): Specifies a target value that is ignored
            and does not contribute to the input gradient. When :attr:`size_average` is
            ``True``, the loss is averaged over non-ignored targets. Note that
            :attr:`ignore_index` is only applicable when the target contains class indices.
        reduce (bool, optional): Deprecated (see :attr:`reduction`). By default, the
            losses are averaged or summed over observations for each minibatch depending
            on :attr:`size_average`. When :attr:`reduce` is ``False``, returns a loss per
            batch element instead and ignores :attr:`size_average`. Default: ``True``
        reduction (str, optional): Specifies the reduction to apply to the output:
            ``'none'`` | ``'mean'`` | ``'sum'``. ``'none'``: no reduction will
            be applied, ``'mean'``: the weighted mean of the output is taken,
            ``'sum'``: the output will be summed. Note: :attr:`size_average`
            and :attr:`reduce` are in the process of being deprecated, and in
            the meantime, specifying either of those two args will override
            :attr:`reduction`. Default: ``'mean'``
        label_smoothing (float, optional): A float in [0.0, 1.0]. Specifies the amount
            of smoothing when computing the loss, where 0.0 means no smoothing. The targets
            become a mixture of the original ground truth and a uniform distribution as described in
            `Rethinking the Inception Architecture for Computer Vision <https://arxiv.org/abs/1512.00567>`__. Default: :math:`0.0`.

    Shape:
        - Input: Shape :math:`(C)`, :math:`(N, C)` or :math:`(N, C, d_1, d_2, ..., d_K)` with :math:`K \geq 1`
          in the case of `K`-dimensional loss.
        - Target: If containing class indices, shape :math:`()`, :math:`(N)` or :math:`(N, d_1, d_2, ..., d_K)` with
          :math:`K \geq 1` in the case of K-dimensional loss where each value should be between :math:`[0, C)`.
          If containing class probabilities, same shape as the input and each value should be between :math:`[0, 1]`.
        - Output: If reduction is 'none', shape :math:`()`, :math:`(N)` or :math:`(N, d_1, d_2, ..., d_K)` with :math:`K \geq 1`
          in the case of K-dimensional loss, depending on the shape of the input. Otherwise, scalar.


        where:

        .. math::
            \begin{aligned}
                C ={} & \text{number of classes} \\
                N ={} & \text{batch size} \\
            \end{aligned}

    Examples::

        >>> # Example of target with class indices
        >>> loss = nn.CrossEntropyLoss()
        >>> input = torch.randn(3, 5, requires_grad=True)
        >>> target = torch.empty(3, dtype=torch.long).random_(5)
        >>> output = loss(input, target)
        >>> output.backward()
        >>>
        >>> # Example of target with class probabilities
        >>> input = torch.randn(3, 5, requires_grad=True)
        >>> target = torch.randn(3, 5).softmax(dim=1)
        >>> output = loss(input, target)
        >>> output.backward()
    """
    __constants__ = ['ignore_index', 'reduction', 'label_smoothing']
    ignore_index: int
    label_smoothing: float

    def __init__(self, weight: Optional[Tensor] = None, size_average=None, ignore_index: int = -100,
                 reduce=None, reduction: str = 'mean', label_smoothing: float = 0.0) -> None:
        super().__init__(weight, size_average, reduce, reduction)
        self.ignore_index = ignore_index
        self.label_smoothing = label_smoothing

    def forward(self, input: Tensor, target: Tensor) -> Tensor:
        return F.cross_entropy(input, target, weight=self.weight,
                               ignore_index=self.ignore_index, reduction=self.reduction,
                               label_smoothing=self.label_smoothing)