안녕하세요, 예전에는 웹서버 글을 올렸었지만 시간이 지나 관심 분야가 바뀌어 인공지능 분야를 공부하게 되었습니다.
제가 아직 전문성이 높은 사람은 절대 아니기에 이상한 부분이 있다면 언제든 알려주세요.
다 적고서 쭉 보니까 의미 없이 길기만 하고 시간도 오래 걸리고 참고 논문들은 보지도 못했네요... 다음엔 다른 형식으로 정리해보겠습니다.
전문성이 높은 것은 아닌데 왜 Lecture 9부터 적는 것인가에는 핑계일 수도 있지만 이유가 있습니다.
앞 Lecture 이름들은 'Image Classification with Linear Classifier', 'Regularization and Optim.', 'NN and Backprop.', 'Image Classification with CNNs', 'CNN Architecture', 'Recurrent Neural Networks', 'Attention and Transformers' 입니다.
저는 Michigan CS 231 N을 Lecture 10까지 (Image Classification, CNN, Training NN 등) 본 적이 있습니다. 논문을 하나하나 다 찾아볼 정도는 아니긴 합니다. 추가로 학교 강의에서도 여러 차례 들었고, 특정 강의의 과제로 CNN, Transformer 논문을 읽기도 했어서 넘어간 것도 있습니다.
잡담은 여기까지 하고 본격적으로 시작하겠습니다.

영상에서는 지금까지 배운 처리 구조에 RNN, CNN, Self Attention이 있다고 언급합니다.
이 중에서 Self-Attention의 장점은 다른 구조보다 연산량이 많은 비싼 연산이고 메모리도 많이 쓰지만, 결과가 월등히 좋아서 Transformer를 쓴다고 설명했습니다.
제가 아는 범위 안에서 RNN과 Conv를 설명해보겠습니다.

RNN이란 이전 상태인 s_t-1와, 현재 상태인 x_t를 입력으로 받아 y_t를 생성하는 구조입니다. Stanford의 강의 자료에는 s_t라고 돼있지 않은데, 이를 단순화해서 표현한 것이라고 할 수 이습니다.
- 학습 가능한 파라미터는 W_s(그림에서는 W), W_x(그림에서는 U) (+Bias) 등이 있고, 나중에 Decode하거나 Classification을 위해 Linear Layer를 쓴다면 이 또한 학습 가능한 파라미터가 될 수 있습니다.
- 장점으로는 이론적으로 길고 가변 길이의 입력을 받아들일 수 있다는 점입니다. 메모리도 폭발적으로 증가하지 않고 O(N)을 유지합니다.
- 단점으로는 병렬화할 수 없어 시간이 O(N)만큼의 시간이 걸릴 수밖에 없습니다. 또한 장기 문맥을 유지하는 데 한계가 있습니다. LSTM, GRU 등의 gate 등을 이용해 극복해보려 하였으나 결국 구조적으로 한계는 있을 수밖에 없습니다.

Conv: MLP는 모든 x_i와 y_i가 가중치로 연결되지만, Conv 연산은 공간적으로 인접한 픽셀(image 기준)들만 연결되어 있습니다. 이미지 처리를 위해 태어났다보니 이미지로 설명하는 경우가 많은데, 우선 이미지의 특정 부분과 filter(=weight, kernel, ...)을 순서대로 포개어 가면서, 각 위치를 곱한 뒤 모두 더하는 것입니다.


다음 그림은 ViT의 첫 번째 방법을 설명한 것입니다. 처리 과정은 다음과 같습니다.
1. 고양이 사진을 N개의 input patch로 변환하는데, 각 크기는 3x16x16이며, 3은 RGB 채널, 16x16은 가로 세로입니다.
2. input patch들을 1자로 폅니다. 예를 들어 [[1,2,3],[4,5,6], [7,8,9]]로 돼있었다면 [1,2,3,4,5,6,7,8,9]로 만든다는 것이죠. 그러면 shape이 [3,16,16]에서 [768]이 될 겁니다. 이때 2D 위치 정보가 사라지게 됩니다. 2D 위치 정보가 사라지기 이걸 Linear Projection, 즉, Wx+b를 해서 D차원 vector로 만들어주는 겁니다.
3. positional embedding을 더합니다. 이는 patch들이 원본 이미지의 어느 위치에 있었는지를 알려주기 위함입니다.
4. 이렇게 완성된 D차원 벡터 N개와 special extra input을 Transformer의 입력으로 넣습니다. 이 special extra input은 D차원 벡터이며, 학습 가능하고, Transformer의 출력을 encode하고 있어 대표로 클래스 score를 담당하게 됩니다. 그래서 우리는 classification token 또는 <CLS>라고도 하죠.
5. Transformer의 출력은 각 N+1개가 되는데, 이 중 classification token의 위치에 있던 output vector를 Linear Projection을 통해 C차원 vector로 변환시키면 그게 바로 각 class에 대한 score가 됩니다. 이후 softmax를 취하든, 어떻게 하든 해서 classification 결과를 얻게 되죠. 이때 각 class에 대한 score라고 했으니 class의 개수는 C개라는 것도 알 수 있겠네요.


이 그림은 ViT의 두 번째 방법입니다. 위와 비슷하지만 <CLS>를 사용하지 않고 Transformer의 모든 출력을 평균 내어 score를 계산하는 Average Pooling을 이용합니다.
순서는 아래와 같고, 첫번째 방법의 1~3번까지는 동일합니다. 앞쪽의 설명을 간단히 요약하여 그림으로 나타나있다고 보시면 되겠습니다.
4. special extra token 없이 그대로 Transformer의 입력으로 넣습니다. 옆에 나와있는 주석을 설명하자면, 입력에 대한 masking은 전혀 하지 않습니다.
오른쪽은 self-attention이 포함돼있는 vanila Transformer의 구조입니다. 이 중 Transformer의 encoder를 가져와서 ViT에 사용하고 있다고 보시면 됩니다. 잘 보시면 위 구조와 대부분 동일합니다. 위 사진의 Self-Attention, Layer Norm은 아래의 Multi-head Attention, Add&Norm과 대응되죠. 다른 점은 아래의 Feed Forward가 위의 MLP로 바뀌어있다 정도가 되겠습니다. FFN은 Linear -> ReLU -> Linear이고, 저 구조에서 MLP 부분은 Linear -> GELU -> Dropout -> Linear -> Dropout로 사용합니다.
중요한 것은 vanila transformer decoder(오른쪽 사진의 오른쪽)에 Masked가 써있다는 것인데, 이는 Transformer의 탄생 기원인 NLP, 즉 자연어처리에서 미래 단어를 예측하지 못하도록 처리하는 것을 말합니다. 이것이 ViT에는 적용되지 않습니다. 이외에 순서가 조금 다르다고 느끼시는 분들은 곧 설명드리겠습니다.
5. Transformer를 거친 뒤에 Pooling을 거치게 되는데, 이는 모든 토큰을 모아 평균을 냈다고 보시면 됩니다. 정확히는 shape이 [N, D]였다면 [1,D]로 돌리는 것이고, point-wise라고도 표현할 수 있겠네요.
이러한 구조를 가지고 있는 ViT는 다음과 같은 Tweak을 이용해 Transformer를 수정했다고 되어 있습니다.


첫 번째는 위에서 말씀드린 순서가 다르다는 부분입니다. vanila transformer는 Add&Norm에 Residual Connectio의 화살표가 가있지만, ViT에서는 Residual Connection이 Layer Norm 바깥으로 연결되죠. Vanila는 Layer Norm에 Residual이 포함되지만 ViT는 포함하지 않고 Residual이 그대로 간다는 뜻입니다. 전자는 Post-Norm, 후자는 Pre-Norm이라고 합니다. Pre-Norm은 경험적으로 학습 안정성을 올려준다고 합니다. 따라서 구조를 조금 수정했다고 보시면 되겠습니다.

두 번째는 Layer Norm 대신 RMSNorm을 이용하는 것입니다. RMSNorm은 평균을 빼지 않고 벡터 크기만 RMS로 나누고 sclae 만 적용합니다. 직관적으로는 각 벡터의 제곱 크기의 평균을 구하고 그걸 루트로 나눕니다. 이걸 RMS(x)라고 부르는 거에요. 이걸 x에 나눠서 값을 안정화시킨다는 겁니다. 마찬가지로 학습 안정성을 좀 더 향상시킵니다.

3번째 방법인 SwiGLU는 MLP를 변형해 가중치 개수를 늘리고 비선형성을 증가시키는 방법입니다. 원래라면 Y = σ(XW1 )W2 [N x D] 이렇게 하지만, W1, W2, W3의 shape을 저렇게 설정하고 Y = (𝜎 𝑋𝑊1 ⊙ 𝑋𝑊2) 𝑊3 이렇게 계산하면 비선형성이 늘어난다는 뜻입니다. 기본적으로는 parameter가 늘어나지만, H=8D/3으로 설정하면 개수가 같고, 그럼에도 비선형성은 늘어난다고 강의에서 설명해주셨습니다.

마지막은 MoE입니다. 중간에 MLP가 1개가 아니라 갑자기 4개가 됐죠? 이건 각각 다른 expert 역할을 하는 MLP를 E개 만든 뒤 Router가 A개만 활성화시켜서 계산시키고, 이를 Router가 가중합해 사용합니다. parameter와 연산량이 늘어나지만 그만큼 robust한 model을 만들 수 있다고 합니다. 이 개수는 hyperparameter이지만 어느 정도 정해진 게 있다고 합니다. 실제 GPT, Claude, Gemini 등에서도 쓰고 있다고 하네요.
이제 ViT는 끝났습니다. 다음으로 넘어가죠.

Semantic Segmentation은 각 픽셀을 의미론적 카테고리로 나누는 것입니다.

하지만 문제가 존재하는데, 일단 각 픽셀 하나만 보고는 어떤 곳인지 판단하기는불가능에 가깝습니다. 따라서 주변 픽셀을 가져와서 CNN 등을 사용해서 classification을 시키는 거죠.


하지만 왼쪽처럼 그냥 CNN을 써버리면 결과처럼 안 나오고, output feature map의 채널 수는 늘고
, H, W는 줄겠죠. 보통 CNN 구조가 이렇습니다.
그래서 낸 아이디어가 FCN입니다. 다른 일반 CNN이 마지막에 Fully Connceted를 이용하는 것과 달리 FCN은 마지막까지도 Conv만 사용한다는 점에서 붙은 이름입니다. 이미지 전체를 한 번에 CNN에 넣으면서도 각 픽셀마다 class score를 내고자 하는 거죠. 입력은 3xHxW, 출력은 HxW가 되는 겁니다.
기본 CNN에는 downsampling이 있다는 건 다들 기억하실 겁니다. pooling 또는 stride를 통해서 말이죠. 여기서는 downsampling 없이 Conv만 반복합니다. 그러면 중간 feature map의 크기는 DxHxW가 됩니다.여기서 D는 feature channel의 수, 즉 filter의 개수입니다. 각 필터에 대응하는 HxW feature map이 생기고, 이를 쌓아 DxHxW가 됩니다.
그리고 마지막 Conv layer는 D를 클래스 개수 C로 바꿔줍니다. 어떻게 하냐면, 1x1 Filter를 C개 사용하면 됩니다. 1x1 Filter의 동작 과정은, 그냥 한 픽셀에 해당하는 D차원만큼의 feature를 Filter값과 곱한 뒤 모두 더해서 1차원으로 만들게 됩니다. 이러한 Filter가 C개 있으면 DxHxW가 CxHxW로 변하겠죠.
정리하자면, D개 종류의 filter를 이용해 Conv를 D번 반복하면 그 결과가 DxHxW가 되고, 마지막에는 D를 C로 바꾸는 Conv를 진행하고 argmax를 한다고 보시면 되겠습니다.
그러나 원 해상도에 맞는 Conv 연산을 반복하는 것은 매우 비싼 연산이 된다는 단점이 있습니다.

그래서 나온 것이, 중간에는 해상도를 줄이는 Downsampling을 진행하고, 나중에 다시 해상도를 늘리는 Upsampling을 진행합니다. 이렇게 되면 H, W가 점점 작아지다가 다시 늘어나는 거죠. 전자는 Encoder이고, 후자는 Decoder라고도 부릅니다.
근데 Downsampling은 Pooling, Stride로 해결할 수 있는데 Upsampling은 어떻게 할까요?


그냥 다 복사하거나, 왼쪽 위로 통일하거나, 원 위치를 기억해뒀다가 복사하는 식으로 합니다.



이런 식으로 Downsampling의 반대로 해서 겹치는 부분은 더하는 식으로 할 수도 있습니다. 3번째 사진은 2D가 아닌 1D 기준으로 설명한 예시입니다.



이걸 실제로 발전시킨 게 U-Net입니다. Downsampling에서는 공간 정보를 잃지만 receptive field가 커지는 셈이 되고요, 다시 Upsampling할 때는 고해상도 매핑을 만들어내게 됩니다.
여기서 아까 사진과 다른 점은 skip connection이 있다는 점입니다. 이 사진에서 encoder의 featrue를 오른쪽 decoder로 직접 넘겨주는데, 이를 통해 사라진 위치 정보를 어느 정도 다시 알아볼 수 있게 해줍니다.

이번엔 Object Detection에 대해 알아보겠습니다. 여기서는 여러 object가 있는 것을 다룹니다.

Object Detection은 classification과 localization(위치 맞추기, 즉 bounding box 그리기)를 동시에 수행한다고 볼 수 있습니다. 그래서 일단 classification은 기존대로 하고, Box Coordinate에 따른 loss도 함께 계산합니다. 이때 정답 label은 (x,y,h,w)입니다. 이후 합쳐서 전체 loss를 만들면 될 것처럼 보입니다.


그러나 사진에 따라 탐지해야 할 객체 수가 다 다르고, 출력해야 할 숫자가 너무나 많아진다는 문제가 생깁니다.

이에 대한 해답은 모든 가능한 crop을 검사하지 말고, 물체가 있을 법한 후보 영역만 먼저 뽑자는 겁니다. 이게 region proposal이고, blobby라는 건 색, 질감, 경계 등이 비슷하게 뭉쳐 있는 이미지 영역을 찾아서 object 후보로 제안하는 것입니다. 여기서 Selective Search는 object proposal을 만드는 전통적 컴퓨터 비전 알고리즘입니다. Selective Search의 흐름은 다음과 같습니다.

sub-segmentation이라고도 부르는 initial segmentation을 진행한 뒤, 비슷한 region들을 점점 합칩니다. 마지막으로 합쳐진 region마다 bounding box를 만듭니다.
비슷한 region을 판단하는 방법에는 4가지가 있습니다. Color Similarity / Texture Similarity / Size Similarity / Fill Similarity입니다. 각각 색, 질감, 작은 region도 object 후보로 성장할 기회를 주는 기준, 두 region을 합쳤을 때 bounding box가 얼마나 빈 공간 없이 잘 채워졌는지를 확인합니다.
그래도 느린 편이라고는 하지만, 일단 전수조사보다는 빠르다고 합니다.
Selective Search 수식 정리
Selective Search는 두 region r_i, r_j를 합칠지 판단하기 위해 여러 similarity score를 계산합니다.
1~5번은 region들을 어떻게 합칠지 결정하는 수식이고, 6~8번은 만들어진 proposal이 정답 박스를 얼마나 잘 맞췄는지 평가하는 수식입니다.
1. Color Similarity
두 region의 color histogram이 얼마나 겹치는지를 계산합니다. 값이 클수록 색 분포가 비슷하다는 뜻입니다.
2. Texture Similarity
두 region의 texture histogram이 얼마나 겹치는지를 계산합니다. 값이 클수록 질감이 비슷하다는 뜻입니다.
3. Size Similarity
작은 region들이 먼저 합쳐질 수 있도록 하는 항입니다. 두 region의 크기 합이 작을수록 score가 커집니다.
4. Fill Similarity
BB_{ij}는 region r_i와 r_j를 함께 감싸는 bounding box입니다. 두 region을 합쳤을 때 bounding box 안이 잘 채워질수록 score가 커집니다.
5. Final Similarity
Selective Search는 최종 similarity가 가장 큰 두 region을 반복적으로 합칩니다.
6. IoU(Intersection over Union, 교집합 / 합집합)
IoU는 proposal box와 ground truth box가 얼마나 겹치는지 측정하는 값입니다.
7. ABO(Average Best Overlap)
하나의 class에 대해, 각 ground truth box가 proposal들 중 가장 잘 맞는 box와 얼마나 겹치는지 평균낸 값입니다.
8. MABO(Mean Average Best Overlap)
모든 class에 대해 ABO를 평균낸 값입니다.

그래서 실제 R-CNN(Region-CNN)은 이렇게 작동합니다.
- 1. Region of Interest, 즉 RoI 2000개 정도를 proposal method로 받아옵니다.
- 2. 이들을 224x224로 바꿔줍니다. 이걸 resize 또는 warp한다고 합니다.
- 3. 각 region을 ConvNet에 통과시킵니다.
- 4. SVM(Support Vector Machine)으로 region들을 분류합니다. SVM은 CNN이 추출한 feature vector를 입력으로 받아, 해당 region이 특정 class인지 아닌지를 판별하는 전통적인 classifier입니다.
- 5. (dx, dy, dw, dh) (각 값을 얼마나 이동할지를 나타내는 값)를 이용해 bounding box들을 보정해 나갑니다.
이렇게 할 때의 문제는 느리다는 겁니다. 많은 region들은 서로 겹치고 공유하는 부분이 많은데, R-CNN은 이걸 매번 새로 crop해서 CNN에 넣습니다. 그래서 느리죠.
그래서 저기 파란 색으로 적힌 방법은 이미지 전체를 CNN에 한 번만 넣고, CNN featuure map 위에서 region을 잘라 쓰자는 것입니다. 이게 Slow에서 Fast로 가는 핵심이죠.
CNN을 적용하면 region이 줄어들지 않냐고요? 줄어든 상태에서 해당하는 부분을 잘라서 쓰면 됩니다.

비교하면 이렇게 됩니다. 파란색 박스 부분에서 Conv가 적용된 값에서 잘라서 RoI로 사용하고 있는 모습을 확인할 수 있죠. 이후에는 저희가 봤던 것처럼 Object를 에측하고 box offset을 맞추는 것을 반복합니다.




이후 Selective Search를 대체하는 Region Proposal Network가 등장합니다. CNN map 위에서 네트워크가 직접 object proposal을 만들려는 것입니다.
그래서 1번째 그림처럼 feature map 각 위치마다 anchor box를 둡니다.3x640x480 이미지가 CNN을 통과하면 512x20x15가 된다고 가정합니다. 그러면 feature map에는 총 300개의 위치가 생깁니다. RPN은 각 위치마다 anchor box라는 미리 존재하는 후보를 둡니다. Anchor box에 대응하는 objectness score를 구하고, 2번째 그림처럼 box correction도 예측합니다. 여기서는 앞선 예시처럼 (dx,dy,dw,dh)를 이용해서 예측하고 수정하는 거죠.
3번째 그림을 보면, 한 위치마다 anchor를 K개씩 둡니다. 그래서 Anchor shape이 Kx20x15입니다. 다만 구현에 따라 2K×20×15가 되는 경우도 있다고 합니다. 출력 shape은 각 anchor마다 (dx,dy,dw,dh)가 나오니 4Kx20x15가 되고요.
이를 통해서 Region Proposal을 만든다고 보시면 되겠습니다.

아까까지 본 건 Two-Stage Object Detector입니다. Image->Region Proposals->Classify proposal 이니까요.
이제 저희가 볼 건 Single-Stage Object Detector입니다. Image->Boxes+Classes 와 같은 흐름입니다.
우선 이미지를 7x7로 나누어 grid cell로 만들고, 그 cell 안에 강아지 중심점이 있으면 그 cell이 강아지를 예측하는 식입니다. 각 grid cell마다 base box, 즉 후보 박스를 여러 개 둡니다. 여기서는 B=3이니까 3개씩 뒀네요.
그리고 여기서는 각 base box마다 (dx,dy,dh,dw,confidence)로 5개를 예측합니다.
각 grid cell마다 class score도 예측해서 Output에 7x7x(5*B+C)가 되었네요.
초창기에는 이러한 grid cell 안에 작은 물체 여러 개가 몰려 있으면 예측이 어려워질 수 있다는 문제가 있었는데, SSD, RetinaNet 등이 여러 feature scale을 사용하거나 focal loss를 도입해서 해결했다고 합니다.




YOLO의 전체적인 흐름을 보겠습니다. 강의에서는 세세한 과정은 생략했다고 하는데, 기회가 되면 논문 리뷰로 돌아오겠습니다.
- 1. 이미지를 SxS로 나눕니다.
- 2. B를 정해서 각 grid cell마다 가질 bounding box 후보의 개수를 정합니다. 각 box는 object confidence와 class probability를 예측하게 됩니다. 따라서 output size는 SxSx(B*5+C)가 됩니다. 3번째 그림에 있는 수많은 박스가 SxSxB개의 박스를 나타낸 것입니다.
- 3. confidence 높은 box만을 남깁니다. threshold보다 confidence가 낮은 box를 버리면 됩니다. 최종적으로 class score를 P(object) * P(class)를 통해 만들고, NMS로 중복 box를 지우면 최종 detection 결과만 남게 됩니다.


DETR라는 방법도 있습니다. 이 방법은 anchor, region propossal, NMS와 같은 방법을 거의 없애고 Transformer가 직접 box들을 출력하게 만드는 것입니다. 다만 강의에서는 기본 DETR이 널리 쓰지 않고 있다고 합니다.

이제 마지막 주제인 Instance Segmentation입니다.


이미지의 bounding box 안에서 실제 이미지가 있는 곳만을 mask하는 것을 예측하고 수정하는 것을 반복합니다. 2번째 그림처럼 말이죠.



굉장히 잘 예측하며, pose 또한 확인할 수 있습니다.
마지막으로 내용이 조금 더 있는데요, 시각화입니다.


이런 식으로 필터가 어떻게 생겼는지 확인하는 건데요, 첫번째 layer는 channel이 3이기 때문에 RGB로 표현 가능하지만 나머지 layer는 그럴 수 없다는 문제가 있습니다.


이를 해결할 다른 방법으로 Saliency가 있습니다. 두드러짐 이라고 번역되는데, 제대로 된 정의는 특정 픽셀을 바꾸었을 때 gradient가 얼마나 변하는지를 확인하는 것입니다. 정확히는 class score가 입력 이미지의 각 픽셀 값에 얼마나 민감한지를 시각화하는 것입니다. 개 사진에서는 개 픽셀을 바꾸면 class probability가 떨어지겠죠.

CAM이라는 방법도 있습니다. CNN 이해에 널리 사용되는 알고리즘입니다.
CNN에서는 마지막 CNN feature map까지 거친 뒤엔 GAP, FC가 붙습니다. 여기서 GAP, FC를 하기 전으로 되돌아가 보자는 겁니다.
GAP를 수식으로 써보면, Channel 별로 평균을 내는 거니까 그림의 F_k로 수식이 적히게 됩니다.
FC는 가중치와 입력값인 F_k를 곱한 뒤 다 더하게 됩니다. 이걸 수식으로 써보면 위 그림 오른쪽의 S_c와 같아지죠.
여기서 제일 중요한 것만 남기면, Class Activation Map은 M_c,h,w가 됩니다.
CAM의 정확한 의미를 알아보면, class c에 대한 위치 (h,w)의 중요도입니다. 예를 들어 class c가 dog라면 CAM M_dog,h,w은 feature map의 (h,w) 위치가 dog class score를 높이는 데 얼마나 기여했는지를 뜻합니다. 즉 모델이 dog라고 판단하는 데 중요하게 본 위치라는 거죠.
이 CAM은 마지막 feature map 크기이기 때문에 보통 원본 이미지보다 작습니다. 따라서 upsampling해서 쓴다고 보면 되겠습니다.

이런 식으로 시각화해서 볼 수 있습니다. 다만, 마지막 Conv layer에만 적용할 수 있습니다.

그래서 나온 것이 Grad-CAM입니다. gradient를 보고 중요도를 계산하는 방식인데, 이를 통해 class score S_c가 feature map A에 얼마나 민감한지를 알 수 있습니다.
- 1. 일단 어떤 layer든 선택하고, S_c에 대한 gradient를 계산합니다.
- 2. GAP를 통해 channel weight을 만듭니다. 원래 gradient는 위치마다 있는데, 이걸 전부 평균 내서 channel k 전체가 class c에 얼마나 중요한지를 하나의 숫자로 만드는 것입니다. channel 개수만큼 생기게 될 겁니다.
- 3. activation map을 가중합한 뒤 ReLU를 거칩니다. 각 channel activation A_h,w,k에 앞에서 구한 값을 곱하여 더하는 가중합 과정을 거치고 ReLU를 한다는 뜻입니다. ReLU를 하는 이유는, class score를 높이는 데 긍정적으로 기여한 위치만 보고 싶기 때문입니다. 음수는 0으로 만들어서 class를 낮추는 방향으로 작용하게 되는데, 그런 걸 없애고 class c를 높이는 영역만을 강조합니다.


그 결과가 여기 나와있는데, 이런식으로 영향을 준 곳을 잘 확인할 수 있습니다.

지금까지 이런 내용들을 같이 봤습니다.
솔직히 제가 너무 설명을 못한 거 같아 아쉽네요. 사실 더 자세히 설명하고도 싶었는데 이런 형식은 너무 길어지고 중요한 것은 너무 그냥 넘어가는 것 같습니다.
다음엔 다른 형식과 주요 논문 리뷰로 좋은 내용으로 돌아올 수 있으면 좋겠네요.
감사합니다.