딥러닝을 공부하다 보면 가장 많이 사용하는 레이어 중 하나가 바로 nn.Linear입니다.
특히 Transformer를 공부하면 다음과 같은 코드를 자주 보게 됩니다.
self.query = nn.Linear(embed_size, embed_size, bias=False)
self.key = nn.Linear(embed_size, embed_size, bias=False)
self.value = nn.Linear(embed_size, embed_size, bias=False)그리고 forward()에서는
queries = self.query(x)
keys = self.key(x)
values = self.value(x)처럼 사용합니다.
처음에는 단순히
“Linear는 차원만 바꾸는 레이어인가?”
라고 생각하기 쉽습니다.
하지만 실제로는 입력 데이터를 새로운 특징 공간(Feature Space)으로 변환(Projection)하는 역할을 수행합니다.
이번 글에서는 nn.Linear가 내부에서 어떤 계산을 수행하는지부터 Weight와 Parameter의 저장 방식, Shape(차원)의 흐름까지 하나씩 자세히 알아보겠습니다.
nn.Linear란?
PyTorch에서 Linear Layer는 다음과 같이 생성합니다.
import torch.nn as nn
linear = nn.Linear(3, 2)의미는 다음과 같습니다.
- 입력 차원(in_features) : 3
- 출력 차원(out_features) : 2
즉,
(3차원 입력)
│
▼
nn.Linear(3,2)
│
▼
(2차원 출력)
입력 벡터를 받아 새로운 2차원 공간으로 변환하는 레이어입니다.
Linear 내부에서는 무엇을 계산할까?
Linear Layer는 다음 수식을 계산합니다.
여기서
- X : 입력(Input)
- W : Weight
- b : Bias
입니다.
즉,
Linear = 행렬곱(Matrix Multiplication) + Bias
라고 이해하면 됩니다.
직접 계산해 보기
입력이
X =
[1
2
3]
Weight가
W =
[[1 2]
[3 4]
[5 6]]
Bias는 사용하지 않는다고 가정합니다.
bias=False
그러면
첫 번째 출력은
1×1 + 2×3 + 3×5 = 22
두 번째 출력은
1×2 + 2×4 + 3×6 = 28
최종 출력은
[22
28]
입니다.
PyTorch에서도 동일하게 확인할 수 있습니다.
import torch
import torch.nn as nn
linear = nn.Linear(3, 2, bias=False)
print("linear weight:\n", linear.weight)
print("linear bias:\n", linear.bias)
with torch.no_grad():
linear.weight.copy_(
torch.tensor([
[1.,3.,5.],
[2.,4.,6.]
])
)
print("linear weight:\n", linear.weight)
print("linear bias:\n", linear.bias)
print("linear(x):\n",linear(x))실행 결과:

계산결과: tensor([[22., 28.]])
직접 계산한 결과와 동일합니다.
Weight(Parameter)는 어디에 저장될까?
많은 사람들이 궁금해하는 부분입니다.
사실 Weight는 우리가 따로 만드는 것이 아니라,
linear = nn.Linear(3,2)
를 실행하는 순간 자동으로 생성됩니다.
즉, 내부적으로는 다음과 같은 구조를 가지고 있습니다.
linear
├── weight
└── bias
여기서 weight와 bias는 모두 학습 가능한 Parameter입니다.
Shape(차원)는 어떻게 될까?
nn.Linear를 처음 공부할 때 가장 많이 헷갈리는 부분이 바로 Shape(차원)입니다.
예를 들어,
linear = nn.Linear(3, 2)
를 생성했다고 가정해 보겠습니다.
많은 사람들이
입력이 3차원이고 출력이 2차원이니까 Weight의 Shape도
(3,2)겠지?
라고 생각합니다.
하지만 실제로는 그렇지 않습니다.
Weight Shape 확인하기
직접 확인해 보겠습니다.
import torch.nn as nn
linear = nn.Linear(3,2)
print(linear.weight.shape)출력
torch.Size([2, 3])
즉,
Weight의 Shape는
(out_features, in_features)
↓
(2,3)
입니다.
왜 (2,3)일까?
PyTorch는 Weight를
(out_features, in_features)
형태로 저장합니다.
예를 들어
nn.Linear(3,2)
라면
Weight
[[w11 w12 w13]
[w21 w22 w23]]
Shape는
(2,3)
입니다.
그런데 계산은 어떻게 할까?
입력이
x.shape
(1,3)
이고,
Weight는
(2,3)
입니다.
행렬곱은
(1,3)
×
(2,3)
으로는 계산이 불가능합니다.
그래서 PyTorch는 내부적으로 Weight를 자동으로 전치(Transpose) 하여 계산합니다.
즉,
Weight.T
↓
(3,2)
를 사용합니다.
실제로 수행되는 연산은
(1,3)
×
(3,2)
↓
(1,2)
가 됩니다.
즉, 내부 계산은
형태로 이루어집니다.
참고
수학 교재에서는 보통 Weight를
(in_features, out_features)형태로 정의하여Y = XW + b라고 표현합니다.하지만 PyTorch는 Weight를
(out_features, in_features)형태로 저장하기 때문에 내부적으로weight.T를 사용하여 동일한 결과를 계산합니다.
직접 확인해 보기
import torch
import torch.nn as nn
linear = nn.Linear(3,2)
x = torch.randn(1,3)
print(x.shape)
print(linear.weight.shape)
print(linear(x).shape)출력
torch.Size([1,3])
torch.Size([2,3])
torch.Size([1,2])
Shape의 흐름은 다음과 같습니다.
입력
(1,3)
│
Weight
(2,3)
│
내부에서 Weight.T
│
(3,2)
│
출력
(1,2)
Batch가 있어도 동일하다
실제로는 대부분 Batch 단위로 입력을 처리합니다.
x = torch.randn(32,3)
y = linear(x)
print(y.shape) # torch.Size([32, 2])Shape는
입력
(32,3)
↓
Linear
↓
출력
(32,2)
가 됩니다.
즉,
- Batch 크기(32)는 그대로 유지되고,
- 마지막 차원만 3 → 2로 변경됩니다.
Transformer에서는 어떻게 될까?
Transformer의 입력 Shape는 일반적으로
(batch_size, seq_len, embed_size)
입니다.
예를 들어
(16,20,512)
이라면
linear = nn.Linear(512,512)
를 통과한 후에도
(16,20,512)
가 됩니다.
왜냐하면 nn.Linear는 항상 마지막 차원(last dimension)에만 연산을 수행하기 때문입니다.
즉,
(16,20,512)
↓
Linear(512→512)
↓
(16,20,512)
입니다.
만약
nn.Linear(512,256)
이라면
(16,20,256)
이 됩니다.
반드시 기억해야 할 Shape 규칙
nn.Linear에서 가장 중요한 Shape 규칙은 다음 세 가지입니다.
1. Weight의 Shape는
(out_features, in_features)
입니다.
2. 내부 계산은
로 수행됩니다.
3. nn.Linear는 항상 마지막 차원(last dimension) 에만 적용됩니다.
즉,
(batch, seq_len, embed)
↓
Linear(embed, hidden)
↓
(batch, seq_len, hidden)
이 규칙만 기억하면 Transformer뿐 아니라 MLP, RNN, CNN의 Fully Connected Layer에서도 Shape를 쉽게 이해할 수 있습니다.
Parameter 확인하기
① Weight 확인하기
print(linear.weight)예를 들어
Parameter containing:
tensor([[ 0.1365, -0.5541, 0.2312],
[-0.2814, 0.6438, 0.0972]],
requires_grad=True)
가 출력됩니다.
Parameter containing이라는 문구를 볼 수 있는데,
이는 Weight가 단순한 Tensor가 아니라 학습 가능한 Parameter라는 의미입니다.
② Bias 확인하기
print(linear.bias) # linear = nn.Linear(3, 2, bias=True)출력
Parameter containing:
tensor([0.2254, -0.1182],
requires_grad=True)
③ Parameter 전체 보기
for p in linear.parameters():
print(p)Weight와 Bias가 모두 출력됩니다.
④ 이름까지 함께 보기
가장 추천하는 방법입니다.
for name, param in linear.named_parameters():
print(name)
print(param)출력
weight
Parameter containing:
tensor(...)
bias
Parameter containing:
tensor(...)
어떤 Parameter인지 한눈에 확인할 수 있습니다.
⑤ Parameter 개수 확인하기
print(sum(p.numel() for p in linear.parameters()))출력
8
왜 8개일까요?
Weight
2 × 3 = 6
Bias(out_features수와 동일합니다)
2
따라서
6 + 2 = 8
개의 학습 가능한 Parameter가 존재합니다.
requires_grad=True는 무슨 뜻일까?
Weight를 출력하면 항상
requires_grad=True
가 함께 표시됩니다.
이는
역전파(Backpropagation)를 통해 자동으로 학습되는 변수
라는 의미입니다.
즉,
- SGD
- Adam
- AdamW
와 같은 Optimizer가 손실 함수(Loss)를 기반으로 Weight를 지속적으로 업데이트합니다.
bias는 왜 존재할까?
Bias는 선형 변환 결과를 일정한 값만큼 이동시키는 역할을 합니다.
수식으로는
에서 + b에 해당합니다.
Bias가 있으면 모델이 더 유연한 표현을 학습할 수 있으며, 입력이 모두 0이더라도 출력이 항상 0이 되지 않습니다.
bias=False라면?
Bias를 제거하면
만 계산합니다.
즉,
행렬곱만 수행합니다.
예를 들어
linear = nn.Linear(3,2,bias=False)라면 내부에는 Weight만 존재합니다.
Transformer에서는 왜 bias=False를 사용할까?
Self-Attention에서는 다음과 같이 Query, Key, Value를 생성합니다.
여기서 목적은 입력을 새로운 특징 공간으로 투영(Projection) 하는 것입니다.
특히 Query와 Key는 이후 내적(Dot Product)을 통해 Attention Score를 계산하는데,
Bias를 추가해도 성능 향상이 크지 않으며 오히려 불필요한 Parameter만 증가하는 경우가 많습니다.
그래서 Transformer 원 논문(Attention Is All You Need)에서는 Q, K, V 생성 시 Bias를 사용하지 않았으며,
현재도 많은 구현이
nn.Linear(embed_size, embed_size, bias=False)를 사용합니다.
다만 최근의 일부 Transformer 변형 모델에서는 Bias를 사용하는 경우도 있으므로, 반드시 bias=False가 정답인 것은 아니며 모델 구현에 따라 달라질 수 있습니다.
정리
nn.Linear는 단순히 차원을 변경하는 레이어가 아닙니다.
내부적으로는
(또는 PyTorch 내부 구현 관점에서는 X @ W.T + b)를 계산하는 선형 변환(Linear Transformation) 레이어이며,
Weight와 Bias는 모두 자동으로 생성되는 학습 가능한 Parameter입니다.
핵심 내용을 정리하면 다음과 같습니다.
nn.Linear는 행렬곱(Matrix Multiplication) + Bias를 수행합니다.- Weight와 Bias는 자동으로 생성되는 학습 가능한 Parameter입니다.
- Weight의 Shape는 (out_features, in_features) 입니다.
- PyTorch는 내부적으로 Weight를 전치(Transpose)하여 계산합니다.
nn.Linear는 항상 마지막 차원(last dimension) 에만 적용됩니다.linear.weight,linear.bias를 통해 Parameter를 직접 확인할 수 있습니다.named_parameters()를 사용하면 이름과 함께 Parameter를 확인할 수 있습니다.requires_grad=True는 역전파를 통해 자동으로 학습되는 변수라는 의미입니다.- Transformer에서는 Query, Key, Value를 생성하기 위해 각각 다른
nn.Linear를 사용하며, 많은 구현에서bias=False를 사용합니다.
이 내용을 이해하면 이후 Self-Attention, Transformer, Feed Forward Network(FFN), MLP 등에서도 nn.Linear가 어떤 역할을 수행하는지 훨씬 쉽게 이해할 수 있을 것입니다.

