반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

https://d2l.ai/chapter_convolutional-modern/cnn-design.html

 

8.8. Designing Convolution Network Architectures — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

8.8. Designing Convolution Network Architectures

The past sections took us on a tour of modern network design for computer vision. Common to all the work we covered was that it heavily relied on the intuition of scientists. Many of the architectures are heavily informed by human creativity and to a much lesser extent by systematic exploration of the design space that deep networks offer. Nonetheless, this network engineering approach has been tremendously successful.

 

지난 섹션에서는 컴퓨터 비전을 위한 최신 네트워크 설계를 살펴보았습니다. 우리가 다룬 모든 작업의 공통점은 과학자의 직관에 크게 의존한다는 것입니다. 많은 아키텍처는 인간의 창의성에 의해 크게 영향을 받으며 심층 네트워크가 제공하는 디자인 공간의 체계적인 탐색에 의해 훨씬 덜 영향을 받습니다. 그럼에도 불구하고 이 네트워크 엔지니어링 접근 방식은 엄청난 성공을 거두었습니다.

 

Since AlexNet (Section 8.1) beat conventional computer vision models on ImageNet, it became popular to construct very deep networks by stacking blocks of convolutions, all designed by the same pattern. In particular, 3×3 convolutions were popularized by VGG networks (Section 8.2). NiN (Section 8.3) showed that even 1×1 convolutions could be beneficial by adding local nonlinearities. Moreover, NiN solved the problem of aggregating information at the head of a network by aggregation across all locations. GoogLeNet (Section 8.4) added multiple branches of different convolution width, combining the advantages of VGG and NiN in its Inception block. ResNets (Section 8.6) changed the inductive bias towards the identity mapping (from f(x)=0). This allowed for very deep networks. Almost a decade later, the ResNet design is still popular, a testament to its design. Lastly, ResNeXt (Section 8.6.5) added grouped convolutions, offering a better trade-off between parameters and computation. A precursor to Transformers for vision, the Squeeze-and-Excitation Networks (SENets) allow for efficient information transfer between locations (Hu et al., 2018). They accomplished this by computing a per-channel global attention function.

 

AlexNet(섹션 8.1)이 ImageNet에서 기존 컴퓨터 비전 모델을 능가했기 때문에 모두 동일한 패턴으로 설계된 컨볼루션 블록을 쌓아 매우 깊은 네트워크를 구성하는 것이 인기를 얻었습니다. 특히 3×3 컨볼루션은 VGG 네트워크에 의해 대중화되었습니다(섹션 8.2). NiN(섹션 8.3)은 1×1 컨볼루션도 로컬 비선형성을 추가하면 도움이 될 수 있음을 보여주었습니다. 또한 NiN은 모든 위치에서 집계하여 네트워크 헤드에서 정보를 집계하는 문제를 해결했습니다. GoogLeNet(섹션 8.4)은 Inception 블록에서 VGG와 NiN의 장점을 결합하여 서로 다른 컨볼루션 폭의 여러 분기를 추가했습니다. ResNets(섹션 8.6)는 identity mapping(f(x)=0에서)에 대한 귀납적 편향을 변경했습니다. 이것은 매우 깊은 네트워크를 허용했습니다. 거의 10년이 지난 후에도 ResNet 디자인은 여전히 인기가 있으며 그 디자인의 증거입니다. 마지막으로 ResNeXt(섹션 8.6.5)는 그룹화 컨볼루션을 추가하여 매개변수와 계산 사이에 더 나은 절충안을 제공합니다. 비전을 위한 Transformers의 선구자인 Squeeze-and-Excitation Networks(SENets)는 위치 간의 효율적인 정보 전송을 허용합니다(Hu et al., 2018). 그들은 채널별 전역 주의 기능을 계산하여 이를 달성했습니다.

 

So far we omitted networks obtained via neural architecture search (NAS) (Liu et al., 2018, Zoph and Le, 2016). We chose to do so since their cost is usually enormous, relying on brute force search, genetic algorithms, reinforcement learning, or some other form of hyperparameter optimization. Given a fixed search space, NAS uses a search strategy to automatically select an architecture based on the returned performance estimation. The outcome of NAS is a single network instance. EfficientNets are a notable outcome of this search (Tan and Le, 2019).

 

지금까지 신경망 구조 검색(NAS)을 통해 얻은 네트워크는 생략했습니다(Liu et al., 2018, Zoph and Le, 2016). 무차별 대입 검색, 유전자 알고리즘, 강화 학습 또는 다른 형태의 하이퍼파라미터 최적화에 의존하는 비용이 일반적으로 엄청나기 때문에 그렇게 하기로 했습니다. 고정된 검색 공간이 주어지면 NAS는 검색 전략을 사용하여 반환된 성능 추정을 기반으로 아키텍처를 자동으로 선택합니다. NAS의 결과는 단일 네트워크 인스턴스입니다. EfficientNets는 이 검색의 주목할 만한 결과입니다(Tan and Le, 2019).

 

In the following we discuss an idea that is quite different to the quest for the single best network. It is computationally relatively inexpensive, it leads to scientific insights on the way, and it is quite effective in terms of the quality of outcomes. Let’s review the strategy by Radosavovic et al. (2020) to design network design spaces. The strategy combines the strength of manual design and NAS. It accomplishes this by operating on distributions of networks and optimizing the distributions in a way to obtain good performance for entire families of networks. The outcome of it are RegNets, specifically RegNetX and RegNetY, plus a range of guiding principles for the design of performant CNNs.

 

다음에서 우리는 하나의 최상의 네트워크를 찾는 것과는 상당히 다른 아이디어에 대해 논의합니다. 그것은 계산적으로 상대적으로 저렴하고 도중에 과학적 통찰력으로 이어지며 결과의 품질 측면에서 상당히 효과적입니다. Radosavovic et al.의 전략을 검토해 보겠습니다. (2020) 네트워크 설계 공간을 설계합니다. 이 전략은 수동 설계와 NAS의 장점을 결합합니다. 네트워크 배포에서 작동하고 전체 네트워크 제품군에 대해 우수한 성능을 얻을 수 있는 방식으로 배포를 최적화하여 이를 수행합니다. 그 결과는 RegNets, 특히 RegNetX 및 RegNetY와 고성능 CNN 설계를 위한 다양한 지침 원리입니다.

 

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

 

8.8.1. The AnyNet Design Space

The description below closely follows the reasoning in Radosavovic et al. (2020) with some abbreviations to make it fit in the scope of the book. To begin, we need a template for the family of networks to explore. One of the commonalities of the designs in this chapter is that the networks consist of a stem, a body and a head. The stem performs initial image processing, often through convolutions with a larger window size. The body consists of multiple blocks, carrying out the bulk of the transformations needed to go from raw images to object representations. Lastly, the head converts this into the desired outputs, such as via a softmax regressor for multiclass classification. The body, in turn, consists of multiple stages, operating on the image at decreasing resolutions. In fact, both the stem and each subsequent stage quarter the spatial resolution. Lastly, each stage consists of one or more blocks. This pattern is common to all networks, from VGG to ResNeXt. Indeed, for the design of generic AnyNet networks, Radosavovic et al. (2020) used the ResNeXt block of Fig. 8.6.5.

 

아래 설명은 Radosavovic et al.의 추론을 밀접하게 따릅니다. (2020) 책의 범위에 맞도록 일부 약어가 포함되어 있습니다. 시작하려면 탐색할 네트워크 제품군에 대한 템플릿이 필요합니다. 이 장에 있는 디자인의 공통점 중 하나는 네트워크가 스템, 바디 및 헤드로 구성된다는 것입니다. 스템은 종종 더 큰 창 크기의 컨볼루션을 통해 초기 이미지 처리를 수행합니다. 본문은 원시 이미지에서 개체 표현으로 이동하는 데 필요한 대부분의 변환을 수행하는 여러 블록으로 구성됩니다. 마지막으로 헤드는 이를 다중 클래스 분류를 위한 softmax 회귀 분석기와 같이 원하는 출력으로 변환합니다. 본체는 여러 단계로 구성되어 해상도가 낮아지는 이미지에서 작동합니다. 실제로 스템과 각 후속 단계는 공간 해상도를 4분의 1로 나눈다. 마지막으로 각 단계는 하나 이상의 블록으로 구성됩니다. 이 패턴은 VGG에서 ResNeXt까지 모든 네트워크에 공통적입니다. 실제로 일반적인 AnyNet 네트워크의 설계를 위해 Radosavovic et al. (2020)은 그림 8.6.5의 ResNeXt 블록을 사용했습니다.

 

Fig. 8.8.1  The AnyNet design space. The numbers (c,r) along each arrow indicate the number of channels c and the resolution r×r of the images at that point. From left to right: generic network structure composed of stem, body, and head; body composed of four stages; detailed structure of a stage; two alternative structures for blocks, one without downsampling and one that halves the resolution in each dimension. Design choices include depth di, the number of output channels ci, the number of groups gi, and bottleneck ratio ki for any stage i.

 

Let’s review the structure outlined in Fig. 8.8.1 in detail. As mentioned, an AnyNet consists of a stem, body, and head. The stem takes as its input RGB images (3 channels), using a 3×3 convolution with a stride of 2, followed by a batch norm, to halve the resolution from r×r to r/2×r/2. Moreover, it generates c0 channels that serve as input to the body.

 

그림 8.8.1의 구조를 자세히 살펴보자. 언급한 바와 같이 AnyNet은 스템, 바디, 헤드로 구성됩니다. 스템은 r×r에서 r/2×r/2로 해상도를 절반으로 줄이기 위해 스트라이드가 2인 3×3 컨볼루션을 사용하여 RGB 이미지(3개 채널)로 사용하고 배치 표준을 따릅니다. 또한 신체에 대한 입력 역할을 하는 c0 채널을 생성합니다.

 

Since the network is designed to work well with ImageNet images of shape 224×224×3, the body serves to reduce this to 7×7×c4 through 4 stages (recall that 224/21+4=7), each with an eventual stride of 2. Lastly, the head employs an entirely standard design via global average pooling, similar to NiN (Section 8.3), followed by a fully connected layer to emit an n-dimensional vector for n-class classification.

 

네트워크는 224×224×3 모양의 ImageNet 이미지와 잘 작동하도록 설계되었기 때문에 본문은 이를 4단계(224/2^1+4=7임을 상기)를 통해 7×7×c4로 줄이는 역할을 합니다. 마지막으로, 헤드는 NiN(섹션 8.3)과 유사한 전역 평균 풀링을 통해 완전히 표준적인 디자인을 사용하고, n-클래스 분류를 위해 n차원 벡터를 방출하기 위해 완전히 연결된 레이어가 뒤따릅니다.

 

Most of the relevant design decisions are inherent to the body of the network. It proceeds in stages, where each stage is composed of the same type of ResNeXt blocks as we discussed in Section 8.6.5. The design there is again entirely generic: we begin with a block that halves the resolution by using a stride of 2 (the rightmost in Fig. 8.8.1). To match this, the residual branch of the ResNeXt block needs to pass through a 1×1 convolution. This block is followed by a variable number of additional ResNeXt blocks that leave both resolution and the number of channels unchanged. Note that a common design practice is to add a slight bottleneck in the design of convolutional blocks. As such, with bottleneck ratio ki≥1 we afford some number of channels ci/ki within each block for stage i (as the experiments show, this is not really effective and should be skipped). Lastly, since we are dealing with ResNeXt blocks, we also need to pick the number of groups gi for grouped convolutions at stage i.

 

대부분의 관련 설계 결정은 네트워크 본문에 내재되어 있습니다. 각 단계는 섹션 8.6.5에서 논의한 것과 동일한 유형의 ResNeXt 블록으로 구성됩니다. 디자인은 다시 완전히 일반적입니다. 우리는 스트라이드 2(그림 8.8.1에서 가장 오른쪽)를 사용하여 해상도를 절반으로 줄이는 블록으로 시작합니다. 이를 일치시키려면 ResNeXt 블록의 잔여 분기가 1×1 컨벌루션을 통과해야 합니다. 이 블록 다음에는 해상도와 채널 수를 모두 변경하지 않고 그대로 두는 다양한 수의 추가 ResNeXt 블록이 옵니다. 일반적인 설계 관행은 컨볼루션 블록 설계에 약간의 병목 현상을 추가하는 것입니다. 이와 같이 병목 비율이 ki≥1인 경우 단계 i에 대해 각 블록 내에서 일정 수의 채널 ci/ki를 제공합니다(실험에서 알 수 있듯이 이것은 실제로 효과적이지 않으며 건너뛰어야 합니다). 마지막으로 ResNeXt 블록을 다루기 때문에 단계 i에서 그룹화된 컨볼루션에 대한 그룹 gi의 수를 선택해야 합니다.

 

This seemingly generic design space provides us nonetheless with many parameters: we can set the block width (number of channels) c0,…c4, the depth (number of blocks) per stage d1,…d4, the bottleneck ratios k1,…k4, and the group widths (numbers of groups) g1,…g4. In total this adds up to 17 parameters, resulting in an unreasonably large number of configurations that would warrant exploring. We need some tools to reduce this huge design space effectively. This is where the conceptual beauty of design spaces comes in. Before we do so, let’s implement the generic design first.

 

겉보기에 일반적인 이 설계 공간은 그럼에도 불구하고 많은 매개변수를 제공합니다. 블록 폭(채널 수) c0,…c4, 단계당 깊이(블록 수) d1,…d4, 병목 비율 k1,…k4, 및 그룹 폭(그룹의 수) g1,…g4. 전체적으로 이것은 최대 17개의 매개변수를 추가하므로 탐색을 보증할 수 있는 비합리적으로 많은 수의 구성이 생성됩니다. 이 거대한 디자인 공간을 효과적으로 줄이기 위한 몇 가지 도구가 필요합니다. 이것은 디자인 공간의 개념적 아름다움이 들어오는 곳입니다. 그렇게 하기 전에 먼저 일반적인 디자인을 구현합시다.

 

class AnyNet(d2l.Classifier):
    def stem(self, num_channels):
        return nn.Sequential(
            nn.LazyConv2d(num_channels, kernel_size=3, stride=2, padding=1),
            nn.LazyBatchNorm2d(), nn.ReLU())

 

Each stage consists of depth ResNeXt blocks, where num_channels specifies the block width. Note that the first block halves the height and width of input images.

 

각 단계는 깊이 ResNeXt 블록으로 구성되며 여기서 num_channels는 블록 너비를 지정합니다. 첫 번째 블록은 입력 이미지의 높이와 너비를 반으로 나눕니다.

 

@d2l.add_to_class(AnyNet)
def stage(self, depth, num_channels, groups, bot_mul):
    blk = []
    for i in range(depth):
        if i == 0:
            blk.append(d2l.ResNeXtBlock(num_channels, groups, bot_mul,
                use_1x1conv=True, strides=2))
        else:
            blk.append(d2l.ResNeXtBlock(num_channels, groups, bot_mul))
    return nn.Sequential(*blk)

Putting the network stem, body, and head together, we complete the implementation of AnyNet.

 

네트워크 스템, 바디, 헤드를 합치면 AnyNet 구현이 완료됩니다.

 

@d2l.add_to_class(AnyNet)
def __init__(self, arch, stem_channels, lr=0.1, num_classes=10):
    super(AnyNet, self).__init__()
    self.save_hyperparameters()
    self.net = nn.Sequential(self.stem(stem_channels))
    for i, s in enumerate(arch):
        self.net.add_module(f'stage{i+1}', self.stage(*s))
    self.net.add_module('head', nn.Sequential(
        nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(),
        nn.LazyLinear(num_classes)))
    self.net.apply(d2l.init_cnn)

 

8.8.2. Distributions and Parameters of Design Spaces

As just discussed in Section 8.8.1, parameters of a design space are hyperparameters of networks in that design space. Consider the problem of identifying good parameters in the AnyNet design space. We could try finding the single best parameter choice for a given amount of computation (e.g., FLOPs and compute time). If we allowed for even only two possible choices for each parameter, we would have to explore 2^17=131072 combinations to find the best solution. This is clearly infeasible due to its exorbitant cost. Even worse, we do not really learn anything from this exercise in terms of how one should design a network. Next time we add, say, an X-stage, or a shift operation, or similar, we would need to start from scratch. Even worse, due to the stochasticity in training (rounding, shuffling, bit errors), no two runs are likely to produce exactly the same results. A better strategy is to try to determine general guidelines of how the choices of parameters should be related. For instance, the bottleneck ratio, the number of channels, blocks, groups, or their change between layers should ideally be governed by a collection of simple rules. The approach in Radosavovic et al. (2019) relies on the following four assumptions:

 

섹션 8.8.1에서 설명한 것처럼 디자인 공간의 매개변수는 해당 디자인 공간에 있는 네트워크의 하이퍼 매개변수입니다. AnyNet 설계 공간에서 좋은 매개변수를 식별하는 문제를 고려하십시오. 주어진 계산량(예: FLOP 및 계산 시간)에 대해 단일 최상의 매개변수 선택을 찾으려고 시도할 수 있습니다. 각 매개변수에 대해 두 가지 가능한 선택만 허용하는 경우 최상의 솔루션을 찾기 위해 2^17=131072 조합을 탐색해야 합니다. 이것은 엄청난 비용 때문에 분명히 실행 불가능합니다. 설상가상으로 우리는 네트워크를 어떻게 설계해야 하는지에 대해 이 연습에서 실제로 아무것도 배우지 않습니다. 다음에 예를 들어 X-단계 또는 교대 작업 또는 이와 유사한 작업을 추가할 때는 처음부터 다시 시작해야 합니다. 설상가상으로 훈련의 확률성(반올림, 섞기, 비트 오류)으로 인해 두 번의 실행이 정확히 동일한 결과를 생성할 가능성이 없습니다. 더 나은 전략은 매개변수 선택이 어떻게 연관되어야 하는지에 대한 일반적인 지침을 결정하는 것입니다. 예를 들어, 병목 현상 비율, 채널, 블록, 그룹의 수 또는 계층 간의 변경은 이상적으로 간단한 규칙 모음에 의해 제어되어야 합니다. Radosavovic et al. (2019)은 다음 네 가지 가정에 의존합니다.

 

  1. We assume that general design principles actually exist, such that many networks satisfying these requirements should offer good performance. Consequently, identifying a distribution over networks can be a good strategy. In other words, we assume that there are many good needles in the haystack.

    우리는 이러한 요구 사항을 충족하는 많은 네트워크가 좋은 성능을 제공해야 하는 일반적인 설계 원칙이 실제로 존재한다고 가정합니다. 결과적으로 네트워크를 통한 분포를 식별하는 것이 좋은 전략이 될 수 있습니다. 즉, 우리는 건초 더미에 좋은 바늘이 많이 있다고 가정합니다.

  2. We need not train networks to convergence before we can assess whether a network is good. Instead, it is sufficient to use the intermediate results as reliable guidance for final accuracy. Using (approximate) proxies to optimize an objective is referred to as multi-fidelity optimization (Forrester et al., 2007). Consequently, design optimization is carried out, based on the accuracy achieved after only a few passes through the dataset, reducing the cost significantly.

    네트워크가 양호한지 평가하기 전에 네트워크를 수렴하도록 교육할 필요는 없습니다. 대신 최종 정확도에 대한 신뢰할 수 있는 지침으로 중간 결과를 사용하는 것으로 충분합니다. 목표를 최적화하기 위해 (대략적인) 프록시를 사용하는 것을 다중 충실도 최적화라고 합니다(Forrester et al., 2007). 결과적으로 데이터 세트를 몇 번 통과한 후에 달성된 정확도를 기반으로 설계 최적화가 수행되어 비용이 크게 절감됩니다.

  3. Results obtained at a smaller scale (for smaller networks) generalize to larger ones. Consequently, optimization is carried out for networks that are structurally similar, but with a smaller number of blocks, fewer channels, etc. Only in the end will we need to verify that the so-found networks also offer good performance at scale.

    더 작은 규모(소규모 네트워크의 경우)에서 얻은 결과는 더 큰 규모로 일반화됩니다. 결과적으로 구조적으로 유사하지만 더 적은 수의 블록, 더 적은 채널 등을 가진 네트워크에 대해 최적화가 수행됩니다. 결국 우리는 이렇게 발견된 네트워크가 대규모로 우수한 성능을 제공하는지 확인해야 합니다.

  4. Aspects of the design can be approximately factorized such that it is possible to infer their effect on the quality of the outcome somewhat independently. In other words, the optimization problem is moderately easy.

    디자인의 측면은 결과의 품질에 대한 영향을 다소 독립적으로 추론할 수 있도록 대략적으로 분해될 수 있습니다. 즉, 최적화 문제는 적당히 쉽습니다.

 

These assumptions allow us to test many networks cheaply. In particular, we can sample uniformly from the space of configurations and evaluate their performance. Subsequently, we can evaluate the quality of the choice of parameters by reviewing the distribution of error/accuracy that can be achieved with said networks. Denote by F(e) the cumulative distribution function (CDF) for errors committed by networks of a given design space, drawn using probability disribution p. That is,

 

이러한 가정을 통해 많은 네트워크를 저렴하게 테스트할 수 있습니다. 특히 구성 공간에서 균일하게 샘플링하여 성능을 평가할 수 있습니다. 그 후, 상기 네트워크로 달성할 수 있는 오류/정확도 분포를 검토하여 매개변수 선택의 품질을 평가할 수 있습니다. F(e)는 확률 분포 p를 사용하여 도출된 주어진 설계 공간의 네트워크에서 저지른 오류에 대한 누적 분포 함수(CDF)를 나타냅니다. 그건,

 

 

Our goal is now to find a distribution p over networks such that most networks have a very low error rate and where the support of p is concise. Of course, this is computationally infeasible to perform accurately. We resort to a sample of networks Z=def {net1,…netn} (with errors e1,…,en, respectively) from p and use the empirical CDF F^(e,Z) instead:

 

우리의 목표는 이제 대부분의 네트워크가 오류율이 매우 낮고 p의 지원이 간결한 네트워크를 통해 분포 p를 찾는 것입니다. 물론 이것은 정확하게 수행하기 위해 계산적으로 불가능합니다. 우리는 p에서 네트워크 Z=def {net1...netn}(각각 오류 e1,…,en 포함)의 샘플에 의존하고 대신 경험적 CDF F^(e,Z)를 사용합니다.

 

 

Whenever the CDF for one set of choices majorizes (or matches) another CDF it follows that its choice of parameters is superior (or indifferent). Accordingly Radosavovic et al. (2020) experimented with a shared network bottleneck ratio ki=k for all stages i of the network. This gets rid of 3 of the 4 parameters governing the bottleneck ratio. To assess whether this (negatively) affects the performance one can draw networks from the constrained and from the unconstrained distribution and compare the corresonding CDFs. It turns out that this constraint does not affect accuracy of the distribution of networks at all, as can be seen in the first panel of Fig. 8.8.2. Likewise, we could choose to pick the same group width gi=g occurring at the various stages of the network. Again, this does not affect performance, as can be seen in the second panel of Fig. 8.8.2. Both steps combined reduce the number of free parameters by 6.

 

하나의 선택 세트에 대한 CDF가 다른 CDF를 메이저화(또는 일치)할 때마다 매개변수 선택이 우월(또는 무관심)합니다. 따라서 Radosavovic et al. (2020)은 네트워크의 모든 단계 i에 대해 공유 네트워크 병목 현상 비율 ki=k로 실험했습니다. 이렇게 하면 병목 현상 비율을 제어하는 4개의 매개변수 중 3개가 제거됩니다. 이것이 성능에 (부정적인) 영향을 미치는지 평가하기 위해 제약이 있는 분포와 제약이 없는 분포에서 네트워크를 끌어와 해당 CDF를 비교할 수 있습니다. 그림 8.8.2의 첫 번째 패널에서 볼 수 있듯이 이 제약 조건은 네트워크 분포의 정확도에 전혀 영향을 미치지 않는 것으로 나타났습니다. 마찬가지로 네트워크의 다양한 단계에서 발생하는 동일한 그룹 너비 gi=g를 선택하도록 선택할 수 있습니다. 다시 말하지만 이것은 그림 8.8.2의 두 번째 패널에서 볼 수 있듯이 성능에 영향을 미치지 않습니다. 두 단계를 결합하면 사용 가능한 매개변수의 수가 6개 줄어듭니다.

 

Fig. 8.8.2  Comparing error empirical distribution functions of design spaces. AnyNetA is the original design space; AnyNetB ties the bottleneck ratios, AnyNetC also ties group widths, AnyNetD increases the network depth across stages. From left to right: (i) tying bottleneck ratios has no effect on performance, (ii) tying group widths has no effect on performance, (iii) increasing network widths (channels) across stages improves performance, (iv) increasing network depths across stages improves performance. Figure courtesy of Radosavovic et al. (2020).

 

Next we look for ways to reduce the multitude of potential choices for width and depth of the stages. It is a reasonable assumption that as we go deeper, the number of channels should increase, i.e., ci≥ci−1 (wi+1≥wi per their notation in Fig. 8.8.2), yielding AnyNetXD. Likewise, it is equally reasonable to assume that as the stages progress, they should become deeper, i.e., di≥di−1, yielding AnyNetXE. This can be experimentally verified in the third and fourth panel of Fig. 8.8.2, respectively.

 

다음으로 스테이지의 폭과 깊이에 대한 다양한 잠재적 선택을 줄이는 방법을 찾습니다. 더 깊이 들어갈수록 채널 수가 증가해야 한다는 합리적인 가정입니다. 마찬가지로 단계가 진행됨에 따라 단계가 더 깊어져야 한다고 가정하는 것도 마찬가지로 합리적입니다(예: di≥di-1). 이는 그림 8.8.2의 세 번째와 네 번째 패널에서 각각 실험적으로 확인할 수 있다.

 

8.8.3. RegNet

The resulting AnyNetXE design space consists of simple networks following easy-to-interpret design principles:

 

결과적인 AnyNetXE 설계 공간은 해석하기 쉬운 설계 원칙을 따르는 간단한 네트워크로 구성됩니다.

 

  • Share the bottleneck ratio ki=k for all stages i;
  • Share the group width gi=g for all stages i;
  • Increase network width across stages: ci≤ci+1;
  • Increase network depth across stages: di≤di+1.

This leaves us with the last set of choices: how to pick the specific values for the above parameters of the eventual AnyNetXE design space. By studying the best-performing networks from the distribution in AnyNetXE one can observe that: the width of the network ideally increases linearly with the block index across the network, i.e., cj≈c0+caj, where j is the block index and slope ca>0. Given that we get to choose a different block width only per stage, we arrive at a piecewise constant function, engineered to match this dependence. Secondly, experiments also show that a bottleneck ratio of k=1 performs best, i.e., we are advised not to use bottlenecks at all.

 

최종적인 AnyNetXE 설계 공간의 위 매개변수에 대한 특정 값을 선택하는 방법과 같은 마지막 선택 세트가 남아 있습니다. AnyNetXE의 분포에서 가장 성능이 좋은 네트워크를 연구하면 다음을 관찰할 수 있습니다. 네트워크의 너비는 네트워크 전체의 블록 인덱스와 함께 이상적으로 선형적으로 증가합니다. 즉, cj≈c0+caj, 여기서 j는 블록 인덱스이고 기울기 ca >0. 단계마다 다른 블록 폭을 선택할 수 있다는 점을 감안할 때, 이 종속성과 일치하도록 설계된 조각별 상수 함수에 도달합니다. 둘째, 실험은 k=1의 병목 현상 비율이 가장 잘 수행됨을 보여줍니다. 즉, 병목 현상을 전혀 사용하지 않는 것이 좋습니다.

 

We recommend the interested reader to review further details for how to design specific networks for different amounts of computation by perusing Radosavovic et al. (2020). For instance, an effective 32-layer RegNetX variant is given by k=1 (no bottleneck), g=16 (group width is 16), c1=32 and c2=80 channels for the first and second stage, respectively, chosen to be d1=4 and d2=6 blocks deep. The astonishing insight from the design is that it applies, even when investigating networks at a larger scale. Even better, it even holds for Squeeze-and-Excitation (SE) network designs (RegNetY) that have a global channel activation (Hu et al., 2018).

 

관심 있는 독자는 Radosavovic et al. (2020). 예를 들어, 효과적인 32계층 RegNetX 변형은 k=1(병목 현상 없음), g=16(그룹 너비는 16), c1=32 및 c2=80 채널로 각각 첫 번째 및 두 번째 단계에 대해 선택됩니다. d1=4 및 d2=6 블록 깊이여야 합니다. 설계의 놀라운 통찰력은 더 큰 규모의 네트워크를 조사할 때에도 적용된다는 것입니다. 더 나아가 글로벌 채널 활성화가 있는 Squeeze-and-Excitation(SE) 네트워크 설계(RegNetY)에도 적용됩니다(Hu et al., 2018).

 

class RegNetX32(AnyNet):
    def __init__(self, lr=0.1, num_classes=10):
        stem_channels, groups, bot_mul = 32, 16, 1
        depths, channels = (4, 6), (32, 80)
        super().__init__(
            ((depths[0], channels[0], groups, bot_mul),
             (depths[1], channels[1], groups, bot_mul)),
            stem_channels, lr, num_classes)

 

We can see that each RegNetX stage progressively reduces resolution and increases output channels.

 

각 RegNetX 단계가 점진적으로 해상도를 줄이고 출력 채널을 증가시키는 것을 볼 수 있습니다.

 

RegNetX32().layer_summary((1, 1, 96, 96))
Sequential output shape:     torch.Size([1, 32, 48, 48])
Sequential output shape:     torch.Size([1, 32, 24, 24])
Sequential output shape:     torch.Size([1, 80, 12, 12])
Sequential output shape:     torch.Size([1, 10])

 

8.8.4. Training

Training the 32-layer RegNetX on the Fashion-MNIST dataset is just like before.

 

Fashion-MNIST 데이터 세트에서 32계층 RegNetX를 교육하는 것은 이전과 동일합니다.

 

model = RegNetX32(lr=0.05)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(96, 96))
trainer.fit(model, data)

 

8.8.5. Discussion

 

With desirable inductive biases (assumptions or preferences) like locality and translation invariance (Section 7.1) for vision, CNNs have been the dominant architectures in this area. This has remained the case since LeNet up until recently when Transformers (Section 11.7) (Dosovitskiy et al., 2021, Touvron et al., 2021) started surpassing CNNs in terms of accuracy. While much of the recent progress in terms of vision Transformers can be backported into CNNs (Liu et al., 2022), it is only possible at a higher computational cost. Just as importantly, recent hardware optimizations (NVIDIA Ampere and Hopper) have only widened the gap in favor of Transformers.

 

시각에 대한 지역성 및 변환 불변성(섹션 7.1)과 같은 바람직한 귀납적 편향(가정 또는 선호도)을 통해 CNN은 이 영역에서 지배적인 아키텍처였습니다. 이는 트랜스포머(섹션 11.7)(Dosovitskiy et al., 2021, Touvron et al., 2021)가 정확성 측면에서 CNN을 능가하기 시작한 최근까지 LeNet 이후로 계속 유지되었습니다. 비전 트랜스포머 측면에서 최근의 많은 발전이 CNN으로 백포트될 수 있지만(Liu et al., 2022), 더 높은 계산 비용에서만 가능합니다. 마찬가지로 중요한 것은 최근의 하드웨어 최적화(NVIDIA Ampere 및 Hopper)가 트랜스포머에 유리한 격차를 더 벌렸을 뿐입니다.

 

It is worth noting that Transformers have a significantly lower degree of inductive bias towards locality and translation invariance than CNNs. It is not the least due to the availability of large image collections, such as LAION-400m and LAION-5B (Schuhmann et al., 2022) with up to 5 billion images that learned structures prevailed. Quite surprisingly, some of the more relevant work in this context even includes MLPs (Tolstikhin et al., 2021).

 

Transformers는 CNN보다 locality 및 translation invariance에 대한 귀납적 편향이 훨씬 낮다는 점은 주목할 가치가 있습니다. 학습 구조가 우세한 최대 50억 개의 이미지가 포함된 LAION-400m 및 LAION-5B(Schuhmann et al., 2022)와 같은 대규모 이미지 컬렉션의 가용성으로 인해 최소한이 아닙니다. 놀랍게도 이 맥락에서 더 관련성이 높은 일부 작업에는 MLP도 포함됩니다(Tolstikhin et al., 2021).

 

In sum, vision Transformers (Section 11.8) by now lead in terms of state-of-the-art performance in large-scale image classification, showing that scalability trumps inductive biases (Dosovitskiy et al., 2021). This includes pretraining large-scale Transformers (Section 11.9) with multi-head self-attention (Section 11.5). We invite the readers to dive into these chapters for a much more detailed discussion.

 

11.5. Multi-Head Attention — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

 

요약하면 비전 트랜스포머(섹션 11.8)는 이제 대규모 이미지 분류에서 최첨단 성능 측면에서 선두를 달리고 있으며 확장성이 유도 편향을 능가한다는 것을 보여줍니다(Dosovitskiy et al., 2021). 여기에는 multi-head self-attention(섹션 11.5)을 사용하여 대규모 Transformers(섹션 11.9)를 사전 훈련하는 것이 포함됩니다. 우리는 독자들이 훨씬 더 자세한 논의를 위해 이 장으로 뛰어들도록 초대합니다.

반응형


반응형

https://d2l.ai/chapter_convolutional-modern/densenet.html

 

8.7. Densely Connected Networks (DenseNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

8.7. Densely Connected Networks (DenseNet)

ResNet significantly changed the view of how to parametrize the functions in deep networks. DenseNet (dense convolutional network) is to some extent the logical extension of this (Huang et al., 2017). DenseNet is characterized by both the connectivity pattern where each layer connects to all the preceding layers and the concatenation operation (rather than the addition operator in ResNet) to preserve and reuse features from earlier layers. To understand how to arrive at it, let’s take a small detour to mathematics.

 

ResNet은 심층 네트워크에서 기능을 매개변수화하는 방법에 대한 관점을 크게 변경했습니다. DenseNet(dense convolutional network)은 어느 정도 이것의 논리적 확장입니다(Huang et al., 2017). DenseNet은 각 레이어가 모든 이전 레이어에 연결되는 연결 패턴과 이전 레이어의 기능을 보존하고 재사용하기 위한 연결 작업(ResNet의 추가 연산자가 아님)이 모두 특징입니다. 그것에 도달하는 방법을 이해하기 위해 수학으로 약간 우회해 봅시다.

 

import torch
from torch import nn
from d2l import torch as d2l

 

8.7.1. From ResNet to DenseNet

 

Recall the Taylor expansion for functions. For the point x=0 it can be written as

함수에 대한 Taylor 확장을 상기하십시오. 점 x=0에 대해 다음과 같이 쓸 수 있습니다.

 

The key point is that it decomposes a function into increasingly higher order terms. In a similar vein, ResNet decomposes functions into

 

요점은 함수를 점점 더 고차 항으로 분해한다는 것입니다. 유사한 맥락에서 ResNet은 기능을 다음으로 분해합니다.

 

 

That is, ResNet decomposes f into a simple linear term and a more complex nonlinear one. What if we wanted to capture (not necessarily add) information beyond two terms? One such solution is DenseNet (Huang et al., 2017).

 

즉, ResNet은 f를 간단한 선형 항과 더 복잡한 비선형 항으로 분해합니다. 두 용어 이상의 정보를 캡처(반드시 추가할 필요는 없음)하려면 어떻게 해야 합니까? 그러한 솔루션 중 하나가 DenseNet입니다(Huang et al., 2017).

 

Fig. 8.7.1  The main difference between ResNet (left) and DenseNet (right) in cross-layer connections: use of addition and use of concatenation.

 

As shown in Fig. 8.7.1, the key difference between ResNet and DenseNet is that in the latter case outputs are concatenated (denoted by [,]) rather than added. As a result, we perform a mapping from x to its values after applying an increasingly complex sequence of functions:

 

그림 8.7.1에서 볼 수 있듯이 ResNet과 DenseNet의 주요 차이점은 후자의 경우 출력이 추가되지 않고 연결된다는 것입니다([,]로 표시). 결과적으로 점점 더 복잡한 함수 시퀀스를 적용한 후 x에서 해당 값으로 매핑을 수행합니다.

 

 

In the end, all these functions are combined in MLP to reduce the number of features again. In terms of implementation this is quite simple: rather than adding terms, we concatenate them. The name DenseNet arises from the fact that the dependency graph between variables becomes quite dense. The last layer of such a chain is densely connected to all previous layers. The dense connections are shown in Fig. 8.7.2.

 

결국 이러한 기능을 모두 MLP로 결합하여 기능 수를 다시 줄입니다. 구현 측면에서 이것은 매우 간단합니다. 용어를 추가하는 대신 용어를 연결합니다. DenseNet이라는 이름은 변수 간의 종속성 그래프가 상당히 조밀해진다는 사실에서 유래되었습니다. 이러한 체인의 마지막 레이어는 이전의 모든 레이어와 조밀하게 연결됩니다. 조밀한 연결은 그림 8.7.2에 나와 있습니다.

 

Fig. 8.7.2  Dense connections in DenseNet. Note how the dimensionality increases with depth.

The main components that compose a DenseNet are dense blocks and transition layers. The former define how the inputs and outputs are concatenated, while the latter control the number of channels so that it is not too large, since the expansion x→[x,f1(x),f2([x,f1(x)]),…] can be quite high-dimensional.

 

DenseNet을 구성하는 주요 구성 요소는 dense block과 transition layer입니다. 전자는 입력과 출력이 연결되는 방식을 정의하고 후자는 너무 크지 않도록 채널 수를 제어합니다. 확장 x→[x,f1(x),f2([x,f1(x)] ),…]은 상당히 고차원적일 수 있습니다.

 

8.7.2. Dense Blocks

DenseNet uses the modified “batch normalization, activation, and convolution” structure of ResNet (see the exercise in Section 8.6). First, we implement this convolution block structure.

 

DenseNet은 ResNet의 수정된 "배치 정규화, 활성화 및 컨볼루션" 구조를 사용합니다(섹션 8.6의 실습 참조). 먼저 이 컨볼루션 블록 구조를 구현합니다.

 

def conv_block(num_channels):
    return nn.Sequential(
        nn.LazyBatchNorm2d(), nn.ReLU(),
        nn.LazyConv2d(num_channels, kernel_size=3, padding=1))

 

A dense block consists of multiple convolution blocks, each using the same number of output channels. In the forward propagation, however, we concatenate the input and output of each convolution block on the channel dimension. Lazy evaluation allows us to adjust the dimensionality automatically.

 

고밀도 블록은 각각 동일한 수의 출력 채널을 사용하는 여러 컨볼루션 블록으로 구성됩니다. 그러나 정방향 전파에서는 채널 차원에서 각 컨볼루션 블록의 입력과 출력을 연결합니다. 게으른 평가를 통해 차원을 자동으로 조정할 수 있습니다.

 

class DenseBlock(nn.Module):
    def __init__(self, num_convs, num_channels):
        super(DenseBlock, self).__init__()
        layer = []
        for i in range(num_convs):
            layer.append(conv_block(num_channels))
        self.net = nn.Sequential(*layer)

    def forward(self, X):
        for blk in self.net:
            Y = blk(X)
            # Concatenate input and output of each block along the channels
            X = torch.cat((X, Y), dim=1)
        return X

 

In the following example, we define a DenseBlock instance with 2 convolution blocks of 10 output channels. When using an input with 3 channels, we will get an output with 3+10+10=23 channels. The number of convolution block channels controls the growth in the number of output channels relative to the number of input channels. This is also referred to as the growth rate.

 

다음 예제에서는 10개 출력 채널의 2개 컨볼루션 블록으로 DenseBlock 인스턴스를 정의합니다. 3채널 입력을 사용하면 3+10+10=23채널 출력이 됩니다. 컨볼루션 블록 채널의 수는 입력 채널 수에 비해 출력 채널 수의 증가를 제어합니다. 이를 성장률이라고도 합니다.

 

blk = DenseBlock(2, 10)
X = torch.randn(4, 3, 8, 8)
Y = blk(X)
Y.shape
torch.Size([4, 23, 8, 8])

 

8.7.3. Transition Layers

Since each dense block will increase the number of channels, adding too many of them will lead to an excessively complex model. A transition layer is used to control the complexity of the model. It reduces the number of channels by using an 1×1 convolution. Moreover, it halves the height and width via average pooling with a stride of 2.

 

밀도가 높은 각 블록은 채널 수를 증가시키므로 채널을 너무 많이 추가하면 모델이 지나치게 복잡해집니다. 전환 레이어는 모델의 복잡성을 제어하는 데 사용됩니다. 1×1 컨벌루션을 사용하여 채널 수를 줄입니다. 또한 스트라이드 2의 평균 풀링을 통해 높이와 너비를 절반으로 줄입니다.

 

def transition_block(num_channels):
    return nn.Sequential(
        nn.LazyBatchNorm2d(), nn.ReLU(),
        nn.LazyConv2d(num_channels, kernel_size=1),
        nn.AvgPool2d(kernel_size=2, stride=2))

Apply a transition layer with 10 channels to the output of the dense block in the previous example. This reduces the number of output channels to 10, and halves the height and width.

 

이전 예에서 고밀도 블록의 출력에 10개의 채널이 있는 전환 레이어를 적용합니다. 이렇게 하면 출력 채널 수가 10개로 줄어들고 높이와 너비가 절반으로 줄어듭니다.

 

blk = transition_block(10)
blk(Y).shape
torch.Size([4, 10, 4, 4])

 

8.7.4. DenseNet Model

Next, we will construct a DenseNet model. DenseNet first uses the same single convolutional layer and max-pooling layer as in ResNet.

 

다음으로 DenseNet 모델을 구성합니다. DenseNet은 먼저 ResNet에서와 동일한 단일 컨벌루션 레이어와 최대 풀링 레이어를 사용합니다.

 

class DenseNet(d2l.Classifier):
    def b1(self):
        return nn.Sequential(
            nn.LazyConv2d(64, kernel_size=7, stride=2, padding=3),
            nn.LazyBatchNorm2d(), nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

 

Then, similar to the four modules made up of residual blocks that ResNet uses, DenseNet uses four dense blocks. Similar to ResNet, we can set the number of convolutional layers used in each dense block. Here, we set it to 4, consistent with the ResNet-18 model in Section 8.6. Furthermore, we set the number of channels (i.e., growth rate) for the convolutional layers in the dense block to 32, so 128 channels will be added to each dense block.

 

그런 다음 ResNet이 사용하는 잔차 블록으로 구성된 4개의 모듈과 유사하게 DenseNet은 4개의 고밀도 블록을 사용합니다. ResNet과 유사하게 각 고밀도 블록에서 사용되는 컨볼루션 레이어의 수를 설정할 수 있습니다. 여기에서는 섹션 8.6의 ResNet-18 모델과 일치하도록 4로 설정했습니다. 또한 dense 블록의 컨볼루션 레이어에 대한 채널 수(즉, 성장 속도)를 32로 설정하여 각 dense 블록에 128개의 채널을 추가합니다.

 

In ResNet, the height and width are reduced between each module by a residual block with a stride of 2. Here, we use the transition layer to halve the height and width and halve the number of channels. Similar to ResNet, a global pooling layer and a fully connected layer are connected at the end to produce the output.

 

ResNet에서 높이와 너비는 stride가 2인 잔여 블록에 의해 각 모듈 사이에서 줄어듭니다. 여기에서 전환 레이어를 사용하여 높이와 너비를 절반으로 줄이고 채널 수를 절반으로 줄입니다. ResNet과 유사하게 전역 풀링 계층과 완전히 연결된 계층이 끝에 연결되어 출력을 생성합니다.

 

@d2l.add_to_class(DenseNet)
def __init__(self, num_channels=64, growth_rate=32, arch=(4, 4, 4, 4),
             lr=0.1, num_classes=10):
    super(DenseNet, self).__init__()
    self.save_hyperparameters()
    self.net = nn.Sequential(self.b1())
    for i, num_convs in enumerate(arch):
        self.net.add_module(f'dense_blk{i+1}', DenseBlock(num_convs,
                                                          growth_rate))
        # The number of output channels in the previous dense block
        num_channels += num_convs * growth_rate
        # A transition layer that halves the number of channels is added
        # between the dense blocks
        if i != len(arch) - 1:
            num_channels //= 2
            self.net.add_module(f'tran_blk{i+1}', transition_block(
                num_channels))
    self.net.add_module('last', nn.Sequential(
        nn.LazyBatchNorm2d(), nn.ReLU(),
        nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(),
        nn.LazyLinear(num_classes)))
    self.net.apply(d2l.init_cnn)

 

8.7.5. Training

Since we are using a deeper network here, in this section, we will reduce the input height and width from 224 to 96 to simplify the computation.

 

여기에서 더 깊은 네트워크를 사용하고 있으므로 이 섹션에서는 계산을 단순화하기 위해 입력 높이와 너비를 224에서 96으로 줄입니다.

 

model = DenseNet(lr=0.01)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(96, 96))
trainer.fit(model, data)

 

8.7.6. Summary and Discussion

 

The main components that compose DenseNet are dense blocks and transition layers. For the latter, we need to keep the dimensionality under control when composing the network by adding transition layers that shrink the number of channels again. In terms of cross-layer connections, unlike ResNet, where inputs and outputs are added together, DenseNet concatenates inputs and outputs on the channel dimension. Although these concatenation operations reuse features to achieve computational efficiency, unfortunately they lead to heavy GPU memory consumption. As a result, applying DenseNet may require more memory-efficient implementations that may increase training time (Pleiss et al., 2017).

 

DenseNet을 구성하는 주요 구성 요소는 dense block과 transition layer입니다. 후자의 경우 채널 수를 다시 줄이는 전환 레이어를 추가하여 네트워크를 구성할 때 차원을 제어해야 합니다. 교차 계층 연결 측면에서 입력과 출력이 함께 추가되는 ResNet과 달리 DenseNet은 채널 차원에서 입력과 출력을 연결합니다. 이러한 연결 작업은 계산 효율성을 달성하기 위해 기능을 재사용하지만 불행하게도 GPU 메모리 사용량이 많이 발생합니다. 결과적으로 DenseNet을 적용하려면 훈련 시간을 늘릴 수 있는 메모리 효율적인 구현이 필요할 수 있습니다(Pleiss et al., 2017).

 

8.7.7. Exercises

  1. Why do we use average pooling rather than max-pooling in the transition layer?
  2. One of the advantages mentioned in the DenseNet paper is that its model parameters are smaller than those of ResNet. Why is this the case?
  3. One problem for which DenseNet has been criticized is its high memory consumption.
    1. Is this really the case? Try to change the input shape to 224×224 to see the actual GPU memory consumption empirically.
    2. Can you think of an alternative means of reducing the memory consumption? How would you need to change the framework?
  4. Implement the various DenseNet versions presented in Table 1 of the DenseNet paper (Huang et al., 2017).
  5. Design an MLP-based model by applying the DenseNet idea. Apply it to the housing price prediction task in Section 5.7.
반응형


반응형

https://d2l.ai/chapter_convolutional-modern/resnet.html

 

8.6. Residual Networks (ResNet) and ResNeXt — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

8.6. Residual Networks (ResNet) and ResNeXt

As we design increasingly deeper networks it becomes imperative to understand how adding layers can increase the complexity and expressiveness of the network. Even more important is the ability to design networks where adding layers makes networks strictly more expressive rather than just different. To make some progress we need a bit of mathematics.

점점 더 깊은 네트워크를 설계함에 따라 레이어 추가가 어떻게 네트워크의 복잡성과 표현력을 증가시킬 수 있는지 이해하는 것이 필수적입니다. 훨씬 더 중요한 것은 레이어를 추가하면 네트워크가 단순히 다른 것보다 훨씬 더 표현력 있게 만드는 네트워크를 설계하는 능력입니다. 진전을 이루려면 약간의 수학이 필요합니다.

 

https://youtu.be/iadEDPoEME8

이때부터 에러율이 사람보다 낮아졌다.

Layer가 깊어질 수록 성능이 좋아지지 않는 이유는 기울기 소실(degradation) 문제 때문임

Conversion block과 Identification block으로 나뉨

아래 방식으로 Vanishing Gradient를 해결 (backpropagate 시 미분값이 덜 적어짐)

https://youtu.be/671BsKl8d0E

Residual learning framework : input 값을 output 값에 더애서 다음 layer의 input 값으로 넣어 줌

: 앞 단계 (layer들)에서 학습된 정보에 현재 layer에서 학습된 정보를 더해 줌으로서 현재 layer까지 학습된 모든 정보를 다음 layer에 전달할 수 있음. ==> layer가 깊어 질 수록 성능이 더 좋아 짐

Conv와 ReLu 사이에 batch normalization 사용함

 

이 논문에 나오는 Identity란?

 

In the context of ResNet's thesis, 'identity' refers to the concept of using the identity mapping as one of the building blocks in the deep neural network architecture. In a traditional deep neural network, each layer is typically responsible for learning a specific transformation from its input to its output. However, as the network becomes deeper, it may face challenges in learning these transformations effectively, leading to issues like vanishing gradients and degradation of performance.

 

ResNet 논문에서의 'identity(항등)'은 딥 뉴럴 네트워크 아키텍처의 구성 요소 중 하나로서 항등 매핑(identity mapping)을 사용하는 개념을 의미합니다. 전통적인 딥 뉴럴 네트워크에서 각 레이어는 일반적으로 입력에서 출력으로의 특정 변환을 학습하는 것으로 구성됩니다. 그러나 네트워크가 깊어질수록 이러한 변환을 효과적으로 학습하는 데 어려움을 겪을 수 있으며, 이로 인해 사라지는 그래디언트와 성능 저하 등의 문제가 발생할 수 있습니다.

 

The ResNet architecture introduces the concept of residual blocks, which allow the network to learn the residual (the difference between the desired output and the input) instead of the entire transformation. The key idea is to define the mapping of each layer as the sum of the original input (identity mapping) and the learned residual mapping. This way, the network can be encouraged to learn small changes to the input data, making it easier for the model to optimize and preventing the vanishing gradient problem.

 

ResNet 아키텍처는 잔차 블록(residual block) 개념을 도입하여 네트워크가 전체 변환 대신 잔차(입력과 원하는 출력 간의 차이)를 학습하도록 할 수 있습니다. 주요 아이디어는 각 레이어의 매핑을 원래 입력(항등 매핑)과 학습된 잔차 매핑의 합으로 정의하는 것입니다. 이렇게 함으로써 네트워크는 입력 데이터에 대한 작은 변경을 학습하도록 장려되며, 모델이 최적화하기 쉽고 사라지는 그래디언트 문제를 방지할 수 있습니다.

 

By introducing identity mappings, the authors of the ResNet paper proposed that deep neural networks could be trained effectively even with hundreds or thousands of layers, allowing them to achieve state-of-the-art performance on various image recognition tasks.

 

항등 매핑을 도입함으로써 ResNet 논문의 저자들은 수백 개 또는 수천 개의 레이어를 가진 깊은 딥 뉴럴 네트워크도 효과적으로 학습할 수 있다고 제안하였으며, 이를 통해 다양한 이미지 인식 작업에서 최첨단 성능을 달성할 수 있었습니다.

 

In summary, 'identity' in ResNet's thesis refers to the direct mapping from input to output, and the use of identity mappings as a key component in the residual blocks helps address the optimization challenges associated with very deep neural networks.

 

요약하면, ResNet 논문에서의 'identity(항등)'은 입력에서 출력으로의 직접적인 매핑을 의미하며, 이러한 항등 매핑을 잔차 블록의 주요 구성 요소로 사용함으로써 매우 깊은 딥 뉴럴 네트워크와 관련된 최적화 문제를 해결하는 데 도움이 되었습니다.

 

https://youtu.be/Fypk0ec32BU

ResNet은 각 layer별로 크게 차이가 나지 않게 함으로서 천천히 작업을 진행하도록 함

차이만 학습하는 것이 ResNet임. 

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

위 코드는 PyTorch와 deep learning 라이브러리인 d2l을 사용하는데 필요한 모듈들을 임포트하는 부분입니다.

  1. import torch: PyTorch 라이브러리를 임포트합니다. PyTorch는 딥러닝 연구 및 개발을 위한 강력한 프레임워크로, 텐서 조작, 모델 구성, 학습 등에 사용됩니다.
  2. from torch import nn: PyTorch의 nn 모듈에서 nn이라는 클래스를 가져옵니다. nn 모듈은 신경망 구성 요소를 정의하는 데 사용되며, 여기서는 nn.Module을 확장한 다양한 층과 모듈들을 사용할 수 있습니다.
  3. from torch.nn import functional as F: PyTorch의 nn.functional 모듈에서 F라는 별칭을 가져옵니다. nn.functional 모듈은 신경망의 활성화 함수, 손실 함수 등과 같은 함수적인 기능들을 제공합니다.
  4. from d2l import torch as d2l: d2l이라는 패키지에서 torch라는 이름의 모듈을 가져옵니다. 이것은 d2l 패키지에서 torch와 관련된 함수들을 사용할 수 있게 해줍니다. d2l은 Dive into Deep Learning (D2L) 교재의 코드를 위한 도우미 라이브러리로, 딥러닝 학습에 도움이 되는 함수들과 유틸리티들을 제공합니다.

이러한 모듈들을 임포트하면 딥러닝 모델을 구성하고 학습하는 데 필요한 다양한 기능들을 사용할 수 있습니다.

 

8.6.1. Function Classes

Consider F, the class of functions that a specific network architecture (together with learning rates and other hyperparameter settings) can reach. That is, for all f∈F there exists some set of parameters (e.g., weights and biases) that can be obtained through training on a suitable dataset. Let’s assume that f∗ is the “truth” function that we really would like to find. If it is in F, we are in good shape but typically we will not be quite so lucky. Instead, we will try to find somefF∗ which is our best bet within F. For instance, given a dataset with features X and labels y, we might try finding it by solving the following optimization problem:

 

특정 네트워크 아키텍처(학습률 및 기타 하이퍼파라미터 설정과 함께)가 도달할 수 있는 함수 클래스인 F를 고려하십시오. 즉, 모든 f∈F에 대해 적절한 데이터 세트에 대한 훈련을 통해 얻을 수 있는 일부 매개변수 세트(예: 가중치 및 편향)가 존재합니다. f*가 우리가 정말로 찾고자 하는 "진실" 함수라고 가정해 봅시다. 그것이 F에 있다면 우리는 좋은 상태이지만 일반적으로 우리는 그렇게 운이 좋지 않을 것입니다. 대신, 우리는 F 내에서 최선의 선택인 fF*를 찾으려고 노력할 것입니다. 예를 들어, 특성 X와 레이블 y가 있는 데이터 세트가 주어지면 다음 최적화 문제를 해결하여 찾을 수 있습니다.

 

 

We know that regularization (Morozov, 1984, Tikhonov and Arsenin, 1977) may control complexity of F and achieve consistency, so a larger size of training data generally leads to better fF∗. It is only reasonable to assume that if we design a different and more powerful architecture F′ we should arrive at a better outcome. In other words, we would expect that fF′∗ is “better” than fF∗. However, if F⊈F′ there is no guarantee that this should even happen. In fact, fF′∗ might well be worse. As illustrated by Fig. 8.6.1, for non-nested function classes, a larger function class does not always move closer to the “truth” function f∗. For instance, on the left of Fig. 8.6.1, though F3 is closer to f∗ than F1, F6 moves away and there is no guarantee that further increasing the complexity can reduce the distance from f∗. With nested function classes where F1⊆…⊆F6 on the right of Fig. 8.6.1, we can avoid the aforementioned issue from the non-nested function classes.

 

우리는 정규화(Morozov, 1984, Tikhonov and Arsenin, 1977)가 F의 복잡성을 제어하고 일관성을 달성할 수 있으므로 일반적으로 훈련 데이터의 크기가 클수록 fF*가 더 좋아진다는 것을 알고 있습니다. 우리가 다르고 더 강력한 아키텍처 F'를 설계하면 더 나은 결과에 도달해야 한다고 가정하는 것이 타당합니다. 즉, fF′∗가 fF∗보다 "더 낫다"고 기대할 수 있습니다. 그러나 F⊈F′이면 이런 일이 발생한다는 보장이 없습니다. 사실 fF′∗가 더 나쁠 수도 있습니다. 그림 8.6.1에서 볼 수 있듯이 중첩되지 않은 함수 클래스의 경우 더 큰 함수 클래스가 항상 "진실" 함수 f*에 더 가깝게 이동하는 것은 아닙니다. 예를 들어 그림 8.6.1의 왼쪽에서 F3이 F1보다 f*에 가깝지만 F6은 멀어지고 복잡도를 더 높이면 f*로부터의 거리가 줄어들 수 있다는 보장이 없습니다.그림 8.6.1의 오른쪽에 F1⊆...⊆F6이 있는 중첩된 함수 클래스를 사용하면 앞서 언급한 중첩되지 않은 함수 클래스의 문제를 피할 수 있습니다.

 

Fig. 8.6.1  For non-nested function classes, a larger (indicated by area) function class does not guarantee to get closer to the “truth” function (f∗). This does not happen in nested function classes. ¶

 

Thus, only if larger function classes contain the smaller ones are we guaranteed that increasing them strictly increases the expressive power of the network. For deep neural networks, if we can train the newly-added layer into an identity function f(x)=x, the new model will be as effective as the original model. As the new model may get a better solution to fit the training dataset, the added layer might make it easier to reduce training errors.

 

따라서 더 큰 함수 클래스가 더 작은 함수 클래스를 포함하는 경우에만 함수를 늘리면 네트워크의 표현력이 엄격하게 증가합니다. 심층 신경망의 경우 새로 추가된 레이어를 항등 함수 (identity function) f(x)=x로 훈련할 수 있으면 새 모델이 원래 모델만큼 효과적일 것입니다. 새 모델이 교육 데이터 세트에 맞는 더 나은 솔루션을 얻을 수 있으므로 추가된 계층을 통해 교육 오류를 더 쉽게 줄일 수 있습니다.

 

This is the question that He et al. (2016) considered when working on very deep computer vision models. At the heart of their proposed residual network (ResNet) is the idea that every additional layer should more easily contain the identity function as one of its elements. These considerations are rather profound but they led to a surprisingly simple solution, a residual block. With it, ResNet won the ImageNet Large Scale Visual Recognition Challenge in 2015. The design had a profound influence on how to build deep neural networks. For instance, residual blocks have been added to recurrent networks (Kim et al., 2017, Prakash et al., 2016). Likewise, Transformers (Vaswani et al., 2017) use them to stack many layers of networks efficiently. It is also used in graph neural networks (Kipf and Welling, 2016) and, as a basic concept, it has been used extensively in computer vision (Redmon and Farhadi, 2018, Ren et al., 2015). Note that residual networks are predated by highway networks (Srivastava et al., 2015) that share some of the motivation, albeit without the elegant parametrization around the identity function.

 

이것은 He et al. (2016)은 매우 깊은 컴퓨터 비전 모델을 작업할 때 고려했습니다. 그들이 제안한 잔차 네트워크(residual network)(ResNet)의 핵심은 모든 추가 계층이 해당 요소 중 하나로 항등 기능(identity function)을 더 쉽게 포함해야 한다는 생각입니다. 이러한 고려 사항은 다소 심오하지만 잔여 블록(residual block)이라는 놀랍도록 간단한 솔루션으로 이어졌습니다. 이를 통해 ResNet은 2015년 ImageNet Large Scale Visual Recognition Challenge에서 우승했습니다. 이 디자인은 심층 신경망을 구축하는 방법에 지대한 영향을 미쳤습니다. 예를 들어 잔여 블록이 순환 네트워크에 추가되었습니다(Kim et al., 2017, Prakash et al., 2016). 마찬가지로 Transformers(Vaswani et al., 2017)는 이를 사용하여 여러 계층의 네트워크를 효율적으로 쌓습니다. 그래프 신경망(Kipf and Welling, 2016)에서도 사용되며, 기본 개념으로 컴퓨터 비전(Redmon and Farhadi, 2018, Ren et al., 2015)에서도 광범위하게 사용되어 왔다. residual networksidentity function에 대한 우아한 매개변수화 없이도 일부 동기를 공유하는  highway networks(Srivastava et al., 2015)보다 앞선다는 점에 유의하십시오.

 

8.6.2. Residual Blocks

Let’s focus on a local part of a neural network, as depicted in Fig. 8.6.2. Denote the input by x. We assume that the desired underlying mapping we want to obtain by learning is f(x), to be used as input to the activation function on the top. On the left, the portion within the dotted-line box must directly learn the mapping f(x). On the right, the portion within the dotted-line box needs to learn the residual mapping g(x)=f(x)−x, which is how the residual block derives its name. If the identity mapping f(x)=x is the desired underlying mapping, the residual mapping amounts to g(x)=0 and it is thus easier to learn: we only need to push the weights and biases of the upper weight layer (e.g., fully connected layer and convolutional layer) within the dotted-line box to zero. The right figure illustrates the residual block of ResNet, where the solid line carrying the layer input x to the addition operator is called a residual connection (or shortcut connection). With residual blocks, inputs can forward propagate faster through the residual connections across layers. In fact, the residual block can be thought of as a special case of the multi-branch Inception block: it has two branches one of which is the identity mapping.

 

그림 8.6.2와 같이 신경망의 로컬 부분에 초점을 맞추겠습니다. x로 입력을 나타냅니다. 우리는 학습을 통해 얻고자 하는 원하는 기본 매핑이 상단의 활성화 함수에 대한 입력으로 사용되는 f(x)라고 가정합니다. 왼쪽에서 점선 상자 안의 부분은 매핑 f(x)를 직접 학습해야 합니다. 오른쪽에서 점선 상자 내의 부분은 잔차 매핑 g(x)=f(x)−x를 학습해야 하며, 이는 잔차 블록이 이름을 파생하는 방법입니다. ID 매핑 f(x)=x가 원하는 기본 매핑인 경우 잔여 매핑은 g(x)=0이 되므로 배우기가 더 쉽습니다. 상위 가중치 레이어의 가중치와 편향만 푸시하면 됩니다( 예를 들어 점선 상자 내에서 완전 연결 계층 및 컨볼루션 계층)을 0으로 설정합니다. 오른쪽 그림은 ResNet의 잔차 블록을 나타낸 것으로, 여기서 레이어 입력 x를 덧셈 연산자로 전달하는 실선을 잔차 연결(또는 바로가기 연결)이라고 합니다. 잔차 블록을 사용하면 입력이 계층 전체의 잔차 연결을 통해 더 빠르게 전달될 수 있습니다. 사실, 잔차 블록은 다중 분기 시작 블록의 특수한 경우로 생각할 수 있습니다. 여기에는 두 개의 분기가 있으며 그 중 하나는 identity mapping입니다.

 

Fig. 8.6.2  In a regular block (left), the portion within the dotted-line box must directly learn the mapping f(x). In a residual block (right), the portion within the dotted-line box needs to learn the residual mapping g(x)=f(x)−x, making the identity mapping f(x)=x easier to learn.

 

ResNet follows VGG’s full 3×3 convolutional layer design. The residual block has two 3×3 convolutional layers with the same number of output channels. Each convolutional layer is followed by a batch normalization layer and a ReLU activation function. Then, we skip these two convolution operations and add the input directly before the final ReLU activation function. This kind of design requires that the output of the two convolutional layers has to be of the same shape as the input, so that they can be added together. If we want to change the number of channels, we need to introduce an additional 1×1 convolutional layer to transform the input into the desired shape for the addition operation. Let’s have a look at the code below.

 

ResNet은 VGG의 전체 3×3 컨볼루션 레이어 디자인을 따릅니다. 잔차 블록에는 출력 채널 수가 같은 두 개의 3×3 컨벌루션 레이어가 있습니다. 각 컨볼루션 계층 다음에는 배치 정규화 계층과 ReLU 활성화 함수가 옵니다. 그런 다음 이 두 컨볼루션 작업을 건너뛰고 최종 ReLU 활성화 함수 바로 앞에 입력을 추가합니다. 이러한 종류의 설계에서는 두 컨볼루션 레이어의 출력이 입력과 동일한 모양이어야 하므로 함께 더할 수 있습니다. 채널 수를 변경하려면 추가 작업을 위해 입력을 원하는 모양으로 변환하기 위해 추가 1x1 컨벌루션 레이어를 도입해야 합니다. 아래 코드를 살펴보겠습니다.

 

class Residual(nn.Module):  #@save
    """The Residual block of ResNet models."""
    def __init__(self, num_channels, use_1x1conv=False, strides=1):
        super().__init__()
        self.conv1 = nn.LazyConv2d(num_channels, kernel_size=3, padding=1,
                                   stride=strides)
        self.conv2 = nn.LazyConv2d(num_channels, kernel_size=3, padding=1)
        if use_1x1conv:
            self.conv3 = nn.LazyConv2d(num_channels, kernel_size=1,
                                       stride=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.LazyBatchNorm2d()
        self.bn2 = nn.LazyBatchNorm2d()

    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        Y += X
        return F.relu(Y)

위 코드는 ResNet 모델의 Residual 블록을 정의하는 클래스입니다.

  1. class Residual(nn.Module):: Residual 클래스는 nn.Module 클래스를 상속하여 정의됩니다. nn.Module은 PyTorch의 모델 구성 요소를 정의하기 위해 사용되는 기본 클래스입니다.
  2. def __init__(self, num_channels, use_1x1conv=False, strides=1):: 클래스의 생성자 함수입니다. 이 함수는 Residual 블록을 초기화하는데 필요한 파라미터들을 받습니다.
  3. self.conv1 = nn.LazyConv2d(num_channels, kernel_size=3, padding=1, stride=strides): 3x3 컨볼루션 레이어를 생성합니다. 이 레이어는 입력 채널의 수 num_channels로 설정되며, 커널 크기는 3x3이고 패딩은 1로 설정됩니다. strides는 컨볼루션의 보폭을 나타냅니다.
  4. self.conv2 = nn.LazyConv2d(num_channels, kernel_size=3, padding=1): 두 번째 3x3 컨볼루션 레이어를 생성합니다. 이 레이어의 설정은 conv1과 동일하지만, 보폭은 따로 지정하지 않아 기본 값으로 1이 됩니다.
  5. if use_1x1conv: ...: 만약 use_1x1conv가 True인 경우 1x1 컨볼루션 레이어를 생성합니다. 이 레이어는 입력 채널을 줄이기 위해 사용되며, 보폭은 strides와 동일하게 설정됩니다. 만약 use_1x1conv가 False라면 이 레이어는 None으로 설정됩니다.
  6. self.bn1 = nn.LazyBatchNorm2d(): 첫 번째 배치 정규화(Batch Normalization) 레이어를 생성합니다.
  7. self.bn2 = nn.LazyBatchNorm2d(): 두 번째 배치 정규화 레이어를 생성합니다.
  8. def forward(self, X): ...: forward 함수는 Residual 블록의 순방향 연산을 정의합니다. 입력 X를 받아서 Residual 블록을 통과시키고 결과를 반환합니다.
  9. Y = F.relu(self.bn1(self.conv1(X))): 입력 X를 첫 번째 컨볼루션 레이어와 배치 정규화 레이어를 통과시키고 활성화 함수 ReLU를 적용합니다.
  10. Y = self.bn2(self.conv2(Y)): 이후 두 번째 컨볼루션 레이어와 배치 정규화 레이어를 통과시키고 결과를 Y에 저장합니다.
  11. if self.conv3: X = self.conv3(X): use_1x1conv가 True일 경우 1x1 컨볼루션 레이어를 통과시키고 결과를 X에 저장합니다.
  12. Y += X: 이전의 Y에 이전 입력 X를 더합니다. 이것이 바로 잔차 연결(Residual Connection)을 의미합니다.
  13. return F.relu(Y): 최종 결과 Y를 ReLU 활성화 함수를 통과시킨 후 반환합니다.

Residual 블록은 ResNet에서 사용되는 핵심 구성 요소로, 잔차 연결을 통해 신경망의 깊이가 깊어져도 그레디언트 소실과 폭주 문제를 완화하고 더욱 쉽게 학습할 수 있도록 도와줍니다. 이 구조를 사용하면 더 깊고 더 강력한 딥러닝 모델을 구축할 수 있습니다.

 

 

This code generates two types of networks: one where we add the input to the output before applying the ReLU nonlinearity whenever use_1x1conv=False, and one where we adjust channels and resolution by means of a 1×1 convolution before adding. Fig. 8.6.3 illustrates this.

 

이 코드는 두 가지 유형의 네트워크를 생성합니다. 하나는 use_1x1conv=False일 때마다 ReLU 비선형성을 적용하기 전에 출력에 입력을 추가하는 것이고, 다른 하나는 추가하기 전에 1×1 컨벌루션을 통해 채널과 해상도를 조정하는 것입니다. 그림 8.6.3이 이를 설명합니다.

 

Fig. 8.6.3  ResNet block with and without 1×1 convolution, which transforms the input into the desired shape for the addition operation.

 

Now let’s look at a situation where the input and output are of the same shape, where 1×1 convolution is not needed.

 

이제 입력과 출력이 같은 모양으로 1×1 컨벌루션이 필요하지 않은 상황을 살펴보겠습니다.

 

blk = Residual(3)
X = torch.randn(4, 3, 6, 6)
blk(X).shape

위 코드는 ResNet의 Residual 블록을 정의하고, 이를 활용하여 입력 데이터 X에 대한 출력의 형태를 계산하는 예시입니다.

  1. blk = Residual(3): Residual 클래스를 이용하여 블록 blk를 생성합니다. 이 블록은 입력 채널이 3인 Residual 블록을 의미합니다.
  2. X = torch.randn(4, 3, 6, 6): 크기가 (4, 3, 6, 6)인 랜덤한 입력 데이터 X를 생성합니다. 이는 4개의 샘플, 3개의 채널, 각각 6x6 크기의 이미지로 구성된 데이터입니다.
  3. blk(X).shape: 생성한 blk에 입력 데이터 X를 통과시켜 출력의 형태를 계산합니다. 이 때 출력의 형태를 확인하기 위해 .shape 메서드를 사용합니다.

결과로 출력된 형태는 입력 데이터 X가 Residual 블록을 통과한 후의 결과 형태를 나타내며, (4, 3, 6, 6)입니다. 이는 입력 데이터 X와 동일한 형태를 가지고 있음을 의미합니다. Residual 블록의 역할은 입력과 출력의 차원을 보존하면서 추가적인 비선형 변환을 적용하여 딥러닝 모델의 성능을 향상시키는 것입니다.

torch.Size([4, 3, 6, 6])

 

We also have the option to halve the output height and width while increasing the number of output channels. In this case we use 1×1 convolutions via use_1x1conv=True. This comes in handy at the beginning of each ResNet block to reduce the spatial dimensionality via strides=2.

 

또한 출력 채널 수를 늘리면서 출력 높이와 너비를 절반으로 줄이는 옵션도 있습니다. 이 경우 use_1x1conv=True를 통해 1×1 컨볼루션을 사용합니다. 이것은 strides=2를 통해 공간 차원을 줄이기 위해 각 ResNet 블록의 시작 부분에서 유용합니다.

 

blk = Residual(6, use_1x1conv=True, strides=2)
blk(X).shape

위 코드는 ResNet의 Residual 블록을 정의하고, 이를 활용하여 입력 데이터 X에 대한 출력의 형태를 계산하는 예시입니다. 이번에는 Residual 블록에 use_1x1conv=True와 strides=2 옵션을 주어 블록을 생성합니다.

  1. blk = Residual(6, use_1x1conv=True, strides=2): Residual 클래스를 이용하여 블록 blk를 생성합니다. 이 블록은 입력 채널이 6인 Residual 블록을 의미합니다. use_1x1conv=True 옵션은 블록 내에서 1x1 컨볼루션 연산을 사용함을 의미하며, strides=2는 블록 내에서 2칸씩 이동하는 스트라이드를 사용함을 의미합니다.
  2. X = torch.randn(4, 6, 6, 6): 크기가 (4, 6, 6, 6)인 랜덤한 입력 데이터 X를 생성합니다. 이는 4개의 샘플, 6개의 채널, 각각 6x6 크기의 이미지로 구성된 데이터입니다.
  3. blk(X).shape: 생성한 blk에 입력 데이터 X를 통과시켜 출력의 형태를 계산합니다. 이 때 출력의 형태를 확인하기 위해 .shape 메서드를 사용합니다.

결과로 출력된 형태는 입력 데이터 X가 Residual 블록을 통과한 후의 결과 형태를 나타내며, (4, 6, 3, 3)입니다. 이는 입력 데이터 X의 채널 수는 그대로 유지되지만, 3x3 크기로 다운샘플링되었음을 의미합니다. strides=2 옵션에 의해 블록 내에서 2칸씩 이동하는 스트라이드를 사용하여 입력 데이터의 공간 해상도를 줄이고, use_1x1conv=True 옵션에 의해 1x1 컨볼루션 연산이 적용되어 채널 수는 유지되면서 공간 크기가 반으로 줄어든 것입니다. 이를 통해 더 깊고 복잡한 모델을 구성할 때 공간 크기를 효과적으로 줄여 계산 비용을 절감하고 성능을 향상시킬 수 있습니다.

torch.Size([4, 6, 3, 3])

 

8.6.3. ResNet Model

The first two layers of ResNet are the same as those of the GoogLeNet we described before: the 7×7 convolutional layer with 64 output channels and a stride of 2 is followed by the 3×3 max-pooling layer with a stride of 2. The difference is the batch normalization layer added after each convolutional layer in ResNet.

 

ResNet의 처음 두 레이어는 이전에 설명한 GoogLeNet의 레이어와 동일합니다. 출력 채널이 64개이고 스트라이드가 2인 7×7 컨볼루션 레이어 다음에는 스트라이드가 2인 3×3 최대 풀링 레이어가 있습니다. 차이점은 ResNet의 각 컨볼루션 계층 뒤에 배치 정규화 계층이 추가된다는 것입니다.

 

class ResNet(d2l.Classifier):
    def b1(self):
        return nn.Sequential(
            nn.LazyConv2d(64, kernel_size=7, stride=2, padding=3),
            nn.LazyBatchNorm2d(), nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

위 코드는 ResNet의 블록을 정의하는 클래스 ResNet입니다. 이 클래스는 d2l.Classifier를 상속하여 정의되었습니다. 해당 클래스 내의 b1 함수는 ResNet에서 첫 번째 블록을 의미합니다. 이 블록은 입력 이미지의 크기를 줄이기 위한 역할을 합니다.

  1. nn.Sequential: nn.Sequential을 사용하여 여러 레이어를 차례대로 쌓아 순차적으로 실행하는 블록을 생성합니다.
  2. nn.LazyConv2d(64, kernel_size=7, stride=2, padding=3): 입력 채널 수가 64인 2D 컨볼루션 레이어를 생성합니다. 커널 크기는 7x7이며, 스트라이드는 2로 설정되어 입력 이미지의 공간 해상도를 절반으로 줄입니다. 패딩은 3으로 설정되어 입력 이미지의 크기를 유지합니다.
  3. nn.LazyBatchNorm2d(): 배치 정규화(Batch Normalization) 레이어를 생성합니다. 배치 정규화는 학습을 안정화시키고 더 빠른 수렴을 도와주는 기법으로, 블록 내의 각 채널에 대해 평균과 표준 편차를 구해 정규화를 수행합니다.
  4. nn.ReLU(): ReLU(ReLU, Rectified Linear Unit) 활성화 함수를 적용합니다. ReLU는 입력값이 양수일 경우 그대로 출력하고, 음수일 경우 0으로 출력합니다.
  5. nn.MaxPool2d(kernel_size=3, stride=2, padding=1): 2D 최대 풀링 레이어를 생성합니다. 커널 크기는 3x3이며, 스트라이드는 2로 설정되어 입력 이미지의 공간 해상도를 절반으로 줄입니다. 패딩은 1로 설정되어 입력 이미지의 크기를 유지합니다.

이렇게 정의된 b1 함수는 ResNet의 첫 번째 블록으로, 입력 이미지의 공간 해상도를 절반으로 줄이고, 일부 채널에 배치 정규화와 ReLU 활성화 함수를 적용하는 과정을 담고 있습니다.

 

 

GoogLeNet uses four modules made up of Inception blocks. However, ResNet uses four modules made up of residual blocks, each of which uses several residual blocks with the same number of output channels. The number of channels in the first module is the same as the number of input channels. Since a max-pooling layer with a stride of 2 has already been used, it is not necessary to reduce the height and width. In the first residual block for each of the subsequent modules, the number of channels is doubled compared with that of the previous module, and the height and width are halved.

 

GoogLeNet은 Inception 블록으로 구성된 4개의 모듈을 사용합니다. 그러나 ResNet은 잔차 블록으로 구성된 4개의 모듈을 사용하며, 각 모듈은 동일한 수의 출력 채널을 가진 여러 잔차 블록을 사용합니다. 첫 번째 모듈의 채널 수는 입력 채널 수와 동일합니다. stride가 2인 max-pooling 레이어가 이미 사용되었으므로 높이와 너비를 줄일 필요가 없습니다. 각 후속 모듈에 대한 첫 번째 잔차 블록에서 채널 수는 이전 모듈에 비해 두 배가 되고 높이와 너비는 절반으로 줄어듭니다.

 

@d2l.add_to_class(ResNet)
def block(self, num_residuals, num_channels, first_block=False):
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(Residual(num_channels, use_1x1conv=True, strides=2))
        else:
            blk.append(Residual(num_channels))
    return nn.Sequential(*blk)

위 코드는 ResNet 클래스에 새로운 함수인 block을 추가하는 부분입니다.

  1. @d2l.add_to_class(ResNet): 이 부분은 ResNet 클래스에 새로운 함수를 추가하기 위해 데코레이터를 사용하는 부분입니다.
  2. def block(self, num_residuals, num_channels, first_block=False):: block 함수는 ResNet의 블록을 구성하는 함수입니다. 이 함수는 다음과 같은 인자를 받습니다.
    • num_residuals: 각 블록에 포함되는 Residual 레이어의 개수입니다.
    • num_channels: Residual 레이어의 출력 채널 수입니다.
    • first_block: 첫 번째 블록인지 여부를 나타내는 불리언 값입니다. 기본값은 False이며, 첫 번째 블록이 아님을 의미합니다.
  3. blk = []: 빈 리스트를 생성하여 블록을 담을 리스트를 초기화합니다.
  4. for i in range(num_residuals):: 지정된 num_residuals 만큼 반복문을 수행합니다.
  5. if i == 0 and not first_block:: 첫 번째 Residual 레이어가 아니고 첫 번째 블록인 경우를 확인합니다.
    • blk.append(Residual(num_channels, use_1x1conv=True, strides=2)): 첫 번째 Residual 레이어이며 1x1 컨볼루션 레이어를 사용하고 스트라이드를 2로 설정하여 입력 이미지의 공간 해상도를 절반으로 줄입니다.
  6. else:
    • blk.append(Residual(num_channels)): 나머지 경우에는 일반적인 Residual 레이어를 추가합니다.
  7. return nn.Sequential(*blk): 생성된 블록 리스트를 nn.Sequential로 묶어서 순차적으로 실행되도록 만듭니다.

이렇게 정의된 block 함수는 ResNet에서 여러 개의 Residual 레이어로 구성된 블록을 만드는 역할을 합니다. 첫 번째 블록인 경우에는 1x1 컨볼루션 레이어와 스트라이드를 사용하여 입력 이미지의 공간 해상도를 절반으로 줄이고, 그 외에는 일반적인 Residual 레이어를 반복하여 쌓습니다. 이렇게 생성된 블록은 순차적으로 연결되어 ResNet의 핵심적인 구조를 형성합니다.

 

 

Then, we add all the modules to ResNet. Here, two residual blocks are used for each module. Lastly, just like GoogLeNet, we add a global average pooling layer, followed by the fully connected layer output.

 

그런 다음 모든 모듈을 ResNet에 추가합니다. 여기서 각 모듈에 대해 두 개의 잔차 블록이 사용됩니다. 마지막으로 GoogLeNet과 마찬가지로 전역 평균 풀링 레이어를 추가한 다음 완전히 연결된 레이어 출력을 추가합니다.

 

@d2l.add_to_class(ResNet)
def __init__(self, arch, lr=0.1, num_classes=10):
    super(ResNet, self).__init__()
    self.save_hyperparameters()
    self.net = nn.Sequential(self.b1())
    for i, b in enumerate(arch):
        self.net.add_module(f'b{i+2}', self.block(*b, first_block=(i==0)))
    self.net.add_module('last', nn.Sequential(
        nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(),
        nn.LazyLinear(num_classes)))
    self.net.apply(d2l.init_cnn)

위 코드는 ResNet 클래스의 생성자 __init__에 새로운 기능을 추가하는 부분입니다.

  1. @d2l.add_to_class(ResNet): 이 부분은 ResNet 클래스에 새로운 함수를 추가하기 위해 데코레이터를 사용하는 부분입니다.
  2. def __init__(self, arch, lr=0.1, num_classes=10):: __init__ 함수는 ResNet의 생성자입니다. 이 함수는 다음과 같은 인자를 받습니다.
    • arch: 블록들의 구조를 정의한 튜플들의 리스트입니다. 각 튜플은 다음과 같은 정보를 포함합니다.
      • num_residuals: 각 블록에 포함되는 Residual 레이어의 개수입니다.
      • num_channels: Residual 레이어의 출력 채널 수입니다.
    • lr: 학습률을 나타내는 값입니다. 기본값은 0.1입니다.
    • num_classes: 분류할 클래스의 개수입니다. 기본값은 10입니다.
  3. super(ResNet, self).__init__(): 상위 클래스인 ResNet의 생성자를 호출하여 초기화합니다.
  4. self.save_hyperparameters(): 하이퍼파라미터들을 저장합니다.
  5. self.net = nn.Sequential(self.b1()): ResNet의 첫 번째 블록인 b1을 순차적으로 실행할 수 있도록 nn.Sequential로 초기화합니다.
  6. for i, b in enumerate(arch):: arch에서 각 블록의 정보를 가져옵니다. enumerate 함수를 사용하여 인덱스와 함께 반복합니다.
  7. self.net.add_module(f'b{i+2}', self.block(*b, first_block=(i==0))): i+2와 b를 사용하여 블록을 순차적으로 추가합니다. first_block 인자는 첫 번째 블록인 경우에 True로 설정하여 1x1 컨볼루션 레이어와 스트라이드를 사용하도록 합니다.
  8. self.net.add_module('last', nn.Sequential(: 마지막 블록인 last를 추가합니다.
  9. nn.AdaptiveAvgPool2d((1, 1)): 주어진 입력 크기에 따라 적응적 평균 풀링 레이어를 생성합니다. 입력 크기를 (1, 1)로 설정하여 공간 차원을 평균화합니다.
  10. nn.Flatten(): 다차원 텐서를 일차원으로 평면화하는 레이어입니다.
  11. nn.LazyLinear(num_classes)): num_classes를 출력 크기로 하는 선형 레이어를 생성합니다.
  12. self.net.apply(d2l.init_cnn): 생성된 ResNet 모델에 CNN 레이어들을 초기화하는 함수인 d2l.init_cnn을 적용합니다.

이렇게 정의된 ResNet 클래스는 입력으로 받은 arch에 따라서 여러 개의 ResNet 블록들을 순차적으로 추가하여 ResNet 모델을 만들게 됩니다. 이때, 첫 번째 블록은 1x1 컨볼루션 레이어와 스트라이드를 사용하여 입력 이미지의 공간 해상도를 줄이게 됩니다. 그리고 마지막 블록에는 평균 풀링과 선형 레이어를 추가하여 최종적으로 출력 클래스의 개수에 맞는 예측 결과를 얻습니다. 이렇게 구성된 ResNet 모델은 self.net에 저장되어 있으며 학습 및 추론에 사용할 수 있습니다.

 

There are 4 convolutional layers in each module (excluding the 1×1 convolutional layer). Together with the first 7×7 convolutional layer and the final fully connected layer, there are 18 layers in total. Therefore, this model is commonly known as ResNet-18. By configuring different numbers of channels and residual blocks in the module, we can create different ResNet models, such as the deeper 152-layer ResNet-152. Although the main architecture of ResNet is similar to that of GoogLeNet, ResNet’s structure is simpler and easier to modify. All these factors have resulted in the rapid and widespread use of ResNet. Fig. 8.6.4 depicts the full ResNet-18.

 

각 모듈에는 4개의 컨볼루션 레이어가 있습니다(1×1 컨볼루션 레이어 제외). 첫 번째 7×7 컨볼루션 레이어와 마지막 완전 연결 레이어를 포함하여 총 18개의 레이어가 있습니다. 따라서 이 모델은 일반적으로 ResNet-18로 알려져 있습니다. 모듈에서 서로 다른 수의 채널과 잔차 블록을 구성하여 더 깊은 152계층 ResNet-152와 같은 다양한 ResNet 모델을 생성할 수 있습니다. ResNet의 주요 아키텍처는 GoogLeNet과 유사하지만 ResNet의 구조는 더 간단하고 수정하기 쉽습니다. 이러한 모든 요인으로 인해 ResNet이 빠르고 광범위하게 사용되었습니다. 그림 8.6.4는 전체 ResNet-18을 보여줍니다.

 

Fig. 8.6.4  The ResNet-18 architecture.

 

Before training ResNet, let’s observe how the input shape changes across different modules in ResNet. As in all the previous architectures, the resolution decreases while the number of channels increases up until the point where a global average pooling layer aggregates all features.

 

ResNet을 교육하기 전에 ResNet의 여러 모듈에서 입력 모양이 어떻게 변경되는지 살펴보겠습니다. 이전의 모든 아키텍처와 마찬가지로 전역 평균 풀링 레이어가 모든 기능을 집계하는 지점까지 채널 수가 증가하는 동안 해상도는 감소합니다.

 

class ResNet18(ResNet):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__(((2, 64), (2, 128), (2, 256), (2, 512)),
                       lr, num_classes)

ResNet18().layer_summary((1, 1, 96, 96))

위 코드는 ResNet18 모델을 정의하는 부분과 해당 모델의 레이어 구성을 확인하는 코드로 이루어져 있습니다.

  1. class ResNet18(ResNet): ResNet18 클래스는 ResNet 클래스를 상속받습니다. 따라서 ResNet18 클래스는 ResNet 클래스의 모든 기능과 구조를 상속받아 사용할 수 있습니다.
  2. def __init__(self, lr=0.1, num_classes=10): ResNet18의 생성자 함수입니다. 이 함수는 다음과 같은 인자를 받습니다.
    • lr: 학습률을 나타내는 값으로 기본값은 0.1입니다.
    • num_classes: 분류할 클래스의 개수로 기본값은 10입니다.
  3. super().__init__(((2, 64), (2, 128), (2, 256), (2, 512)), lr, num_classes): ResNet 클래스의 생성자를 호출하여 ResNet18 모델을 초기화합니다. 인자로는 ResNet18 모델의 구조를 정의하는 튜플들의 리스트를 전달합니다. 각 튜플은 다음과 같은 정보를 포함합니다.
    • num_residuals: 각 Residual 블록에 포함되는 레이어의 개수입니다.
    • num_channels: Residual 블록의 출력 채널 수입니다.
  4. ResNet18().layer_summary((1, 1, 96, 96)): ResNet18 모델의 레이어 구성을 확인하는 코드입니다. 이를 위해 layer_summary 함수를 사용하여 입력 이미지 크기가 (1, 1, 96, 96)인 경우의 모델 구성을 요약해서 보여줍니다.

ResNet18 모델은 ResNet 클래스를 상속받아 ResNet 구조에 기반하여 만들어졌으며, ResNet18 모델의 구조는 18개의 레이어를 가진 ResNet 버전입니다. 또한 layer_summary 함수를 사용하여 모델의 레이어 구성을 확인할 수 있습니다.

Sequential output shape:     torch.Size([1, 64, 24, 24])
Sequential output shape:     torch.Size([1, 64, 24, 24])
Sequential output shape:     torch.Size([1, 128, 12, 12])
Sequential output shape:     torch.Size([1, 256, 6, 6])
Sequential output shape:     torch.Size([1, 512, 3, 3])
Sequential output shape:     torch.Size([1, 10])

 

8.6.4. Training

We train ResNet on the Fashion-MNIST dataset, just like before. ResNet is quite a powerful and flexible architecture. The plot capturing training and validation loss illustrates a significant gap between both graphs, with the training loss being significantly lower. For a network of this flexibility, more training data would offer significant benefit in closing the gap and improving accuracy.

 

이전과 마찬가지로 Fashion-MNIST 데이터 세트에서 ResNet을 교육합니다. ResNet은 매우 강력하고 유연한 아키텍처입니다. 훈련 및 검증 손실을 캡처하는 플롯은 훈련 손실이 훨씬 더 낮은 두 그래프 사이의 상당한 차이를 보여줍니다. 이러한 유연성을 갖춘 네트워크의 경우 더 많은 교육 데이터가 격차를 좁히고 정확도를 개선하는 데 상당한 이점을 제공할 것입니다.

 

model = ResNet18(lr=0.01)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(96, 96))
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

위 코드는 ResNet18 모델을 생성하고 이를 FashionMNIST 데이터셋으로 학습하는 과정을 나타내고 있습니다.

  1. model = ResNet18(lr=0.01): ResNet18 모델을 생성하고 학습률을 0.01로 설정하여 초기화합니다.
  2. trainer = d2l.Trainer(max_epochs=10, num_gpus=1): d2l 라이브러리의 Trainer를 생성합니다. 이 때, 최대 에폭(epoch)을 10으로 설정하고 하나의 GPU를 사용하여 학습합니다.
  3. data = d2l.FashionMNIST(batch_size=128, resize=(96, 96)): FashionMNIST 데이터셋을 생성합니다. 이 데이터셋은 배치 크기를 128로 설정하고 이미지 크기를 (96, 96)으로 변환합니다.
  4. model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn): 모델의 가중치를 초기화합니다. 이를 위해 FashionMNIST 데이터셋의 첫 번째 배치를 가져와서 모델에 적용하여 가중치를 초기화합니다. 초기화 방법으로는 d2l.init_cnn 함수를 사용합니다.
  5. trainer.fit(model, data): 생성한 모델과 데이터셋을 사용하여 학습을 수행합니다. Trainer의 fit 함수를 호출하여 모델을 학습시키고, 데이터셋을 사용하여 모델을 평가합니다. 학습은 최대 10 에폭까지 진행됩니다.

이 코드는 ResNet18 모델을 FashionMNIST 데이터셋으로 학습하는 과정을 단계별로 나타낸 것입니다. ResNet18 모델을 생성하고 학습 데이터셋으로 학습하여 모델을 최적화하는 과정을 쉽게 이해할 수 있도록 코드로 표현한 것입니다.

8.6.5. ResNeXt

 

One of the challenges one encounters in the design of ResNet is the trade-off between nonlinearity and dimensionality within a given block. That is, we could add more nonlinearity by increasing the number of layers, or by increasing the width of the convolutions. An alternative strategy is to increase the number of channels that can carry information between blocks. Unfortunately, the latter comes with a quadratic penalty since the computational cost of ingesting ci channels and emitting co channels is proportional to O(ci⋅co) (see our discussion in Section 7.4).

 

ResNet 설계에서 직면하는 문제 중 하나는 주어진 블록 내에서 비선형성과 차원 간의 절충입니다. 즉, 레이어 수를 늘리거나 컨볼루션의 너비를 늘려 더 많은 비선형성을 추가할 수 있습니다. 대안 전략은 블록 간에 정보를 전달할 수 있는 채널의 수를 늘리는 것입니다. 불행하게도 후자는 ci 채널을 수집하고 co 채널을 방출하는 계산 비용이 O(ci⋅co)에 비례하기 때문에 2차 페널티가 있습니다(섹션 7.4의 논의 참조).

 

We can take some inspiration from the Inception block of Fig. 8.4.1 which has information flowing through the block in separate groups. Applying the idea of multiple independent groups to the ResNet block of Fig. 8.6.3 led to the design of ResNeXt (Xie et al., 2017). Different from the smorgasbord of transformations in Inception, ResNeXt adopts the same transformation in all branches, thus minimizing the need for manual tuning of each branch.

 

그림 8.4.1의 인셉션 블록에서 정보가 개별 그룹으로 흐르는 정보를 가지고 있는 것에서 영감을 얻을 수 있습니다. 그림 8.6.3의 ResNet 블록에 여러 독립 그룹의 아이디어를 적용하면 ResNeXt가 설계되었습니다(Xie et al., 2017). Inception의 다양한 변환과 달리 ResNeXt는 모든 분기에서 동일한 변환을 채택하므로 각 분기의 수동 조정 필요성이 최소화됩니다.

 

ig. 8.6.5  The ResNeXt block. The use of grouped convolution with g groups is g times faster than a dense convolution. It is a bottleneck residual block when the number of intermediate channels b is less than c.

 

Breaking up a convolution from ci to co channels into one of g groups of size ci/g generating g outputs of size co/g is called, quite fittingly, a grouped convolution. The computational cost (proportionally) is reduced from O(ci⋅co) to O(g⋅(ci/g)⋅(co/g))=O(ci⋅co/g), i.e., it is g times faster. Even better, the number of parameters needed to generate the output is also reduced from a ci×co matrix to g smaller matrices of size (ci/g)×(co/g), again a g times reduction. In what follows we assume that both ci and co are divisible by g.

 

ci에서 co 채널로의 컨볼루션을 크기 co/g의 g 출력을 생성하는 크기 ci/g의 g 그룹 중 하나로 분해하는 것을 그룹화 컨벌루션이라고 합니다. 계산 비용은 (비례적으로) O(ci⋅co)에서 O(g⋅(ci/g)⋅(co/g))=O(ci⋅co/g)로 감소합니다. 즉, g배 더 빠릅니다. 더 좋은 점은 출력을 생성하는 데 필요한 매개변수의 수도 ci×co 행렬에서 (ci/g)×(co/g) 크기의 더 작은 행렬 g로 줄어 다시 g배 감소한다는 것입니다. 다음에서 우리는 ci와 co 모두 g로 나눌 수 있다고 가정합니다.

 

The only challenge in this design is that no information is exchanged between the g groups. The ResNeXt block of Fig. 8.6.5 amends this in two ways: the grouped convolution with a 3×3 kernel is sandwiched in between two 1×1 convolutions. The second one serves double duty in changing the number of channels back. The benefit is that we only pay the O(c⋅b) cost for 1×1 kernels and can make do with an O(b2/g) cost for 3×3 kernels. Similar to the residual block implementation in Section 8.6.2, the residual connection is replaced (thus generalized) by a 1×1 convolution.

 

이 디자인의 유일한 문제는 g 그룹 간에 정보가 교환되지 않는다는 것입니다. 그림 8.6.5의 ResNeXt 블록은 이를 두 가지 방식으로 수정합니다. 3×3 커널이 있는 그룹화된 컨볼루션이 두 개의 1×1 컨볼루션 사이에 끼어 있습니다. 두 번째는 채널 수를 다시 변경하는 이중 역할을 합니다. 이점은 1×1 커널에 대한 O(c⋅b) 비용만 지불하고 3×3 커널에 대한 O(b2/g) 비용으로 해결할 수 있다는 것입니다. 섹션 8.6.2의 잔차 블록 구현과 유사하게 잔차 연결은 1×1 컨벌루션으로 대체됩니다(따라서 일반화됨).

 

The right figure in Fig. 8.6.5 provides a much more concise summary of the resulting network block. It will also play a major role in the design of generic modern CNNs in Section 8.8. Note that the idea of grouped convolutions dates back to the implementation of AlexNet (Krizhevsky et al., 2012). When distributing the network across two GPUs with limited memory, the implementation treated each GPU as its own channel with no ill effects.

 

그림 8.6.5의 오른쪽 그림은 결과 네트워크 블록에 대한 훨씬 더 간결한 요약을 제공합니다. 또한 섹션 8.8에서 일반적인 최신 CNN 설계에 중요한 역할을 할 것입니다. 그룹 컨볼루션의 아이디어는 AlexNet 구현으로 거슬러 올라갑니다(Krizhevsky et al., 2012). 메모리가 제한된 두 개의 GPU에 네트워크를 분산할 때 구현 시 각 GPU를 악영향 없이 자체 채널로 처리했습니다.

 

The following implementation of the ResNeXtBlock class takes as argument groups (g), with bot_channels (b) intermediate (bottleneck) channels. Lastly, when we need to reduce the height and width of the representation, we add a stride of 2 by setting use_1x1conv=True, strides=2.

 

ResNeXtBlock 클래스의 다음 구현은 인수 그룹(g)과 bot_channels(b) 중간(병목) 채널을 사용합니다. 마지막으로 표현의 높이와 너비를 줄여야 할 때 use_1x1conv=True, strides=2를 설정하여 stride 2를 추가합니다.

 

class ResNeXtBlock(nn.Module):  #@save
    """The ResNeXt block."""
    def __init__(self, num_channels, groups, bot_mul, use_1x1conv=False,
                 strides=1):
        super().__init__()
        bot_channels = int(round(num_channels * bot_mul))
        self.conv1 = nn.LazyConv2d(bot_channels, kernel_size=1, stride=1)
        self.conv2 = nn.LazyConv2d(bot_channels, kernel_size=3,
                                   stride=strides, padding=1,
                                   groups=bot_channels//groups)
        self.conv3 = nn.LazyConv2d(num_channels, kernel_size=1, stride=1)
        self.bn1 = nn.LazyBatchNorm2d()
        self.bn2 = nn.LazyBatchNorm2d()
        self.bn3 = nn.LazyBatchNorm2d()
        if use_1x1conv:
            self.conv4 = nn.LazyConv2d(num_channels, kernel_size=1,
                                       stride=strides)
            self.bn4 = nn.LazyBatchNorm2d()
        else:
            self.conv4 = None

    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = F.relu(self.bn2(self.conv2(Y)))
        Y = self.bn3(self.conv3(Y))
        if self.conv4:
            X = self.bn4(self.conv4(X))
        return F.relu(Y + X)

위 코드는 ResNeXt 블록을 정의한 클래스인 ResNeXtBlock을 나타내고 있습니다.

ResNeXt 블록은 ResNet과 유사한 구조를 가지며, 여러 그룹으로 나누어 병렬적으로 처리하는 특징을 가지고 있습니다. 각각의 그룹은 동일한 작은 네트워크 블록을 가지고 있으며, 이들을 병렬적으로 실행함으로써 더 강력한 표현력을 얻을 수 있습니다.

ResNeXtBlock 클래스는 다음과 같은 인자들을 사용하여 초기화됩니다.

  • num_channels: 블록의 입력 채널 수입니다.
  • groups: 그룹 수입니다. 그룹의 수가 채널의 수를 나눈 값이며, 각 그룹은 병렬적으로 작동합니다.
  • bot_mul: 작은 네트워크 블록의 채널 수를 조절하는 비율입니다.
  • use_1x1conv: 1x1 합성곱을 사용할지 여부를 결정하는 플래그입니다.
  • strides: 컨볼루션 연산의 스트라이드 값을 지정합니다.

ResNeXtBlock 클래스는 다음과 같은 레이어들을 가지고 있습니다.

  • self.conv1: 1x1 컨볼루션 레이어
  • self.conv2: 3x3 컨볼루션 레이어
  • self.conv3: 1x1 컨볼루션 레이어
  • self.bn1, self.bn2, self.bn3: 배치 정규화(Batch Normalization) 레이어들
  • self.conv4, self.bn4: use_1x1conv가 True일 경우 추가로 사용되는 1x1 컨볼루션 레이어와 배치 정규화 레이어

forward 함수는 블록의 순전파(forward) 연산을 정의하고 있습니다. 입력 X를 먼저 1x1 컨볼루션 레이어를 통과시킨 후 배치 정규화와 ReLU 활성화 함수를 적용합니다. 다음으로 3x3 컨볼루션 레이어를 통과시킨 후 다시 배치 정규화와 ReLU를 적용합니다. 그리고 다시 1x1 컨볼루션 레이어와 배치 정규화를 거친 후 추가적으로 self.conv4와 self.bn4를 사용하는 경우 해당 레이어를 통과시킵니다. 최종적으로 ReLU를 적용한 후 입력 X와 더해진 결과를 반환합니다. 이를 통해 ResNeXt 블록의 순전파 연산이 수행됩니다.

 

Its use is entirely analogous to that of the ResNetBlock discussed previously. For instance, when using (use_1x1conv=False, strides=1), the input and output are of the same shape. Alternatively, setting use_1x1conv=True, strides=2 halves the output height and width.

 

그 사용은 이전에 논의된 ResNetBlock의 사용과 완전히 유사합니다. 예를 들어 (use_1x1conv=False, strides=1)을 사용하면 입력과 출력이 같은 모양입니다. 또는 use_1x1conv=True, strides=2로 설정하면 출력 높이와 너비가 반으로 줄어듭니다.

 

blk = ResNeXtBlock(32, 16, 1)
X = torch.randn(4, 32, 96, 96)
blk(X).shape

위 코드는 ResNeXt 블록인 ResNeXtBlock 클래스를 사용하여 새로운 블록 blk를 생성하고, 임의의 입력 데이터 X에 대해 blk를 통과시킨 후 출력의 크기를 확인하는 내용입니다.

ResNeXtBlock은 다음과 같은 인자들을 사용하여 초기화됩니다.

  • num_channels: 블록의 입력 채널 수입니다. 위 코드에서는 32로 설정되어 있습니다.
  • groups: 그룹 수입니다. 그룹의 수가 채널의 수를 나눈 값이며, 각 그룹은 병렬적으로 작동합니다. 위 코드에서는 16으로 설정되어 있습니다.
  • bot_mul: 작은 네트워크 블록의 채널 수를 조절하는 비율입니다. 위 코드에서는 1로 설정되어 있습니다.
  • use_1x1conv: 1x1 합성곱을 사용할지 여부를 결정하는 플래그입니다. 위 코드에서는 False로 설정되어 있으므로 1x1 합성곱은 사용되지 않습니다.
  • strides: 컨볼루션 연산의 스트라이드 값을 지정합니다. 위 코드에서는 기본값인 1로 설정되어 있습니다.

위 코드에서는 ResNeXtBlock을 사용하여 blk 객체를 생성한 후, 크기가 (4, 32, 96, 96)인 입력 데이터 X를 blk에 통과시키고, 최종적으로 출력의 크기를 확인하는 작업을 수행합니다.

출력의 크기를 확인하기 위해 blk(X).shape를 호출하면, 입력 X를 blk에 통과시켜 나온 출력의 크기를 반환합니다. 위 코드에서는 입력 X의 크기가 (4, 32, 96, 96)이므로 blk(X)의 출력 크기 또한 (4, 32, 96, 96)입니다. 이 결과는 ResNeXt 블록의 순전파 연산을 통해 출력이 입력과 동일한 크기를 가지는 것을 의미합니다.

torch.Size([4, 32, 96, 96])

 

8.6.6. Summary and Discussion

Nested function classes are desirable since they allow us to obtain strictly more powerful rather than also subtly different function classes when adding capacity. One way to accomplish this is by allowing additional layers to simply pass through the input to the output. Residual connections allow for this. As a consequence, this changes the inductive bias from simple functions being of the form f(x)=0 to simple functions looking like f(x)=x.

 

중첩된 함수 클래스는 용량을 추가할 때 미묘하게 다른 함수 클래스가 아니라 엄격하게 더 강력한 기능을 얻을 수 있기 때문에 바람직합니다. 이를 달성하는 한 가지 방법은 추가 레이어가 단순히 입력을 통해 출력으로 전달되도록 하는 것입니다. 잔여 연결이 이를 허용합니다. 결과적으로 이것은 f(x)=0 형식의 단순 함수에서 f(x)=x처럼 보이는 단순 함수로 유도 편향을 변경합니다.

 

The residual mapping can learn the identity function more easily, such as pushing parameters in the weight layer to zero. We can train an effective deep neural network by having residual blocks. Inputs can forward propagate faster through the residual connections across layers. As a consequence, we can thus train much deeper networks. For instance, the original ResNet paper (He et al., 2016) allowed for up to 152 layers. Another benefit of residual networks is that it allows us to add layers, initialized as the identity function, during the training process. After all, the default behavior of a layer is to let the data pass through unchanged. This can accelerate the training of very large networks in some cases.

 

residual  매핑은 가중치 계층의 매개변수를 0으로 푸는 것과 같이 항등 함수를 보다 쉽게 학습할 수 있습니다. 잔차 블록을 가짐으로써 효과적인 심층 신경망을 훈련시킬 수 있습니다. 입력은 레이어 전체의 나머지 연결을 통해 더 빠르게 전달될 수 있습니다. 결과적으로 우리는 훨씬 더 깊은 네트워크를 훈련시킬 수 있습니다. 예를 들어 원래 ResNet 논문(He et al., 2016)은 최대 152개의 레이어를 허용했습니다. 잔여 네트워크의 또 다른 이점은 훈련 과정 중에 항등 함수로 초기화된 계층을 추가할 수 있다는 것입니다. 결국 레이어의 기본 동작은 데이터가 변경되지 않은 상태로 전달되도록 하는 것입니다. 이것은 경우에 따라 매우 큰 네트워크의 훈련을 가속화할 수 있습니다.

 

Prior to residual connections, bypassing paths with gating units were introduced to effectively train highway networks with over 100 layers (Srivastava et al., 2015). Using identity functions as bypassing paths, ResNet performed remarkably well on multiple computer vision tasks. Residual connections had a major influence on the design of subsequent deep neural networks, both for convolutional and sequential nature. As we will introduce later, the Transformer architecture (Vaswani et al., 2017) adopts residual connections (together with other design choices) and is pervasive in areas as diverse as language, vision, speech, and reinforcement learning.

 

잔류 연결 이전에는 게이팅 장치가 있는 우회 경로가 도입되어 100개 이상의 레이어가 있는 고속도로 네트워크를 효과적으로 훈련했습니다(Srivastava et al., 2015). ID 기능을 우회 경로로 사용하여 ResNet은 여러 컴퓨터 비전 작업에서 놀라운 성능을 보였습니다. 잔여 연결은 컨볼루션 및 순차 특성 모두에 대해 후속 심층 신경망 설계에 큰 영향을 미쳤습니다. 나중에 소개하겠지만 Transformer 아키텍처(Vaswani et al., 2017)는 잔류 연결(다른 설계 선택과 함께)을 채택하고 언어, 시각, 음성 및 강화 학습과 같은 다양한 영역에 널리 퍼져 있습니다.

 

ResNeXt is an example for how the design of convolutional neural networks has evolved over time: by being more frugal with computation and trading it off with the size of the activations (number of channels), it allows for faster and more accurate networks at lower cost. An alternative way of viewing grouped convolutions is to think of a block-diagonal matrix for the convolutional weights. Note that there are quite a few such “tricks” that lead to more efficient networks. For instance, ShiftNet (Wu et al., 2018) mimicks the effects of a 3×3 convolution, simply by adding shifted activations to the channels, offering increased function complexity, this time without any computational cost.

 

ResNeXt는 컨볼루션 신경망의 설계가 시간이 지남에 따라 어떻게 발전해 왔는지에 대한 예입니다. 계산을 더 검소하게 하고 활성화 크기(채널 수)와 교환함으로써 더 낮은 비용으로 더 빠르고 더 정확한 네트워크를 허용합니다. . 그룹화된 컨볼루션을 보는 또 다른 방법은 컨볼루션 가중치에 대한 블록-대각선 행렬을 생각하는 것입니다. 보다 효율적인 네트워크로 이끄는 이러한 "트릭"이 상당히 많이 있다는 점에 유의하십시오. 예를 들어, ShiftNet(Wu et al., 2018)은 단순히 채널에 이동된 활성화를 추가하여 3×3 컨볼루션의 효과를 모방하여 이번에는 계산 비용 없이 향상된 기능 복잡성을 제공합니다.

 

A common feature of the designs we have discussed so far is that the network design is fairly manual, primarily relying on the ingenuity of the designer to find the “right” network hyperparameters. While clearly feasible, it is also very costly in terms of human time and there is no guarantee that the outcome is optimal in any sense. In Section 8.8 we will discuss a number of strategies for obtaining high quality networks in a more automated fashion. In particular, we will review the notion of network design spaces that led to the RegNetX/Y models (Radosavovic et al., 2020).

 

지금까지 논의한 설계의 공통적인 특징은 네트워크 설계가 "올바른" 네트워크 하이퍼파라미터를 찾기 위해 디자이너의 독창성에 주로 의존하는 상당히 수동적이라는 것입니다. 분명히 실현 가능하지만 인적 시간 측면에서 비용이 많이 들고 결과가 어떤 의미에서든 최적이라는 보장이 없습니다. 섹션 8.8에서 우리는 보다 자동화된 방식으로 고품질 네트워크를 얻기 위한 여러 가지 전략에 대해 논의할 것입니다. 특히, RegNetX/Y 모델(Radosavovic et al., 2020)로 이어진 네트워크 설계 공간의 개념을 검토할 것입니다.

 

8.6.7. Exercises

  1. What are the major differences between the Inception block in Fig. 8.4.1 and the residual block? How do they compare in terms of computation, accuracy, and the classes of functions they can describe?
  2. Refer to Table 1 in the ResNet paper (He et al., 2016) to implement different variants of the network.
  3. For deeper networks, ResNet introduces a “bottleneck” architecture to reduce model complexity. Try to implement it.
  4. In subsequent versions of ResNet, the authors changed the “convolution, batch normalization, and activation” structure to the “batch normalization, activation, and convolution” structure. Make this improvement yourself. See Figure 1 in He et al. (2016) for details.
  5. Why can’t we just increase the complexity of functions without bound, even if the function classes are nested?
반응형


반응형

https://d2l.ai/chapter_convolutional-modern/batch-norm.html

 

8.5. Batch Normalization — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

8.5. Batch Normalization

Training deep neural networks is difficult. Getting them to converge in a reasonable amount of time can be tricky. In this section, we describe batch normalization, a popular and effective technique that consistently accelerates the convergence of deep networks (Ioffe and Szegedy, 2015). Together with residual blocks—covered later in Section 8.6—batch normalization has made it possible for practitioners to routinely train networks with over 100 layers. A secondary (serendipitous) benefit of batch normalization lies in its inherent regularization.

 

심층 신경망을 훈련시키는 것은 어렵습니다. 합리적인 시간 내에 수렴하는 것은 까다로울 수 있습니다. 이 섹션에서는 딥 네트워크의 수렴을 지속적으로 가속화하는 널리 사용되고 효과적인 기술인 배치 정규화에 대해 설명합니다(Ioffe and Szegedy, 2015). 섹션 8.6에서 나중에 다룰 잔차 블록(residual blocks)과 함께 배치 정규화를 통해 실무자는 100개 이상의 계층으로 네트워크를 일상적으로 훈련할 수 있습니다. 배치 정규화의 두 번째(우연한) 이점은 고유한 정규화에 있습니다.

 

import torch
from torch import nn
from d2l import torch as d2l

8.5.1. Training Deep Networks

When working with data, we often preprocess before training. Choices regarding data preprocessing often make an enormous difference in the final results. Recall our application of MLPs to predicting house prices (Section 5.7). Our first step when working with real data was to standardize our input features to have zero mean μ=0 and unit variance Σ=1 across multiple observations (Friedman, 1987). At a minimum, one frequently rescales it such that the diagonal is unity, i.e., Σii=1. Yet another strategy is to rescale vectors to unit length, possibly zero mean per observation. This can work well, e.g., for spatial sensor data. These preprocessing techniques and many more are beneficial to keep the estimation problem well controlled. See e.g., the articles by Guyon et al. (2008) for a review of feature selection and extraction techniques. Standardizing vectors also has the nice side-effect of constraining the function complexity of functions that act upon it. For instance, the celebrated radius-margin bound (Vapnik, 1995) in support vector machines and the Perceptron Convergence Theorem (Novikoff, 1962) rely on inputs of bounded norm.

 

데이터로 작업할 때 훈련 전에 전처리하는 경우가 많습니다. 데이터 전처리와 관련된 선택은 종종 최종 결과에 엄청난 차이를 만듭니다. 주택 가격 예측에 MLP를 적용한 것을 상기하십시오(섹션 5.7). 실제 데이터로 작업할 때 첫 번째 단계는 입력 기능을 표준화하여 여러 관측치에서 zero mean μ=0 및 unit varianceΣ=1을 갖도록 표준화하는 것이었습니다(Friedman, 1987). 최소한 대각선이 1이 되도록(예: Σii=1) 자주 크기를 조정합니다. 또 다른 전략은 벡터를 단위 길이로 재조정하는 것입니다. 관찰당 평균은 0일 수 있습니다. 예를 들어 공간 센서 데이터에 대해 잘 작동할 수 있습니다. 이러한 전처리 기술과 기타 많은 기술은 추정 문제를 잘 제어하는 데 유용합니다. 예를 들어 Guyon 등의 기사를 참조하십시오. (2008) feature selectionextraction techniques 에 대해 아실 수 있습니다. 벡터를 표준화하면 그에 따라 작용하는 함수의 복잡도를 제한하는 좋은 부작용도 있습니다. 예를 들어, 서포트 벡터 머신의 유명한 반경-여백 경계(Vapnik, 1995)와 퍼셉트론 수렴 정리(Novikoff, 1962)는 경계 규범의 입력에 의존합니다.

 

Intuitively, this standardization plays nicely with our optimizers since it puts the parameters a priori at a similar scale. As such, it is only natural to ask whether a corresponding normalization step inside a deep network might not be beneficial. While this is not quite the reasoning that led to the invention of batch normalization (Ioffe and Szegedy, 2015), it is a useful way of understanding it and its cousin, layer normalization (Ba et al., 2016) within a unified framework.

 

직관적으로 이 표준화는 매개변수를 비슷한 규모로 선험적으로 설정하기 때문에 옵티마이저와 잘 어울립니다. 따라서 딥 네트워크 내부의 해당 정규화 단계가 도움이 되지 않을 수 있는지 묻는 것은 자연스러운 일입니다. 이것이 배치 정규화(Ioffe and Szegedy, 2015)의 발명으로 이어진 추론은 아니지만 통합 프레임워크 내에서 배치 정규화와 그 사촌인 레이어 정규화(Ba et al., 2016)를 이해하는 데 유용한 방법입니다.

 

Second, for a typical MLP or CNN, as we train, the variables in intermediate layers (e.g., affine transformation outputs in MLP) may take values with widely varying magnitudes: both along the layers from input to output, across units in the same layer, and over time due to our updates to the model parameters. The inventors of batch normalization postulated informally that this drift in the distribution of such variables could hamper the convergence of the network. Intuitively, we might conjecture that if one layer has variable activations that are 100 times that of another layer, this might necessitate compensatory adjustments in the learning rates. Adaptive solvers such as AdaGrad (Duchi et al., 2011), Adam (Kingma and Ba, 2014), Yogi (Zaheer et al., 2018), or Distributed Shampoo (Anil et al., 2020) aim to address this from the viewpoint of optimization, e.g., by adding aspects of second-order methods. The alternative is to prevent the problem from occurring, simply by adaptive normalization.

 

둘째, 일반적인 MLP 또는 CNN의 경우, 우리가 훈련할 때 중간 계층의 변수(예: MLP의 아핀 변환 출력)는 입력에서 출력까지 계층을 따라, 동일한 계층의 단위 간에 매우 다양한 크기의 값을 가질 수 있습니다. , 모델 매개변수에 대한 업데이트로 인해 시간이 지남에 따라 배치 정규화의 발명가는 이러한 변수 분포의 드리프트가 네트워크의 수렴을 방해할 수 있다고 비공식적으로 가정했습니다. 직관적으로, 우리는 한 레이어가 다른 레이어의 100배 가변 활성화를 갖는 경우 학습 속도에서 보상 조정이 필요할 수 있다고 추측할 수 있습니다. AdaGrad(Duchi et al., 2011), Adam(Kingma and Ba, 2014), Yogi(Zaheer et al., 2018) 또는 Distributed Shampoo(Anil et al., 2020)와 같은 적응형 솔버는 예를 들어 2차 방법의 측면을 추가함으로써 최적화의 관점. 대안은 단순히 적응 정규화를 통해 문제가 발생하지 않도록 하는 것입니다.

 

Third, deeper networks are complex and tend to be more easily capable of overfitting. This means that regularization becomes more critical. A common technique for regularization is noise injection. This has been known for a long time, e.g., with regard to noise injection for the inputs (Bishop, 1995). It also forms the basis of dropout in Section 5.6. As it turns out, quite serendipitously, batch normalization conveys all three benefits: preprocessing, numerical stability, and regularization.

 

셋째, 더 깊은 네트워크는 복잡하고 더 쉽게 과적합될 수 있는 경향이 있습니다. 이것은 정규화가 더 중요해진다는 것을 의미합니다. 정규화를 위한 일반적인 기술은 노이즈 주입입니다. 이것은 예를 들어 입력에 대한 노이즈 주입과 관련하여 오랫동안 알려져 왔습니다(Bishop, 1995). 또한 섹션 5.6에서 탈락의 기초를 형성합니다. 결과적으로 배치 정규화는 전처리, 수치 안정성 및 정규화라는 세 가지 이점을 모두 전달합니다.

 

Batch normalization is applied to individual layers, or optionally, to all of them: In each training iteration, we first normalize the inputs (of batch normalization) by subtracting their mean and dividing by their standard deviation, where both are estimated based on the statistics of the current minibatch. Next, we apply a scale coefficient and an offset to recover the lost degrees of freedom. It is precisely due to this normalization based on batch statistics that batch normalization derives its name.

 

배치 정규화는 개별 레이어에 적용되거나 선택적으로 모든 레이어에 적용됩니다. 각 교육 반복에서 먼저 평균을 빼고 표준 편차로 나누어 입력(배치 정규화의)을 정규화합니다. 여기서 둘 다 통계를 기반으로 추정됩니다. 현재 미니 배치의. 다음으로 스케일 계수와 오프셋을 적용하여 손실된 자유도를 복구합니다. 배치 정규화가 그 이름을 파생시킨 배치 통계에 기반한 정규화 때문입니다.

 

Note that if we tried to apply batch normalization with minibatches of size 1, we would not be able to learn anything. That is because after subtracting the means, each hidden unit would take value 0. As you might guess, since we are devoting a whole section to batch normalization, with large enough minibatches, the approach proves effective and stable. One takeaway here is that when applying batch normalization, the choice of batch size is even more significant than without batch normalization, or at least, suitable calibration is needed as we might adjust it.

 

크기가 1인 미니 배치로 배치 정규화를 적용하려고 하면 아무 것도 배울 수 없습니다. 이는 평균을 뺀 후 각 숨겨진 단위가 값 0을 갖기 때문입니다. 짐작할 수 있듯이 전체 섹션을 배치 정규화에 할애하고 있으므로 충분히 큰 미니배치를 사용하여 접근 방식이 효과적이고 안정적입니다. 여기서 한 가지 중요한 점은 배치 정규화를 적용할 때 배치 정규화를 적용하지 않을 때보다 배치 크기 선택이 훨씬 더 중요하거나 적어도 조정할 수 있으므로 적절한 보정이 필요하다는 것입니다.

 

Denote by B a minibatch and let x∈B be an input to batch normalization (BN). In this case the batch normalization is defined as follows:

 

미니배치를 B로 표시하고 x∈B를 배치 정규화(BN)에 대한 입력으로 둡니다. 이 경우 배치 정규화는 다음과 같이 정의됩니다.

 

 

In (8.5.1), μ^B is the sample mean and σ^B is the sample standard deviation of the minibatch B. After applying standardization, the resulting minibatch has zero mean and unit variance. The choice of unit variance (vs. some other magic number) is an arbitrary choice. We recover this degree of freedom by including an elementwise scale parameter γ and shift parameter B that have the same shape as x. Both are parameters that need to be learned as part of model training.

 

(8.5.1)에서 μ^B는 표본 평균이고 σ^B는 미니 배치 B의 표본 표준 편차입니다. 표준화를 적용한 후 결과 미니 배치는 평균이 0이고 단위 분산이 있습니다. 단위 분산(다른 매직 넘버와 비교하여)의 선택은 임의의 선택입니다. 우리는 x와 같은 모양을 가진 요소별 척도 매개변수 γ와 이동 매개변수 B를 포함하여 이 자유도를 복구합니다. 둘 다 모델 학습의 일부로 학습해야 하는 매개변수입니다.

 

The variable magnitudes for intermediate layers cannot diverge during training since batch normalization actively centers and rescales them back to a given mean and size (via μ^B and σ^B). Practical experience confirms that, as alluded to when discussing feature rescaling, batch normalization seems to allow for more aggressive learning rates. We calculate μ^B and σ^B in (8.5.1) as follows:

 

중간 레이어의 변수 크기는 훈련 중에 발산할 수 없습니다. 배치 정규화가 능동적으로 중앙에 배치하고 주어진 평균 및 크기로 재조정하기 때문입니다(μ^B 및 σ^B를 통해). 실제 경험에 따르면 기능 크기 조정을 논의할 때 언급했듯이 배치 정규화가 보다 공격적인 학습 속도를 허용하는 것으로 보입니다. (8.5.1)에서 μ^B 및 σ^B를 다음과 같이 계산합니다.

 

 

Note that we add a small constant ϵ>0 to the variance estimate to ensure that we never attempt division by zero, even in cases where the empirical variance estimate might be very small or even vanish. The estimates μ^B and σ^B counteract the scaling issue by using noisy estimates of mean and variance. You might think that this noisiness should be a problem. Quite to the contrary, this is actually beneficial.

 

경험적 분산 추정이 매우 작거나 심지어 사라질 수 있는 경우에도 0으로 나누기를 시도하지 않도록 분산 추정에 작은 상수 ϵ>0을 추가합니다. 추정치 μ^B 및 σ^B는 평균 및 분산의 노이즈 추정치를 사용하여 스케일링 문제에 대응합니다. 이 소음이 문제가 되어야 한다고 생각할 수도 있습니다. 오히려 이것은 실제로 유익합니다.

 

This turns out to be a recurring theme in deep learning. For reasons that are not yet well-characterized theoretically, various sources of noise in optimization often lead to faster training and less overfitting: this variation appears to act as a form of regularization. Teye et al. (2018) and Luo et al. (2018) related the properties of batch normalization to Bayesian priors and penalties, respectively. In particular, this sheds some light on the puzzle of why batch normalization works best for moderate minibatches sizes in the 50∼100 range. This particular size of minibatch seems to inject just the “right amount” of noise per layer, both in terms of scale via σ^, and in terms of offset via μ^: a larger minibatch regularizes less due to the more stable estimates, whereas tiny minibatches destroy useful signal due to high variance. Exploring this direction further, considering alternative types of preprocessing and filtering may yet lead to other effective types of regularization.

 

이것은 딥 러닝에서 되풀이되는 주제로 밝혀졌습니다. 이론적으로 아직 잘 특성화되지 않은 이유로 인해 최적화에서 다양한 노이즈 소스는 종종 더 빠른 훈련과 덜 과대적합으로 이어집니다. 이러한 변형은 정규화의 한 형태로 작용하는 것으로 보입니다. Teyeet al. (2018) 및 Luo et al. (2018)은 배치 정규화의 속성을 각각 베이지안 사전 및 페널티와 관련시켰습니다. 특히 이것은 배치 정규화가 50~100 범위의 적당한 미니배치 크기에 가장 적합한 이유에 대한 퍼즐에 약간의 빛을 제공합니다. 미니배치의 이 특정 크기는 σ^를 통한 스케일과 μ^를 통한 오프셋 측면 모두에서 레이어당 "적절한 양"의 노이즈를 주입하는 것으로 보입니다. 작은 미니 배치는 높은 분산으로 인해 유용한 신호를 파괴합니다. 다른 유형의 전처리 및 필터링을 고려하여 이 방향을 더 탐색하면 다른 효과적인 유형의 정규화로 이어질 수 있습니다.

 

Fixing a trained model, you might think that we would prefer using the entire dataset to estimate the mean and variance. Once training is complete, why would we want the same image to be classified differently, depending on the batch in which it happens to reside? During training, such exact calculation is infeasible because the intermediate variables for all data examples change every time we update our model. However, once the model is trained, we can calculate the means and variances of each layer’s variables based on the entire dataset. Indeed this is standard practice for models employing batch normalization and thus batch normalization layers function differently in training mode (normalizing by minibatch statistics) and in prediction mode (normalizing by dataset statistics). In this form they closely resemble the behavior of dropout regularization of Section 5.6, where noise is only injected during training.

 

훈련된 모델을 수정하면 평균과 분산을 추정하기 위해 전체 데이터 세트를 사용하는 것이 더 좋다고 생각할 수 있습니다. 학습이 완료되면 배치에 따라 동일한 이미지를 다르게 분류해야 하는 이유는 무엇입니까? 학습 중에는 모델을 업데이트할 때마다 모든 데이터 예제의 중간 변수가 변경되기 때문에 이러한 정확한 계산은 불가능합니다. 그러나 모델이 훈련되면 전체 데이터 세트를 기반으로 각 계층 변수의 평균과 분산을 계산할 수 있습니다. 실제로 이것은 배치 정규화를 사용하는 모델의 표준 사례이므로 배치 정규화 계층은 교육 모드(미니배치 통계로 정규화)와 예측 모드(데이터 세트 통계로 정규화)에서 다르게 작동합니다. 이 형태에서 노이즈는 학습 중에만 주입되는 섹션 5.6의 드롭아웃 정규화 동작과 매우 유사합니다.

 

Batch Normalization 이란?

 

In deep learning, Batch Normalization (BN) is a technique used to improve the training process and stability of neural networks. It was proposed to address the problem of internal covariate shift, which occurs when the distribution of the inputs to a layer changes during training.

 

딥 러닝에서 배치 정규화(Batch Normalization, BN)은 신경망의 학습 과정과 안정성을 향상시키기 위한 기법입니다. 이 기법은 내부 공변량 변화(Internal Covariate Shift)라는 문제를 해결하기 위해 제안되었습니다. 내부 공변량 변화란, 신경망의 각 층의 입력 분포가 학습 중에 크게 변하는 현상을 의미합니다.

 

During the training of deep neural networks, the distribution of the activations in each layer can change significantly due to updates in the model's parameters during the optimization process. This can slow down training and make it harder for the model to converge to good solutions. Batch Normalization addresses this issue by normalizing the activations of each layer across mini-batches of data during training.

 

딥 뉴럴 네트워크를 학습할 때, 최적화 과정에서 모델의 매개변수가 업데이트되면서 각 층의 활성화 분포가 크게 변할 수 있습니다. 이는 학습 속도를 느리게 하고 모델이 좋은 솔루션으로 수렴하기 어렵게 만듭니다. 배치 정규화는 학습 과정에서 각 층의 활성화를 미니 배치 단위로 정규화하여 이 문제를 해결합니다.

 

The Batch Normalization algorithm works as follows:

 

배치 정규화 알고리즘의 동작은 다음과 같습니다:

 

  1. For each mini-batch of data during training, the mean and variance of the activations in each layer are computed.
    학습 과정에서 각 미니 배치에 대해 각 층의 활성화의 평균과 분산을 계산합니다.
  2. The activations are then normalized by subtracting the mean and dividing by the square root of the variance. This step ensures that the activations have a mean close to zero and a standard deviation close to one.
    그런 다음 활성화를 정규화하기 위해 평균을 빼고 분산의 제곱근으로 나눕니다. 이 단계는 활성화의 평균이 거의 0이 되고 표준 편차가 거의 1이 되도록 합니다.

  3. The normalized activations are then scaled and shifted using learnable parameters (gamma and beta) to allow the model to learn the optimal scale and shift for each activation.
    정규화된 활성화는 가중치와 편향을 이용해 스케일링과 시프트됩니다. 이러한 가중치와 편향은 모델이 각 활성화에 대해 최적의 스케일과 시프트를 학습할 수 있게 합니다.

The benefits of Batch Normalization include:
배치 정규화의 이점은 다음과 같습니다:

  1. Improved training speed: Normalizing the activations helps to reduce internal covariate shift, which can speed up the training process and allow for the use of higher learning rates.
    학습 속도 향상: 정규화된 활성화는 내부 공변량 변화를 줄여 학습 속도를 향상시키고 더 높은 학습률을 사용할 수 있게 합니다.

  2. Increased stability: Batch Normalization can make the optimization process more stable, making it less likely for the model to diverge or get stuck in poor local minima.
    안정성 향상: 배치 정규화는 최적화 과정을 더 안정적으로 만들어 모델이 발산하거나 나쁜 지역 최솟값에 빠지는 것을 방지합니다.

  3. Regularization: Batch Normalization acts as a form of regularization by adding some noise to the activations during training, which can help prevent overfitting.
    정규화 효과: 배치 정규화는 활성화에 약간의 노이즈를 추가하여 정규화의 역할을 하며, 과적합을 방지하는데 도움을 줍니다.

Batch Normalization has become a standard component in most deep neural network architectures and is widely used in various tasks such as image classification, object detection, and natural language processing.

 

배치 정규화는 현재 대부분의 딥 뉴럴 네트워크 구조에서 표준 구성 요소가 되어 있으며, 이미지 분류, 객체 검출, 자연어 처리 등 다양한 작업에 널리 사용됩니다.

 

8.5.2. Batch Normalization Layers

Batch normalization implementations for fully connected layers and convolutional layers are slightly different. One key difference between batch normalization and other layers is that because batch normalization operates on a full minibatch at a time, we cannot just ignore the batch dimension as we did before when introducing other layers.

 

완전 연결 계층과 컨벌루션 계층에 대한 배치 정규화 구현은 약간 다릅니다. 배치 정규화와 다른 레이어의 주요 차이점 중 하나는 배치 정규화가 한 번에 전체 미니배치에서 작동하기 때문에 이전에 다른 레이어를 도입할 때 했던 것처럼 배치 차원을 무시할 수 없다는 것입니다.

 

8.5.2.1. Fully Connected Layers

When applying batch normalization to fully connected layers, the original paper inserted batch normalization after the affine transformation and before the nonlinear activation function. Later applications experimented with inserting batch normalization right after activation functions (Ioffe and Szegedy, 2015). Denoting the input to the fully connected layer by x, the affine transformation by Wx+b (with the weight parameter W and the bias parameter b), and the activation function by ϕ, we can express the computation of a batch-normalization-enabled, fully connected layer output  as follows:

 

완전 연결 레이어에 배치 정규화를 적용할 때 원본 논문에서는 아핀 변환 후와 비선형 활성화 함수 전에 배치 정규화를 삽입했습니다. 이후 애플리케이션에서는 활성화 함수 바로 뒤에 배치 정규화를 삽입하는 실험을 했습니다(Ioffe and Szegedy, 2015). 완전 연결 레이어에 대한 입력을 x, 아핀 변환을 Wx+b(가중 매개변수 W 및 편향 매개변수 b 사용), 활성화 함수를 φ로 나타내면 배치 정규화가 가능한 계산을 다음과 같이 표현할 수 있습니다. , 완전히 연결된 레이어 출력 ℎ은 다음과 같습니다.

 

 

Recall that mean and variance are computed on the same minibatch on which the transformation is applied.

평균과 분산은 변환이 적용된 동일한 미니배치에서 계산됩니다.

 

8.5.2.2. Convolutional Layers

Similarly, with convolutional layers, we can apply batch normalization after the convolution and before the nonlinear activation function. The key difference from batch normalization in fully connected layers is that we apply the operation on a per-channel basis across all locations. This is compatible with our assumption of translation invariance that led to convolutions: we assumed that the specific location of a pattern within an image was not critical for the purpose of understanding.

 

마찬가지로 컨볼루션 레이어를 사용하면 컨볼루션 이후와 비선형 활성화 함수 이전에 배치 정규화를 적용할 수 있습니다. 완전히 연결된 레이어의 배치 정규화와 주요 차이점은 모든 위치에서 채널별로 작업을 적용한다는 것입니다. 이는 컨볼루션으로 이어지는 변환 불변성 가정과 호환됩니다. 이미지 내 패턴의 특정 위치가 이해 목적에 중요하지 않다고 가정했습니다.

 

Assume that our minibatches contain m examples and that for each channel, the output of the convolution has height p and width q. For convolutional layers, we carry out each batch normalization over the m⋅p⋅q elements per output channel simultaneously. Thus, we collect the values over all spatial locations when computing the mean and variance and consequently apply the same mean and variance within a given channel to normalize the value at each spatial location. Each channel has its own scale and shift parameters, both of which are scalars.

 

미니배치가 m개의 예제를 포함하고 각 채널에 대한 컨볼루션 출력의 높이가 p이고 너비가 q라고 가정합니다. 컨벌루션 레이어의 경우 출력 채널당 m⋅p⋅q 요소에 대해 각 배치 정규화를 동시에 수행합니다. 따라서 평균과 분산을 계산할 때 모든 공간 위치에 대한 값을 수집하고 결과적으로 주어진 채널 내에서 동일한 평균과 분산을 적용하여 각 공간 위치에서 값을 정규화합니다. 각 채널에는 자체 스케일 및 시프트 매개변수가 있으며 둘 다 스칼라입니다.

 

8.5.2.3. Layer Normalization

Note that in the context of convolutions the batch normalization is well-defined even for minibatches of size 1: after all, we have all the locations across an image to average. Consequently, mean and variance are well defined, even if it is just within a single observation. This consideration led Ba et al. (2016) to introduce the notion of layer normalization. It works just like a batch norm, only that it is applied to one observation at a time. Consequently both the offset and the scaling factor are scalars. Given an n-dimensional vector x layer norms are given by

 

회선의 맥락에서 배치 정규화는 크기 1의 미니배치에 대해서도 잘 정의되어 있습니다. 결국 이미지 전체의 모든 위치를 평균화할 수 있습니다. 결과적으로 평균과 분산은 단일 관측치 내에 있더라도 잘 정의됩니다. 이러한 고려 사항은 Ba et al. (2016) 레이어 정규화의 개념을 소개합니다. 배치 표준처럼 작동하지만 한 번에 하나의 관측치에만 적용됩니다. 결과적으로 오프셋과 배율 인수는 모두 스칼라입니다. 주어진 n차원 벡터 x 레이어 규범은 다음과 같이 지정됩니다.

 

where scaling and offset are applied coefficient-wise and given by

 

여기서 스케일링 및 오프셋은 계수별로 적용되며 다음과 같이 지정됩니다.

 

 

As before we add a small offset ε>0 to prevent division by zero. One of the major benefits of using layer normalization is that it prevents divergence. After all, ignoring ε, the output of the layer normalization is scale independent. That is, we have LN(x)≈LN(αx) for any choice of α≠0. This becomes an equality for |α|→∞ (the approximate equality is due to the offset ε for the variance).

 

이전과 마찬가지로 작은 오프셋 ε>0을 추가하여 0으로 나누는 것을 방지합니다. 계층 정규화 사용의 주요 이점 중 하나는 발산을 방지한다는 것입니다. 결국, ε을 무시하면 레이어 정규화의 출력은 스케일에 독립적입니다. 즉, α≠0을 선택하는 경우 LN(x)≈LN(αx)가 있습니다. 이는 |α|→∞에 대한 등식이 됩니다(대략적인 등식은 분산에 대한 오프셋 ε 때문입니다).

 

Layer Normalization 이란?

 

딥 러닝에서 레이어 정규화(Layer Normalization, LN)은 배치 정규화와 마찬가지로 내부 공변량 변화(Internal Covariate Shift)를 해결하기 위해 제안된 정규화 기법입니다. 내부 공변량 변화란, 신경망의 각 층의 입력 분포가 학습 중에 크게 변하는 현상을 의미합니다. 배치 정규화는 미니 배치 단위로 정규화하지만, 레이어 정규화는 미니 배치가 아니라 층 내에서 정규화를 수행합니다.

레이어 정규화 알고리즘의 동작은 다음과 같습니다:

  1. 학습 과정에서 각 층의 활성화에 대해 평균과 분산을 계산합니다.
  2. 그런 다음 활성화를 정규화하기 위해 평균을 빼고 분산의 제곱근으로 나눕니다. 이 단계는 활성화의 평균이 거의 0이 되고 표준 편차가 거의 1이 되도록 합니다.
  3. 정규화된 활성화는 가중치와 편향을 이용해 스케일링과 시프트됩니다. 이러한 가중치와 편향은 모델이 각 활성화에 대해 최적의 스케일과 시프트를 학습할 수 있게 합니다.

레이어 정규화는 배치 크기에 상관없이 항상 일관된 정규화를 제공하므로, 배치 크기가 작거나 크더라도 안정적인 학습을 가능하게 합니다. 또한 레이어 정규화는 미니 배치의 크기가 1일 때도 사용할 수 있으며, RNN과 같은 순환 신경망에서도 적용할 수 있습니다.

레이어 정규화는 배치 정규화와 비교하여 메모리 요구량이 더 적고, 학습 시간이 더 빠르며, 미니 배치 크기에 덜 민감합니다. 따라서 최근의 딥 러닝 모델에서 레이어 정규화가 널리 사용되고 있으며, 배치 정규화와 함께 다양한 응용 분야에서 성능을 향상시키는데 기여하고 있습니다.

 

 

Internal Covariate Shift란?

 

내부 공변량 변화(Internal Covariate Shift)란 딥 러닝 모델의 각 층의 입력 분포가 학습 도중 크게 변하는 현상을 의미합니다. 딥 러닝 신경망은 여러 개의 층으로 구성되어 있으며, 각 층에서는 입력 데이터에 가중치를 적용하고 비선형 활성화 함수를 거쳐 출력을 계산합니다. 이렇게 여러 개의 층을 거치면서 입력 데이터의 분포가 변화하게 되는데, 이러한 변화를 내부 공변량 변화라고 합니다.

내부 공변량 변화는 심층 신경망에서 학습을 어렵게 만들 수 있습니다. 이는 두 가지 주요 이유로 발생합니다. 첫째, 각 층마다 입력 데이터의 분포가 변화하면 학습 과정에서 각 층을 통과한 출력의 분포도 달라집니다. 이는 가중치 업데이트를 어렵게 하며, 학습이 불안정해지게 합니다. 둘째, 내부 공변량 변화는 각 층의 가중치를 재사용하기 어렵게 만들어, 효과적인 학습을 어렵게 합니다.

이러한 내부 공변량 변화를 해결하는 방법으로 배치 정규화(Batch Normalization)과 레이어 정규화(Layer Normalization) 등의 정규화 기법이 제안되었습니다. 이러한 정규화 기법은 각 층의 입력 데이터의 분포를 안정화시켜 학습을 원활하게 만들어주고, 심층 신경망의 학습을 향상시키는데 기여합니다. 내부 공변량 변화의 해결은 딥 러닝 모델의 안정적인 학습과 성능 향상을 위해 중요한 문제 중 하나입니다.

 

8.5.2.4. Batch Normalization During Prediction

As we mentioned earlier, batch normalization typically behaves differently in training mode and prediction mode. First, the noise in the sample mean and the sample variance arising from estimating each on minibatches are no longer desirable once we have trained the model. Second, we might not have the luxury of computing per-batch normalization statistics. For example, we might need to apply our model to make one prediction at a time.

 

앞서 언급했듯이 배치 정규화는 일반적으로 훈련 모드와 예측 모드에서 다르게 작동합니다. 첫째, 샘플 평균의 노이즈와 미니 배치에서 각각을 추정하여 발생하는 샘플 분산은 모델을 훈련한 후에는 더 이상 바람직하지 않습니다. 둘째, 배치당 정규화 통계를 계산할 여유가 없을 수도 있습니다. 예를 들어 한 번에 하나의 예측을 수행하기 위해 모델을 적용해야 할 수 있습니다.

 

Typically, after training, we use the entire dataset to compute stable estimates of the variable statistics and then fix them at prediction time. Consequently, batch normalization behaves differently during training and at test time. Recall that dropout also exhibits this characteristic.

 

일반적으로 교육 후 전체 데이터 세트를 사용하여 변수 통계의 안정적인 추정치를 계산한 다음 예측 시간에 수정합니다. 결과적으로 배치 정규화는 훈련 중과 테스트 중에 다르게 작동합니다. 드롭아웃도 이러한 특성을 나타냄을 상기하십시오.

 

8.5.3. Implementation from Scratch

To see how batch normalization works in practice, we implement one from scratch below.

배치 정규화가 실제로 어떻게 작동하는지 확인하기 위해 아래에서 하나를 처음부터 구현합니다.

 

def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
    # Use is_grad_enabled to determine whether we are in training mode
    if not torch.is_grad_enabled():
        # In prediction mode, use mean and variance obtained by moving average
        X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
    else:
        assert len(X.shape) in (2, 4)
        if len(X.shape) == 2:
            # When using a fully connected layer, calculate the mean and
            # variance on the feature dimension
            mean = X.mean(dim=0)
            var = ((X - mean) ** 2).mean(dim=0)
        else:
            # When using a two-dimensional convolutional layer, calculate the
            # mean and variance on the channel dimension (axis=1). Here we
            # need to maintain the shape of X, so that the broadcasting
            # operation can be carried out later
            mean = X.mean(dim=(0, 2, 3), keepdim=True)
            var = ((X - mean) ** 2).mean(dim=(0, 2, 3), keepdim=True)
        # In training mode, the current mean and variance are used
        X_hat = (X - mean) / torch.sqrt(var + eps)
        # Update the mean and variance using moving average
        moving_mean = (1.0 - momentum) * moving_mean + momentum * mean
        moving_var = (1.0 - momentum) * moving_var + momentum * var
    Y = gamma * X_hat + beta  # Scale and shift
    return Y, moving_mean.data, moving_var.data

 

위 코드는 배치 정규화(Batch Normalization) 기능을 수행하는 함수를 정의한 것입니다. 배치 정규화는 딥 러닝 모델에서 내부 공변량 변화(Internal Covariate Shift)를 해결하고 학습을 안정화시키기 위해 사용되는 기법 중 하나입니다.

이 함수에서 사용되는 인자들은 다음과 같습니다.

  • X: 입력 데이터
  • gamma: 스케일(scale) 파라미터
  • beta: 시프트(shift) 파라미터
  • moving_mean: 이동 평균(Moving Average)을 저장하기 위한 변수
  • moving_var: 이동 분산(Moving Variance)을 저장하기 위한 변수
  • eps: 분모가 0이 되는 것을 방지하기 위한 작은 값(epsilon)
  • momentum: 이동 평균과 이동 분산을 업데이트할 때 사용되는 모멘텀 파라미터

함수의 동작은 다음과 같습니다.

  1. torch.is_grad_enabled() 함수를 사용하여 현재 학습 모드인지 판단합니다.
  2. 학습 모드가 아닐 경우(예측 모드), 이동 평균과 이동 분산을 사용하여 정규화된 데이터 X_hat을 계산합니다.
  3. 학습 모드일 경우, 입력 데이터 X의 shape에 따라 평균(mean)과 분산(var)을 계산합니다. Fully connected layer인 경우 feature 차원을 기준으로, 2D 합성곱(Convolutional) layer인 경우 채널 차원을 기준으로 평균과 분산을 계산합니다.
  4. 학습 모드일 경우, 계산된 평균과 분산을 사용하여 X를 정규화하고, 이동 평균과 이동 분산을 업데이트합니다.
  5. 최종적으로 정규화된 X_hat에 스케일(gamma)과 시프트(beta)를 적용하여 최종 결과 Y를 반환합니다.

이렇게 배치 정규화는 입력 데이터의 분포를 안정화시키고 학습을 더욱 안정적으로 만들어주는 기법으로 널리 사용됩니다. 주로 딥 러닝 모델의 층 사이에 배치 정규화를 추가하여 학습을 개선하는데 사용됩니다.

 

We can now create a proper BatchNorm layer. Our layer will maintain proper parameters for scale gamma and shift beta, both of which will be updated in the course of training. Additionally, our layer will maintain moving averages of the means and variances for subsequent use during model prediction.

 

이제 적절한 BatchNorm 레이어를 생성할 수 있습니다. 우리 레이어는 스케일 감마 및 시프트 베타에 대한 적절한 매개 변수를 유지하며 둘 다 교육 과정에서 업데이트됩니다. 또한 레이어는 모델 예측 중에 후속 사용을 위해 평균 및 분산의 이동 평균을 유지합니다.

 

Putting aside the algorithmic details, note the design pattern underlying our implementation of the layer. Typically, we define the mathematics in a separate function, say batch_norm. We then integrate this functionality into a custom layer, whose code mostly addresses bookkeeping matters, such as moving data to the right device context, allocating and initializing any required variables, keeping track of moving averages (here for mean and variance), and so on. This pattern enables a clean separation of mathematics from boilerplate code. Also note that for the sake of convenience we did not worry about automatically inferring the input shape here, thus we need to specify the number of features throughout. By now all modern deep learning frameworks offer automatic detection of size and shape in the high-level batch normalization APIs (in practice we will use this instead).

 

알고리즘 세부 사항은 제쳐두고 레이어 구현의 기본 디자인 패턴에 주목하십시오. 일반적으로 별도의 함수인 batch_norm에서 수학을 정의합니다. 그런 다음 이 기능을 사용자 지정 계층에 통합합니다. 이 계층의 코드는 데이터를 올바른 장치 컨텍스트로 이동, 필요한 변수 할당 및 초기화, 이동 평균 추적(여기서는 평균 및 분산) 등과 같은 부기 문제를 주로 처리합니다. . 이 패턴을 사용하면 상용구 코드에서 수학을 깔끔하게 분리할 수 있습니다. 또한 편의를 위해 여기에서 입력 모양을 자동으로 유추하는 것에 대해 걱정하지 않았으므로 전체 기능의 수를 지정해야 합니다. 지금까지 모든 최신 딥 러닝 프레임워크는 높은 수준의 배치 정규화 API에서 크기와 모양을 자동으로 감지합니다(실제로는 이를 대신 사용함).

 

class BatchNorm(nn.Module):
    # num_features: the number of outputs for a fully connected layer or the
    # number of output channels for a convolutional layer. num_dims: 2 for a
    # fully connected layer and 4 for a convolutional layer
    def __init__(self, num_features, num_dims):
        super().__init__()
        if num_dims == 2:
            shape = (1, num_features)
        else:
            shape = (1, num_features, 1, 1)
        # The scale parameter and the shift parameter (model parameters) are
        # initialized to 1 and 0, respectively
        self.gamma = nn.Parameter(torch.ones(shape))
        self.beta = nn.Parameter(torch.zeros(shape))
        # The variables that are not model parameters are initialized to 0 and
        # 1
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.ones(shape)

    def forward(self, X):
        # If X is not on the main memory, copy moving_mean and moving_var to
        # the device where X is located
        if self.moving_mean.device != X.device:
            self.moving_mean = self.moving_mean.to(X.device)
            self.moving_var = self.moving_var.to(X.device)
        # Save the updated moving_mean and moving_var
        Y, self.moving_mean, self.moving_var = batch_norm(
            X, self.gamma, self.beta, self.moving_mean,
            self.moving_var, eps=1e-5, momentum=0.1)
        return Y

 

위 코드는 배치 정규화를 수행하는 사용자 정의 클래스인 BatchNorm을 정의한 것입니다. 배치 정규화는 딥 러닝 모델에서 내부 공변량 변화(Internal Covariate Shift)를 줄이고 학습을 안정화시키기 위해 사용되는 기법 중 하나입니다.

클래스의 생성자(__init__)에서는 다음과 같은 인자들을 받습니다:

  • num_features: fully connected layer의 출력 뉴런 수 또는 합성곱 레이어의 출력 채널 수
  • num_dims: fully connected layer의 경우 2, 합성곱 레이어의 경우 4

클래스의 동작은 다음과 같습니다:

  1. 생성자에서 스케일 파라미터 gamma와 시프트 파라미터 beta를 초기화합니다. 이들은 모델의 학습 가능한 파라미터로 선언되며, nn.Parameter를 사용하여 정의됩니다. 초기값으로는 스케일 파라미터 gamma는 1로 초기화하고, 시프트 파라미터 beta는 0으로 초기화합니다.
  2. 이동 평균과 이동 분산을 저장할 변수 self.moving_mean과 self.moving_var를 정의합니다. 이들은 학습 가능한 파라미터가 아니며, 초기값으로는 이동 평균을 0으로, 이동 분산을 1로 설정합니다.
  3. 클래스의 forward 메서드에서는 입력 데이터 X에 대해 배치 정규화를 수행합니다. 이 때, 이동 평균과 이동 분산은 이전 단계에서 업데이트된 값을 사용합니다.
  4. 만약 입력 데이터 X가 주 메모리에 있지 않은 경우, 이동 평균과 이동 분산을 X와 동일한 디바이스로 복사합니다.
  5. batch_norm 함수를 호출하여 X를 정규화하고, 결과로 스케일과 시프트가 적용된 Y를 얻습니다. 이 때, 이동 평균과 이동 분산은 업데이트된 값으로 갱신됩니다.
  6. 최종적으로 스케일과 시프트가 적용된 정규화된 데이터 Y를 반환합니다.

이렇게 BatchNorm 클래스를 사용하면 배치 정규화를 쉽게 사용할 수 있으며, 딥 러닝 모델의 학습과 안정화에 도움이 됩니다.

 

We used momentum to govern the aggregation over past mean and variance estimates. This is somewhat of a misnomer as it has nothing whatsoever to do with the momentum term of optimization in Section 12.6. Nonetheless, it is the commonly adopted name for this term and in deference to API naming convention we use the same variable name in our code, too.

 

모멘텀을 사용하여 과거 평균 및 분산 추정치에 대한 집계를 관리했습니다. 이것은 섹션 12.6의 최적화의 모멘텀 항과 전혀 관련이 없기 때문에 다소 잘못된 이름입니다. 그럼에도 불구하고 이 용어에 대해 일반적으로 채택되는 이름이며 API 명명 규칙에 따라 코드에서도 동일한 변수 이름을 사용합니다.

 

8.5.4. LeNet with Batch Normalization

To see how to apply BatchNorm in context, below we apply it to a traditional LeNet model (Section 7.6). Recall that batch normalization is applied after the convolutional layers or fully connected layers but before the corresponding activation functions.

 

컨텍스트에서 BatchNorm을 적용하는 방법을 확인하기 위해 아래에서 이를 기존 LeNet 모델에 적용합니다(섹션 7.6). 배치 정규화는 컨벌루션 계층 또는 완전 연결 계층 이후에 적용되지만 해당 활성화 함수 이전에 적용됩니다.

 

class BNLeNetScratch(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(6, kernel_size=5), BatchNorm(6, num_dims=4),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.LazyConv2d(16, kernel_size=5), BatchNorm(16, num_dims=4),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(), nn.LazyLinear(120),
            BatchNorm(120, num_dims=2), nn.Sigmoid(), nn.LazyLinear(84),
            BatchNorm(84, num_dims=2), nn.Sigmoid(),
            nn.LazyLinear(num_classes))

위 코드는 Scratch에서 학습하는 Batch Normalization을 적용한 LeNet과 같은 모델인 BNLeNetScratch 클래스를 정의하는 것입니다.

BNLeNetScratch 클래스의 생성자(__init__)에서는 다음과 같은 인자들을 받습니다:

  • lr: 학습률 (기본값은 0.1)
  • num_classes: 분류하고자 하는 클래스의 수 (기본값은 10)

클래스의 동작은 다음과 같습니다:

  1. nn.Sequential을 사용하여 모델 레이어를 순차적으로 쌓습니다.
  2. 첫 번째 합성곱 레이어 (nn.LazyConv2d) 다음에 배치 정규화 레이어 (BatchNorm)를 적용합니다. 이렇게 함으로써 입력 데이터의 분포를 정규화하고 학습을 안정화시킬 수 있습니다. 각 합성곱 레이어는 5x5 커널 크기를 사용하며, 첫 번째 레이어는 6개의 출력 채널을 가지고, 두 번째 레이어는 16개의 출력 채널을 가집니다.
  3. 배치 정규화 레이어 이후에는 활성화 함수로 시그모이드 (nn.Sigmoid())를 사용합니다.
  4. 평균 풀링 레이어 (nn.AvgPool2d)를 적용하여 특성 맵의 크기를 줄입니다.
  5. 평탄화 레이어 (nn.Flatten())를 사용하여 2D 텐서를 1D 벡터로 변환합니다.
  6. 완전 연결 레이어 (nn.LazyLinear)를 추가하고 배치 정규화 레이어를 적용합니다. 첫 번째 완전 연결 레이어는 120개의 출력 뉴런을 가지고, 두 번째 레이어는 84개의 출력 뉴런을 가집니다.
  7. 완전 연결 레이어 이후에는 다시 시그모이드 활성화 함수를 사용합니다.
  8. 마지막으로 완전 연결 레이어를 추가하고, 클래스의 수에 해당하는 출력 뉴런을 가지게 됩니다.

이렇게 정의된 BNLeNetScratch 클래스는 학습 가능한 모델로, 배치 정규화를 통해 학습 안정성을 증가시키고, 일반화 능력을 향상시킬 수 있습니다.

 

As before, we will train our network on the Fashion-MNIST dataset. This code is virtually identical to that when we first trained LeNet.

 

이전과 마찬가지로 Fashion-MNIST 데이터 세트에서 네트워크를 훈련할 것입니다. 이 코드는 LeNet을 처음 학습했을 때와 거의 동일합니다.

 

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128)
model = BNLeNetScratch(lr=0.1)
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

 

위 코드는 다음과 같은 작업을 수행하는 것입니다.

  1. d2l.Trainer 클래스의 인스턴스를 생성합니다. Trainer는 딥러닝 모델을 학습시키기 위한 도우미 클래스로, 에폭 수(max_epochs)를 10으로 설정하고, 사용할 GPU 개수(num_gpus)를 1개로 설정합니다.
  2. d2l.FashionMNIST 클래스의 인스턴스를 생성하여 데이터를 로드합니다. 이 데이터셋은 패션 관련 이미지를 분류하는데 사용되며, 배치 크기(batch_size)는 128로 설정됩니다.
  3. BNLeNetScratch 클래스의 인스턴스를 생성합니다. 이 모델은 BNLeNetScratch(lr=0.1)로 생성되며, 학습률(lr)은 0.1로 설정됩니다.
  4. model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)를 호출하여 모델의 파라미터를 초기화합니다. 이 함수는 BNLeNetScratch 클래스의 인스턴스 model과 데이터 로더의 첫 번째 미니배치를 사용하여, 미리 정의된 d2l.init_cnn 함수를 이용해 모델의 파라미터를 초기화합니다.
  5. trainer.fit(model, data)를 호출하여 모델을 학습합니다. Trainer 클래스의 fit 메서드를 사용하여 모델과 데이터를 전달하면, 지정한 에폭 수만큼 모델을 학습합니다. 학습은 미니배치 단위로 이루어지며, 지정된 에폭 수 만큼 반복하여 모델의 파라미터를 조정하면서 손실 함수를 최적화하여 모델을 훈련시킵니다.

이렇게 코드를 실행하면 BNLeNetScratch 모델이 Fashion MNIST 데이터셋에 대해 학습되고, 훈련된 모델을 사용하여 패션 관련 이미지를 분류할 수 있습니다.

 

 

 

Let’s have a look at the scale parameter gamma and the shift parameter beta learned from the first batch normalization layer.

 

첫 번째 배치 정규화 레이어에서 학습한 척도 매개변수 감마와 이동 매개변수 베타를 살펴보겠습니다.

 

model.net[1].gamma.reshape((-1,)), model.net[1].beta.reshape((-1,))
(tensor([1.7430, 1.9467, 1.6972, 1.5474, 2.0986, 1.8447], device='cuda:0',
        grad_fn=<ReshapeAliasBackward0>),
 tensor([ 0.9244, -1.3682,  1.4599, -1.5325,  1.3034, -0.0391], device='cuda:0',
        grad_fn=<ReshapeAliasBackward0>))

위 코드는 모델의 Batch Normalization(BN) 레이어에서 사용되는 스케일 파라미터(gamma)와 시프트 파라미터(beta)를 1차원으로 변환하여 출력하는 코드입니다.

  • model.net[1]: 모델(BNLeNetScratch)의 nn.Sequential에서 두 번째 레이어를 선택합니다. 두 번째 레이어는 Batch Normalization 레이어입니다.
  • model.net[1].gamma: 선택된 Batch Normalization 레이어의 스케일 파라미터(gamma)를 가져옵니다. 스케일 파라미터는 학습되는 모델 파라미터이며, 각 채널(channel)마다 하나의 값이 있습니다.
  • model.net[1].beta: 선택된 Batch Normalization 레이어의 시프트 파라미터(beta)를 가져옵니다. 시프트 파라미터도 스케일 파라미터와 같이 학습되는 모델 파라미터입니다.
  • model.net[1].gamma.reshape((-1,)): 스케일 파라미터인 gamma를 1차원으로 변환합니다. reshape 함수를 사용하여 모든 채널의 값을 일렬로 나열합니다.
  • model.net[1].beta.reshape((-1,)): 시프트 파라미터인 beta를 1차원으로 변환합니다. 마찬가지로 reshape 함수를 사용하여 모든 채널의 값을 일렬로 나열합니다.

즉, 위 코드는 Batch Normalization 레이어의 스케일 파라미터와 시프트 파라미터를 각각 1차원 벡터로 변환하여 출력합니다. 이렇게 1차원 벡터로 변환하는 이유는, 이후에 이 스케일 파라미터와 시프트 파라미터를 사용하여 테스트 데이터에 대해 Batch Normalization을 적용하기 위해서입니다. 일반적으로 테스트 시에는 미리 학습된 모델의 파라미터만 사용하므로, 학습된 스케일 파라미터와 시프트 파라미터를 사용하여 정규화를 수행합니다.

 

 

8.5.5. Concise Implementation

Compared with the BatchNorm class, which we just defined ourselves, we can use the BatchNorm class defined in high-level APIs from the deep learning framework directly. The code looks virtually identical to our implementation above, except that we no longer need to provide additional arguments for it to get the dimensions right.

 

방금 정의한 BatchNorm 클래스와 비교하면 딥러닝 프레임워크에서 상위 API에 정의된 BatchNorm 클래스를 직접 사용할 수 있습니다. 코드는 치수를 올바르게 가져오기 위해 더 이상 추가 인수를 제공할 필요가 없다는 점을 제외하면 위의 구현과 거의 동일합니다.

 

class BNLeNet(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(6, kernel_size=5), nn.LazyBatchNorm2d(),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.LazyConv2d(16, kernel_size=5), nn.LazyBatchNorm2d(),
            nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(), nn.LazyLinear(120), nn.LazyBatchNorm1d(),
            nn.Sigmoid(), nn.LazyLinear(84), nn.LazyBatchNorm1d(),
            nn.Sigmoid(), nn.LazyLinear(num_classes))

위 코드는 Batch Normalization을 포함하는 LeNet 모델(BNLeNet)을 정의하는 코드입니다.

  • nn.LazyConv2d(6, kernel_size=5): 입력 채널이 6개인 2D 컨볼루션 레이어를 생성합니다. 커널 크기는 5x5 입니다.
  • nn.LazyBatchNorm2d(): 2D Batch Normalization 레이어를 생성합니다. 이 레이어는 컨볼루션 레이어의 출력에 대해 각 채널별로 정규화를 수행합니다.
  • nn.Sigmoid(): Sigmoid 활성화 함수를 추가합니다.
  • nn.AvgPool2d(kernel_size=2, stride=2): 2x2 크기의 평균 풀링 레이어를 생성합니다. 스트라이드는 2로 설정되어 입력 이미지의 크기를 반으로 줄입니다.

이와 같은 구조를 반복하여 모델을 정의하고, 마지막에는 클래스의 개수에 해당하는 출력 노드 개수를 가진 nn.LazyLinear(num_classes) 레이어를 추가합니다. 이 모델은 입력 이미지를 처리하여 클래스를 분류하는 데 사용됩니다. 또한 Batch Normalization 레이어가 컨볼루션 레이어와 완전 연결 레이어에 모두 사용되는 것을 볼 수 있습니다. 이렇게 Batch Normalization을 적용하여 모델의 학습 안정성을 향상시킬 수 있습니다.

 

Below, we use the same hyperparameters to train our model. Note that as usual, the high-level API variant runs much faster because its code has been compiled to C++ or CUDA while our custom implementation must be interpreted by Python.

 

아래에서는 동일한 하이퍼파라미터를 사용하여 모델을 훈련합니다. 평소와 같이 고수준 API 변형은 코드가 C++ 또는 CUDA로 컴파일되었기 때문에 훨씬 빠르게 실행되는 반면 사용자 정의 구현은 Python으로 해석되어야 합니다.

 

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128)
model = BNLeNet(lr=0.1)
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

위 코드는 BNLeNet 모델을 FashionMNIST 데이터셋으로 학습하는 과정을 보여주는 코드입니다.

  • trainer = d2l.Trainer(max_epochs=10, num_gpus=1): 학습을 수행하기 위한 트레이너 객체를 생성합니다. max_epochs는 최대 학습 에포크(epoch) 수를 의미하고, num_gpus는 사용할 GPU 개수를 나타냅니다.
  • data = d2l.FashionMNIST(batch_size=128): FashionMNIST 데이터셋을 생성하고 배치 크기(batch_size)를 128로 설정합니다.
  • model = BNLeNet(lr=0.1): BNLeNet 모델을 생성하고, 학습률(learning rate)로 0.1을 설정합니다.
  • model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn): 모델의 파라미터들을 초기화합니다. data.get_dataloader(True)로부터 다음 배치를 가져와 모델의 초기화에 사용합니다.
  • trainer.fit(model, data): 앞서 생성한 트레이너를 사용하여 모델을 FashionMNIST 데이터셋으로 학습합니다. 학습은 최대 10 에포크 동안 진행됩니다.

이렇게 코드를 실행하면 BNLeNet 모델이 FashionMNIST 데이터셋으로 학습되고, 최대 10 에포크까지 학습이 진행됩니다. 학습이 끝나면 모델은 FashionMNIST 데이터셋의 분류 작업에 적용할 수 있습니다.

 

 

8.5.6. Discussion

Intuitively, batch normalization is thought to make the optimization landscape smoother. However, we must be careful to distinguish between speculative intuitions and true explanations for the phenomena that we observe when training deep models. Recall that we do not even know why simpler deep neural networks (MLPs and conventional CNNs) generalize well in the first place. Even with dropout and weight decay, they remain so flexible that their ability to generalize to unseen data likely needs significantly more refined learning-theoretic generalization guarantees.

 

직관적으로 배치 정규화는 최적화 환경을 더 매끄럽게 만드는 것으로 생각됩니다. 그러나 딥 모델을 훈련할 때 관찰하는 현상에 대한 추론적 직관과 참된 설명을 구별하는 데 주의해야 합니다. 더 간단한 심층 신경망(MLP 및 기존 CNN)이 처음부터 잘 일반화되는 이유조차 알지 못한다는 점을 상기하십시오. 드롭아웃 및 가중치 감소에도 불구하고 그들은 매우 유연하여 보이지 않는 데이터를 일반화하는 능력에는 훨씬 더 세련된 학습 이론 일반화 보장이 필요할 수 있습니다.

 

In the original paper proposing batch normalization (Ioffe and Szegedy, 2015), in addition to introducing a powerful and useful tool, offered an explanation for why it works: by reducing internal covariate shift. Presumably by internal covariate shift the authors meant something like the intuition expressed above—the notion that the distribution of variable values changes over the course of training. However, there were two problems with this explanation: i) This drift is very different from covariate shift, rendering the name a misnomer. If anything, it is closer to concept drift. ii) The explanation offers an under-specified intuition but leaves the question of why precisely this technique works an open question wanting for a rigorous explanation. Throughout this book, we aim to convey the intuitions that practitioners use to guide their development of deep neural networks. However, we believe that it is important to separate these guiding intuitions from established scientific fact. Eventually, when you master this material and start writing your own research papers you will want to be clear to delineate between technical claims and hunches.

 

배치 정규화를 제안하는 원본 논문(Ioffe and Szegedy, 2015)에서 강력하고 유용한 도구를 소개하는 것 외에도 내부 공변량 이동을 줄임으로써 작동하는 이유에 대한 설명을 제공했습니다. 아마도 내부 공변량 이동에 의해 저자는 위에서 표현된 직관과 같은 것을 의미했습니다. 즉, 변수 값의 분포가 훈련 과정에서 변경된다는 개념입니다. 그러나이 설명에는 두 가지 문제가 있습니다. i) 이 드리프트는 공변량 이동과 매우 다르기 때문에 이름이 잘못되었습니다. 오히려 개념 드리프트에 가깝다. ii) 설명은 덜 구체화된 직관을 제공하지만 정확히 이 기술이 작동하는 이유에 대한 질문을 엄격한 설명이 필요한 열린 질문으로 남겨 둡니다. 이 책 전체에서 우리는 실무자가 심층 신경망 개발을 안내하는 데 사용하는 직관을 전달하는 것을 목표로 합니다. 그러나 우리는 이러한 직관을 확립된 과학적 사실과 분리하는 것이 중요하다고 믿습니다. 결국, 이 자료를 마스터하고 자신의 연구 논문을 작성하기 시작할 때 기술적 주장과 직감을 명확하게 구분하고 싶을 것입니다.

 

Following the success of batch normalization, its explanation in terms of internal covariate shift has repeatedly surfaced in debates in the technical literature and broader discourse about how to present machine learning research. In a memorable speech given while accepting a Test of Time Award at the 2017 NeurIPS conference, Ali Rahimi used internal covariate shift as a focal point in an argument likening the modern practice of deep learning to alchemy. Subsequently, the example was revisited in detail in a position paper outlining troubling trends in machine learning (Lipton and Steinhardt, 2018). Other authors have proposed alternative explanations for the success of batch normalization, some claiming that batch normalization’s success comes despite exhibiting behavior that is in some ways opposite to those claimed in the original paper (Santurkar et al., 2018).

 

배치 정규화의 성공에 따라 내부 공변량 변화에 대한 설명이 기계 학습 연구를 제시하는 방법에 대한 기술 문헌 및 광범위한 담론에서 반복적으로 표면화되었습니다. 2017 NeurIPS 컨퍼런스에서 Test of Time Award를 수상하면서 기억에 남는 연설에서 Ali Rahimi는 딥 러닝의 현대적 관행을 연금술에 비유하는 논쟁에서 내부 공변량 이동을 초점으로 사용했습니다. 그 후, 기계 학습의 문제가 되는 추세를 요약한 입장 문서에서 이 예를 자세히 다시 검토했습니다(Lipton and Steinhardt, 2018). 다른 저자들은 배치 정규화의 성공에 대한 대안적인 설명을 제안했으며, 일부는 원래 논문에서 주장한 것과 반대되는 행동을 보임에도 불구하고 배치 정규화의 성공이 왔다고 주장했습니다(Santurkar et al., 2018).

 

We note that the internal covariate shift is no more worthy of criticism than any of thousands of similarly vague claims made every year in the technical machine learning literature. Likely, its resonance as a focal point of these debates owes to its broad recognizability to the target audience. Batch normalization has proven an indispensable method, applied in nearly all deployed image classifiers, earning the paper that introduced the technique tens of thousands of citations. We conjecture, though, that the guiding principles of regularization through noise injection, acceleration through rescaling and lastly preprocessing may well lead to further inventions of layers and techniques in the future.

 

우리는 내부 공변량 변화가 기술 기계 학습 문헌에서 매년 제기되는 유사하게 모호한 수천 건의 주장보다 더 이상 비판할 가치가 없다는 점에 주목합니다. 아마도 이러한 논쟁의 초점으로서의 공명은 대상 청중에 대한 광범위한 인식 가능성 때문일 것입니다. 배치 정규화는 배포된 거의 모든 이미지 분류기에 적용되는 필수적인 방법으로 입증되었으며, 이 기술을 소개한 논문은 수만 번 인용되었습니다. 그러나 잡음 주입을 통한 정규화, 크기 조정을 통한 가속 및 마지막으로 전처리의 기본 원리는 향후 레이어 및 기술의 추가 발명으로 이어질 수 있다고 추측합니다.

 

On a more practical note, there are a number of aspects worth remembering about batch normalization:

 

보다 실용적으로 배치 정규화에 대해 기억할 가치가 있는 여러 측면이 있습니다.

 

  • During model training, batch normalization continuously adjusts the intermediate output of the network by utilizing the mean and standard deviation of the minibatch, so that the values of the intermediate output in each layer throughout the neural network are more stable.
  • 모델 학습 중에 배치 정규화는 미니배치의 평균과 표준편차를 활용하여 네트워크의 중간 출력을 지속적으로 조정하여 신경망 전체의 각 계층의 중간 출력 값이 보다 안정적이 되도록 합니다.
  • Batch normalization for fully connected layers and convolutional layers are slightly different. In fact, for convolutional layers, layer normalization can sometimes be used as an alternative.
  • 완전 연결 계층과 컨벌루션 계층의 배치 정규화는 약간 다릅니다. 실제로 컨볼루션 레이어의 경우 레이어 정규화가 때때로 대안으로 사용될 수 있습니다.
  • Like a dropout layer, batch normalization layers have different behaviors in training mode and prediction mode.
  • 드롭아웃 레이어와 마찬가지로 배치 정규화 레이어는 훈련 모드와 예측 모드에서 서로 다른 동작을 합니다.
  • Batch normalization is useful for regularization and improving convergence in optimization. On the other hand, the original motivation of reducing internal covariate shift seems not to be a valid explanation.
  • 배치 정규화는 최적화에서 정규화 및 수렴 개선에 유용합니다. 반면에 내부 공변량 이동을 줄이려는 원래 동기는 유효한 설명이 아닌 것 같습니다.
  • For more robust models that are less sensitive to input perturbations, consider removing batch normalization (Wang et al., 2022).
  • 입력 섭동에 덜 민감한 보다 강력한 모델의 경우 배치 정규화를 제거하는 것이 좋습니다(Wang et al., 2022).

 

8.5.7. Exercises

  1. Should we remove the bias parameter from the fully connected layer or the convolutional layer before the batch normalization? Why?
  2. Compare the learning rates for LeNet with and without batch normalization.
    1. Plot the increase in validation accuracy.
    2. How large can you make the learning rate before the optimization fails in both cases?
  3. Do we need batch normalization in every layer? Experiment with it?
  4. Implement a “lite” version of batch normalization that only removes the mean, or alternatively one that only removes the variance. How does it behave?
  5. Fix the parameters beta and gamma. Observe and analyze the results.
  6. Can you replace dropout by batch normalization? How does the behavior change?
  7. Research ideas: think of other normalization transforms that you can apply:
    1. Can you apply the probability integral transform?
    2. Can you use a full rank covariance estimate? Why should you probably not do that?
    3. Can you use other compact matrix variants (block-diagonal, low-displacement rank, Monarch, etc.)?
    4. Does a sparsification compression act as a regularizer?
    5. Are there other projections (e.g., convex cone, symmetry group-specific transforms) that you can use?
반응형


반응형

https://d2l.ai/chapter_convolutional-modern/googlenet.html

 

8.4. Multi-Branch Networks (GoogLeNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

8.4. Multi-Branch Networks (GoogLeNet)

In 2014, GoogLeNet won the ImageNet Challenge (Szegedy et al., 2015), using a structure that combined the strengths of NiN (Lin et al., 2013), repeated blocks (Simonyan and Zisserman, 2014), and a cocktail of convolution kernels. It is arguably also the first network that exhibits a clear distinction among the stem (data ingest), body (data processing), and head (prediction) in a CNN. This design pattern has persisted ever since in the design of deep networks: the stem is given by the first 2–3 convolutions that operate on the image. They extract low-level features from the underlying images. This is followed by a body of convolutional blocks. Finally, the head maps the features obtained so far to the required classification, segmentation, detection, or tracking problem at hand.
 
2014년 GoogLeNet은 NiN과(Lin et al., 2013), repeated blocks(Simonyan and Zisserman, 2014) 그리고 convolution kernels의 cocktail 을 결합한 구조를 사용하여 ImageNet Challenge(Szegedy et al., 2015)에서 우승했습니다. 또한 CNN에서 stem (data ingest), body (data processing)head (prediction) 간에 명확한 구분을 나타내는 최초의 네트워크이기도 합니다. 이 디자인 패턴은 딥 네트워크의 디자인 이후로 지속되어 왔습니다. 스템은 이미지에서 작동하는 처음 2-3개의 컨볼루션에 의해 제공됩니다. 기본 이미지에서 낮은 수준의 기능을 추출합니다. 그 다음에는 컨볼루션 블록의 본문이 이어집니다. 마지막으로, 헤드는 지금까지 얻은 기능을 당면한 필요한 분류, 세분화, 감지 또는 추적 문제에 매핑합니다.

The key contribution in GoogLeNet was the design of the network body. It solved the problem of selecting convolution kernels in an ingenious way. While other works tried to identify which convolution, ranging from 1×1 to 11×11 would be best, it simply concatenated multi-branch convolutions. In what follows we introduce a slightly simplified version of GoogLeNet: the original design included a number of tricks to stabilize training through intermediate loss functions, applied to multiple layers of the network. They are no longer necessary due to the availability of improved training algorithms.

 

GoogLeNet의 주요 기여는 design of the network body였습니다. 컨볼루션 커널을 선택하는 문제를 기발한 방식으로 해결했습니다. 다른 작업에서는 1×1에서 11×11까지 어떤 컨볼루션이 가장 좋은지 식별하려고 시도했지만 단순히 다중 분기 컨볼루션을 연결했습니다. 다음에서 우리는 GoogLeNet의 약간 단순화된 버전을 소개합니다. 원래 설계에는 네트워크의 여러 계층에 적용된 중간 손실 함수를 통해 훈련을 안정화하는 여러 트릭이 포함되었습니다. 개선된 훈련 알고리즘의 가용성으로 인해 더 이상 필요하지 않습니다.

 

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

위 코드는 PyTorch와 d2l 패키지로부터 필요한 모듈을 불러오는 코드입니다. 각 라인별로 설명하겠습니다:

  1. import torch: PyTorch 패키지를 불러옵니다. 이를 통해 텐서 연산과 딥러닝 모델 구축을 위한 다양한 기능을 사용할 수 있습니다.
  2. from torch import nn: PyTorch의 nn 모듈을 불러옵니다. 이는 딥러닝 모델을 구성하기 위한 다양한 레이어와 손실 함수 등을 포함하고 있습니다.
  3. from torch.nn import functional as F: PyTorch의 functional 모듈을 불러옵니다. 이 모듈은 활성화 함수, 손실 함수 등과 같은 기능들을 포함하고 있습니다. 여기서는 F라는 이름으로 모듈을 불러왔습니다.
  4. from d2l import torch as d2l: d2l 패키지에서 torch를 불러옵니다. d2l은 "Dive into Deep Learning" 책의 코드 예제를 제공하는 패키지입니다. 이를 통해 책의 예제 코드들을 사용할 수 있습니다.

https://youtu.be/xHgGtnef9mA

 

https://youtu.be/05PCt_JFc84

https://youtu.be/zCagtR4xLMg

https://youtu.be/W9MlakX3vko

Google net : Inception Block (Inception Modul)을 이해 해야 함

Inception Module 개념으로 깊은 네트워크에서도 비교적 적은 파라미터를 사용할 수 있도록 함 => 모델 성능 향상

1*1 Conv : 연산량을 줄이기 위해 사용함

Auxiliary Classifiers : Layer 가 깊어질수록 Vanishing Gradient 가 나올 가능성이 커짐 => 중간중간 Backprapagate를 해서 Gradient를 보관 함

2014년도에 VGG가 2등 GoogLeNet이 1등을 함 (MSRA가 3등): VGG가 feature를 만드는데 강점이 있다는 평가가 있어서 더 많이 사용함

 

https://youtu.be/_POOiiV0_3I

8.4.1. Inception Blocks

 

The basic convolutional block in GoogLeNet is called an Inception block, stemming from the meme “we need to go deeper” of the movie Inception.

 

GoogLeNet의 basic convolutional block은 영화 인셉션의 "우리는 더 깊이 들어가야 합니다"라는 밈에서 유래한 인셉션 블록이라고 합니다.

 

Fig. 8.4.1&nbsp; Structure of the Inception block. &para;

 

 

As depicted in Fig. 8.4.1, the inception block consists of four parallel branches. The first three branches use convolutional layers with window sizes of 1×1, 3×3, and 5×5 to extract information from different spatial sizes. The middle two branches also add a 1×1 convolution of the input to reduce the number of channels, reducing the model’s complexity. The fourth branch uses a 3×3 max-pooling layer, followed by a 1×1 convolutional layer to change the number of channels. The four branches all use appropriate padding to give the input and output the same height and width. Finally, the outputs along each branch are concatenated along the channel dimension and comprise the block’s output. The commonly-tuned hyperparameters of the Inception block are the number of output channels per layer, i.e., how to allocate capacity among convolutions of different size.

 

그림 8.4.1과 같이 시작 블록은 4개의 병렬 분기로 구성됩니다. 처음 세 가지 분기는 1×1, 3×3 및 5×5의 창 크기를 가진 컨벌루션 레이어를 사용하여 서로 다른 공간 크기에서 정보를 추출합니다. 가운데 두 가지도 채널 수를 줄이기 위해 입력의 1×1 컨벌루션을 추가하여 모델의 복잡성을 줄입니다. 네 번째 브랜치는 3×3 최대 풀링 레이어를 사용하고 채널 수를 변경하기 위해 1×1 컨벌루션 레이어를 사용합니다. 네 가지 모두 적절한 패딩을 사용하여 입력과 출력에 동일한 높이와 너비를 제공합니다. 마지막으로 각 분기의 출력은 채널 차원을 따라 연결되며 블록의 출력을 구성합니다. Inception 블록의 일반적으로 튜닝되는 하이퍼파라미터는 레이어당 출력 채널 수, 즉 크기가 다른 컨볼루션 간에 용량을 할당하는 방법입니다.

 

class Inception(nn.Module):
    # c1--c4 are the number of output channels for each branch
    def __init__(self, c1, c2, c3, c4, **kwargs):
        super(Inception, self).__init__(**kwargs)
        # Branch 1
        self.b1_1 = nn.LazyConv2d(c1, kernel_size=1)
        # Branch 2
        self.b2_1 = nn.LazyConv2d(c2[0], kernel_size=1)
        self.b2_2 = nn.LazyConv2d(c2[1], kernel_size=3, padding=1)
        # Branch 3
        self.b3_1 = nn.LazyConv2d(c3[0], kernel_size=1)
        self.b3_2 = nn.LazyConv2d(c3[1], kernel_size=5, padding=2)
        # Branch 4
        self.b4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
        self.b4_2 = nn.LazyConv2d(c4, kernel_size=1)

    def forward(self, x):
        b1 = F.relu(self.b1_1(x))
        b2 = F.relu(self.b2_2(F.relu(self.b2_1(x))))
        b3 = F.relu(self.b3_2(F.relu(self.b3_1(x))))
        b4 = F.relu(self.b4_2(self.b4_1(x)))
        return torch.cat((b1, b2, b3, b4), dim=1)

위 코드는 Inception 블록을 정의하는 클래스인 Inception을 구현한 것입니다. 이 블록은 GoogLeNet 네트워크에 사용되며, 다양한 크기의 커널을 사용하여 다양한 방향의 특징을 추출하는 것을 목표로 합니다. 코드를 각 라인별로 설명하겠습니다:

  1. class Inception(nn.Module):: nn.Module을 상속하여 Inception 클래스를 정의합니다. 이 클래스는 PyTorch의 모듈로 사용자 정의 모델을 구현하는데 사용됩니다.
  2. def __init__(self, c1, c2, c3, c4, **kwargs):: Inception 클래스의 생성자입니다. 다양한 파라미터를 입력으로 받습니다. c1, c2, c3, c4는 각각 브랜치의 출력 채널 수를 나타내는 파라미터입니다. **kwargs는 추가적인 키워드 인수를 받는 매개변수입니다.
  3. super(Inception, self).__init__(**kwargs): 상위 클래스의 생성자를 호출하여 초기화합니다.
  4. self.b1_1 = nn.LazyConv2d(c1, kernel_size=1): 첫 번째 브랜치를 정의합니다. 1x1 커널을 사용하는 합성곱 레이어를 정의합니다.
  5. self.b2_1 = nn.LazyConv2d(c2[0], kernel_size=1): 두 번째 브랜치의 첫 번째 레이어를 정의합니다. 1x1 커널을 사용하는 합성곱 레이어를 정의합니다.
  6. self.b2_2 = nn.LazyConv2d(c2[1], kernel_size=3, padding=1): 두 번째 브랜치의 두 번째 레이어를 정의합니다. 3x3 커널을 사용하는 합성곱 레이어를 정의합니다.
  7. self.b3_1 = nn.LazyConv2d(c3[0], kernel_size=1): 세 번째 브랜치의 첫 번째 레이어를 정의합니다. 1x1 커널을 사용하는 합성곱 레이어를 정의합니다.
  8. self.b3_2 = nn.LazyConv2d(c3[1], kernel_size=5, padding=2): 세 번째 브랜치의 두 번째 레이어를 정의합니다. 5x5 커널을 사용하는 합성곱 레이어를 정의합니다.
  9. self.b4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1): 네 번째 브랜치의 첫 번째 레이어를 정의합니다. 3x3 최대 풀링 레이어를 정의합니다.
  10. self.b4_2 = nn.LazyConv2d(c4, kernel_size=1): 네 번째 브랜치의 두 번째 레이어를 정의합니다. 1x1 커널을 사용하는 합성곱 레이어를 정의합니다.
  11. def forward(self, x):: forward 메서드를 정의합니다. 이는 모델을 통과할 때 호출되는 메서드입니다.
  12. b1 = F.relu(self.b1_1(x)): 첫 번째 브랜치의 계산을 수행합니다. 입력 x를 1x1 커널을 사용하는 합성곱 레이어를 통과시키고 ReLU 활성화 함수를 적용합니다.
  13. b2 = F.relu(self.b2_2(F.relu(self.b2_1(x)))): 두 번째 브랜치의 계산을 수행합니다. 입력 x를 먼저 1x1 커널을 사용하는 합
  14. b3 = F.relu(self.b3_2(F.relu(self.b3_1(x)))): 세 번째 브랜치의 계산을 수행합니다. 입력 x를 먼저 1x1 커널을 사용하는 합성곱 레이어를 통과시키고 ReLU 활성화 함수를 적용합니다. 그리고 이를 5x5 커널을 사용하는 합성곱 레이어를 통과시키고 다시 ReLU 활성화 함수를 적용합니다.
  15. b4 = F.relu(self.b4_2(self.b4_1(x))): 네 번째 브랜치의 계산을 수행합니다. 입력 x를 먼저 3x3 최대 풀링 레이어를 통과시킵니다. 그리고 이를 1x1 커널을 사용하는 합성곱 레이어를 통과시키고 다시 ReLU 활성화 함수를 적용합니다.
  16. return torch.cat((b1, b2, b3, b4), dim=1): 네 개의 브랜치를 합칩니다. 이를 위해 torch.cat 함수를 사용하여 네 개의 브랜치를 차원 1을 따라 연결합니다. 이렇게 하여 Inception 블록의 출력이 반환됩니다.

 

To gain some intuition for why this network works so well, consider the combination of the filters. They explore the image in a variety of filter sizes. This means that details at different extents can be recognized efficiently by filters of different sizes. At the same time, we can allocate different amounts of parameters for different filters.

 

이 네트워크가 잘 작동하는 이유에 대한 직관을 얻으려면 필터 조합을 고려하십시오. 다양한 필터 크기로 이미지를 탐색합니다. 즉, 다양한 크기의 필터를 통해 다양한 범위의 세부 정보를 효율적으로 인식할 수 있습니다. 동시에 서로 다른 필터에 서로 다른 양의 매개 변수를 할당할 수 있습니다.

 

8.4.2. GoogLeNet Model

As shown in Fig. 8.4.2, GoogLeNet uses a stack of a total of 9 inception blocks, arranged into 3 groups with max-pooling in between, and global average pooling in its head to generate its estimates. Max-pooling between inception blocks reduces the dimensionality. At its stem, the first module is similar to AlexNet and LeNet.

 

8.4. Multi-Branch Networks (GoogLeNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

그림 8.4.2에서 볼 수 있듯이 GoogLeNet은 총 9개의 시작 블록 스택을 사용하여 3개의 그룹으로 배열하고 그 사이에 max-pooling을 사용하고 헤드에서 global average pooling을 사용하여 추정치를 생성합니다. 시작 블록 간의 최대 풀링은 차원을 줄입니다. 줄기에서 첫 번째 모듈은 AlexNet 및 LeNet과 유사합니다.

 

Fig. 8.4.2&nbsp; The GoogLeNet architecture.

We can now implement GoogLeNet piece by piece. Let’s begin with the stem. The first module uses a 64-channel 7×7 convolutional layer.

 

이제 하나씩 GoogLeNet을 구현할 수 있습니다. 줄기부터 시작합시다. 첫 번째 모듈은 64채널 7×7 컨벌루션 레이어를 사용합니다.

 

class GoogleNet(d2l.Classifier):
    def b1(self):
        return nn.Sequential(
            nn.LazyConv2d(64, kernel_size=7, stride=2, padding=3),
            nn.ReLU(), nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

위 코드는 GoogLeNet(구글넷)이라는 딥러닝 아키텍처를 구현하는 클래스인 GoogleNet을 정의한 것입니다. 코드를 각 라인별로 설명하겠습니다.

  1. class GoogleNet(d2l.Classifier):: GoogleNet 클래스를 정의하고, d2l.Classifier를 상속하여 사용자 정의 분류기 클래스를 만듭니다.
  2. def b1(self):: b1이라는 함수를 정의합니다. 이 함수는 GoogLeNet의 첫 번째 브랜치를 정의하는 역할을 합니다.
  3. return nn.Sequential(...) : 여러 모듈을 순차적으로 쌓아서 신경망을 정의하는 nn.Sequential 클래스를 반환합니다.
  4. nn.LazyConv2d(64, kernel_size=7, stride=2, padding=3): 7x7 크기의 커널을 사용하는 합성곱 레이어를 정의합니다. 입력 채널 수는 64이며, 스트라이드는 2이고, 패딩은 3입니다.
  5. nn.ReLU(): ReLU 활성화 함수를 정의합니다.
  6. nn.MaxPool2d(kernel_size=3, stride=2, padding=1): 3x3 크기의 최대 풀링 레이어를 정의합니다. 스트라이드는 2이고, 패딩은 1입니다.

이렇게 정의된 b1 함수는 GoogLeNet 아키텍처의 첫 번째 브랜치를 정의하는데 사용됩니다.

 

The second module uses two convolutional layers: first, a 64-channel 1×1 convolutional layer, followed by a 3×3 convolutional layer that triples the number of channels. This corresponds to the second branch in the Inception block and concludes the design of the body. At this point we have 192 channels.

 

두 번째 모듈은 두 개의 컨볼루션 레이어를 사용합니다. 첫 번째는 64채널 1×1 컨볼루션 레이어이고 그 다음에는 채널 수를 세 배로 늘리는 3×3 컨볼루션 레이어가 있습니다. 이것은 Inception 블록의 두 번째 분기에 해당하며 본체 디자인을 마칩니다. 현재 192개의 채널이 있습니다.

 

@d2l.add_to_class(GoogleNet)
def b2(self):
    return nn.Sequential(
        nn.LazyConv2d(64, kernel_size=1), nn.ReLU(),
        nn.LazyConv2d(192, kernel_size=3, padding=1), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

위 코드는 GoogleNet 클래스에 새로운 메서드 b2를 추가하는 부분입니다. 코드를 각 라인별로 설명하겠습니다.

  1. @d2l.add_to_class(GoogleNet): 데코레이터를 사용하여 GoogleNet 클래스에 새로운 메서드를 추가합니다.
  2. def b2(self):: b2라는 함수를 정의합니다. 이 함수는 GoogLeNet의 두 번째 브랜치를 정의하는 역할을 합니다.
  3. return nn.Sequential(...) : 여러 모듈을 순차적으로 쌓아서 신경망을 정의하는 nn.Sequential 클래스를 반환합니다.
  4. nn.LazyConv2d(64, kernel_size=1): 1x1 크기의 커널을 사용하는 합성곱 레이어를 정의합니다. 입력 채널 수는 64입니다.
  5. nn.ReLU(): ReLU 활성화 함수를 정의합니다.
  6. nn.LazyConv2d(192, kernel_size=3, padding=1): 3x3 크기의 커널을 사용하는 합성곱 레이어를 정의합니다. 입력 채널 수는 192이며, 패딩은 1입니다.
  7. nn.ReLU(): ReLU 활성화 함수를 정의합니다.
  8. nn.MaxPool2d(kernel_size=3, stride=2, padding=1): 3x3 크기의 최대 풀링 레이어를 정의합니다. 스트라이드는 2이고, 패딩은 1입니다.

이렇게 정의된 b2 함수는 GoogLeNet 아키텍처의 두 번째 브랜치를 정의하는데 사용됩니다.

 

The third module connects two complete Inception blocks in series. The number of output channels of the first Inception block is 64+128+32+32=256. This amounts to a ratio of the number of output channels among the four branches of 2:4:1:1. Achieving this, we first reduce the input dimensions by 1/2 and by 1/12 in the second and third branch respectively to arrive at 96=192/2 and 16=192/12 channels respectively.

 

세 번째 모듈은 두 개의 완전한 Inception 블록을 직렬로 연결합니다. 첫 번째 Inception 블록의 출력 채널 수는 64+128+32+32=256입니다. 이는 2:4:1:1의 4개 분기 중 출력 채널 수의 비율에 해당합니다. 이를 달성하기 위해 먼저 입력 크기를 두 번째 및 세 번째 분기에서 각각 1/2 및 1/12씩 줄여 각각 96=192/2 및 16=192/12 채널에 도달합니다.

 

The number of output channels of the second Inception block is increased to 128+192+96+64=480, yielding a ratio of 128:192:96:64=4:6:3:2. As before, we need to reduce the number of intermediate dimensions in the second and third channel. A scale of 1/2 and 1/8 respectively suffices, yielding 128 and 32 channels respectively. This is captured by the arguments of the following Inception block constructors.

 

두 번째 인셉션 블록의 출력 채널 수는 128+192+96+64=480으로 증가하여 128:192:96:64=4:6:3:2 비율이 됩니다. 이전과 마찬가지로 두 번째 및 세 번째 채널에서 중간 차원의 수를 줄여야 합니다. 각각 1/2 및 1/8 스케일이면 충분하며 각각 128 및 32 채널이 생성됩니다. 이것은 다음 Inception 블록 생성자의 인수에 의해 캡처됩니다.

 

@d2l.add_to_class(GoogleNet)
def b3(self):
    return nn.Sequential(Inception(64, (96, 128), (16, 32), 32),
                         Inception(128, (128, 192), (32, 96), 64),
                         nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

위 코드는 GoogleNet 클래스에 새로운 메서드 b3를 추가하는 부분입니다. 코드를 각 라인별로 설명하겠습니다.

  1. @d2l.add_to_class(GoogleNet): 데코레이터를 사용하여 GoogleNet 클래스에 새로운 메서드를 추가합니다.
  2. def b3(self):: b3라는 함수를 정의합니다. 이 함수는 GoogLeNet의 세 번째 브랜치를 정의하는 역할을 합니다.
  3. return nn.Sequential(...) : 여러 모듈을 순차적으로 쌓아서 신경망을 정의하는 nn.Sequential 클래스를 반환합니다.
  4. Inception(64, (96, 128), (16, 32), 32): 앞서 정의한 Inception 클래스를 사용하여 인셉션 블록을 정의합니다. 이 블록은 각각 64개, (96, 128)개, (16, 32)개, 32개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  5. Inception(128, (128, 192), (32, 96), 64): 앞서 정의한 Inception 클래스를 사용하여 또 다른 인셉션 블록을 정의합니다. 이 블록은 각각 128개, (128, 192)개, (32, 96)개, 64개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  6. nn.MaxPool2d(kernel_size=3, stride=2, padding=1): 3x3 크기의 최대 풀링 레이어를 정의합니다. 스트라이드는 2이고, 패딩은 1입니다.

이렇게 정의된 b3 함수는 GoogLeNet 아키텍처의 세 번째 브랜치를 정의하는데 사용됩니다. 이 브랜치는 두 개의 인셉션 블록으로 시작하고, 그 후에 최대 풀링 레이어로 마무리됩니다.

 

The fourth module is more complicated. It connects five Inception blocks in series, and they have 192+208+48+64=512, 160+224+64+64=512, 128+256+64+64=512, 112+288+64+64=528, and 256+320+128+128=832 output channels, respectively. The number of channels assigned to these branches is similar to that in the third module: the second branch with the 3×3 convolutional layer outputs the largest number of channels, followed by the first branch with only the 1×1 convolutional layer, the third branch with the 5×5 convolutional layer, and the fourth branch with the 3×3 max-pooling layer. The second and third branches will first reduce the number of channels according to the ratio. These ratios are slightly different in different Inception blocks.

 

네 번째 모듈은 더 복잡합니다. 5개의 인셉션 블록을 직렬로 연결하여 192+208+48+64=512, 160+224+64+64=512, 128+256+64+64=512, 112+288+64+64=528 , 및 256+320+128+128=832 출력 채널. 이 가지에 할당된 채널의 수는 세 번째 모듈과 비슷합니다. 3×3 컨볼루션 레이어가 있는 두 번째 브랜치가 가장 많은 수의 채널을 출력하고 그 다음으로 1×1 컨볼루션 레이어만 있는 첫 번째 브랜치가 출력하고 세 번째 5×5 컨벌루션 레이어가 있는 분기, 3×3 최대 풀링 레이어가 있는 네 번째 분기. 두 번째 및 세 번째 분기는 먼저 비율에 따라 채널 수를 줄입니다. 이 비율은 다른 시작 블록에서 약간 다릅니다.

 

@d2l.add_to_class(GoogleNet)
def b4(self):
    return nn.Sequential(Inception(192, (96, 208), (16, 48), 64),
                         Inception(160, (112, 224), (24, 64), 64),
                         Inception(128, (128, 256), (24, 64), 64),
                         Inception(112, (144, 288), (32, 64), 64),
                         Inception(256, (160, 320), (32, 128), 128),
                         nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

위 코드는 GoogleNet 클래스에 새로운 메서드 b4를 추가하는 부분입니다. 코드를 각 라인별로 설명하겠습니다.

  1. @d2l.add_to_class(GoogleNet): 데코레이터를 사용하여 GoogleNet 클래스에 새로운 메서드를 추가합니다.
  2. def b4(self):: b4라는 함수를 정의합니다. 이 함수는 GoogLeNet의 네 번째 브랜치를 정의하는 역할을 합니다.
  3. return nn.Sequential(...) : 여러 모듈을 순차적으로 쌓아서 신경망을 정의하는 nn.Sequential 클래스를 반환합니다.
  4. Inception(192, (96, 208), (16, 48), 64): 앞서 정의한 Inception 클래스를 사용하여 인셉션 블록을 정의합니다. 이 블록은 각각 192개, (96, 208)개, (16, 48)개, 64개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  5. Inception(160, (112, 224), (24, 64), 64): 앞서 정의한 Inception 클래스를 사용하여 또 다른 인셉션 블록을 정의합니다. 이 블록은 각각 160개, (112, 224)개, (24, 64)개, 64개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  6. Inception(128, (128, 256), (24, 64), 64): 앞서 정의한 Inception 클래스를 사용하여 또 다른 인셉션 블록을 정의합니다. 이 블록은 각각 128개, (128, 256)개, (24, 64)개, 64개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  7. Inception(112, (144, 288), (32, 64), 64): 앞서 정의한 Inception 클래스를 사용하여 또 다른 인셉션 블록을 정의합니다. 이 블록은 각각 112개, (144, 288)개, (32, 64)개, 64개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  8. Inception(256, (160, 320), (32, 128), 128): 앞서 정의한 Inception 클래스를 사용하여 또 다른 인셉션 블록을 정의합니다. 이 블록은 각각 256개, (160, 320)개, (32, 128)개, 128개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  9. nn.MaxPool2d(kernel_size=3, stride=2, padding=1): 3x3 크기의 최대 풀링 레이어를 정의합니다. 스트라이드는 2이고, 패딩은 1입니다.

이렇게 정의된 b4 함수는 GoogLeNet 아키텍처의 네 번째 브랜치를 정의하는데 사용됩니다. 이 브랜치는 다섯 개의 인셉션 블록으로 시작하고, 그 후에 최대 풀링 레이어로 마무리됩니다.

 

 

The fifth module has two Inception blocks with 256+320+128+128=832 and 384+384+128+128=1024 output channels. The number of channels assigned to each branch is the same as that in the third and fourth modules, but differs in specific values. It should be noted that the fifth block is followed by the output layer. This block uses the global average pooling layer to change the height and width of each channel to 1, just as in NiN. Finally, we turn the output into a two-dimensional array followed by a fully connected layer whose number of outputs is the number of label classes.

 

다섯 번째 모듈에는 256+320+128+128=832 및 384+384+128+128=1024 출력 채널이 있는 두 개의 Inception 블록이 있습니다. 각 분기에 할당된 채널 수는 세 번째 및 네 번째 모듈과 동일하지만 세부적인 값이 다릅니다. 다섯 번째 블록 다음에는 출력 레이어가 옵니다. 이 블록은 전역 평균 풀링 계층을 사용하여 NiN에서와 마찬가지로 각 채널의 높이와 너비를 1로 변경합니다. 마지막으로 출력을 2차원 배열로 변환한 다음 출력 수가 레이블 클래스의 수인 완전 연결 계층으로 전환합니다.

 

@d2l.add_to_class(GoogleNet)
def b5(self):
    return nn.Sequential(Inception(256, (160, 320), (32, 128), 128),
                         Inception(384, (192, 384), (48, 128), 128),
                         nn.AdaptiveAvgPool2d((1,1)), nn.Flatten())

위 코드는 GoogleNet 클래스에 새로운 메서드 b5를 추가하는 부분입니다. 코드를 각 라인별로 설명하겠습니다.

  1. @d2l.add_to_class(GoogleNet): 데코레이터를 사용하여 GoogleNet 클래스에 새로운 메서드를 추가합니다.
  2. def b5(self):: b5라는 함수를 정의합니다. 이 함수는 GoogLeNet의 다섯 번째 브랜치를 정의하는 역할을 합니다.
  3. return nn.Sequential(...) : 여러 모듈을 순차적으로 쌓아서 신경망을 정의하는 nn.Sequential 클래스를 반환합니다.
  4. Inception(256, (160, 320), (32, 128), 128): 앞서 정의한 Inception 클래스를 사용하여 인셉션 블록을 정의합니다. 이 블록은 각각 256개, (160, 320)개, (32, 128)개, 128개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  5. Inception(384, (192, 384), (48, 128), 128): 앞서 정의한 Inception 클래스를 사용하여 또 다른 인셉션 블록을 정의합니다. 이 블록은 각각 384개, (192, 384)개, (48, 128)개, 128개의 출력 채널을 가지는 네 가지 합성곱 레이어로 구성됩니다.
  6. nn.AdaptiveAvgPool2d((1,1)): 입력 텐서의 크기를 (1,1)로 자동으로 조정하는 전역 평균 풀링 레이어를 정의합니다. 이렇게 하면 출력 텐서의 크기는 항상 (1,1)이 됩니다.
  7. nn.Flatten(): 2D 입력 텐서를 1D로 펼치는 레이어입니다. 이를 통해 텐서를 신경망의 완전 연결 레이어에 입력으로 사용할 수 있게 됩니다.

이렇게 정의된 b5 함수는 GoogLeNet 아키텍처의 다섯 번째 브랜치를 정의하는데 사용됩니다. 이 브랜치는 두 개의 인셉션 블록으로 시작하고, 그 후에 전역 평균 풀링 레이어와 펼치기 레이어로 마무리됩니다.

 

Now that we defined all blocks b1 through b5, it is just a matter of assembling them all into a full network.

 

이제 b1에서 b5까지 모든 블록을 정의했으므로 전체 네트워크로 모두 조립하는 문제입니다.

 

@d2l.add_to_class(GoogleNet)
def __init__(self, lr=0.1, num_classes=10):
    super(GoogleNet, self).__init__()
    self.save_hyperparameters()
    self.net = nn.Sequential(self.b1(), self.b2(), self.b3(), self.b4(),
                             self.b5(), nn.LazyLinear(num_classes))
    self.net.apply(d2l.init_cnn)

위 코드는 GoogleNet 클래스에 새로운 __init__ 메서드를 추가하는 부분입니다. 코드를 각 라인별로 설명하겠습니다.

  1. @d2l.add_to_class(GoogleNet): 데코레이터를 사용하여 GoogleNet 클래스에 새로운 메서드를 추가합니다.
  2. def __init__(self, lr=0.1, num_classes=10):: 새로운 __init__ 메서드를 정의합니다. 이 메서드는 GoogleNet 클래스의 인스턴스를 초기화하는 역할을 합니다. lr은 학습률을 설정하는 매개변수이며, num_classes는 분류할 클래스의 수를 나타내는 매개변수입니다.
  3. super(GoogleNet, self).__init__(): 상위 클래스인 nn.Module의 __init__ 메서드를 호출하여 부모 클래스의 초기화 메서드를 실행합니다. 이를 통해 GoogleNet 클래스는 nn.Module 클래스의 속성과 메서드를 상속받습니다.
  4. self.save_hyperparameters(): d2l.Classifier의 메서드인 save_hyperparameters를 호출하여 현재 클래스의 하이퍼파라미터를 저장합니다. 이를 통해 모델을 저장하거나 로드할 때 하이퍼파라미터 값을 기억할 수 있습니다.
  5. self.net = nn.Sequential(self.b1(), self.b2(), self.b3(), self.b4(), self.b5(), nn.LazyLinear(num_classes)): GoogLeNet의 신경망 아키텍처를 정의합니다. nn.Sequential을 사용하여 각 블록을 순차적으로 쌓아서 전체 네트워크를 구성합니다. self.b1(), self.b2(), self.b3(), self.b4(), self.b5()는 앞서 정의한 메서드로, 각각 GoogLeNet의 다섯 번째 브랜치까지의 블록을 정의하는 역할을 합니다.
  6. self.net.apply(d2l.init_cnn): 이전에 정의한 d2l.init_cnn 함수를 사용하여 신경망의 모든 가중치를 초기화합니다.

위 코드에서 GoogleNet 클래스는 GoogLeNet 아키텍처를 정의하는데 사용됩니다. b1, b2, b3, b4, b5 메서드를 사용하여 각 브랜치의 블록을 정의하고, 이를 nn.Sequential을 이용하여 순차적으로 결합하여 전체 네트워크를 생성합니다. 그리고 d2l.init_cnn 함수를 사용하여 모든 가중치를 초기화합니다. 이렇게 정의된 GoogleNet 클래스를 사용하여 학습하거나 추론을 수행할 수 있습니다.

 

The GoogLeNet model is computationally complex. Note the large number of relatively arbitrary hyperparameters in terms of the number of channels chosen, the number of blocks prior to dimensionality reduction, the relative partitioning of capacity across channels, etc. Much of it is due to the fact that at the time when GoogLeNet was introduced, automatic tools for network definition or design exploration were not yet available. For instance, by now we take it for granted that a competent deep learning framework is capable of inferring dimensionalities of input tensors automatically. At the time, many such configurations had to be specified explicitly by the experimenter, thus often slowing down active experimentation. Moreover, the tools needed for automatic exploration were still in flux and initial experiments largely amounted to costly brute force exploration, genetic algorithms, and similar strategies.

 

GoogLeNet 모델은 계산적으로 복잡합니다. 선택된 채널 수, 차원 감소 이전의 블록 수, 채널 간 용량의 상대적 분할 등과 관련하여 상대적으로 임의적인 하이퍼파라미터가 많다는 점에 유의하십시오. 대부분은 GoogLeNet이 네트워크 정의 또는 설계 탐색을 위한 자동 도구는 아직 사용할 수 없었습니다. 예를 들어, 이제 우리는 유능한 딥 러닝 프레임워크가 입력 텐서의 차원을 자동으로 추론할 수 있다는 것을 당연하게 여깁니다. 그 당시에는 이러한 많은 구성을 실험자가 명시적으로 지정해야 했기 때문에 활성 실험 속도가 느려지는 경우가 많았습니다. 더욱이 자동 탐사에 필요한 도구는 여전히 유동적이었고 초기 실험은 대부분 비용이 많이 드는 무차별 탐색, 유전 알고리즘 및 유사한 전략에 달했습니다.

 

For now the only modification we will carry out is to reduce the input height and width from 224 to 96 to have a reasonable training time on Fashion-MNIST. This simplifies the computation. Let’s have a look at the changes in the shape of the output between the various modules.

 

지금 우리가 수행할 유일한 수정은 Fashion-MNIST에서 합리적인 훈련 시간을 갖기 위해 입력 높이와 너비를 224에서 96으로 줄이는 것입니다. 이것은 계산을 단순화합니다. 다양한 모듈 간의 출력 형태 변화를 살펴보겠습니다.

 

model = GoogleNet().layer_summary((1, 1, 96, 96))

위 코드는 GoogleNet 모델을 생성하고, layer_summary 메서드를 사용하여 모델의 각 레이어의 출력 크기를 확인하는 부분입니다. 코드를 각 라인별로 설명하겠습니다.

  1. model = GoogleNet(): GoogleNet 클래스의 인스턴스인 model을 생성합니다. 이를 통해 GoogLeNet 모델을 초기화합니다.
  2. model.layer_summary((1, 1, 96, 96)): 이전에 생성한 model을 사용하여 layer_summary 메서드를 호출합니다. 이 메서드는 모델의 입력 데이터 크기를 (1, 1, 96, 96)로 설정한 뒤, 각 레이어의 출력 크기를 출력합니다. 이렇게 하면 모델의 각 레이어에서 데이터가 어떻게 변화하는지를 확인할 수 있습니다.

이 코드를 실행하면 GoogLeNet 모델의 각 레이어의 출력 크기가 출력되게 됩니다. 이를 통해 모델의 구조를 이해하고 입력 데이터가 어떻게 변화하는지를 쉽게 파악할 수 있습니다.

Sequential output shape:     torch.Size([1, 64, 24, 24])
Sequential output shape:     torch.Size([1, 192, 12, 12])
Sequential output shape:     torch.Size([1, 480, 6, 6])
Sequential output shape:     torch.Size([1, 832, 3, 3])
Sequential output shape:     torch.Size([1, 1024])
Linear output shape:         torch.Size([1, 10])

 

8.4.3. Training

As before, we train our model using the Fashion-MNIST dataset. We transform it to 96×96 pixel resolution before invoking the training procedure.

 

이전과 마찬가지로 Fashion-MNIST 데이터 세트를 사용하여 모델을 훈련합니다. 학습 절차를 호출하기 전에 96×96 픽셀 해상도로 변환합니다.

 

model = GoogleNet(lr=0.01)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(96, 96))
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

위 코드는 GoogleNet 모델을 생성하고 학습시키는 부분으로, 각 라인별로 설명하겠습니다.

  1. model = GoogleNet(lr=0.01): GoogleNet 클래스의 인스턴스인 model을 생성합니다. 이때 학습률 lr을 0.01로 설정하여 생성합니다.
  2. trainer = d2l.Trainer(max_epochs=10, num_gpus=1): d2l.Trainer 클래스의 인스턴스인 trainer를 생성합니다. max_epochs는 최대 학습 에폭 수를 10으로 설정하고, num_gpus는 사용할 GPU 수를 1로 설정합니다.
  3. data = d2l.FashionMNIST(batch_size=128, resize=(96, 96)): FashionMNIST 데이터셋을 로드하여 data 변수에 저장합니다. 배치 크기는 128로 설정하고, 이미지 크기를 96x96 픽셀로 변환합니다.
  4. model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn): 모델을 초기화합니다. 이때 첫 번째 미니배치 데이터를 사용하여 모델 파라미터를 초기화합니다. d2l.init_cnn은 모델 파라미터를 초기화하는 함수입니다.
  5. trainer.fit(model, data): 모델을 학습합니다. trainer를 사용하여 데이터셋 data로부터 모델 model을 학습시킵니다.

위 코드를 실행하면 GoogleNet 모델이 FashionMNIST 데이터셋으로 학습되게 됩니다. 학습이 완료된 모델은 model 변수에 저장되며, 이후 다른 데이터에 대해 예측이나 평가를 수행할 수 있습니다.

8.4.4. Discussion

 

A key feature of GoogLeNet is that it is actually cheaper to compute than its predecessors while simultaneously providing improved accuracy. This marks the beginning of a much more deliberate network design that trades off the cost of evaluating a network with a reduction in errors. It also marks the beginning of experimentation at a block level with network design hyperparameters, even though it was entirely manual at the time. We will revisit this topic in Section 8.8 when discussing strategies for network structure exploration.

 

GoogLeNet의 핵심 기능은 향상된 정확도를 제공하는 동시에 이전 모델보다 계산 비용이 실제로 저렴하다는 것입니다. 이는 네트워크 평가 비용과 오류 감소를 절충하는 훨씬 더 신중한 네트워크 설계의 시작을 나타냅니다. 또한 당시에는 완전히 수동이었지만 네트워크 설계 하이퍼파라미터를 사용하여 블록 수준에서 실험을 시작했습니다. 네트워크 구조 탐색을 위한 전략을 논의할 때 섹션 8.8에서 이 주제를 다시 다룰 것입니다.

 

Over the following sections we will encounter a number of design choices (e.g., batch normalization, residual connections, and channel grouping) that allow us to improve networks significantly. For now, you can be proud to have implemented what is arguably the first truly modern CNN.

 

다음 섹션에서는 네트워크를 크게 개선할 수 있는 여러 설계 선택(예: 배치 정규화, 잔류 연결 및 채널 그룹화)을 접하게 됩니다. 지금은 틀림없이 최초의 진정으로 현대적인 CNN을 구현한 것을 자랑스럽게 생각할 수 있습니다.

 

8.4.5. Exercises

  1. GoogLeNet was so successful that it went through a number of iterations. There are several iterations of GoogLeNet that progressively improved speed and accuracy. Try to implement and run some of them. They include the following:
  2. Add a batch normalization layer (Ioffe and Szegedy, 2015), as described later in Section 8.5.
  3. Make adjustments to the Inception block (width, choice and order of convolutions), as described in Szegedy et al. (2016).
  4. Use label smoothing for model regularization, as described in Szegedy et al. (2016).
  5. Make further adjustments to the Inception block by adding residual connection (Szegedy et al., 2017), as described later in Section 8.6.
  6. What is the minimum image size for GoogLeNet to work?
  7. Can you design a variant of GoogLeNet that works on Fashion-MNIST’s native resolution of 28×28 pixels? How would you need to change the stem, the body, and the head of the network, if anything at all?
  8. Compare the model parameter sizes of AlexNet, VGG, NiN, and GoogLeNet. How do the latter two network architectures significantly reduce the model parameter size?
  9. Compare the amount of computation needed in GoogLeNet and AlexNet. How does this affect the design of an accelerator chip, e.g., in terms of memory size, memory bandwidth, cache size, the amount of computation, and the benefit of specialized operations?
반응형


반응형

8.3. Network in Network (NiN) — Dive into Deep Learning 1.0.0-beta0 documentation (d2l.ai)

 

8.3. Network in Network (NiN) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

8.3. Network in Network (NiN)

 

LeNet, AlexNet, and VGG all share a common design pattern: extract features exploiting spatial structure via a sequence of convolutions and pooling layers and post-process the representations via fully connected layers. The improvements upon LeNet by AlexNet and VGG mainly lie in how these later networks widen and deepen these two modules.

 

LeNet, AlexNet 및 VGG는 모두 공통 설계 패턴을 공유합니다. 컨볼루션 시퀀스 및 풀링 레이어를 통해 spatial  구조를 활용하는 기능을 추출하고 완전히 연결된 레이어를 통해 representations 을 후처리합니다. AlexNet 및 VGG에 의한 LeNet의 개선 사항은 주로 이러한 최신 네트워크가 이 두 모듈을 확장하고 심화시키는 방법에 있습니다.

 

This design poses two major challenges. First, the fully connected layers at the end of the architecture consume tremendous numbers of parameters. For instance, even a simple model such as VGG-11 requires a monstrous 25088×4096 matrix, occupying almost 400MB of RAM in single precision (FP32). This is a significant impediment to computation, in particular on mobile and embedded devices. After all, even high-end mobile phones sport no more than 8GB of RAM. At the time VGG was invented, this was an order of magnitude less (the iPhone 4S had 512MB). As such, it would have been difficult to justify spending the majority of memory on an image classifier.

 

이 설계에는 두 가지 주요 과제가 있습니다. 첫째, 아키텍처 끝에 있는 fully connected layers은 엄청난 수의 매개변수를 사용합니다. 예를 들어, VGG-11과 같은 간단한 모델도 단일 정밀도(FP32)에서 거의 400MB의 RAM을 차지하는 엄청난 25088×4096 매트릭스가 필요합니다. 이것은 특히 모바일 및 임베디드 장치에서 계산에 상당한 장애가 됩니다. 결국 고급 휴대폰도 8GB 이하의 RAM을 사용합니다. VGG가 발명되었을 때 이것은 훨씬 적었습니다(iPhone 4S는 512MB였습니다). 따라서 이미지 분류기에 대부분의 메모리를 소비하는 것을 정당화하기 어려웠을 것입니다.

 

Second, it is equally impossible to add fully connected layers earlier in the network to increase the degree of nonlinearity: doing so would destroy the spatial structure and require potentially even more memory.

 

둘째, 비선형성의 정도를 높이기 위해 네트워크 초기에 완전히 연결된 계층을 추가하는 것도 똑같이 불가능합니다. 그렇게 하면 공간 구조가 파괴되고 잠재적으로 더 많은 메모리가 필요할 수 있습니다.

 

The network in network (NiN) blocks (Lin et al., 2013) offer an alternative, capable of solving both problems in one simple strategy. They were proposed based on a very simple insight: (i) use 1×1 convolutions to add local nonlinearities across the channel activations and (ii) use global average pooling to integrate across all locations in the last representation layer. Note that global average pooling would not be effective, were it not for the added nonlinearities. Let’s dive into this in detail.

 

network in network (NiN) blocks (Lin et al., 2013)는 하나의 간단한 전략으로 두 가지 문제를 모두 해결할 수 있는 대안을 제공합니다. 그들은 매우 간단한 통찰력을 기반으로 제안되었습니다. (i) 1×1 컨볼루션을 사용하여 채널 활성화에 로컬 비선형성을 추가하고 (ii) global average pooling을 사용하여 마지막 representation  레이어의 모든 위치에 걸쳐 통합합니다. 추가된 비선형성이 없다면 전역 평균 풀링은 효과적이지 않을 것입니다. 이에 대해 자세히 알아보겠습니다.

 

Network in Network (NiN) 이란?

 

Network in Network (NiN) is a deep learning architecture introduced to enhance the expressiveness and efficiency of convolutional neural networks (CNNs). Unlike traditional CNNs that use linear filters followed by nonlinear activation functions, NiN introduces the concept of "micro neural networks" to capture complex patterns within each spatial location.

 

네트워크 인 네트워크(NiN)는 합성곱 신경망(Convolutional Neural Network, CNN)의 표현력과 효율성을 향상시키기 위해 도입된 딥러닝 아키텍처입니다. 기존의 CNN이 선형 필터를 사용하고 이후에 비선형 활성화 함수를 적용하는 방식과는 달리, NiN은 "마이크로 신경망"이라고 불리는 개념을 도입하여 각 공간 위치에서 복잡한 패턴을 포착합니다.

 

In NiN, instead of using a single convolutional layer with linear filters, it employs a set of parallel MLP-like convolutional layers called "networks". Each network consists of a series of 1x1 convolutional layers followed by nonlinearity. These 1x1 convolutions are responsible for capturing the nonlinear interactions between the channels. By stacking these network modules, NiN can learn more expressive feature representations.

 

NiN에서는 선형 필터로 구성된 단일 합성곱 레이어 대신 "네트워크"라고 불리는 병렬 MLP(다중 퍼셉트론) 형태의 합성곱 레이어 집합을 사용합니다. 각 네트워크는 1x1 합성곱 레이어들과 비선형 활성화 함수로 구성됩니다. 이러한 1x1 합성곱은 채널 간의 비선형 상호작용을 포착하는 역할을 담당합니다. 이러한 네트워크 모듈들을 쌓음으로써 NiN은 더욱 표현력 있는 특성 표현을 학습할 수 있습니다.

 

The key advantages of NiN are its ability to capture complex features using small receptive fields, reducing the number of parameters and improving computational efficiency. It also introduces a global average pooling layer that spatially averages the features to form a fixed-length vector, enabling the network to have a flexible input size.

 

NiN의 주요 장점은 작은 수용 영역을 사용하여 복잡한 특성을 포착할 수 있으며, 매개변수 수를 줄이고 계산 효율성을 향상시킬 수 있다는 것입니다. 또한, 입력 크기에 유연하게 대응할 수 있도록 전역 평균 풀링 레이어를 도입합니다.

 

NiN has been successful in various computer vision tasks, showing improved performance and interpretability compared to traditional CNN architectures.

 

NiN은 다양한 컴퓨터 비전 작업에서 성공적으로 적용되어 기존의 CNN 아키텍처와 비교하여 성능과 해석 가능성을 향상시킵니다.

 

Network In Network(NIN) 정리 (velog.io)

 

Network In Network(NIN) 정리

2014년에 ICLR에 accept된 Network In Network를 정리해본다.논문 작성자는 수용영역안에서 local patches에 대한 모델 차별성을 높이기 위해 Network In Network 모델 구조를 제시한다.고전적 convolution 모델은 비

velog.io

Micro Neural Network : 전통적 convolution 모델은 비선형 활성화 함수 + 선형 필터. but NiN은 수용 영역 안에서 데이터를 더 복잡하게 추상화 할 수 있는 micro neural network를 사용

Global average pooling : 모델 해석이 쉬워짐, fully-connected layer에서 발생할 수 있는 over-fitting 영향 줄여줌

 

Mlpconv Layer를 여러겹 쌓은 것이 NiN임

NiN에서는 classification을 위해 fully connected layer대신 global average pooling을 사용.

 

fully connected layer는 dropout에 의존적이고 파라미터 수가 폭발적으로 증가

global average pooling은 파라미터 수가 늘지 않기 때문에 overfitting이 되지 않음

 

일반적인 CNN은 conv layer를 지난 feature map이 fully connected layer를 거친 후 softmax layer를 통해 결과 값 제시

NiN에서는 fully connected layer 대신 global average pooling을 제시

global average pooling은 이 그림에서 처럼 각 feature map의 평균을 계산하는 것.

conv layer를 통과한 각각의 feature map을 평균을 냄. 그러므로 각 feature map의 특성이 어느정도 남아 있다.

==> 이는 모델의 해석에 도움을 준다. 평균을 내기 때문에 parameter가 없다. (overfitting) 방지

 

NiN Structure

 

이 Structure에서는 3개의 Mlpconv layers와 global average pooling layer로 구성. (layer의 갯수는 변할 수 있다.)

 

import torch
from torch import nn
from d2l import torch as d2l

 

8.3.1. NiN Blocks

 

Recall Section 7.4.3. In it we discussed that the inputs and outputs of convolutional layers consist of four-dimensional tensors with axes corresponding to the example, channel, height, and width. Also recall that the inputs and outputs of fully connected layers are typically two-dimensional tensors corresponding to the example and feature. The idea behind NiN is to apply a fully connected layer at each pixel location (for each height and width). The resulting 1×1 convolution can be thought as a fully connected layer acting independently on each pixel location.

 

섹션 7.4.3을 상기하십시오. 여기에서 우리는 컨볼루션 레이어의 입력과 출력이 채널, 높이 및 너비에 해당하는 축을 가진 4차원 텐서로 구성된다고 논의했습니다. 또한 완전히 연결된 계층의 입력과 출력은 일반적으로 예제와 기능에 해당하는 2차원 텐서라는 점을 상기하십시오. NiN의 기본 아이디어는 각 픽셀 위치(각 높이와 너비에 대해)에 완전히 연결된 레이어를 적용하는 것입니다. 결과 1×1 컨볼루션은 각 픽셀 위치에서 독립적으로 작동하는 완전히 연결된 레이어로 생각할 수 있습니다.

 

Fig. 8.3.1 illustrates the main structural differences between VGG and NiN, and their blocks. Note both the difference in the NiN blocks (the initial convolution is followed by 1×1 convolutions, whereas VGG retains 3×3 convolutions) and in the end where we no longer require a giant fully connected layer.

 

그림 8.3.1은 VGG와 NiN 사이의 주요 구조적 차이점과 해당 블록을 보여줍니다. NiN 블록의 차이점(초기 컨볼루션 다음에는 1×1 컨볼루션이 이어지는 반면 VGG는 3×3 컨볼루션을 유지함)과 결국 더 이상 거대한 fully connected layer가 필요하지 않은 점에 유의하십시오.

 

Fig. 8.3.1&nbsp; Comparing the architectures of VGG and NiN, and of their blocks.

 

def nin_block(out_channels, kernel_size, strides, padding):
    return nn.Sequential(
        nn.LazyConv2d(out_channels, kernel_size, strides, padding), nn.ReLU(),
        nn.LazyConv2d(out_channels, kernel_size=1), nn.ReLU(),
        nn.LazyConv2d(out_channels, kernel_size=1), nn.ReLU())
  • nin_block 함수는 NiN 블록을 생성하는 함수입니다. 이 함수는 출력 채널 수 out_channels, 커널 크기 kernel_size, 스트라이드 strides, 패딩 padding을 인자로 받습니다.
  • nn.Sequential은 여러 개의 모듈을 순차적으로 쌓아 하나의 모듈로 만들어주는 함수입니다. 이를 통해 NiN 블록을 정의합니다.
  • 첫 번째 nn.LazyConv2d 레이어는 출력 채널 수 out_channels, 커널 크기 kernel_size, 스트라이드 strides, 패딩 padding을 가진 합성곱 레이어입니다. 이후에 nn.ReLU() 함수를 사용하여 비선형 활성화 함수인 ReLU를 적용합니다.
  • 두 번째와 세 번째 nn.LazyConv2d 레이어는 출력 채널 수 out_channels, 커널 크기 1을 가진 합성곱 레이어입니다. 이는 NiN 블록 내에서 1x1 컨볼루션 연산을 수행하기 위한 레이어입니다. 마찬가지로 nn.ReLU() 함수를 사용하여 비선형 활성화 함수인 ReLU를 적용합니다.
  • 이렇게 생성된 레이어들은 nn.Sequential을 통해 하나의 모듈로 합쳐진 후 반환됩니다.

8.3.2. NiN Model

NiN uses the same initial convolution sizes as AlexNet (it was proposed shortly thereafter). The kernel sizes are 11×11, 5×5, and 3×3, respectively, and the numbers of output channels match those of AlexNet. Each NiN block is followed by a max-pooling layer with a stride of 2 and a window shape of 3×3.

 

NiN은 AlexNet과 동일한 초기 컨볼루션 크기를 사용합니다(그 직후에 제안됨). 커널 크기는 각각 11×11, 5×5, 3×3이며 출력 채널의 수는 AlexNet과 일치합니다. 각 NiN 블록 다음에는 보폭이 2이고 창 모양이 3×3인 최대 풀링 레이어가 옵니다.

 

The second significant difference between NiN and both AlexNet and VGG is that NiN avoids fully connected layers altogether. Instead, NiN uses a NiN block with a number of output channels equal to the number of label classes, followed by a global average pooling layer, yielding a vector of logits. This design significantly reduces the number of required model parameters, albeit at the expense of a potential increase in training time.

 

NiN과 AlexNet 및 VGG의 두 번째 중요한 차이점은 NiN이 fully connected layers를 모두 피한다는 것입니다. 대신 NiN은 레이블 클래스 수와 동일한 수의 출력 채널이 있는 NiN 블록을 사용하고 뒤이어 global average pooling layer 를 사용하여 로짓 벡터를 생성합니다. 이 디자인은 학습 시간이 잠재적으로 증가하더라도 필요한 모델 매개변수의 수를 크게 줄입니다.

 

class NiN(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nin_block(96, kernel_size=11, strides=4, padding=0),
            nn.MaxPool2d(3, stride=2),
            nin_block(256, kernel_size=5, strides=1, padding=2),
            nn.MaxPool2d(3, stride=2),
            nin_block(384, kernel_size=3, strides=1, padding=1),
            nn.MaxPool2d(3, stride=2),
            nn.Dropout(0.5),
            nin_block(num_classes, kernel_size=3, strides=1, padding=1),
            nn.AdaptiveAvgPool2d((1, 1)),
            nn.Flatten())
        self.net.apply(d2l.init_cnn)
  • NiN 클래스는 NiN 모델을 정의하는 클래스입니다. 생성자 함수 __init__을 통해 모델을 초기화합니다. 학습률 lr과 클래스의 개수 num_classes를 인자로 받습니다.
  • super().__init__()을 사용하여 상위 클래스인 d2l.Classifier의 초기화 함수를 호출합니다.
  • self.save_hyperparameters()를 사용하여 하이퍼파라미터를 저장합니다.
  • self.net은 nn.Sequential을 통해 여러 개의 레이어를 순차적으로 쌓은 네트워크 모델입니다.
  • nin_block 함수를 사용하여 NiN 블록을 생성하고 nn.Sequential에 추가합니다. 첫 번째 NiN 블록은 96개의 출력 채널을 가지며, 커널 크기는 11, 스트라이드는 4, 패딩은 0입니다.
  • nn.MaxPool2d 레이어를 사용하여 최대 풀링을 수행합니다. 첫 번째 풀링 레이어는 커널 크기가 3이고 스트라이드가 2입니다.
  • 두 번째 NiN 블록은 256개의 출력 채널을 가지며, 커널 크기는 5, 스트라이드는 1, 패딩은 2입니다.
  • 두 번째 풀링 레이어는 동일하게 커널 크기가 3이고 스트라이드가 2입니다.
  • 세 번째 NiN 블록은 384개의 출력 채널을 가지며, 커널 크기는 3, 스트라이드는 1, 패딩은 1입니다.
  • 세 번째 풀링 레이어도 동일하게 커널 크기가 3이고 스트라이드가 2입니다.
  • nn.Dropout 레이어를 사용하여 드롭아웃을 수행합니다. 확률은 0.5로 설정됩니다.
  • 네 번째 NiN 블록은 클래스 개수 num_classes를 가지며, 커널 크기는 3, 스트라이드는 1, 패딩은 1입니다.
  • nn.AdaptiveAvgPool2d 레이어를 사용하여 출력 특성맵의 크기를 고정된 크기로 조정합니다. 이 경우 (1, 1) 크기로 조정됩니다.
  • nn.Flatten 레이어를 사용하여 특성맵을 1차원으로 평탄화합니다.
  • self.net.apply(d2l.init_cnn)를 통해 네트워크의 가중치를 초기화합니다.

AdaptiveAvgPool2d — PyTorch 2.0 documentation

 

AdaptiveAvgPool2d — PyTorch 2.0 documentation

Shortcuts

pytorch.org

We create a data example to see the output shape of each block.

 

각 블록의 출력 형태를 보기 위해 데이터 예제를 생성합니다.

 

NiN().layer_summary((1, 1, 224, 224))
  • NiN 클래스의 인스턴스를 생성합니다.
  • layer_summary 메서드를 호출하여 모델의 레이어 요약 정보를 출력합니다. 인자로 입력 데이터의 크기를 전달합니다. 이 경우 입력 데이터의 크기는 (1, 1, 224, 224)입니다.

8.3.3. Training

As before we use Fashion-MNIST to train the model using the same optimizer that we used for AlexNet and VGG.

 

이전과 마찬가지로 Fashion-MNIST를 사용하여 AlexNet 및 VGG에 사용한 것과 동일한 옵티마이저를 사용하여 모델을 교육합니다.

 

model = NiN(lr=0.05)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(224, 224))
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)
  • NiN 클래스의 인스턴스인 model을 생성합니다. 학습률 lr은 0.05로 설정되어 있습니다.
  • Trainer 클래스의 인스턴스인 trainer를 생성합니다. max_epochs는 10으로 설정되어 있고, num_gpus는 1로 설정되어 있습니다.
  • FashionMNIST 데이터셋을 로드합니다. 배치 크기는 128이고, 이미지 크기는 (224, 224)로 변경되도록 설정되어 있습니다.
  • data를 사용하여 모델의 가중치를 초기화합니다. 초기화 방법은 d2l.init_cnn 함수를 사용하여 첫 번째 미니 배치의 입력 데이터로 초기화됩니다.
  • trainer를 사용하여 model을 data에 대해 학습시킵니다.

SageMaker

CoLab

8.3.4. Summary

 

NiN has dramatically fewer parameters than AlexNet and VGG. This stems primarily from the fact that it needs no giant fully connected layers. Instead, it uses global average pooling to aggregate across all image locations after the last stage of the network body. This obviates the need for expensive (learned) reduction operations and replaces them by a simple average. What was surprising at the time is the fact that this averaging operation did not harm accuracy. Note that averaging across a low-resolution representation (with many channels) also adds to the amount of translation invariance that the network can handle.

 

NiN은 AlexNet 및 VGG보다 매개변수가 훨씬 적습니다. 이것은 주로 거대한 fully connected layers가 필요하지 않다는 사실에서 비롯됩니다. 대신 global average pooling을 사용하여 네트워크 본문의 마지막 단계 이후 모든 이미지 위치에 걸쳐 집계합니다. 이는 비용이 많이 드는(학습된) 축소 작업의 필요성을 없애고 단순 평균으로 대체합니다. 당시 놀라운 점은 이 평균 연산이 정확도를 해치지 않았다는 사실입니다. 저해상도 표현(많은 채널 포함)에 대한 평균화는 네트워크가 처리할 수 있는 변환 불변의 양을 추가합니다.

 

Choosing fewer convolutions with wide kernels and replacing them by 1×1 convolutions aids the quest for fewer parameters further. It affords for a significant amount of nonlinearity across channels within any given location. Both 1×1 convolutions and global average pooling significantly influenced subsequent CNN designs.

 

넓은 커널이 있는 더 적은 컨볼루션을 선택하고 1×1 컨볼루션으로 대체하면 더 적은 매개변수를 찾는 데 도움이 됩니다. 주어진 위치 내에서 채널 전반에 걸쳐 상당한 양의 비선형성을 제공합니다. 1×1 컨볼루션과 전역 평균 풀링은 후속 CNN 설계에 상당한 영향을 미쳤습니다.

 

8.3.5. Exercises

  1. Why are there two 1×1 convolutional layers per NiN block? Increase their number to three. Reduce their number to one. What changes?
  2. What changes if you replace the 1×1 convolutions by 3×3 convolutions?
  3. What happens if you replace the global average pooling by a fully connected layer (speed, accuracy, number of parameters)?
  4. Calculate the resource usage for NiN.
    1. What is the number of parameters?
    2. What is the amount of computation?
    3. What is the amount of memory needed during training?
    4. What is the amount of memory needed during prediction?
  5. What are possible problems with reducing the 384×5×5 representation to a 10×5×5 representation in one step?
  6. Use the structural design decisions in VGG that led to VGG-11, VGG-16, and VGG-19 to design a family of NiN-like networks.

 

반응형


반응형

8.2. Networks Using Blocks (VGG) — Dive into Deep Learning 1.0.0-beta0 documentation (d2l.ai)

 

8.2. Networks Using Blocks (VGG) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

 

8.2. Networks Using Blocks (VGG)

While AlexNet offered empirical evidence that deep CNNs can achieve good results, it did not provide a general template to guide subsequent researchers in designing new networks. In the following sections, we will introduce several heuristic concepts commonly used to design deep networks.

 

AlexNet은 심층 CNN이 좋은 결과를 달성할 수 있다는 경험적 증거를 제공했지만 후속 연구원이 새로운 네트워크를 설계하는 데 도움이 되는 일반적인 템플릿은 제공하지 않았습니다. 다음 섹션에서는 딥 네트워크를 설계하는 데 일반적으로 사용되는 몇 가지 휴리스틱 개념을 소개합니다.

 

Progress in this field mirrors that of VLSI (very large scale integration) in chip design where engineers moved from placing transistors to logical elements to logic blocks (Mead, 1980). Similarly, the design of neural network architectures has grown progressively more abstract, with researchers moving from thinking in terms of individual neurons to whole layers, and now to blocks, repeating patterns of layers. A decade later, this has now progressed to researchers using entire trained models to repurpose them for different, albeit related, tasks. Such large pretrained models are typically called foundation models (Bommasani et al., 2021).

 

이 분야의 발전은 엔지니어가 트랜지스터 배치에서 논리 요소, 논리 블록으로 이동한 칩 설계의 VLSI(초대규모 통합)를 반영합니다(Mead, 1980). 유사하게, 신경망 구조의 디자인은 연구자들이 개별 뉴런의 관점에서 생각하는 것에서 전체 층으로, 이제는 층의 패턴을 반복하는 블록으로 이동하면서 점점 더 추상적으로 성장했습니다. 10년 후, 이것은 비록 관련이 있긴 하지만 다른 작업을 위해 용도를 변경하기 위해 전체 훈련된 모델을 사용하는 연구자에게 발전했습니다. 이러한 대규모 사전 훈련 모델은 일반적으로 foundation models이라고 합니다(Bommasani et al., 2021).

 

Back to network design. The idea of using blocks first emerged from the Visual Geometry Group (VGG) at Oxford University, in their eponymously-named VGG network (Simonyan and Zisserman, 2014). It is easy to implement these repeated structures in code with any modern deep learning framework by using loops and subroutines.

 

네트워크 설계로 돌아갑니다. 블록을 사용한다는 아이디어는 옥스포드 대학의 VGG(Visual Geometry Group)에서 VGG 네트워크라는 이름으로 처음 등장했습니다(Simonyan and Zisserman, 2014). 루프와 서브루틴을 사용하여 최신 딥 러닝 프레임워크를 사용하여 코드에서 이러한 반복 구조를 쉽게 구현할 수 있습니다.

 

Vissual Geometry Group (VGG) 란?

 

The Visual Geometry Group (VGG) is a convolutional neural network architecture that was proposed by the Visual Geometry Group at the University of Oxford. VGG is known for its simplicity and effectiveness in image classification tasks.

 

Visual Geometry Group (VGG)은 옥스퍼드 대학교의 Visual Geometry Group에서 제안한 합성곱 신경망 구조입니다. VGG는 이미지 분류 작업에서의 간결성과 효율성으로 알려져 있습니다.

 

The VGG architecture consists of a series of convolutional layers, followed by max-pooling layers, and finally fully connected layers. The key characteristic of VGG is that it uses a stack of small-sized convolutional filters (3x3) with a stride of 1, and always uses the same padding to maintain the spatial resolution of the feature maps. This design choice allows VGG to learn hierarchical representations of visual patterns at different scales.

 

VGG 아키텍처는 일련의 합성곱 레이어, 맥스 풀링 레이어, 그리고 완전 연결 레이어로 구성됩니다. VGG의 주요 특징은 스트라이드 1과 동일한 패딩을 사용하여 작은 크기의 합성곱 필터(3x3)를 스택 형태로 사용한다는 점입니다. 이러한 설계 선택은 VGG가 다양한 스케일의 시각적 패턴에 대한 계층적인 표현을 학습할 수 있도록 합니다.

 

The original VGG network comes in different variants, such as VGG16 and VGG19, which differ in the number of layers. VGG16 has 16 layers, including 13 convolutional layers and 3 fully connected layers, while VGG19 has 19 layers. The deeper architectures allow VGG to capture more complex features and achieve higher accuracy on image classification tasks.

 

원래의 VGG 네트워크에는 VGG16과 VGG19와 같은 여러 가지 변형이 있으며, 이는 레이어의 수에 차이가 있습니다. VGG16은 13개의 합성곱 레이어와 3개의 완전 연결 레이어를 포함하여 총 16개의 레이어로 구성되어 있으며, VGG19는 19개의 레이어로 이루어져 있습니다. 더 깊은 아키텍처를 통해 VGG는 더 복잡한 특징을 학습하고 이미지 분류 작업에서 더 높은 정확도를 달성할 수 있습니다.

 

VGG networks have been widely used as a benchmark architecture for various computer vision tasks, including image classification, object detection, and image segmentation. They have also influenced the design of subsequent convolutional neural network architectures.

 

VGG 네트워크는 이미지 분류, 객체 검출, 이미지 세그멘테이션 등 다양한 컴퓨터 비전 작업에서 벤치마크 아키텍처로 널리 사용되었습니다. 또한, VGG는 후속 합성곱 신경망 아키텍처의 설계에도 영향을 미쳤습니다.

 

Overall, VGG is known for its simplicity, strong performance, and ability to learn expressive representations of visual data, making it a popular choice in the field of deep learning for computer vision tasks.

 

전반적으로 VGG는 간결성, 강력한 성능, 시각적 데이터의 표현 학습 능력을 갖춘 특징으로 인해 컴퓨터 비전 작업에서 인기 있는 선택지입니다.

 

https://youtu.be/MaDakbMDBrI

 

VGGNet 
* Convolution + ReLU, max poling, fully connected + ReLU, softmax
* 3X3 convolution -> Max Pooling을 계속 반복함 => 이 반복하는 구간을 Block 이라고 함 (VGG Block)
  블럭 내에서 Convolution을 몇번 반복 할 것인가? 그리고 필터는 몇개를 쓸 것인가? 를 결정해야 함
* Receptive Field : Convolution을 많이 반복 할 수록 더 큰 영역의 원본 이미지를 처리하게 된다.

 

https://youtu.be/Ifgtl1LpYsI

import torch
from torch import nn
from d2l import torch as d2l

 

8.2.1. VGG Blocks

The basic building block of CNNs is a sequence of the following: (i) a convolutional layer with padding to maintain the resolution, (ii) a nonlinearity such as a ReLU, (iii) a pooling layer such as max-pooling to reduce the resolution. One of the problems with this approach is that the spatial resolution decreases quite rapidly. In particular, this imposes a hard limit of log2d convolutional layers on the network before all dimensions (d) are used up. For instance, in the case of ImageNet, it would be impossible to have more than 8 convolutional layers in this way.

 

CNN의 기본 빌딩 블록은 (i) 해상도를 유지하기 위한 패딩이 있는 컨볼루션 레이어, (ii) ReLU와 같은 비선형성, (iii) 해결. 이 접근법의 문제점 중 하나는 공간 해상도가 매우 빠르게 감소한다는 것입니다. 특히 이것은 모든 차원(d)이 사용되기 전에 네트워크에서 log2⁡d 컨벌루션 계층의 엄격한 제한을 부과합니다. 예를 들어 ImageNet의 경우 이런 방식으로 8개 이상의 컨볼루션 레이어를 갖는 것은 불가능합니다.

 

The key idea of Simonyan and Zisserman (2014) was to use multiple convolutions in between downsampling via max-pooling in the form of a block. They were primarily interested in whether deep or wide networks perform better. For instance, the successive application of two 3×3 convolutions touches the same pixels as a single 5×5 convolution does. At the same time, the latter uses approximately as many parameters (25⋅c2) as three 3×3 convolutions do (3⋅9⋅c2). In a rather detailed analysis they showed that deep and narrow networks significantly outperform their shallow counterparts. This set deep learning on a quest for ever deeper networks with over 100 layers for typical applications. Stacking 3×3 convolutions has become a gold standard in later deep networks (a design decision only to be revisited recently by Liu et al. (2022)). Consequently, fast implementations for small convolutions have become a staple on GPUs (Lavin and Gray, 2016).

 

Simonyan과 Zisserman(2014)의 핵심 아이디어는 블록 형태의 최대 풀링을 통해 다운샘플링 사이에 다중 컨벌루션을 사용하는 것이었습니다. 그들은 주로 깊은 네트워크 또는 넓은 네트워크가 더 잘 수행되는지 여부에 관심이 있었습니다. 예를 들어 두 개의 3×3 컨볼루션을 연속적으로 적용하면 단일 5×5 컨볼루션과 동일한 픽셀에 닿습니다. 동시에 후자는 대략 3개의 3×3 컨볼루션(3⋅9⋅c2)만큼 많은 매개변수(25⋅c2)를 사용합니다. 다소 상세한 분석에서 그들은 깊고 좁은 네트워크가 얕은 네트워크보다 훨씬 뛰어난 성능을 보인다는 것을 보여주었습니다. 이는 일반적인 애플리케이션을 위한 100개 이상의 레이어가 있는 더 깊은 네트워크에 대한 탐구에 대한 딥 러닝을 설정합니다. Stacking 3×3 Convolution은 이후 딥 네트워크에서 금본위제가 되었습니다(Liu et al.(2022)이 최근에 재검토한 디자인 결정). 결과적으로 작은 컨볼루션을 위한 빠른 구현은 GPU의 필수 요소가 되었습니다(Lavin and Gray, 2016).

 

Back to VGG: a VGG block consists of a sequence of convolutions with 3×3 kernels with padding of 1 (keeping height and width) followed by a 2×2 max-pooling layer with stride of 2 (halving height and width after each block). In the code below, we define a function called vgg_block to implement one VGG block.

 

VGG로 돌아가서: VGG 블록은 패딩이 1(높이와 너비 유지)인 3×3 커널과 보폭이 2인 2×2 최대 풀링 레이어(각 블록 후 높이와 너비를 반으로 줄임)가 있는 일련의 컨볼루션으로 구성됩니다. ). 아래 코드에서는 하나의 VGG 블록을 구현하기 위해 vgg_block이라는 함수를 정의합니다.

 

The function below takes two arguments, corresponding to the number of convolutional layers num_convs and the number of output channels num_channels.

 

아래 함수는 컨벌루션 레이어의 수 num_convs와 출력 채널의 수 num_channels에 해당하는 두 개의 인수를 사용합니다.

 

def vgg_block(num_convs, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.LazyConv2d(out_channels, kernel_size=3, padding=1))
        layers.append(nn.ReLU())
    layers.append(nn.MaxPool2d(kernel_size=2,stride=2))
    return nn.Sequential(*layers)

위의 코드는 VGG 블록을 생성하는 함수인 vgg_block을 정의합니다. VGG 블록은 일련의 합성곱 레이어, 활성화 함수(ReLU), 그리고 맥스 풀링 레이어로 구성됩니다.

함수의 인자로는 num_convs와 out_channels가 있습니다. num_convs는 VGG 블록 내에서 반복되는 합성곱 레이어의 개수를 나타냅니다. out_channels는 각 합성곱 레이어의 출력 채널 수를 의미합니다.

함수는 빈 리스트인 layers를 생성한 후, num_convs만큼의 반복문을 실행합니다. 각 반복에서는 합성곱 레이어(nn.LazyConv2d)와 활성화 함수(ReLU)를 순서대로 layers 리스트에 추가합니다.

반복문이 끝난 후에는 맥스 풀링 레이어(nn.MaxPool2d)를 layers 리스트에 추가합니다. 맥스 풀링 레이어는 입력의 크기를 절반으로 줄이는 역할을 수행합니다.

마지막으로, layers 리스트의 모든 요소를 nn.Sequential을 사용하여 순차적으로 결합한 후 반환합니다. 이렇게 생성된 VGG 블록은 더 큰 VGG 네트워크에서 사용될 수 있습니다.

 

8.2.2. VGG Network

Like AlexNet and LeNet, the VGG Network can be partitioned into two parts: the first consisting mostly of convolutional and pooling layers and the second consisting of fully connected layers that are identical to those in AlexNet. The key difference is that the convolutional layers are grouped in nonlinear transformations that leave the dimensonality unchanged, followed by a resolution-reduction step, as depicted in Fig. 8.2.1.

 

AlexNet 및 LeNet과 마찬가지로 VGG 네트워크는 두 부분으로 나눌 수 있습니다. 첫 번째 부분은 주로 컨벌루션 및 풀링 레이어로 구성되고 두 번째 부분은 AlexNet의 레이어와 동일한 완전히 연결된 레이어로 구성됩니다. 주요 차이점은 그림 8.2.1에 묘사된 것처럼 컨벌루션 레이어가 차원을 변경하지 않고 해상도 감소 단계가 뒤따르는 비선형 변환으로 그룹화된다는 것입니다.

 

Fig. 8.2.1&nbsp; From AlexNet to VGG. The key difference is that VGG consists of blocks of layers, whereas AlexNet&rsquo;s layers are all designed individually

 

The convolutional part of the network connects several VGG blocks from Fig. 8.2.1 (also defined in the vgg_block function) in succession. This grouping of convolutions is a pattern that has remained almost unchanged over the past decade, although the specific choice of operations has undergone considerable modifications. The variable conv_arch consists of a list of tuples (one per block), where each contains two values: the number of convolutional layers and the number of output channels, which are precisely the arguments required to call the vgg_block function. As such, VGG defines a family of networks rather than just a specific manifestation. To build a specific network we simply iterate over arch to compose the blocks.

 

네트워크의 컨벌루션 부분은 그림 8.2.1(vgg_block 함수에서도 정의됨)의 여러 VGG 블록을 연속적으로 연결합니다. 이 컨볼루션 그룹화는 특정 작업 선택이 상당한 수정을 거쳤지만 지난 10년 동안 거의 변경되지 않은 패턴입니다. 변수 conv_arch는 튜플 목록(블록당 하나)으로 구성되며 각 튜플에는 vgg_block 함수를 호출하는 데 필요한 정확히 인수인 컨벌루션 레이어 수와 출력 채널 수라는 두 가지 값이 포함됩니다. 이와 같이 VGG는 특정 표현이 아닌 네트워크 제품군을 정의합니다. 특정 네트워크를 구축하기 위해 우리는 단순히 블록을 구성하기 위해 아치를 반복합니다.

 

class VGG(d2l.Classifier):
    def __init__(self, arch, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        conv_blks = []
        for (num_convs, out_channels) in arch:
            conv_blks.append(vgg_block(num_convs, out_channels))
        self.net = nn.Sequential(
            *conv_blks, nn.Flatten(),
            nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(0.5),
            nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(0.5),
            nn.LazyLinear(num_classes))
        self.net.apply(d2l.init_cnn)

위의 코드는 VGG 모델을 정의하는 VGG 클래스를 나타냅니다. VGG 클래스는 d2l.Classifier 클래스를 상속받습니다.

클래스의 __init__ 메서드에서는 VGG 모델의 구조를 정의하고 초기화를 수행합니다. arch 인자는 VGG 모델의 구조를 나타내는 리스트로, 각 요소는 (num_convs, out_channels) 형태의 튜플입니다. num_convs는 VGG 블록 내에서 반복되는 합성곱 레이어의 개수를 의미하고, out_channels는 각 합성곱 레이어의 출력 채널 수를 나타냅니다.

conv_blks 리스트를 생성한 후, arch를 순회하면서 각각의 (num_convs, out_channels)에 대해 vgg_block 함수를 호출하여 VGG 블록을 생성하고 conv_blks 리스트에 추가합니다.

그 다음, nn.Sequential을 사용하여 conv_blks 리스트에 저장된 VGG 블록들을 순차적으로 결합합니다. 이후에는 nn.Flatten 레이어를 추가하여 다차원 텐서를 1차원으로 평탄화합니다.

마지막으로, fully connected 레이어를 추가합니다. nn.LazyLinear은 지연 초기화된 선형 레이어를 나타냅니다. VGG 모델의 fully connected 레이어는 두 개의 4096 차원 레이어와 마지막에 출력 클래스 수에 해당하는 레이어로 구성됩니다. 활성화 함수로는 ReLU를 사용하고, dropout을 적용하여 모델의 일반화 능력을 향상시킵니다.

마지막으로, self.net에 적용된 d2l.init_cnn 함수를 사용하여 모델의 가중치를 초기화합니다. 이렇게 정의된 VGG 클래스는 이미지 분류 작업에 사용될 수 있는 VGG 모델을 생성합니다.

 

Sequential — PyTorch 2.0 documentation

 

Sequential — PyTorch 2.0 documentation

Shortcuts

pytorch.org

LazyLinear — PyTorch 2.0 documentation

 

LazyLinear — PyTorch 2.0 documentation

Shortcuts

pytorch.org

 

The original VGG network had 5 convolutional blocks, among which the first two have one convolutional layer each and the latter three contain two convolutional layers each. The first block has 64 output channels and each subsequent block doubles the number of output channels, until that number reaches 512. Since this network uses 8 convolutional layers and 3 fully connected layers, it is often called VGG-11.

 

원래 VGG 네트워크에는 5개의 컨볼루션 블록이 있으며, 그 중 처음 2개는 각각 1개의 컨볼루션 레이어를, 나머지 3개는 각각 2개의 컨볼루션 레이어를 포함합니다. 첫 번째 블록에는 64개의 출력 채널이 있고 각 후속 블록은 그 수가 512에 도달할 때까지 출력 채널 수를 두 배로 늘립니다. 이 네트워크는 8개의 컨볼루션 레이어와 3개의 완전 연결 레이어를 사용하므로 종종 VGG-11이라고 합니다.

 

VGG(arch=((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))).layer_summary(
    (1, 1, 224, 224))

위의 코드는 VGG 모델의 구조를 정의한 후, layer_summary 메서드를 사용하여 각 레이어의 출력 형태를 요약하는 예시입니다.

VGG(arch=((1, 64), (1, 128), (2, 256), (2, 512), (2, 512)))는 VGG 모델을 생성하는데, arch 인자로 (num_convs, out_channels) 형태의 튜플로 이루어진 리스트를 전달합니다. 각 튜플은 VGG 블록 내에서의 합성곱 레이어 개수와 출력 채널 수를 나타냅니다.

그리고 layer_summary 메서드를 호출하여 모델의 레이어를 요약합니다. 이 메서드는 주어진 입력 형태 (1, 1, 224, 224)에 대해 각 레이어의 출력 형태를 출력합니다. 이를 통해 모델의 구조와 레이어 간의 입력-출력 관계를 파악할 수 있습니다.

As you can see, we halve height and width at each block, finally reaching a height and width of 7 before flattening the representations for processing by the fully connected part of the network. Simonyan and Zisserman (2014) described several other variants of VGG. In fact, it has become the norm to propose families of networks with different speed-accuracy trade-off when introducing a new architecture.

 

보시다시피, 우리는 각 블록에서 높이와 너비를 절반으로 줄였고, 완전히 연결된 네트워크 부분에서 처리하기 위해 표현을 평면화하기 전에 마침내 높이와 너비가 7에 도달했습니다. Simonyan과 Zisserman(2014)은 VGG의 몇 가지 다른 변종을 설명했습니다. 실제로 새로운 아키텍처를 도입할 때 서로 다른 속도-정확도 트레이드 오프를 가진 네트워크 제품군을 제안하는 것이 일반적이 되었습니다.

 

 

8.2.3. Training

Since VGG-11 is computationally more demanding than AlexNet we construct a network with a smaller number of channels. This is more than sufficient for training on Fashion-MNIST. The model training process is similar to that of AlexNet in Section 8.1. Again observe the close match between validation and training loss, suggesting only a small amount of overfitting.

 

8.1. Deep Convolutional Neural Networks (AlexNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

VGG-11은 AlexNet보다 계산적으로 더 까다롭기 때문에 더 적은 수의 채널로 네트워크를 구성합니다. 이것은 Fashion-MNIST 교육에 충분합니다. 모델 학습 과정은 섹션 8.1의 AlexNet과 유사합니다. 유효성 검사와 훈련 손실 사이의 밀접한 일치를 다시 관찰하여 소량의 과적합만 제안합니다.

 

model = VGG(arch=((1, 16), (1, 32), (2, 64), (2, 128), (2, 128)), lr=0.01)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(224, 224))
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
trainer.fit(model, data)

위의 코드는 VGG 모델을 생성하고 훈련하는 과정을 나타냅니다.

model = VGG(arch=((1, 16), (1, 32), (2, 64), (2, 128), (2, 128)), lr=0.01)은 VGG 모델을 생성합니다. arch 인자에는 VGG 블록 내의 합성곱 레이어 개수와 출력 채널 수를 지정한 튜플로 이루어진 리스트를 전달합니다. 또한, 학습률 lr도 지정합니다.

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)은 훈련에 필요한 Trainer 객체를 생성합니다. max_epochs는 최대 에폭 수를, num_gpus는 사용할 GPU 개수를 나타냅니다.

data = d2l.FashionMNIST(batch_size=128, resize=(224, 224))는 FashionMNIST 데이터셋을 로드하고 전처리합니다. 배치 크기 batch_size와 이미지 크기 resize를 지정합니다.

model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)은 모델의 가중치를 초기화합니다. 데이터로더에서 첫 번째 배치를 가져와서 입력으로 사용하고, d2l.init_cnn 함수를 통해 가중치를 초기화합니다.

trainer.fit(model, data)은 모델을 훈련합니다. Trainer 객체를 사용하여 지정된 데이터셋을 사용하여 모델을 학습하고, 주어진 에폭 수만큼 반복적으로 훈련을 진행합니다.

 

8.2.4. Summary

 

One might argue that VGG is the first truly modern convolutional neural network. While AlexNet introduced many of the components of what make deep learning effective at scale, it is VGG that arguably introduced key properties such as blocks of multiple convolutions and a preference for deep and narrow networks. It is also the first network that is actually an entire family of similarly parametrized models, giving the practitioner ample trade-off between complexity and speed. This is also the place where modern deep learning frameworks shine. It is no longer necessary to generate XML config files to specify a network but rather, to assemble said networks through simple Python code.

 

VGG가 최초의 진정한 현대 컨볼루션 신경망이라고 주장할 수도 있습니다. AlexNet은 딥 러닝을 대규모로 효과적으로 만드는 많은 구성 요소를 도입했지만 VGG는 여러 컨볼루션의 블록 및 깊고 좁은 네트워크에 대한 선호와 같은 주요 속성을 도입했다고 주장할 수 있습니다. 이것은 실제로 유사하게 매개변수화된 모델의 전체 제품군인 최초의 네트워크로, 실무자에게 복잡성과 속도 사이에서 충분한 절충안을 제공합니다. 이것은 또한 최신 딥 러닝 프레임워크가 빛나는 곳이기도 합니다. 더 이상 네트워크를 지정하기 위해 XML 구성 파일을 생성할 필요가 없으며 간단한 Python 코드를 통해 해당 네트워크를 조립할 수 있습니다.

 

Very recently ParNet (Goyal et al., 2021) demonstrated that it is possible to achieve competitive performance using a much more shallow architecture through a large number of parallel computations. This is an exciting development and there’s hope that it will influence architecture designs in the future. For the remainder of the chapter, though, we will follow the path of scientific progress over the past decade.

 

아주 최근에 ParNet(Goyal et al., 2021)은 많은 수의 병렬 계산을 통해 훨씬 더 얕은 아키텍처를 사용하여 경쟁력 있는 성능을 달성할 수 있음을 보여주었습니다. 이것은 흥미로운 발전이며 미래의 건축 디자인에 영향을 미칠 것이라는 희망이 있습니다. 하지만 이 장의 나머지 부분에서는 지난 10년 동안의 과학적 진보의 길을 따라갈 것입니다.

 

8.2.5. Exercises

  1. Compared with AlexNet, VGG is much slower in terms of computation, and it also needs more GPU memory.
    1. Compare the number of parameters needed for AlexNet and VGG.
    2. Compare the number of floating point operations used in the convolutional layers and in the fully connected layers.
    3. How could you reduce the computational cost created by the fully connected layers?
  2. When displaying the dimensions associated with the various layers of the network, we only see the information associated with 8 blocks (plus some auxiliary transforms), even though the network has 11 layers. Where did the remaining 3 layers go?
  3. Use Table 1 in the VGG paper (Simonyan and Zisserman, 2014) to construct other common models, such as VGG-16 or VGG-19.
  4. Upsampling the resolution in Fashion-MNIST by a factor of 8 from 28×28 to 224×224 dimensions is very wasteful. Try modifying the network architecture and resolution conversion, e.g., to 56 or to 84 dimensions for its input instead. Can you do so without reducing the accuracy of the network? Consider the VGG paper (Simonyan and Zisserman, 2014) for ideas on adding more nonlinearities prior to downsampling.

 

 

반응형


반응형

8.1. Deep Convolutional Neural Networks (AlexNet) — Dive into Deep Learning 1.0.0-beta0 documentation (d2l.ai)

 

8.1. Deep Convolutional Neural Networks (AlexNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

https://youtu.be/CQwzsNDpE1c

* AlexNet
  - 머신러닝 기법 탈피 (심층 신경망 모델 사용)
  - Vanishing Gradient 문제 많이 해소 (ReLU activation function 사용)
  - Larger Dataset 사용
  - GPU 를 사용 (GTX580)
  - 과대적합 방지 : Dropoout

 

https://youtu.be/40Gdctb55BY

* AlexNet Architecture : ReLUs, GPU 2대 병렬, Local response norm, overlapping pooling, data augmentation, dropout, Convolutional Layers (5개), Fully-connected layers, 1000-way softmax

 

https://youtu.be/VJX2kBWN7pQ

(2012) AlexNet
- LeNet : AlexNet 이전에 나옴. 손글씨 숫자 인식 하는 모델. tanh activation function 사용, avg pooling, Backpropagation 마지막 레이어에서만 사용
- AlexNet : 5 convolutions, 3 FS, 60M params, 1000 classes, ReLU, 2 GPUs, Local Response Normalization, Overlapping Pooling

 

 

8.1. Deep Convolutional Neural Networks (AlexNet)

 

Although CNNs were well known in the computer vision and machine learning communities following the introduction of LeNet (LeCun et al., 1995), they did not immediately dominate the field. Although LeNet achieved good results on early small datasets, the performance and feasibility of training CNNs on larger, more realistic datasets had yet to be established. In fact, for much of the intervening time between the early 1990s and the watershed results of 2012 (Krizhevsky et al., 2012), neural networks were often surpassed by other machine learning methods, such as kernel methods (Schölkopf and Smola, 2002), ensemble methods (Freund et al., 1996), and structured estimation (Taskar et al., 2004).

 

CNN은 LeNet(LeCun et al., 1995)의 도입 이후 컴퓨터 비전 및 기계 학습 커뮤니티에서 잘 알려져 있었지만 즉시 해당 분야를 지배하지는 못했습니다. LeNet은 초기 소규모 데이터 세트에서 좋은 결과를 얻었지만 더 크고 현실적인 데이터 세트에서 CNN을 교육하는 성능과 실행 가능성은 아직 확립되지 않았습니다. 사실, 1990년대 초반과 2012년 있었던 분수령 (Krizhevsky et al., 2012) 사이의 중간 기간 동안 신경망은 종종 커널 방법, (Schölkopf and Smola, 2002). , 앙상블 방법(Freund et al., 1996) 및 구조화된 추정(Taskar et al., 2004)과 같은 다른 기계 학습 방법에 의해 추월되었습니다.

 

For computer vision, this comparison is perhaps not entirely accurate. That is, although the inputs to convolutional networks consist of raw or lightly-processed (e.g., by centering) pixel values, practitioners would never feed raw pixels into traditional models. Instead, typical computer vision pipelines consisted of manually engineering feature extraction pipelines, such as SIFT (Lowe, 2004), SURF (Bay et al., 2006), and bags of visual words (Sivic and Zisserman, 2003). Rather than learning the features, the features were crafted. Most of the progress came from having more clever ideas for feature extraction on the one hand and deep insight into geometry (Hartley and Zisserman, 2000) on the other hand. The learning algorithm was often considered an afterthought.

 

컴퓨터 비전의 경우 이 비교가 완전히 정확하지 않을 수 있습니다. 즉, 컨볼루션 네트워크에 대한 입력이 원시 또는 가볍게 처리된(예: 센터링) 픽셀 값으로 구성되지만 실무자는 원시 픽셀을 기존 모델에 공급하지 않습니다. 대신 일반적인 컴퓨터 비전 파이프라인은 SIFT(Lowe, 2004), SURF(Bay et al., 2006) 및 시각적 단어 백(Sivic and Zisserman, 2003)과 같은 수동 엔지니어링 feature  추출 파이프라인으로 구성되었습니다. feature 을 배우는 대신 feature 을 제작했습니다. 대부분의 발전은 한편으로는 feature  추출에 대한 더 영리한 아이디어와 다른 한편으로는 기하학에 대한 깊은 통찰력을 갖는 것에서 비롯되었습니다(Hartley and Zisserman, 2000). 학습 알고리즘은 종종 나중에 생각하는 것으로 간주되었습니다.

 

Although some neural network accelerators were available in the 1990s, they were not yet sufficiently powerful to make deep multichannel, multilayer CNNs with a large number of parameters. For instance, NVIDIA’s GeForce 256 from 1999 was able to process at most 480 million operations per second (MFLOPs), without any meaningful programming framework for operations beyond games. Today’s accelerators are able to perform in excess of 300 TFLOPs per device (NVIDIA’s Ampere A100). Note that FLOPs are floating-point operations such as multiplications and additions. Moreover, datasets were still relatively small: OCR on 60,000 low-resolution 28×28 pixel images was considered a highly challenging task. Added to these obstacles, key tricks for training neural networks including parameter initialization heuristics (Glorot and Bengio, 2010), clever variants of stochastic gradient descent (Kingma and Ba, 2014), non-squashing activation functions (Nair and Hinton, 2010), and effective regularization techniques (Srivastava et al., 2014) were still missing.

 

1990년대에 일부 neural network accelerators를 사용할 수 있었지만 아직 많은 매개변수가 있는 깊은 다중 채널, 다층 CNN을 만들 만큼 강력하지 않았습니다. 예를 들어, 1999년 NVIDIA의 GeForce 256은 게임 이외의 작업을 위한 의미 있는 프로그래밍 프레임워크 없이 최대 4억 8천만 MFLOP(초당 작업)를 처리할 수 있었습니다. 오늘날의 가속기는 장치당 300 TFLOP 이상을 수행할 수 있습니다(NVIDIA의 Ampere A100). FLOP는 곱셈 및 덧셈과 같은 부동 소수점 연산입니다. 게다가 데이터 세트는 여전히 상대적으로 작았습니다. 60,000개의 저해상도 28×28 픽셀 이미지에 대한 OCR은 매우 어려운 작업으로 간주되었습니다. 이러한 장애물에 추가하여 매개변수 초기화 휴리스틱(Glorot 및 Bengio, 2010), 확률적 경사 하강의 영리한 변형(Kingma 및 Ba, 2014), 비압축 활성화 기능(Nair 및 Hinton, 2010), 효과적인 정규화 기술(Srivastava et al., 2014)이 여전히 누락되었습니다.

 

Thus, rather than training end-to-end (pixel to classification) systems, classical pipelines looked more like this:

 

따라서 end-to-end(픽셀에서 분류로) 시스템을 교육하는 대신 classical pipelines은 다음과 같이 생겼습니다.

 

  1. Obtain an interesting dataset. In the early days, these datasets required expensive sensors. For instance, the Apple QuickTake 100 of 1994 sported a whopping 0.3 Megapixel (VGA) resolution, capable of storing up to 8 images, all for the price of $1,000.
    흥미로운 데이터 세트를 얻습니다. 초기에는 이러한 데이터 세트에 값비싼 센서가 필요했습니다. 예를 들어, 1994년 Apple QuickTake 100은 무려 0.3메가픽셀(VGA)의 해상도를 자랑했으며, 모두 1,000달러의 가격으로 최대 8개의 이미지를 저장할 수 있었습니다.

  2. Preprocess the dataset with hand-crafted features based on some knowledge of optics, geometry, other analytic tools, and occasionally on the serendipitous discoveries of lucky graduate students.
    광학, 기하학, 기타 분석 도구에 대한 약간의 지식과 때때로 운이 좋은 대학원생의 우연한 발견을 기반으로 수작업으로 만든 기능으로 데이터 세트를 전처리합니다.

  3. Feed the data through a standard set of feature extractors such as the SIFT (scale-invariant feature transform) (Lowe, 2004), the SURF (speeded up robust features) (Bay et al., 2006), or any number of other hand-tuned pipelines. OpenCV still provides SIFT extractors to this day!
    SIFT(scale-invariant feature transform)(Lowe, 2004), SURF(speeded up robust features)(Bay et al., 2006)와 같은 standard set of feature extractors 세트를 통해 데이터를 공급합니다. -튜닝된 파이프라인. OpenCV는 현재까지도 여전히 SIFT 추출기를 제공합니다!

  4. Dump the resulting representations into your favorite classifier, likely a linear model or kernel method, to train a classifier.
    결과 representations favorite classifier(예: 선형 모델 또는 커널 메서드)에 덤프하여 classifier를 교육합니다.

 

If you spoke to machine learning researchers, they believed that machine learning was both important and beautiful. Elegant theories proved the properties of various classifiers (Boucheron et al., 2005) and convex optimization (Boyd and Vandenberghe, 2004) had become the mainstay for obtaining them. The field of machine learning was thriving, rigorous, and eminently useful. However, if you spoke to a computer vision researcher, you would hear a very different story. The dirty truth of image recognition, they would tell you, is that features, geometry (Hartley and Zisserman, 2000, Hartley and Kahl, 2009), and engineering, rather than novel learning algorithms, drove progress. Computer vision researchers justifiably believed that a slightly bigger or cleaner dataset or a slightly improved feature-extraction pipeline mattered far more to the final accuracy than any learning algorithm.

 

machine learning 연구원들과 대화를 나눈다면 그들은 기계 학습이 중요하고 아름답다고 믿었다고 했을 겁니다. 우아한 이론은 various classifiers(Boucheron et al., 2005)의 속성을 입증했으며 convex optimization(Boyd and Vandenberghe, 2004)는 이를 얻기 위한 주류가 되었습니다. 기계 학습 분야는 번성하고 엄격하며 매우 유용했습니다. 그러나 컴퓨터 비전 연구원과 대화하면 매우 다른 이야기를 듣게 될 것입니다. 이미지 인식의 더러운 진실은 새로운 학습 알고리즘이 아니라 기능, 기하학(Hartley and Zisserman, 2000, Hartley and Kahl, 2009) 및 엔지니어링이 발전을 주도했다는 것입니다. 컴퓨터 비전 연구자들은 약간 더 크거나 깨끗한 데이터 세트 또는 약간 개선된 특징 추출 파이프라인이 어떤 학습 알고리즘보다 최종 정확도에 훨씬 더 중요하다고 정당하게 믿었습니다.

 

Convex optimization refers to the field of mathematical optimization that deals with optimization problems where the objective function and constraints exhibit convexity. In convex optimization, the objective function is a convex function and the feasible region defined by the constraints is a convex set.

Convex optimization problems have several important properties. First, convexity guarantees the existence of a global minimum, meaning there is a unique optimal solution that can be found. Second, any local minimum of a convex optimization problem is also a global minimum, which simplifies the search for the optimal solution. Third, convex optimization problems have efficient algorithms that can solve them to optimality with polynomial time complexity.

Convex optimization has widespread applications in various fields, including machine learning, operations research, finance, engineering, and many others. It provides a powerful framework for formulating and solving optimization problems with desirable properties and efficient algorithms.

 

볼록 최적화(convex optimization)는 목적 함수와 제약 조건이 볼록성(convexity)을 가지는 최적화 문제를 다루는 수학적 최적화 분야를 의미합니다. 볼록 최적화에서는 목적 함수가 볼록 함수(convex function)이고, 제약 조건으로 정의된 실행 가능한 영역이 볼록 집합(convex set)인 경우를 다룹니다.

볼록 최적화 문제는 몇 가지 중요한 특성을 가지고 있습니다. 첫째로, 볼록성은 전역 최솟값의 존재를 보장합니다. 즉, 찾을 수 있는 고유한 최적해가 있습니다. 둘째로, 볼록 최적화 문제의 모든 국소 최솟값은 동시에 전역 최솟값이기 때문에 최적해를 찾는 과정이 단순화됩니다. 셋째로, 볼록 최적화 문제는 다항 시간 복잡도로 최적해를 찾을 수 있는 효율적인 알고리즘을 가지고 있습니다.

볼록 최적화는 기계 학습, 운영 연구, 금융, 공학 등 다양한 분야에서 광범위하게 응용되며, 바람직한 속성과 효율적인 알고리즘을 통해 최적화 문제를 정의하고 해결하는 강력한 프레임워크를 제공합니다.

 

import torch
from torch import nn
from d2l import torch as d2l

 

8.1.1. Representation Learning

Another way to cast the state of affairs is that the most important part of the pipeline was the representation. And up until 2012 the representation was calculated mostly mechanically. In fact, engineering a new set of feature functions, improving results, and writing up the method was a prominent genre of paper. SIFT (Lowe, 2004), SURF (Bay et al., 2006), HOG (histograms of oriented gradient) (Dalal and Triggs, 2005), bags of visual words (Sivic and Zisserman, 2003), and similar feature extractors ruled the roost.

 

state of affairs를 캐스팅하는 또 다른 방법은 파이프라인의 가장 중요한 부분이 표현(representation)이라는 것입니다. 그리고 2012년까지 표현(representation)은 대부분 기계적으로 계산되었습니다. 사실, 새로운 feature functions 세트를 엔지니어링하고, 결과를 개선하고, 방법을 작성하는 것이 중요한 논문 장르였습니다. SIFT(Lowe, 2004), SURF(Bay et al., 2006), HOG(Histograms of oriented gradient)(Dalal and Triggs, 2005), bag of visual words(Sivic and Zisserman, 2003), 그리고 similar feature extractorsroost를 지배했습니다.

 

Another group of researchers, including Yann LeCun, Geoff Hinton, Yoshua Bengio, Andrew Ng, Shun-ichi Amari, and Juergen Schmidhuber, had different plans. They believed that features themselves ought to be learned. Moreover, they believed that to be reasonably complex, the features ought to be hierarchically composed with multiple jointly learned layers, each with learnable parameters. In the case of an image, the lowest layers might come to detect edges, colors, and textures, in analogy to how the visual system in animals processes its input. In particular, the automatic design of visual features such as those obtained by sparse coding (Olshausen and Field, 1996) remained an open challenge until the advent of modern CNNs. It was not until Dean et al. (2012), Le (2013) that the idea of generating features from image data automatically gained significant traction.

 

Yann LeCun, Geoff Hinton, Yoshua Bengio, Andrew Ng, Shun-ichi Amari 및 Juergen Schmidhuber를 포함한 다른 연구원 그룹은 다른 계획을 세웠습니다. 그들은 기능(features ) 자체가 학습되어야 한다고 믿었습니다. 더욱이 그들은 합리적으로 복잡하기 위해서는 features 가 각각 학습 가능한 매개변수가 있는 여러 공동 학습 레이어로 계층적으로 구성되어야 한다고 믿었습니다. 이미지의 경우 동물의 시각 시스템이 입력을 처리하는 방식과 유사하게 최하위 계층이 가장자리, 색상 및 질감을 감지할 수 있습니다. 특히 스파스 코딩(Olshausen and Field, 1996)으로 얻은 것과 같은 시각적 기능의 자동 설계는 현대 CNN이 등장할 때까지 열린 과제로 남아 있었습니다. Dean et al. (2012), Le(2013)는 이미지 데이터에서 features 을 자동으로 생성한다는 아이디어가 상당한 견인력을 얻었다고 말했습니다.

 

The first modern CNN (Krizhevsky et al., 2012), named AlexNet after one of its inventors, Alex Krizhevsky, is largely an evolutionary improvement over LeNet. It achieved excellent performance in the 2012 ImageNet challenge.

 

발명가 중 한 명인 Alex Krizhevsky의 이름을 따서 AlexNet으로 명명된 최초의 현대식 CNN(Krizhevsky et al., 2012)은 대체로 LeNet에 비해 진화적으로 개선된 것입니다. 2012 ImageNet 챌린지에서 우수한 성능을 달성했습니다.

 

Fig. 8.1.1&nbsp; Image filters learned by the first layer of AlexNet. Reproduction courtesy of&nbsp;Krizhevsky&nbsp;et al.&nbsp;(2012).

 

Interestingly in the lowest layers of the network, the model learned feature extractors that resembled some traditional filters. Fig. 8.1.1 shows lower-level image descriptors. Higher layers in the network might build upon these representations to represent larger structures, like eyes, noses, blades of grass, and so on. Even higher layers might represent whole objects like people, airplanes, dogs, or frisbees. Ultimately, the final hidden state learns a compact representation of the image that summarizes its contents such that data belonging to different categories can be easily separated.

 

흥미롭게도 네트워크의 가장 낮은 계층에서 모델은 일부 traditional filters와 유사한  feature extractors를 학습했습니다. 그림 8.1.1은 lower-level image descriptors를 보여줍니다. 네트워크의 상위 계층은 눈, 코, 풀잎 등과 같은 더 큰 구조를 나타내기 위해 이러한 표현을 기반으로 구축될 수 있습니다. 더 높은 계층은 사람, 비행기, 개 또는 프리스비와 같은 전체 개체를 나타낼 수 있습니다. 궁극적으로 최종 숨겨진 상태는 다른 범주에 속하는 데이터를 쉽게 분리할 수 있도록 내용을 요약하는 이미지의 간결한 표현을 학습합니다.

 

AlexNet (2012) and its precursor LeNet (1995) share many architectural elements. This begs the question: why did it take so long? A key difference is that over the past two decades, the amount of data and computing power available had increased significantly. As such AlexNet was much larger: it was trained on much more data, and on much faster GPUs, compared to the CPUs available in 1995.

 

AlexNet(2012)과 그 전신인 LeNet(1995)은 많은 아키텍처 요소를 공유합니다. 이것은 질문을 던집니다. 왜 그렇게 오래 걸렸습니까? 주요 차이점은 지난 20년 동안 사용 가능한 데이터의 양과 컴퓨팅 성능이 크게 증가했다는 것입니다. 따라서 AlexNet은 훨씬 더 컸습니다. 1995년에 사용 가능한 CPU에 비해 훨씬 더 많은 데이터와 훨씬 더 빠른 GPU에서 훈련되었습니다.

 

8.1.1.1. Missing Ingredient: Data

Deep models with many layers require large amounts of data in order to enter the regime where they significantly outperform traditional methods based on convex optimizations (e.g., linear and kernel methods). However, given the limited storage capacity of computers, the relative expense of (imaging) sensors, and the comparatively tighter research budgets in the 1990s, most research relied on tiny datasets. Numerous papers relied on the UCI collection of datasets, many of which contained only hundreds or (a few) thousands of images captured in low resolution and often with an artificially clean background.

 

레이어가 많은 Deep models은 볼록 최적화-convex optimizations-(예: 선형 및 커널 방법)를 기반으로 하는 기존 방법을 훨씬 능가하는 체제에 진입하기 위해 많은 양의 데이터가 필요합니다. 그러나 컴퓨터의 제한된 저장 용량, (이미징) 센서의 상대적 비용 및 1990년대의 상대적으로 빠듯한 연구 예산을 고려할 때 대부분의 연구는 작은 데이터 세트에 의존했습니다. 수많은 논문이 UCI 데이터 세트 컬렉션에 의존했으며, 그 중 다수는 저해상도로 캡처된 이미지와 종종 인위적으로 깨끗한 배경을 포함하는 수백 또는 (몇) 수천 개의 이미지만 포함했습니다.

 

In 2009, the ImageNet dataset was released (Deng et al., 2009), challenging researchers to learn models from 1 million examples, 1000 each from 1000 distinct categories of objects. The categories themselves were based on the most popular noun nodes in WordNet (Miller, 1995). The ImageNet team used Google Image Search to prefilter large candidate sets for each category and employed the Amazon Mechanical Turk crowdsourcing pipeline to confirm for each image whether it belonged to the associated category. This scale was unprecedented, exceeding others by over an order of magnitude (e.g., CIFAR-100 has 60,000 images). Another aspect was that the images were at relatively high resolution of 224×224 pixels, unlike the 80 million sized TinyImages dataset (Torralba et al., 2008), consisting of 32×32 pixel thumbnails. This allowed for the formation of higher-level features. The associated competition, dubbed the ImageNet Large Scale Visual Recognition Challenge (Russakovsky et al., 2015), pushed computer vision and machine learning research forward, challenging researchers to identify which models performed best at a greater scale than academics had previously considered. The largest vision datasets, such as LAION-5B (Schuhmann et al., 2022) contain billions of images with additional metadata.

 

2009년에 ImageNet 데이터 세트가 출시되었으며(Deng et al., 2009), 연구자들은 1000개의 서로 다른 개체 범주에서 각각 1000개씩 100만 개의 예제에서 모델을 학습해야 했습니다. 범주 자체는 WordNet에서 가장 인기 있는 명사 노드를 기반으로 합니다(Miller, 1995). ImageNet 팀은 Google 이미지 검색을 사용하여 각 범주에 대한 대규모 후보 세트를 사전 필터링하고 Amazon Mechanical Turk 크라우드소싱 파이프라인을 사용하여 각 이미지가 관련 범주에 속하는지 여부를 확인했습니다. 이 규모는 전례가 없었으며 다른 규모보다 한 자릿수 이상 뛰어났습니다(예: CIFAR-100에는 60,000개의 이미지가 있음). 또 다른 측면은 이미지가 32×32 픽셀 썸네일로 구성된 8천만 크기의 TinyImages 데이터 세트(Torralba et al., 2008)와 달리 224×224 픽셀의 비교적 높은 해상도라는 것입니다. 이를 통해 더 높은 수준의 기능을 형성할 수 있었습니다. ImageNet 대규모 시각적 인식 챌린지(Russakovsky et al., 2015)라고 불리는 관련 대회는 컴퓨터 비전 및 기계 학습 연구를 발전시켜 연구자들이 이전에 학자들이 고려했던 것보다 더 큰 규모에서 가장 잘 수행된 모델을 식별하도록 도전했습니다. LAION-5B(Schuhmann et al., 2022)와 같은 가장 큰 비전 데이터 세트에는 추가 메타데이터가 있는 수십억 개의 이미지가 포함되어 있습니다.

 

8.1.1.2. Missing Ingredient: Hardware

 

Deep learning models are voracious consumers of compute cycles. Training can take hundreds of epochs, and each iteration requires passing data through many layers of computationally expensive linear algebra operations. This is one of the main reasons why in the 1990s and early 2000s, simple algorithms based on the more-efficiently optimized convex objectives were preferred.

 

딥 러닝 모델은 compute cycles를 탐욕스럽게 소비합니다. 교육에는 수백 에포크가 걸릴 수 있으며 각 반복에는 계산 비용이 많이 드는 선형 대수 연산의 많은 계층을 통해 데이터를 전달해야 합니다. 이것이 1990년대와 2000년대 초반에 보다 효율적으로 최적화된  convex objectives에 기반한 간단한 알고리즘이 선호되었던 주요 이유 중 하나입니다.

 

Graphical processing units (GPUs) proved to be a game changer in making deep learning feasible. These chips had long been developed for accelerating graphics processing to benefit computer games. In particular, they were optimized for high throughput 4×4 matrix-vector products, which are needed for many computer graphics tasks. Fortunately, the math is strikingly similar to that required to calculate convolutional layers. Around that time, NVIDIA and ATI had begun optimizing GPUs for general computing operations (Fernando, 2004), going as far as to market them as general-purpose GPUs (GPGPUs).

 

그래픽 처리 장치(GPU)는 딥 러닝을 실현 가능하게 만드는 게임 체인저임이 입증되었습니다. 이 칩은 컴퓨터 게임에 도움이 되는 그래픽 처리를 가속화하기 위해 오랫동안 개발되었습니다. 특히 많은 컴퓨터 그래픽 작업에 필요한 높은 처리량의 4×4 행렬-벡터 제품에 최적화되었습니다. 다행스럽게도 수학은 컨볼루션 레이어를 계산하는 데 필요한 것과 놀랍도록 유사합니다. 그 무렵 NVIDIA와 ATI는 일반 컴퓨팅 작업을 위해 GPU를 최적화하기 시작했으며(Fernando, 2004) 범용 GPU(GPGPU)로 마케팅하기까지 했습니다.

 

To provide some intuition, consider the cores of a modern microprocessor (CPU). Each of the cores is fairly powerful running at a high clock frequency and sporting large caches (up to several megabytes of L3). Each core is well-suited to executing a wide range of instructions, with branch predictors, a deep pipeline, specialized execution units, speculative execution, and many other bells and whistles that enable it to run a large variety of programs with sophisticated control flow. This apparent strength, however, is also its Achilles heel: general-purpose cores are very expensive to build. They excel at general-purpose code with lots of control flow. This requires lots of chip area, not just for the actual ALU (arithmetic logical unit) where computation happens, but also for all the aforementioned bells and whistles, plus memory interfaces, caching logic between cores, high-speed interconnects, and so on. CPUs are comparatively bad at any single task when compared to dedicated hardware. Modern laptops have 4–8 cores, and even high-end servers rarely exceed 64 cores per socket, simply because it is not cost-effective.

 

직관을 제공하기 위해 최신 마이크로프로세서(CPU)의 코어를 고려하십시오. 각 코어는 높은 클록 주파수에서 상당히 강력하게 실행되며 대형 캐시(최대 몇 메가바이트의 L3)를 자랑합니다. 각 코어는 branch predictors, a deep pipeline, specialized execution units, speculative execution 및 정교한 제어 흐름으로 다양한 프로그램을 실행할 수 있게 해주는 기타 많은 부가 기능을 통해 광범위한 명령을 실행하는 데 매우 적합합니다. 그러나 이러한 명백한 강점은 또한 약점이기도 합니다. 범용 코어는 구축 비용이 매우 많이 듭니다. 제어 흐름이 많은 범용 코드에 탁월합니다. 여기에는 연산이 발생하는 실제 ALU(산술 논리 장치)뿐만 아니라 앞서 언급한 모든 부가 기능, 메모리 인터페이스, 코어 간 캐싱 논리, 고속 상호 연결 등 많은 칩 영역이 필요합니다. CPU는 전용 하드웨어와 비교할 때 단일 작업에서 비교적 나쁩니다. 최신 노트북에는 4~8개의 코어가 있으며 고급 서버도 비용 효율적이지 않기 때문에 소켓당 64개의 코어를 거의 초과하지 않습니다.

 

By comparison, GPUs can consist of thousands of small processing elements (NIVIDA’s latest Ampere chips have up to 6912 CUDA cores), often grouped into larger groups (NVIDIA calls them warps). The details differ somewhat between NVIDIA, AMD, ARM and other chip vendors. While each core is relatively weak, running at about 1GHz clock frequency, it is the total number of such cores that makes GPUs orders of magnitude faster than CPUs. For instance, NVIDIA’s recent Ampere A100 GPU offers over 300 TFLOPs per chip for specialized 16 bit precision (BFLOAT16) matrix-matrix multiplications, and up to 20 TFLOPs for more general-purpose floating point operations (FP32). At the same time, floating point performance of CPUs rarely exceeds 1 TFLOPs. For instance, Amazon’s Graviton 3 reaches 2 TFLOPs peak performance for 16 bit precision operations, a number similar to the GPU performance of Apple’s M1 processor.

 

이에 비해 GPU는 수천 개의 작은 처리 요소(NIVIDA의 최신 Ampere 칩에는 최대 6912개의 CUDA 코어가 있음)로 구성될 수 있으며 종종 더 큰 그룹으로 그룹화됩니다(NVIDIA에서는 이를 워프라고 함). 세부 사항은 NVIDIA, AMD, ARM 및 기타 칩 공급업체 간에 다소 다릅니다. 각 코어는 상대적으로 약하고 약 1GHz 클록 주파수에서 실행되지만 GPU를 CPU보다 수십 배 더 빠르게 만드는 것은 이러한 코어의 총 수입니다. 예를 들어, NVIDIA의 최신 Ampere A100 GPU는 전문화된 16비트 정밀도(BFLOAT16) 행렬-행렬 곱셈을 위해 칩당 300 TFLOP 이상을 제공하고 보다 범용적인 부동 소수점 연산(FP32)을 위해 최대 20 TFLOP를 제공합니다. 동시에 CPU의 부동 소수점 성능은 거의 1 TFLOP를 초과하지 않습니다. 예를 들어 Amazon의 Graviton 3은 16비트 정밀 작업에서 2 TFLOPs의 최고 성능에 도달하며 이는 Apple의 M1 프로세서의 GPU 성능과 비슷한 수치입니다.

 

There are many reasons why GPUs are much faster than CPUs in terms of FLOPs. First, power consumption tends to grow quadratically with clock frequency. Hence, for the power budget of a CPU core that runs 4 times faster (a typical number), you can use 16 GPU cores at 1/4 the speed, which yields 16×1/4=4 times the performance. Second, GPU cores are much simpler (in fact, for a long time they were not even able to execute general-purpose code), which makes them more energy efficient. For instance, (i) they tend not to support speculative evaluation, (ii) it typically is not possible to program each processing element individually, and (iii) the caches per core tend to be much smaller. Last, many operations in deep learning require high memory bandwidth. Again, GPUs shine here with buses that are at least 10 times as wide as many CPUs.

 

FLOP 측면에서 GPU가 CPU보다 훨씬 빠른 데는 여러 가지 이유가 있습니다. 첫째, 전력 소비는 클록 주파수에 따라 2차적으로 증가하는 경향이 있습니다. 따라서 4배 더 빠르게 실행되는 CPU 코어의 전력 예산(일반적인 숫자)의 경우 1/4의 속도로 16개의 GPU 코어를 사용할 수 있으며, 이는 16×1/4=4배의 성능을 제공합니다. 둘째, GPU 코어는 훨씬 단순하기 때문에(사실 오랫동안 범용 코드를 실행할 수조차 없었습니다) 에너지 효율이 높아집니다. 예를 들어, (i) 추측 평가를 지원하지 않는 경향이 있고, (ii) 일반적으로 각 처리 요소를 개별적으로 프로그래밍할 수 없으며, (iii) 코어당 캐시가 훨씬 작은 경향이 있습니다. 마지막으로 딥 러닝의 많은 작업에는 높은 메모리 대역폭이 필요합니다. 여기서도 GPU는 CPU보다 최소 10배 더 넓은 버스로 빛을 발합니다.

 

Back to 2012. A major breakthrough came when Alex Krizhevsky and Ilya Sutskever implemented a deep CNN that could run on GPUs. They realized that the computational bottlenecks in CNNs, convolutions and matrix multiplications, are all operations that could be parallelized in hardware. Using two NVIDIA GTX 580s with 3GB of memory, either of which was capable of 1.5 TFLOPs (still a challenge for most CPUs a decade later), they implemented fast convolutions. The cuda-convnet code was good enough that for several years it was the industry standard and powered the first couple years of the deep learning boom.

 

2012년으로 돌아가 보자. Alex Krizhevsky와 Ilya Sutskever가 GPU에서 실행할 수 있는 심층 CNN을 구현했을 때 중대한 돌파구가 마련되었습니다. 그들은 CNN의 계산 병목 현상, 회선 및 행렬 곱셈이 모두 하드웨어에서 병렬화될 수 있는 작업이라는 것을 깨달았습니다. 3GB 메모리가 장착된 2개의 NVIDIA GTX 580을 사용하여 둘 중 하나는 1.5 TFLOP(10년 후에도 대부분의 CPU에는 여전히 문제임)를 지원하여 빠른 컨볼루션을 구현했습니다. cuda-convnet 코드는 충분히 훌륭하여 몇 년 동안 업계 표준이 되었고 딥 러닝 붐의 첫 몇 년 동안 동력이 되었습니다.

 

8.1.2. AlexNet

AlexNet, which employed an 8-layer CNN, won the ImageNet Large Scale Visual Recognition Challenge 2012 by a large margin (Russakovsky et al., 2013). This network showed, for the first time, that the features obtained by learning can transcend manually-designed features, breaking the previous paradigm in computer vision.

 

8 레이어 CNN을 사용하는 AlexNet은 ImageNet Large Scale Visual Recognition Challenge 2012에서 큰 차이로 우승했습니다(Russakovsky et al., 2013). 이 네트워크는 처음으로 학습을 통해 얻은 기능이 수동으로 설계된 기능을 초월하여 컴퓨터 비전의 이전 패러다임을 깨뜨릴 수 있음을 보여주었습니다.

 

The architectures of AlexNet and LeNet are strikingly similar, as Fig. 8.1.2 illustrates. Note that we provide a slightly streamlined version of AlexNet removing some of the design quirks that were needed in 2012 to make the model fit on two small GPUs.

 

AlexNet과 LeNet의 아키텍처는 그림 8.1.2에서 볼 수 있듯이 놀랍도록 유사합니다. 모델을 2개의 작은 GPU에 맞추기 위해 2012년에 필요했던 일부 디자인 문제를 제거한 AlexNet의 약간 간소화된 버전을 제공합니다.

 

Fig. 8.1.2&nbsp; From LeNet (left) to AlexNet (right).

 

There are also significant differences between AlexNet and LeNet. First, AlexNet is much deeper than the comparatively small LeNet5. AlexNet consists of eight layers: five convolutional layers, two fully connected hidden layers, and one fully connected output layer. Second, AlexNet used the ReLU instead of the sigmoid as its activation function. Let’s delve into the details below.

 

AlexNet과 LeNet 사이에는 중요한 차이점도 있습니다. 첫째, AlexNet은 비교적 작은 LeNet5보다 훨씬 더 깊습니다. AlexNet은 5개의 컨볼루션 레이어, 2개의 fully connected hidden layers, 1개의 fully connected output layer 등 8개의 레이어로 구성됩니다. 둘째, AlexNet은 활성화 함수로 시그모이드 대신 ReLU를 사용했습니다. 자세한 내용은 아래에서 살펴보겠습니다.

 

8.1.2.1. Architecture

In AlexNet’s first layer, the convolution window shape is 11×11. Since the images in ImageNet are eight times higher and wider than the MNIST images, objects in ImageNet data tend to occupy more pixels with more visual detail. Consequently, a larger convolution window is needed to capture the object. The convolution window shape in the second layer is reduced to 5×5, followed by 3×3. In addition, after the first, second, and fifth convolutional layers, the network adds max-pooling layers with a window shape of 3×3 and a stride of 2. Moreover, AlexNet has ten times more convolution channels than LeNet.

 

AlexNet의 첫 번째 레이어에서 컨볼루션 창 모양은 11×11입니다. ImageNet의 이미지는 MNIST 이미지보다 8배 더 높고 넓기 때문에 ImageNet 데이터의 개체는 더 많은 시각적 세부 정보로 더 많은 픽셀을 차지하는 경향이 있습니다. 결과적으로 개체를 캡처하려면 더 큰 컨볼루션 창이 필요합니다. 두 번째 레이어의 컨볼루션 창 모양은 5×5로 축소된 다음 3×3으로 축소됩니다. 또한, 첫 번째, 두 번째, 다섯 번째 컨볼루션 레이어 이후에 네트워크는 3×3의 창 모양과 2의 스트라이드를 갖는 최대 풀링 레이어를 추가합니다. 게다가 AlexNet은 LeNet보다 10배 더 많은 컨볼루션 채널을 가지고 있습니다.

 

After the last convolutional layer, there are two huge fully connected layers with 4096 outputs. These layers require nearly 1GB model parameters. Due to the limited memory in early GPUs, the original AlexNet used a dual data stream design, so that each of their two GPUs could be responsible for storing and computing only its half of the model. Fortunately, GPU memory is comparatively abundant now, so we rarely need to break up models across GPUs these days (our version of the AlexNet model deviates from the original paper in this aspect).

 

마지막 컨볼루션 레이어 다음에는 4096개의 출력을 가진 두 개의 거대한 완전 연결 레이어가 있습니다. 이러한 레이어에는 거의 1GB의 모델 매개변수가 필요합니다. 초기 GPU의 제한된 메모리로 인해 원래 AlexNet은 이중 데이터 스트림 설계를 사용하여 두 개의 GPU가 각각 모델의 절반만 저장하고 계산할 수 있도록 했습니다. 다행스럽게도 현재 GPU 메모리는 비교적 풍부하기 때문에 요즘에는 모델을 여러 GPU로 분할할 필요가 거의 없습니다(AlexNet 모델 버전은 이 측면에서 원본 논문과 다릅니다).

 

8.1.2.2. Activation Functions

Besides, AlexNet changed the sigmoid activation function to a simpler ReLU activation function. On the one hand, the computation of the ReLU activation function is simpler. For example, it does not have the exponentiation operation found in the sigmoid activation function. On the other hand, the ReLU activation function makes model training easier when using different parameter initialization methods. This is because, when the output of the sigmoid activation function is very close to 0 or 1, the gradient of these regions is almost 0, so that backpropagation cannot continue to update some of the model parameters. In contrast, the gradient of the ReLU activation function in the positive interval is always 1 (Section 5.1.2). Therefore, if the model parameters are not properly initialized, the sigmoid function may obtain a gradient of almost 0 in the positive interval, so that the model cannot be effectively trained.

 

게다가 AlexNet은 시그모이드 활성화 함수를 더 간단한 ReLU 활성화 함수로 변경했습니다. 한편으로 ReLU 활성화 함수의 계산은 더 간단합니다. 예를 들어 시그모이드 활성화 함수에 있는 지수 연산이 없습니다. 반면에 ReLU 활성화 기능은 다른 매개변수 초기화 방법을 사용할 때 모델 교육을 더 쉽게 만듭니다. 이는 시그모이드 활성화 함수의 출력이 0 또는 1에 매우 가까울 때 이러한 영역의 기울기가 거의 0이므로 역전파가 일부 모델 매개변수를 계속 업데이트할 수 없기 때문입니다. 대조적으로 양의 구간에서 ReLU 활성화 함수의 기울기는 항상 1입니다(섹션 5.1.2). 따라서 모델 매개변수가 제대로 초기화되지 않으면 시그모이드 함수는 양의 구간에서 거의 0의 기울기를 얻을 수 있으므로 모델을 효과적으로 학습할 수 없습니다.

 

8.1.2.3. Capacity Control and Preprocessing

AlexNet controls the model complexity of the fully connected layer by dropout (Section 5.6), while LeNet only uses weight decay. To augment the data even further, the training loop of AlexNet added a great deal of image augmentation, such as flipping, clipping, and color changes. This makes the model more robust and the larger sample size effectively reduces overfitting. We will discuss data augmentation in greater detail in Section 14.1. See also Buslaev et al. (2020) for an in-depth review of such preprocessing steps.

 

AlexNet은 드롭아웃(섹션 5.6)에 의해 완전히 연결된 계층의 모델 복잡성을 제어하는 반면 LeNet은 가중치 감쇠만 사용합니다. 데이터를 더욱 보강하기 위해 AlexNet의 훈련 루프는 뒤집기, 클리핑 및 색상 변경과 같은 많은 이미지 확대를 추가했습니다. 이렇게 하면 모델이 더 견고해지고 더 큰 샘플 크기가 과적합을 효과적으로 줄입니다. 데이터 증대에 대해서는 14.1절에서 더 자세히 논의할 것입니다. Buslaev et al. (2020) 이러한 전처리 단계에 대한 심층 검토.

 

class AlexNet(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(96, kernel_size=11, stride=4, padding=1),
            nn.ReLU(), nn.MaxPool2d(kernel_size=3, stride=2),
            nn.LazyConv2d(256, kernel_size=5, padding=2), nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.LazyConv2d(384, kernel_size=3, padding=1), nn.ReLU(),
            nn.LazyConv2d(384, kernel_size=3, padding=1), nn.ReLU(),
            nn.LazyConv2d(256, kernel_size=3, padding=1), nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2), nn.Flatten(),
            nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(p=0.5),
            nn.LazyLinear(4096), nn.ReLU(),nn.Dropout(p=0.5),
            nn.LazyLinear(num_classes))
        self.net.apply(d2l.init_cnn)

위 코드는 AlexNet이라는 CNN 모델을 정의하는 부분입니다. AlexNet 클래스는 d2l.Classifier를 상속하고 있으며, 하이퍼파라미터로 학습률(lr)과 클래스의 개수(num_classes)를 받습니다.

self.net은 nn.Sequential을 사용하여 다양한 합성곱(Convolutional) 층과 완전 연결(Fully-Connected) 층, 활성화 함수, 풀링(Pooling) 층, 드롭아웃(Dropout) 등이 순차적으로 배치되어 전체 신경망 모델을 구성합니다. 각 층은 AlexNet 구조에 맞게 설정되어 있으며, 합성곱 층의 파라미터로는 필터 개수, 커널 크기, 스트라이드, 패딩 값 등이 사용되었습니다.

마지막으로 self.net에 d2l.init_cnn 함수를 적용하여 가중치 초기화를 수행합니다.

 

torch.nn.LazyCOnv2d() 

 

LazyConv2d — PyTorch 2.0 documentation

Shortcuts

pytorch.org

torch.nn.LazyConv2d()는 2D 컨볼루션 레이어를 나타내는 PyTorch의 클래스입니다. 이 레이어는 컨볼루션 연산을 수행하여 입력 데이터의 특징을 추출하는 역할을 합니다. "LazyConv2d"라는 이름은 이 레이어가 실제로 계산을 수행하지 않고 필요할 때까지 연산을 지연시키는 특징을 가지고 있음을 나타냅니다.

LazyConv2d는 컨볼루션 필터(kernel)의 크기, 스트라이드(stride), 패딩(padding) 등을 설정하여 입력 데이터에 대한 컨볼루션 연산을 수행합니다. 이를 통해 입력 이미지 또는 특징 맵에 대해 지역적인 패턴을 인식하고 추출할 수 있습니다. LazyConv2d는 컨볼루션 연산을 효율적으로 수행하고, 파라미터로 전달된 설정에 따라 입력 데이터의 크기와 채널 수를 조절하여 다양한 네트워크 구조에서 사용할 수 있습니다.

LazyConv2d는 PyTorch의 nn.Module 클래스를 상속하여 정의되며, 순전파(forward) 메서드를 통해 입력 데이터를 받아 컨볼루션 연산을 수행한 결과를 반환합니다. 이 클래스는 PyTorch의 다른 레이어와 함께 사용하여 신경망 모델을 구성할 수 있으며, 학습이나 추론 과정에서 자동 미분(autograd)을 통해 그래디언트(gradient)를 계산할 수 있습니다.

LazyConv2d의 사용은 신경망 모델을 정의하고 학습하는 과정에서 필요한 컨볼루션 레이어를 구성하는 데 사용됩니다. 이를 통해 컨볼루션 신경망(Convolutional Neural Network, CNN)을 구성하고 이미지 분류, 객체 검출, 세그멘테이션 등의 컴퓨터 비전 작업에 적용할 수 있습니다.

 

nn.LazyConv2d(96, kernel_size=11, stride=4, padding=1)는 96개의 출력 채널을 가지는 2D 컨볼루션 레이어를 나타냅니다. 이 레이어는 입력 데이터에 대해 11x11 크기의 컨볼루션 필터를 사용하여 4개의 픽셀 간격으로 스트라이드(stride)를 적용하고, 입력 주변에 1개의 픽셀을 패딩(padding)합니다.

이러한 설정을 통해 LazyConv2d는 입력 데이터에 대해 지역적인 패턴을 탐지하고 특징을 추출하는 역할을 합니다. 96개의 출력 채널은 컨볼루션 연산을 통해 얻어진 다양한 특징 맵(feature map)을 의미하며, 각 채널은 입력 데이터에서 다른 특징을 인식합니다.

LazyConv2d의 주요한 파라미터는 다음과 같습니다:

  • 입력 채널 수: 이 경우에는 입력 데이터의 채널 수를 나타냅니다. 신경망의 이전 레이어에서 전달된 출력 채널 수와 일치해야 합니다.
  • 컨볼루션 필터 크기: 11x11 크기의 필터를 사용하여 입력 데이터와 합성곱을 수행합니다.
  • 스트라이드(stride): 4개의 픽셀 간격으로 입력 데이터에 대해 컨볼루션 연산을 수행합니다. 이를 통해 출력 특징 맵의 크기가 입력과 비교해 줄어듭니다.
  • 패딩(padding): 입력 데이터 주변에 1개의 픽셀을 추가하여 컨볼루션 연산을 수행하기 전에 입력의 크기를 유지합니다. 이를 통해 출력 특징 맵의 크기를 조절할 수 있습니다.

LazyConv2d는 PyTorch의 nn.Module 클래스를 상속받아 정의되며, 신경망 모델에서 다른 레이어와 함께 사용하여 컨볼루션 신경망(Convolutional Neural Network, CNN)을 구성하는 데 활용됩니다. 이 레이어는 학습 과정에서 가중치를 학습하고, 순전파(forward) 메서드를 통해 입력 데이터에 대한 컨볼루션 연산을 수행하여 출력을 계산합니다.

 

We construct a single-channel data example with both height and width of 224 to observe the output shape of each layer. It matches the AlexNet architecture in Fig. 8.1.2.

 

각 레이어의 출력 모양을 관찰하기 위해 높이와 너비가 모두 224인 단일 채널 데이터 예제를 구성합니다. 그림 8.1.2의 AlexNet 아키텍처와 일치합니다.

 

ReLU()

 

ReLU — PyTorch 2.0 documentation

Shortcuts

pytorch.org

torch.nn.ReLU()는 Rectified Linear Unit(ReLU) 활성화 함수를 나타내는 클래스입니다. ReLU는 주어진 입력에 대해 양수 값을 그대로 반환하고, 음수 값은 0으로 변환하는 비선형 함수입니다.

ReLU 함수는 다음과 같은 수식으로 정의됩니다: f(x) = max(0, x)

여기서 x는 입력값을 나타내며, f(x)는 출력값을 의미합니다. 입력값이 양수인 경우, ReLU 함수는 입력값을 그대로 반환하고, 입력값이 음수인 경우 0으로 변환됩니다. 따라서 ReLU 함수는 입력값이 양수일 때는 선형 함수처럼 작용하고, 음수일 때는 비선형 함수의 특성을 가집니다.

ReLU 함수는 주로 신경망 모델의 비선형성을 증가시키고, 신경망이 복잡한 패턴을 학습할 수 있도록 돕는데 사용됩니다. 특히, 음수 값을 0으로 변환하는 특성으로 인해 희소성(Sparsity)를 도출하며, 신경망의 연산량을 줄이고 계산 효율성을 향상시킬 수 있습니다.

torch.nn.ReLU() 클래스는 PyTorch의 nn.Module 클래스를 상속받아 정의되었으며, 신경망 모델에서 다른 레이어와 함께 사용하여 비선형성을 도입하는 데 활용됩니다. 입력값에 대한 순전파(forward) 연산을 수행하며, 학습 과정에서는 역전파(backward) 연산을 통해 기울기(gradient)를 계산합니다.

 

nn.MaxPool2d(kernel_size=3, stride=2)

torch.nn.MaxPool2d(kernel_size=3, stride=2)는 2D Max Pooling 연산을 수행하는 클래스입니다. Max Pooling은 입력 이미지 또는 특성 맵의 각 영역에서 최댓값을 추출하여 다운샘플링하는 연산입니다.

Max Pooling은 다음과 같은 파라미터를 가집니다:

  • kernel_size: Max Pooling을 수행할 영역의 크기를 정의합니다. 이는 정사각형 형태로 지정됩니다.
  • stride: Max Pooling을 수행할 영역을 이동하는 간격을 정의합니다. 이는 정사각형 형태로 지정됩니다.

Max Pooling은 입력 이미지나 특성 맵의 각 영역에서 가장 큰 값을 선택하여 다운샘플링합니다. 이를 통해 공간 해상도를 줄이고, 이미지의 변형에 대한 강인성을 향상시키고, 계산 부하를 감소시킵니다.

예를 들어, kernel_size=3, stride=2로 설정된 Max Pooling은 입력 이미지나 특성 맵을 3x3 크기의 영역으로 나누고, 각 영역에서 가장 큰 값을 선택합니다. 그리고 이동 간격인 2만큼 영역을 이동시켜 다음 영역에서도 최댓값을 선택합니다.

torch.nn.MaxPool2d 클래스는 PyTorch의 nn.Module 클래스를 상속받아 정의되었으며, 신경망 모델에서 다른 레이어와 함께 사용하여 공간적인 정보를 다운샘플링하고 추상화하는 데 활용됩니다. 입력값에 대한 순전파(forward) 연산을 수행하며, 학습 과정에서는 역전파(backward) 연산을 통해 기울기(gradient)를 계산합니다.

 

nn.Flatten()

Flatten — PyTorch 2.0 documentation

 

Flatten — PyTorch 2.0 documentation

Shortcuts

pytorch.org

nn.Flatten()은 다차원의 텐서를 1차원으로 평탄화(flatten)하는 연산을 수행하는 클래스입니다. 이는 다차원 입력 데이터를 선형 레이어에 전달하기 위해 차원을 조정하는 데 사용됩니다.

nn.Flatten()은 입력 텐서의 모든 차원을 하나의 차원으로 통합하여 1차원 벡터로 만듭니다. 예를 들어, 입력 텐서의 크기가 (batch_size, channels, height, width)인 경우, nn.Flatten()을 적용하면 (batch_size, channels * height * width) 크기의 출력을 얻을 수 있습니다. 이렇게 평탄화된 텐서는 선형 레이어의 입력으로 사용될 수 있습니다.

nn.Flatten() 클래스는 PyTorch의 nn.Module 클래스를 상속받아 정의되었으며, 신경망 모델에서 다양한 레이어와 함께 사용될 수 있습니다. 주로 이미지 처리와 관련된 신경망에서 다차원 입력 데이터를 1차원으로 변환하는 용도로 활용됩니다. 평탄화 연산은 입력 데이터의 공간적 구조를 보존하면서 선형 변환을 적용하기 위해 필요한 전처리 단계입니다.

 

nn.LazyLinear(4096)

LazyLinear — PyTorch 2.0 documentation

 

LazyLinear — PyTorch 2.0 documentation

Shortcuts

pytorch.org

torch.nn.LazyLinear(4096)는 선형 변환(linear transformation)을 수행하는 클래스입니다. 선형 변환은 입력 벡터를 선형 함수를 통해 출력 벡터로 매핑하는 연산을 의미합니다.

nn.LazyLinear은 다음과 같은 파라미터를 가집니다:

  • in_features: 입력 특성의 크기를 정의합니다. 이는 선형 변환의 입력 벡터의 크기입니다.
  • out_features: 출력 특성의 크기를 정의합니다. 이는 선형 변환의 출력 벡터의 크기입니다.

예를 들어, nn.LazyLinear(4096)는 입력 벡터의 크기가 4096인 데이터를 받아들여 선형 변환을 수행하여 출력 벡터의 크기가 4096인 결과를 반환합니다.

torch.nn.LazyLinear 클래스는 PyTorch의 nn.Module 클래스를 상속받아 정의되었으며, 신경망 모델의 선형 레이어로 활용됩니다. 선형 변환은 입력 데이터의 특성을 변환하고 차원을 조정하는 데 사용됩니다. 순전파(forward) 연산에서는 입력값에 선형 변환을 적용하고, 역전파(backward) 연산을 통해 기울기(gradient)를 계산합니다. 이를 통해 신경망의 학습 과정에서 가중치와 편향을 조정하여 최적화할 수 있습니다.

 

nn.Dropout(p=0.5)

nn.Dropout(p=0.5)은 신경망 모델에서 사용되는 드롭아웃(dropout) 연산을 수행하는 클래스입니다. 드롭아웃은 모델의 일부 뉴런을 임의로 비활성화하여 일부러 과적합(overfitting)을 방지하고 일반화 성능을 향상시키는 데 사용됩니다.

nn.Dropout 클래스의 생성자에는 확률적으로 비활성화할 뉴런의 비율을 나타내는 매개변수 p가 포함됩니다. 이 값은 일반적으로 0과 1 사이의 실수로 지정되며, 각 뉴런이 비활성화될 확률을 나타냅니다. 예를 들어, p=0.5인 경우 각 뉴런이 50%의 확률로 비활성화됩니다.

드롭아웃은 학습 중에만 적용되며, 테스트 시에는 모든 뉴런을 활성화하여 출력을 계산합니다. 이는 모델의 일반화 능력을 향상시키는 데 도움이 되는 방법 중 하나입니다. 드롭아웃은 특히 크고 복잡한 신경망에서 과적합을 방지하고 일반화 성능을 향상시키는 데 효과적입니다.

nn.Dropout 클래스는 PyTorch의 nn.Module 클래스를 상속받아 정의되었으며, 신경망 모델의 다른 레이어와 함께 사용될 수 있습니다. 주로 fully connected 레이어 또는 합성곱 레이어 다음에 추가하여 사용되며, 모델의 성능을 개선하고 일반화 성능을 향상시키는 데 도움을 줍니다.

 

---------------------------------------------------------

 

AlexNet().layer_summary((1, 1, 224, 224))

위 코드는 AlexNet 모델의 레이어 요약 정보를 출력하는 부분입니다. AlexNet()을 호출하여 AlexNet 모델의 객체를 생성한 후, layer_summary((1, 1, 224, 224))를 호출합니다. 이를 통해 입력 데이터의 shape를 (1, 1, 224, 224)로 설정하고, 모델의 각 레이어를 순차적으로 통과시킨 후, 각 레이어의 출력 형태를 출력합니다. 이를 통해 모델의 각 레이어가 입력 데이터에 대해 어떤 변화를 주는지 확인할 수 있습니다.

 

형상 (1, 1, 224, 224)은 4차원 텐서를 나타냅니다. 각 차원은 특정한 의미를 가지고 있습니다:

  • 첫 번째 차원 (1)은 배치 크기를 나타냅니다. 이는 한 번의 순전파 또는 역전파 과정에서 함께 처리되는 샘플 또는 예제의 수를 나타냅니다.
  • 두 번째 차원 (1)은 채널의 수를 나타냅니다. 이 경우 1이므로 텐서는 단일 채널을 가지고 있음을 나타냅니다. 예를 들어, 흑백 이미지의 경우 채널은 각 픽셀의 밝기 값을 나타냅니다.
  • 세 번째 차원 (224)은 텐서의 높이를 나타냅니다. 이는 각 채널에서의 행 또는 픽셀 수에 해당합니다.
  • 네 번째 차원 (224)은 텐서의 너비를 나타냅니다. 이는 각 채널에서의 열 또는 픽셀 수에 해당합니다.

요약하면, 형상 (1, 1, 224, 224)은 높이와 너비가 각각 224 픽셀인 단일 흑백 이미지를 나타냅니다. 첫 번째 차원은 배치 크기를 나타내며, 이 경우 1입니다. 두 번째 차원은 채널의 수를 나타내며, 흑백 이미지의 경우 1입니다.

torch.Size([1, 96, 54, 54])는 4차원 텐서의 크기를 나타냅니다. 각 차원은 특정한 의미를 가지고 있습니다:

  • 첫 번째 차원 (1)은 배치 크기를 나타냅니다. 이는 한 번의 순전파 또는 역전파 과정에서 함께 처리되는 샘플 또는 예제의 수를 나타냅니다.
  • 두 번째 차원 (96)은 채널의 수를 나타냅니다. 이 경우 96이므로 텐서는 96개의 채널을 가지고 있음을 나타냅니다. 예를 들어, 컨볼루션 신경망에서는 여러 개의 필터 또는 특성 맵을 사용하여 다양한 채널을 생성합니다.
  • 세 번째 차원 (54)은 텐서의 높이를 나타냅니다. 이는 각 채널에서의 행 또는 픽셀 수에 해당합니다.
  • 네 번째 차원 (54)은 텐서의 너비를 나타냅니다. 이는 각 채널에서의 열 또는 픽셀 수에 해당합니다.

요약하면, torch.Size([1, 96, 54, 54])는 배치 크기가 1이고 96개의 채널을 가진 텐서로, 각 채널은 높이와 너비가 각각 54인 이미지 또는 특성 맵을 나타냅니다.

8.1.3. Training

 

Although AlexNet was trained on ImageNet in Krizhevsky et al. (2012), we use Fashion-MNIST here since training an ImageNet model to convergence could take hours or days even on a modern GPU. One of the problems with applying AlexNet directly on Fashion-MNIST is that its images have lower resolution (28×28 pixels) than ImageNet images. To make things work, we upsample them to 224×224. This is generally not a smart practice, as it simply increases the computational complexity without adding information. Nonetheless, we do it here to be faithful to the AlexNet architecture. We perform this resizing with the resize argument in the d2l.FashionMNIST constructor.

 

AlexNet은 Krizhevsky et al. (2012), ImageNet 모델을 컨버전스로 교육하는 데 최신 GPU에서도 몇 시간 또는 며칠이 걸릴 수 있으므로 여기서는 Fashion-MNIST를 사용합니다. Fashion-MNIST에 AlexNet을 직접 적용할 때의 문제점 중 하나는 이미지가 ImageNet 이미지보다 해상도(28×28 픽셀)가 낮다는 것입니다. 작업을 수행하기 위해 224×224로 업샘플링합니다. 이는 정보를 추가하지 않고 단순히 계산 복잡성을 증가시키기 때문에 일반적으로 현명한 방법이 아닙니다. 그럼에도 불구하고 여기서는 AlexNet 아키텍처에 충실하기 위해 수행합니다. d2l.FashionMNIST 생성자에서 resize 인수를 사용하여 이 크기 조정을 수행합니다.

 

Now, we can start training AlexNet. Compared to LeNet in Section 7.6, the main change here is the use of a smaller learning rate and much slower training due to the deeper and wider network, the higher image resolution, and the more costly convolutions.

 

7.6. Convolutional Neural Networks (LeNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

 

이제 AlexNet 교육을 시작할 수 있습니다. 섹션 7.6의 LeNet과 비교할 때 여기서 주요 변경 사항은 더 깊고 넓은 네트워크, 더 높은 이미지 해상도 및 더 많은 비용이 드는 컨볼루션으로 인해 더 작은 학습 속도와 훨씬 더 느린 훈련을 사용한다는 것입니다.

 

model = AlexNet(lr=0.01)
data = d2l.FashionMNIST(batch_size=128, resize=(224, 224))
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(model, data)

위 코드는 AlexNet 모델을 사용하여 FashionMNIST 데이터셋을 학습하는 부분입니다.

먼저 AlexNet(lr=0.01)을 호출하여 model이라는 AlexNet 모델 객체를 생성합니다. 이 때, 학습률 lr은 0.01로 설정됩니다.

다음으로 d2l.FashionMNIST(batch_size=128, resize=(224, 224))를 호출하여 FashionMNIST 데이터셋을 생성합니다. 이 때, 배치 크기 batch_size는 128로 설정되고, 이미지 크기를 (224, 224)로 리사이즈합니다.

마지막으로 d2l.Trainer(max_epochs=10, num_gpus=1)를 호출하여 트레이너 객체 trainer를 생성합니다. 이 때, 최대 에폭 수 max_epochs는 10으로 설정되고, GPU 개수 num_gpus는 1로 설정됩니다.

마지막으로 trainer.fit(model, data)를 호출하여 모델을 데이터에 대해 학습시킵니다. 학습은 지정된 최대 에폭 수까지 진행되며, GPU를 사용하여 학습을 가속화합니다.

 

Result from Book

Result from CoLab

 

Result from SageMaker

 

8.1.4. Discussion

 

AlexNet’s structure bears a striking resemblance to LeNet, with a number of critical improvements, both for accuracy (dropout) and for ease of training (ReLU). What is equally striking is the amount of progress that has been made in terms of deep learning tooling. What was several months of work in 2012 can now be accomplished in a dozen lines of code using any modern framework.

 

AlexNet의 구조는 정확성(드롭아웃)과 교육 용이성(ReLU) 모두에서 여러 가지 중요한 개선 사항을 포함하여 LeNet과 놀라울 정도로 유사합니다. 똑같이 놀라운 것은 딥 러닝 툴링 측면에서 이루어진 진전의 양입니다. 2012년에 몇 달 동안 작업했던 작업을 이제 최신 프레임워크를 사용하여 12줄의 코드로 수행할 수 있습니다. 

 

Reviewing the architecture, we see that AlexNet has an Achilles heel when it comes to efficiency: the last two hidden layers require matrices of size 6400×4096 and 4096×4096, respectively. This corresponds to 164 MB of memory and 81 MFLOPs of computation, both of which are a nontrivial outlay, especially on smaller devices, such as mobile phones. This is one of the reasons why AlexNet has been surpassed by much more effective architectures that we will cover in the following sections. Nonetheless, it is a key step from shallow to deep networks that are used nowadays. Note that even though the number of parameters by far exceeds the amount of training data in our experiments (the last two layers have more than 40 million parameters, trained on a datasets of 60 thousand images), there is hardly any overfitting: training and validation loss are virtually identical throughout training. This is due to the improved regularization, such as Dropout, inherent in modern deep network designs.

 

아키텍처를 검토하면 AlexNet이 효율성 측면에서 약점이 있음을 알 수 있습니다. 마지막 두 개의 숨겨진 레이어에는 각각 크기가 6400×4096 및 4096×4096인 행렬이 필요합니다. 이것은 164MB의 메모리와 81MFLOP의 계산에 해당하며, 둘 다 특히 휴대폰과 같은 소형 장치에서 적지 않은 지출입니다. 이것은 다음 섹션에서 다룰 훨씬 더 효과적인 아키텍처가 AlexNet을 능가하는 이유 중 하나입니다. 그럼에도 불구하고 오늘날 사용되는 얕은 네트워크에서 깊은 네트워크로의 핵심 단계입니다. 매개변수의 수가 실험에서 훈련 데이터의 양을 훨씬 초과하더라도(마지막 두 레이어에는 4천만 개 이상의 매개변수가 있으며 6만 개의 이미지 데이터 세트에서 훈련됨) 과적합이 거의 없습니다. 훈련 및 검증 손실은 훈련 전반에 걸쳐 거의 동일합니다. 이는 최신 심층 네트워크 디자인에 내재된 Dropout과 같은 개선된 정규화 때문입니다.

 

Although it seems that there are only a few more lines in AlexNet’s implementation than in LeNet’s, it took the academic community many years to embrace this conceptual change and take advantage of its excellent experimental results. This was also due to the lack of efficient computational tools. At the time neither DistBelief (Dean et al., 2012) nor Caffe (Jia et al., 2014) existed, and Theano (Bergstra et al., 2010) still lacked many distinguishing features. It is only the availability of TensorFlow (Abadi et al., 2016) that changed this situation dramatically.

 

AlexNet의 구현에는 LeNet보다 몇 줄만 더 있는 것처럼 보이지만 학계에서 이러한 개념적 변화를 수용하고 우수한 실험 결과를 활용하는 데 수년이 걸렸습니다. 이는 효율적인 계산 도구가 부족했기 때문이기도 합니다. 그 당시에는 DistBelief(Dean et al., 2012)나 Caffe(Jia et al., 2014)도 존재하지 않았고 Theano(Bergstra et al., 2010)는 여전히 많은 구별 기능이 부족했습니다. 이 상황을 극적으로 변화시킨 것은 TensorFlow(Abadi et al., 2016)의 가용성뿐입니다.

 

8.1.5. Exercises

  1. Following up on the discussion above, analyze the computational properties of AlexNet.
    1. Compute the memory footprint for convolutions and fully connected layers, respectively. Which one dominates?
    2. Calculate the computational cost for the convolutions and the fully connected layers.
    3. How does the memory (read and write bandwidth, latency, size) affect computation? Is there any difference in its effects for training and inference?
  2. You are a chip designer and need to trade off computation and memory bandwidth. For example, a faster chip requires more power and possibly a larger chip area. More memory bandwidth requires more pins and control logic, thus also more area. How do you optimize?
  3. Why do engineers no longer report performance benchmarks on AlexNet?
  4. Try increasing the number of epochs when training AlexNet. Compared with LeNet, how do the results differ? Why?
  5. AlexNet may be too complex for the Fashion-MNIST dataset, in particular due to the low resolution of the initial images.
    1. Try simplifying the model to make the training faster, while ensuring that the accuracy does not drop significantly.
    2. Design a better model that works directly on 28×28 images.
  6. Modify the batch size, and observe the changes in throughput (images/s), accuracy, and GPU memory.
  7. Apply dropout and ReLU to LeNet-5. Does it improve? Can you improve things further by preprocessing to take advantage of the invariances inherent in the images?
  8. Can you make AlexNet overfit? Which feature do you need to remove or change to break training?
반응형


반응형

8. Modern Convolutional Neural Networks — Dive into Deep Learning 1.0.0-beta0 documentation (d2l.ai)

 

8. Modern Convolutional Neural Networks — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

 

8. Modern Convolutional Neural Networks

 

Now that we understand the basics of wiring together CNNs, let’s take a tour of modern CNN architectures. This tour is, by necessity, incomplete, thanks to the plethora of exciting new designs being added. Their importance derives from the fact that not only can they be used directly for vision tasks, but they also serve as basic feature generators for more advanced tasks such as tracking (Zhang et al., 2021), segmentation (Long et al., 2015), object detection (Redmon and Farhadi, 2018), or style transformation (Gatys et al., 2016). In this chapter, most sections correspond to a significant CNN architecture that was at some point (or currently) the base model upon which many research projects and deployed systems were built. Each of these networks was briefly a dominant architecture and many were winners or runners-up in the ImageNet competition which has served as a barometer of progress on supervised learning in computer vision since 2010. It is only recently that Transformers have begun to displace CNNs, starting with Dosovitskiy et al. (2021) and followed by the Swin Transformer (Liu et al., 2021). We will cover this development later in the chapter on Attention Mechanisms and Transformers.

 

이제 CNN을 연결하는 기본 사항을 이해했으므로 최신 CNN 아키텍처를 살펴보겠습니다. 이 투어는 필요에 따라 불완전할 수 있습니다. 흥미진진한 새로운 디자인이 추가되고 있기 때문입니다. 그들의 중요성은 비전 작업에 직접 사용될 수 있을 뿐만 아니라 tracking (Zhang et al., 2021), segmentation  (Long et al., 2015), object detection(Redmon and Farhadi, 2018) 또는 style transformation(Gatys et al., 2016)과 같은 고급 작업을 위한 기본 기능 생성기 역할도 한다는 사실에서 비롯됩니다 . 이 장에서 대부분의 섹션은 특정 시점(또는 현재)에 많은 연구 프로젝트와 배포된 시스템이 구축된 기본 모델이었던 중요한 CNN 아키텍처에 해당합니다. 이러한 각 네트워크는 잠시 동안 지배적인 아키텍처였으며 2010년 이후 컴퓨터 비전에서 감독 학습의 진행 상황을 나타내는 척도 역할을 해 온 ImageNet 경쟁에서 많은 네트워크가 승자 또는 준우승자였습니다. 트랜스포머가 CNN을 대체하기 시작한 것은 최근의 일입니다. Dosovitskiy et al. (2021), Swin Transformer(Liu et al., 2021)가 그 뒤를 이었습니다. Attention Mechanisms and Transformers에 대한 장에서 나중에 이 개발을 다룰 것입니다.

 

While the idea of deep neural networks is quite simple (stack together a bunch of layers), performance can vary wildly across architectures and hyperparameter choices. The neural networks described in this chapter are the product of intuition, a few mathematical insights, and a lot of trial and error. We present these models in chronological order, partly to convey a sense of the history so that you can form your own intuitions about where the field is heading and perhaps develop your own architectures. For instance, batch normalization and residual connections described in this chapter have offered two popular ideas for training and designing deep models, both of which have since been applied to architectures beyond computer vision, too.

 

심층 신경망의 아이디어는 매우 간단하지만(여러 레이어를 함께 쌓음) 성능은 아키텍처와 하이퍼파라미터 선택에 따라 크게 다를 수 있습니다. 이 장에서 설명하는 신경망은 직관, 몇 가지 수학적 통찰, 그리고 많은 시행착오의 산물입니다. 우리는 이러한 모델을 연대순으로 제시하며 부분적으로는 역사 감각을 전달하여 해당 분야가 어디로 향하고 있는지에 대한 직관을 형성하고 아마도 자신만의 아키텍처를 개발할 수 있도록 합니다. 예를 들어, 이 장에서 설명하는 batch normalizationresidual connections은 딥 모델 훈련 및 설계에 대한 두 가지 인기 있는 아이디어를 제공했으며, 둘 다 이후 컴퓨터 비전을 넘어 아키텍처에도 적용되었습니다.

 

Batch Normalization 이란.

 

Batch Normalization is a technique used in Convolutional Neural Networks (CNNs) to normalize the activations of each layer during the training process. It aims to stabilize and improve the performance of the model by adjusting the distribution of input data within each mini-batch.

 

배치 정규화(Batch Normalization)는 합성곱 신경망(Convolutional Neural Networks, CNN)에서 사용되는 기법으로, 훈련 과정에서 각 층의 활성화를 정규화(normalize)하는 역할을 합니다. 이를 통해 모델의 안정성을 향상시키고 성능을 개선하기 위해 입력 데이터의 분포를 조정합니다.

 

The main idea behind Batch Normalization is to normalize the activation values of each layer. As the distribution of activation values may change throughout the layers, it can make training difficult and sensitive to hyperparameter tuning. Batch Normalization addresses this issue by normalizing the inputs of each layer using the mean and variance calculated within each mini-batch.

 

배치 정규화의 주요 아이디어는 각 층의 활성화 값을 정규화하는 것입니다. 각 층에서 활성화 값의 분포가 변할 수 있으므로 이는 훈련을 어렵게 하고 하이퍼파라미터 튜닝에 민감하게 만들 수 있습니다. 배치 정규화는 이러한 문제를 해결하기 위해 각 미니배치 내에서 입력 데이터의 평균과 분산을 계산하여 입력 데이터를 정규화합니다.

 

The normalization process in Batch Normalization involves calculating the mean and variance of the input data within each mini-batch. The input data is then normalized using these statistics. After normalization, the layer applies scale and shift parameters to the normalized inputs to compute the layer outputs. This helps to maintain a stable distribution of the input data across the layers, resulting in stabilized training and improved generalization performance.

 

배치 정규화의 정규화 과정은 각 미니배치 내에서 입력 데이터의 평균과 분산을 계산하는 단계로 이루어집니다. 그 후 입력 데이터는 이러한 통계치를 사용하여 정규화됩니다. 정규화된 입력에는 스케일과 쉬프트 파라미터가 적용되어 층의 출력을 계산합니다. 이를 통해 입력 데이터의 분포를 안정화하여 훈련 과정을 안정화시키고 일반화 성능을 향상시킵니다.

 

Batch Normalization offers several advantages in CNNs. It helps mitigate the issues of gradient vanishing and exploding that can occur during training. It improves the speed of convergence by reducing the internal covariate shift. It also reduces the sensitivity to hyperparameter tuning, making the network more robust.

 

배치 정규화는 CNN에서 여러 가지 이점을 제공합니다. 그레이디언트 소실과 폭주와 같은 문제를 완화시킵니다. 내부 공변량 이동(internal covariate shift)을 감소시켜 수렴 속도를 향상시킵니다. 또한 하이퍼파라미터 튜닝에 대한 민감성을 감소시켜 모델을 더 견고하게 만듭니다.

 

Batch Normalization is widely used in CNNs and has become an essential component for improving stability and performance in deep learning models.

 

배치 정규화는 CNN에서 널리 사용되며, 딥러닝 모델의 안정성과 성능 향상에 필수적인 구성 요소로 자리잡았습니다.

 

 

Residual Connections 란?

 

Residual Connections, also known as skip connections, are a technique used in Convolutional Neural Networks (CNNs) to address the vanishing gradient problem and enable the training of very deep networks.

 

Residual Connections(잔차 연결), 또는 스킵 연결,은 합성곱 신경망(CNN)에서 사용되는 기술로, 소실 그래디언트 문제(vanishing gradient problem)를 해결하고 매우 깊은 네트워크의 훈련을 가능하게 합니다.

 

In a standard CNN, each layer takes the output of the previous layer as input and applies a series of convolutional and activation operations. During training, gradients are backpropagated through the layers to update the network parameters. However, as the network gets deeper, the gradients can become very small, leading to the vanishing gradient problem. This makes it difficult for deep networks to learn and slows down the training process.

 

일반적인 CNN에서 각 층은 이전 층의 출력을 입력으로 받아 일련의 합성곱과 활성화 연산을 적용합니다. 훈련 중에는 그래디언트가 층을 통해 역전파되어 네트워크 매개변수를 업데이트합니다. 그러나 네트워크가 더 깊어질수록 그래디언트가 매우 작아지는 소실 그래디언트 문제가 발생할 수 있습니다. 이로 인해 깊은 네트워크가 학습하기 어려워지고 훈련 과정이 느려집니다.

 

Residual Connections aim to alleviate this problem by introducing skip connections that directly connect earlier layers to later layers. Instead of relying solely on the information flowing through the layers, residual connections allow the network to learn residual mappings. The output of a layer is added to the output of a previous layer, allowing the network to learn the difference or residual between these two outputs.

Mathematically, a residual connection can be represented as:

 

Residual Connections은 이 문제를 완화하기 위해 이전 층과 후속 층을 직접 연결하는 스킵 연결을 도입합니다. 층 사이를 통과하는 정보에만 의존하는 대신, 잔차 연결을 통해 네트워크는 잔차 매핑(residual mapping)을 학습할 수 있습니다. 층의 출력은 이전 층의 출력과 더해져 차이나 잔차를 학습하는 것입니다.

수학적으로 잔차 연결은 다음과 같이 표현될 수 있습니다:

output = input + F(input)

where input is the input to the layer, F(input) represents the transformation performed by the layer, and output is the combined output.

 

여기서 '입력'은 층에 주어진 입력, 'F(입력)'은 layer에 의해 수행된 변환, '출력'은 두 출력을 합친 것을 의미합니다.

 

By adding these residual connections, the network can effectively bypass and shortcut some of the layers. This helps in propagating gradients more easily and enables the network to learn deeper and more complex representations. It also allows the network to retain important information from earlier layers, even if subsequent layers try to modify or suppress it.

 

이러한 잔차 연결을 추가함으로써 네트워크는 일부 층을 우회하고 건너뛸 수 있습니다. 이를 통해 그래디언트를 보다 쉽게 전파할 수 있으며 네트워크가 더 깊고 복잡한 표현을 학습할 수 있게 됩니다. 또한 잔차 연결은 후속 층이 이를 수정하거나 억제하려고 할지라도 이전 층에서 중요한 정보를 보존할 수 있도록 도와줍니다.

 

Residual Connections have been shown to improve the training and performance of deep CNNs. They have been widely adopted in architectures like ResNet, where residual blocks are used to build very deep networks. These connections enable the successful training of models with hundreds or even thousands of layers and have contributed to significant advancements in computer vision tasks.

 

잔차 연결은 깊은 CNN의 훈련과 성능을 개선하는 데 도움이 됩니다. 잔차 블록(residual block)이 사용되는 ResNet과 같은 아키텍처에서 널리 채택되었습니다. 이러한 연결은 수백 개 또는 수천 개의 층을 가진 모델을 성공적으로 훈련할 수 있게 하며 컴퓨터 비전 작업에서의 중요한 발전에 기여하였습니다.

 

We begin our tour of modern CNNs with AlexNet (Krizhevsky et al., 2012), the first large-scale network deployed to beat conventional computer vision methods on a large-scale vision challenge; the VGG network (Simonyan and Zisserman, 2014), which makes use of a number of repeating blocks of elements; the network in network (NiN) that convolves whole neural networks patch-wise over inputs (Lin et al., 2013); GoogLeNet that uses networks with multi-branch convolutions (Szegedy et al., 2015); the residual network (ResNet) (He et al., 2016), which remains some of the most popular off-the-shelf architectures in computer vision; ResNeXt blocks (Xie et al., 2017) for sparser connections; and DenseNet (Huang et al., 2017) for a generalization of the residual architecture. Over time many special optimizations for efficient networks were developed, such as coordinate shifts (ShiftNet) (Wu et al., 2018). This culminated in the automatic search for efficient architectures such as MobileNet v3 (Howard et al., 2019). It also includes the semi-automatic design exploration of Radosavovic et al. (2020) that led to the RegNetX/Y which we will discuss later in this chapter. The work is instructive insofar as it offers a path to marry brute force computation with the ingenuity of an experimenter in the search for efficient design spaces. Of note is also the work of Liu et al. (2022) as it shows that training techniques (e.g., optimizers, data augmentation, and regularization) play a pivotal role in improving accuracy. It also shows that long-held assumptions, such as the size of a convolution window, may need to be revisited, given the increase in computation and data. We will cover this and many more questions in due course throughout this chapter.

 

우리는 대규모 비전 챌린지에서 기존의 컴퓨터 비전 방법을 능가하기 위해 배치된 최초의 대규모 네트워크인 AlexNet(Krizhevsky et al., 2012)으로 최신 CNN 투어를 시작합니다. VGG 네트워크(Simonyan and Zisserman, 2014)는 반복되는 여러 요소 블록을 사용합니다. 전체 신경망을 입력에 대해 패치 방식으로 컨볼루션하는 NiN(Network in Network)(Lin et al., 2013); 다중 분기 컨볼루션이 있는 네트워크를 사용하는 GoogLeNet(Szegedy et al., 2015); 잔여 네트워크(ResNet)(He et al., 2016)는 컴퓨터 비전에서 가장 인기 있는 기성품 아키텍처 중 일부로 남아 있습니다. 박한 연결을 위한 ResNeXt 블록(Xie et al., 2017); 잔차 아키텍처의 일반화를 위한 DenseNet(Huang et al., 2017) 등의 방법론들이 있습니다.

시간이 지남에 따라 좌표 이동(ShiftNet)과 같은 효율적인 네트워크를 위한 많은 특수 최적화가 개발되었습니다(Wu et al., 2018). 이는 MobileNet v3(Howard et al., 2019)와 같은 효율적인 아키텍처에 대한 자동 검색으로 절정에 달했습니다. 또한 Radosavovic et al.의 반자동 설계 탐색도 포함됩니다. (2020) 이 장의 뒷부분에서 논의할 RegNetX/Y로 이어졌습니다. 이 작업은 효율적인 설계 공간을 찾는 실험자의 독창성과 무차별 대입 계산을 결합하는 경로를 제공한다는 점에서 유익합니다. 주목할 만한 것은 Liu et al. (2022)는 학습 기술(예: 최적화 프로그램, 데이터 확대 및 정규화)이 정확도 향상에 중추적인 역할을 한다는 것을 보여줍니다. 또한 컨볼루션 창의 크기와 같은 오랜 가정을 계산 및 데이터의 증가로 인해 재검토해야 할 수도 있음을 보여줍니다. 우리는 이 장 전체에서 이 문제와 더 많은 질문을 다룰 것입니다.

 

 

https://youtu.be/iE4u8iu6Ioc

https://youtu.be/1Q_etC_GHHk

 

반응형


반응형

7.6. Convolutional Neural Networks (LeNet) — Dive into Deep Learning 1.0.0-beta0 documentation (d2l.ai)

 

7.6. Convolutional Neural Networks (LeNet) — Dive into Deep Learning 1.0.0-beta0 documentation

 

d2l.ai

 

7.6. Convolutional Neural Networks (LeNet)

 

We now have all the ingredients required to assemble a fully-functional CNN. In our earlier encounter with image data, we applied a linear model with softmax regression (Section 4.4) and an MLP (Section 5.2) to pictures of clothing in the Fashion-MNIST dataset. To make such data amenable we first flattened each image from a 28×28 matrix into a fixed-length 784-dimensional vector, and thereafter processed them in fully connected layers. Now that we have a handle on convolutional layers, we can retain the spatial structure in our images. As an additional benefit of replacing fully connected layers with convolutional layers, we will enjoy more parsimonious models that require far fewer parameters.

 

이제 완전한 기능을 갖춘 CNN을 조립하는 데 필요한 모든 요소가 있습니다. 이전 이미지 데이터와의 만남에서 Softmax 회귀(섹션 4.4) 및 MLP(섹션 5.2)가 포함된 선형 모델을 Fashion-MNIST 데이터 세트의 의류 사진에 적용했습니다. 이러한 데이터를 사용 가능하게 만들기 위해 먼저 28×28 매트릭스의 각 이미지를 고정 길이 784차원 벡터로 평면화한 다음 완전히 연결된 레이어에서 처리했습니다. 이제 컨볼루션 레이어에 대한 핸들이 있으므로 이미지의 공간 구조를 유지할 수 있습니다. 완전 연결 레이어를 컨볼루션 레이어로 대체하는 추가 이점으로 훨씬 적은 매개변수가 필요한 더 간결한 모델을 즐길 수 있습니다.

 

In this section, we will introduce LeNet, among the first published CNNs to capture wide attention for its performance on computer vision tasks. The model was introduced by (and named for) Yann LeCun, then a researcher at AT&T Bell Labs, for the purpose of recognizing handwritten digits in images (LeCun et al., 1998). This work represented the culmination of a decade of research developing the technology. In 1989, LeCun’s team published the first study to successfully train CNNs via backpropagation (LeCun et al., 1989).

 

이 섹션에서는 컴퓨터 비전 작업에 대한 성능으로 많은 관심을 끌기 위해 처음으로 게시된 CNN 중 LeNet을 소개합니다. 이 모델은 당시 AT&T Bell Labs의 연구원이었던 Yann LeCun에 의해 이미지에서 손으로 쓴 숫자를 인식할 목적으로 도입되었습니다(LeCun et al., 1998). 이 작업은 기술 개발에 대한 10년 간의 연구의 정점을 나타냅니다. 1989년 LeCun 팀은 backpropagation 를 통해 CNN을 성공적으로 훈련시키는 첫 번째 연구를 발표했습니다(LeCun et al., 1989).

 

At the time LeNet achieved outstanding results matching the performance of support vector machines, then a dominant approach in supervised learning, achieving an error rate of less than 1% per digit. LeNet was eventually adapted to recognize digits for processing deposits in ATM machines. To this day, some ATMs still run the code that Yann LeCun and his colleague Leon Bottou wrote in the 1990s!

 

당시 LeNet은 지원 벡터 머신의 성능과 일치하는 뛰어난 결과를 달성했으며 지도 학습에서 지배적인 접근 방식으로 자릿수당 1% 미만의 오류율을 달성했습니다. LeNet은 결국 ATM 기계에서 예금을 처리하기 위해 숫자를 인식하도록 조정되었습니다. 현재까지도 일부 ATM은 Yann LeCun과 그의 동료인 Leon Bottou가 1990년대에 작성한 코드를 실행하고 있습니다!

 

import torch
from torch import nn
from d2l import torch as d2l

 

7.6.1. LeNet

 

At a high level, LeNet (LeNet-5) consists of two parts: (i) a convolutional encoder consisting of two convolutional layers; and (ii) a dense block consisting of three fully connected layers; The architecture is summarized in Fig. 7.6.1.

 

대략적으로 LeNet(LeNet-5)은 두 부분으로 구성됩니다. (i) 두 개의 컨볼루션 레이어로 구성된 컨볼루션 인코더 및 (ii) 3개의 완전히 연결된 레이어로 구성된 조밀한 블록; 아키텍처는 그림 7.6.1에 요약되어 있습니다.

 

Fig. 7.6.1&nbsp; Data flow in LeNet. The input is a handwritten digit, the output a probability over 10 possible outcomes.

 

The basic units in each convolutional block are a convolutional layer, a sigmoid activation function, and a subsequent average pooling operation. Note that while ReLUs and max-pooling work better, these discoveries had not yet been made at the time. Each convolutional layer uses a 5×5 kernel and a sigmoid activation function. These layers map spatially arranged inputs to a number of two-dimensional feature maps, typically increasing the number of channels. The first convolutional layer has 6 output channels, while the second has 16. Each 2×2 pooling operation (stride 2) reduces dimensionality by a factor of 4 via spatial downsampling. The convolutional block emits an output with shape given by (batch size, number of channel, height, width).

 

각 컨볼루션 블록의 기본 단위는 컨볼루션 레이어, 시그모이드 활성화 함수 및 후속 평균 풀링 연산입니다. ReLU와 최대 풀링이 더 잘 작동하지만 당시에는 이러한 발견이 아직 이루어지지 않았습니다. 각 컨볼루션 레이어는 5×5 커널과 시그모이드 활성화 함수를 사용합니다. 이러한 레이어는 공간적으로 배열된 입력을 여러 2차원 기능 맵에 매핑하여 일반적으로 채널 수를 늘립니다. 첫 번째 컨볼루션 레이어에는 6개의 출력 채널이 있고 두 번째에는 16개의 출력 채널이 있습니다. 각 2×2 풀링 작업(스트라이드 2)은 공간적 다운샘플링을 통해 차원을 4배로 줄입니다. 컨벌루션 블록은 (배치 크기, 채널 수, 높이, 너비)로 지정된 형태의 출력을 내보냅니다.

 

In order to pass output from the convolutional block to the dense block, we must flatten each example in the minibatch. In other words, we take this four-dimensional input and transform it into the two-dimensional input expected by fully connected layers: as a reminder, the two-dimensional representation that we desire uses the first dimension to index examples in the minibatch and the second to give the flat vector representation of each example. LeNet’s dense block has three fully connected layers, with 120, 84, and 10 outputs, respectively. Because we are still performing classification, the 10-dimensional output layer corresponds to the number of possible output classes.

 

컨벌루션 블록의 출력을 밀집 블록으로 전달하려면 미니배치의 각 예제를 평면화해야 합니다. 다시 말해, 우리는 이 4차원 입력을 가져와 완전히 연결된 레이어에서 예상되는 2차원 입력으로 변환합니다. 다시 말해, 우리가 원하는 2차원 표현은 첫 번째 차원을 사용하여 미니배치의 예제를 인덱싱하고 두 번째로 각 예제의 플랫 벡터 표현을 제공합니다. LeNet의 고밀도 블록에는 각각 120, 84 및 10개의 출력이 있는 3개의 완전히 연결된 계층이 있습니다. 여전히 분류를 수행하고 있기 때문에 10차원 출력 계층은 가능한 출력 클래스의 수에 해당합니다.

 

While getting to the point where you truly understand what is going on inside LeNet may have taken a bit of work, hopefully the following code snippet will convince you that implementing such models with modern deep learning frameworks is remarkably simple. We need only to instantiate a Sequential block and chain together the appropriate layers, using Xavier initialization as introduced in Section 5.4.2.2.

 

LeNet 내부에서 진행되는 작업을 진정으로 이해하는 지점에 도달하는 동안 약간의 작업이 필요할 수 있지만 다음 코드 스니펫을 통해 이러한 모델을 최신 딥 러닝 프레임워크로 구현하는 것이 매우 간단하다는 것을 확신할 수 있기를 바랍니다. 섹션 5.4.2.2에서 소개한 대로 Xavier 초기화를 사용하여 Sequential 블록을 인스턴스화하고 적절한 레이어를 함께 연결하기만 하면 됩니다.

 

def init_cnn(module):  #@save
    """Initialize weights for CNNs."""
    if type(module) == nn.Linear or type(module) == nn.Conv2d:
        nn.init.xavier_uniform_(module.weight)

class LeNet(d2l.Classifier):  #@save
    """The LeNet-5 model."""
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(6, kernel_size=5, padding=2), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.LazyConv2d(16, kernel_size=5), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(),
            nn.LazyLinear(120), nn.Sigmoid(),
            nn.LazyLinear(84), nn.Sigmoid(),
            nn.LazyLinear(num_classes))

 

  • init_cnn(module) 함수는 CNN 모델의 가중치를 초기화하는 역할을 합니다.
  • 함수 내부에서 nn.Linear 또는 nn.Conv2d 모듈의 가중치에 Xavier 초기화(Xavier initialization)를 적용합니다.
  • LeNet 클래스는 d2l.Classifier 클래스를 상속받아서 정의된 LeNet-5 모델입니다.
  • lr=0.1과 num_classes=10은 초기화 시 인자로 받는 학습률과 클래스 수를 나타냅니다.
  • self.save_hyperparameters()는 하이퍼파라미터를 저장하는 역할을 합니다.
  • self.net은 LeNet-5 모델의 구조를 정의하는 nn.Sequential 객체입니다.
  • nn.Sequential 객체는 여러 개의 순차적인 레이어를 포함하는 신경망을 정의할 수 있습니다.
  • 각 레이어는 nn.LazyConv2d, nn.Sigmoid, nn.AvgPool2d, nn.Flatten, nn.LazyLinear 등으로 구성됩니다.
  • nn.LazyConv2d는 2D 컨볼루션 레이어를 나타내며, kernel_size와 padding 등의 인자를 설정합니다.
  • nn.Sigmoid는 시그모이드 활성화 함수를 적용하는 레이어입니다.
  • nn.AvgPool2d는 2D 평균 풀링 레이어를 나타내며, kernel_size와 stride 등의 인자를 설정합니다.
  • nn.Flatten은 입력 데이터를 1차원으로 펼치는 레이어입니다.
  • nn.LazyLinear은 선형 레이어를 나타내며, num_classes를 포함한 출력 차원을 설정합니다.
  • num_classes는 분류할 클래스의 개수를 나타냅니다.

 

We take some liberty in the reproduction of LeNet insofar as we replace the Gaussian activation layer by a softmax layer. This greatly simplifies the implementation, not the least due to the fact that the Gaussian decoder is rarely used nowadays. Other than that, this network matches the original LeNet-5 architecture.

 

우리는 가우시안 활성화 레이어를 소프트맥스 레이어로 대체하는 한 LeNet의 재생산에서 약간의 자유를 얻습니다. 이것은 가우시안 디코더가 요즘 거의 사용되지 않는다는 사실 때문에 구현을 크게 단순화합니다. 그 외에는 이 네트워크가 원래 LeNet-5 아키텍처와 일치합니다.

 

Let’s see what happens inside the network. By passing a single-channel (black and white) 28×28 image through the network and printing the output shape at each layer, we can inspect the model to make sure that its operations line up with what we expect from Fig. 7.6.2.

 

네트워크 내부에서 무슨 일이 일어나는지 봅시다. 네트워크를 통해 단일 채널(흑백) 28×28 이미지를 전달하고 각 레이어에서 출력 모양을 인쇄함으로써 모델을 검사하여 작업이 그림 7.6.2에서 예상한 것과 일치하는지 확인할 수 있습니다. .

 

Fig. 7.6.2&nbsp; Compressed notation for LeNet-5.

 

@d2l.add_to_class(d2l.Classifier)  #@save
def layer_summary(self, X_shape):
    X = torch.randn(*X_shape)
    for layer in self.net:
        X = layer(X)
        print(layer.__class__.__name__, 'output shape:\t', X.shape)

model = LeNet()
model.layer_summary((1, 1, 28, 28))

 

  • layer_summary(self, X_shape) 함수는 모델의 레이어들에 대한 요약 정보를 출력하는 역할을 합니다.
  • @d2l.add_to_class(d2l.Classifier)는 layer_summary 함수를 d2l.Classifier 클래스에 추가하는 데코레이터입니다.
  • X_shape은 입력 데이터의 형상을 나타내는 튜플입니다.
  • X는 X_shape 형상에 맞게 생성된 정규분포를 따르는 무작위 데이터입니다.
  • for 루프를 통해 self.net에 포함된 각 레이어에 입력 데이터 X를 전달하고 출력 데이터의 형상을 출력합니다.
  • layer.__class__.__name__은 레이어의 클래스 이름을 가져옵니다.
  • X.shape는 출력 데이터의 형상을 나타냅니다.
  • model = LeNet()은 LeNet 모델의 인스턴스를 생성합니다.
  • model.layer_summary((1, 1, 28, 28))은 생성된 모델의 layer_summary 함수를 호출하여 입력 데이터의 형상을 전달합니다. 이를 통해 레이어별 출력 형상을 확인할 수 있습니다.

 

 

 

Note that the height and width of the representation at each layer throughout the convolutional block is reduced (compared with the previous layer). The first convolutional layer uses 2 pixels of padding to compensate for the reduction in height and width that would otherwise result from using a 5×5 kernel. As an aside, the image size of 28×28 pixels in the original MNIST OCR dataset is a result of trimming 2 pixel rows (and columns) from the original scans that measured 32×32 pixels. This was done primarily to save space (a 30% reduction) at a time when Megabytes mattered.

 

컨볼루션 블록 전체에 걸쳐 각 레이어에서 표현의 높이와 너비가 줄어듭니다(이전 레이어와 비교하여). 첫 번째 컨볼루션 레이어는 5×5 커널을 사용할 때 발생할 수 있는 높이와 너비의 감소를 보상하기 위해 2픽셀의 패딩을 사용합니다. 여담으로 원본 MNIST OCR 데이터 세트의 이미지 크기 28×28픽셀은 32×32픽셀로 측정된 원본 스캔에서 2픽셀 행(및 열)을 트리밍한 결과입니다. 이것은 주로 메가바이트가 중요할 때 공간을 절약(30% 감소)하기 위해 수행되었습니다.

 

In contrast, the second convolutional layer forgoes padding, and thus the height and width are both reduced by 4 pixels. As we go up the stack of layers, the number of channels increases layer-over-layer from 1 in the input to 6 after the first convolutional layer and 16 after the second convolutional layer. However, each pooling layer halves the height and width. Finally, each fully connected layer reduces dimensionality, finally emitting an output whose dimension matches the number of classes.

 

대조적으로 두 번째 컨볼루션 레이어는 패딩을 생략하므로 높이와 너비가 모두 4픽셀씩 줄어듭니다. 레이어 스택 위로 올라갈수록 채널 수는 입력의 1개에서 첫 번째 컨볼루션 레이어 이후 6개, 두 번째 컨볼루션 레이어 이후 16개로 레이어별로 증가합니다. 그러나 각 풀링 레이어는 높이와 너비를 절반으로 줄입니다. 마지막으로, 완전히 연결된 각 레이어는 차원을 줄이고 차원이 클래스 수와 일치하는 출력을 내보냅니다.

 

 

7.6.2. Training

 

Now that we have implemented the model, let’s run an experiment to see how the LeNet-5 model fares on Fashion-MNIST.

 

이제 모델을 구현했으므로 LeNet-5 모델이 Fashion-MNIST에서 어떻게 작동하는지 실험을 실행해 보겠습니다.

 

While CNNs have fewer parameters, they can still be more expensive to compute than similarly deep MLPs because each parameter participates in many more multiplications. If you have access to a GPU, this might be a good time to put it into action to speed up training. Note that the d2l.Trainer class takes care of all details. By default, it initializes the model parameters on the available devices. Just as with MLPs, our loss function is cross-entropy, and we minimize it via minibatch stochastic gradient descent.

 

CNN은 매개변수가 적지만 각 매개변수가 더 많은 곱셈에 참여하기 때문에 유사한 심층 MLP보다 계산 비용이 여전히 더 비쌉니다. GPU에 액세스할 수 있는 경우 훈련 속도를 높이기 위해 GPU를 실행하기에 좋은 시기일 수 있습니다. d2l.Trainer 클래스가 모든 세부 사항을 처리합니다. 기본적으로 사용 가능한 장치에서 모델 매개변수를 초기화합니다. MLP와 마찬가지로 손실 함수는 교차 엔트로피이며 미니배치 확률적 경사 하강을 통해 최소화합니다.

 

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128)
model = LeNet(lr=0.1)
model.apply_init([next(iter(data.get_dataloader(True)))[0]], init_cnn)
trainer.fit(model, data)
  • trainer = d2l.Trainer(max_epochs=10, num_gpus=1)는 훈련을 수행하기 위한 Trainer 객체를 생성합니다. 최대 에포크 수는 10이며, GPU를 1개 사용합니다.
  • data = d2l.FashionMNIST(batch_size=128)는 FashionMNIST 데이터셋을 로드하는데 사용되는 FashionMNIST 객체를 생성합니다. 배치 크기는 128입니다.
  • model = LeNet(lr=0.1)는 LeNet 모델의 인스턴스를 생성합니다. 학습률은 0.1로 설정됩니다.
  • model.apply_init([next(iter(data.get_dataloader(True)))[0]], init_cnn)은 모델의 가중치를 초기화하는 데 사용됩니다. FashionMNIST 데이터셋에서 첫 번째 미니배치의 입력 데이터를 가져와 가중치 초기화 함수 init_cnn을 적용합니다.
  • trainer.fit(model, data)는 모델을 훈련 데이터셋에 대해 학습시키는 역할을 합니다. 훈련 데이터셋은 data로 전달되고, 모델은 model로 전달됩니다.

 

7.6.3. Summary

In this chapter we made significant progress. We moved from the MLPs of the 1980s to the CNNs of the 1990s and early 2000s. The architectures proposed, e.g., in the form of LeNet-5 remain meaningful, even to this day. It is worth comparing the error rates on Fashion-MNIST achievable with LeNet-5 both to the very best possible with MLPs (Section 5.2) and those with significantly more advanced architectures such as ResNet (Section 8.6). LeNet is much more similar to the latter than to the former. One of the primary differences, as we shall see, is that greater amounts of computation afforded significantly more complex architectures.

 

이 장에서 우리는 상당한 진전을 이루었습니다. 우리는 1980년대의 MLP에서 1990년대와 2000년대 초반의 CNN으로 이동했습니다. 예를 들어 LeNet-5의 형태로 제안된 아키텍처는 오늘날까지도 의미가 있습니다. LeNet-5로 달성할 수 있는 Fashion-MNIST의 오류율을 MLP(섹션 5.2)와 ResNet(섹션 8.6)과 같은 훨씬 더 고급 아키텍처를 사용하는 오류율과 비교할 가치가 있습니다. LeNet은 전자보다 후자에 훨씬 더 유사합니다. 주요 차이점 중 하나는 훨씬 더 복잡한 아키텍처를 제공하는 더 많은 계산량입니다.

 

A second difference is the relative ease with which we were able to implement LeNet. What used to be an engineering challenge worth months of C++ and assembly code, engineering to improve SN, an early Lisp based deep learning tool (Bottou and Le Cun, 1988), and finally experimentation with models can now be accomplished in minutes. It is this incredible productivity boost that has democratized deep learning model development tremendously. In the next chapter we will follow down this rabbit to hole to see where it takes us.

 

두 번째 차이점은 우리가 LeNet을 구현할 수 있었던 상대적 용이성입니다. C++ 및 어셈블리 코드, SN 개선을 위한 엔지니어링, 초기 Lisp 기반 딥 러닝 도구(Bottou and Le Cun, 1988), 마지막으로 모델을 사용한 실험이 이제 몇 분 안에 완료될 수 있습니다. 딥 러닝 모델 개발을 엄청나게 민주화한 것은 이 놀라운 생산성 향상입니다. 다음 장에서 우리는 이 토끼가 우리를 어디로 데려가는지 알아보기 위해 구멍까지 따라갈 것입니다.

 

7.6.4. Exercises

  1. Let’s modernize LeNet. Implement and test the following changes:
    1. Replace the average pooling with max-pooling.
    2. Replace the softmax layer with ReLU.
  2. Try to change the size of the LeNet style network to improve its accuracy in addition to max-pooling and ReLU.
    1. Adjust the convolution window size.
    2. Adjust the number of output channels.
    3. Adjust the number of convolution layers.
    4. Adjust the number of fully connected layers.
    5. Adjust the learning rates and other training details (e.g., initialization and number of epochs.)
  3. Try out the improved network on the original MNIST dataset.
  4. Display the activations of the first and second layer of LeNet for different inputs (e.g., sweaters and coats).
  5. What happens to the activations when you feed significantly different images into the network (e.g., cats, cars, or even random noise)?

 

반응형
이전 1 2 다음