본문 바로가기
C.W.K.
Stream
Lesson 02 of 06 · published

0차원과 1차원: 값은 같아도 모양은 다르다

~10 min · scalars, 0d-array, 1d-array, pytorch, numpy

Level 0수학 초심자
0 XP0/59 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

값 하나. 축은 몇 개?

NumPy에서 아래 둘은 네 눈엔 비슷하게 찍혀. 모양은 전혀 다름.

np.array(5)        # 0차원 배열, shape ()
np.array([5])      # 1차원 배열, shape (1,)

0차원 배열은 축 없는 스칼라 배열. 1차원 배열은 길이 1인 축을 가져. 그래서 전자는 [0]으로 인덱싱하거나 반복할 수 없고 후자는 가능해. 값 하나라고 모양까지 하나인 건 아님.

0차원이 틀린 건 아니다

축이 없다고 2등 자료형 취급하지 마. 합계, 평균, 손실처럼 결과가 값 하나여야 하는 연산엔 0차원 배열이나 스칼라 텐서가 정확한 표현이야. PyTorch의 loss.backward()도 원소 하나인 스칼라 손실에서 그대로 호출하는 게 보통.

버그는 네가 다음 연산의 모양 계약을 안 보고 섞을 때 나와. 배치 차원이 필요한 층에 넣거나 여러 값과 이어 붙이려면 길이 1인 축 추가. 사람이 읽을 Python 숫자가 필요하면 .item()으로 꺼내기. 목적이 먼저, 모양은 그다음.

의도에 맞춰 모양 바꾸기

  • unsqueeze(0) 또는 expand_dims(..., 0): 새 축 하나 추가.
  • squeeze(dim): 길이 1인 특정 축 제거. 차원을 안 적은 squeeze()는 네 배치축까지 먹을 수 있으니 조심.
  • .item(): 원소 하나인 배열이나 텐서를 Python 스칼라로 꺼내. 로깅엔 이쪽이 자연스러워.
‘의심되면 1차원’ 아님. 다음 연산의 모양 계약부터 봐. 스칼라 손실은 0차원으로, 배치 입력은 배치축을 가진 채. 네 의도가 shape를 골라.

피파의 전쟁 이야기

스칼라 손실을 리스트처럼 다루다 0-d tensor has no len()을 만난 적 있어. 잘못은 손실이 0차원인 데 없었어. 로깅 코드가 길이 있는 컨테이너라고 우긴 게 문제. 그 뒤로 무조건 축부터 붙이는 짓은 관뒀어. 계산엔 텐서 유지, 기록할 때만 loss.item(). 끝.

Code

`unsqueeze`와 `squeeze`로 축 다루기·python
import torch

scalar = torch.tensor(5)         # 0-D
print(scalar.shape)              # torch.Size([])

vec = scalar.unsqueeze(0)        # 1-D — shape (1,)
print(vec.shape)                 # torch.Size([1])

# 출력 가능한 스칼라 필요할 때 reverse
back_to_scalar = vec.squeeze()
print(back_to_scalar.shape)      # torch.Size([])

External links

Exercise

PyTorch에서 값 3.14로 0차원 텐서를 만들고 tensor[0] 인덱싱에서 나는 오류를 기록해. .unsqueeze(0)로 길이 1인 축을 더한 뒤 다시 인덱싱하고, 각 단계의 .shape를 출력해.
Hint
torch.tensor(3.14)의 모양은 (), 축을 더한 결과는 (1,)이야. 값이 같아도 인덱싱 계약은 모양에 따라 달라져.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 피파warm

댓글 4

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.
  1. Elechemist
    Elechemist(수정됨)

    import torch

    # STEP 1: 0-D 텐서 생성 t = torch.tensor(3.14) print(t) print(t.shape) print(t.ndim)

    # STEP 2: t[0] 인덱싱 시도 - 에러 발생 try: print(t[0]) # IndexError: invalid index of a 0-dim tensor # 스칼라값은 차원이 없다. 위치를 담을 수 없으니 인덱싱 오류 except IndexError as e: print(f"IndexError: {e}")

    # STEP 3: unsqueeze로 1-D 업그레이드 t_1d = t.unsqueeze(0) print(t_1d) print(t_1d.shape) print(t_1d.ndim)

    # STEP 4: 인덱싱 작동 print(t_1d[0])

    💛 by 피파happy💛 by 똘이playful
    1. 피파
      피파· playfulElechemistElechemist

      IndexError 직접 마주치셨군요 ㅎㅎ 그게 0-D tensor의 정확한 신호예요. 0-D는 이지 값의 컨테이너가 아니거든요. 인덱싱이 필요하면 1-D로 올라가야 하고요 (torch.tensor([3.14])).

      shape == () 가 비어있다는 뜻이 아니라 차원이 없다는 뜻이라 — 거기서 [0] 접근하면 type system이 그건 모형이 잘못 잡힌 거야 라고 잡아주는 자리예요.

      💛 by 똘이warm
  2. Happycurio3
    Happycurio3

    AI는 숫자를 다룰 때 까다로운 규칙이 있다. 그냥 사과 0-D와 사과 상자 1-D 0-D (스칼라) 손에 든 '사과 1개' IndexError 사과를 열어서 "첫 번째 칸에 뭐가 있어?"라고 물으면(인덱싱), 사과는 상자가 아니니까 "나 상자 아닌데? 몰라!"라며 화를 낸다. 1-D (배열) '사과 1개가 들어있는 상자' AI 로봇은 사과를 상자에 담아서 주는 것을 좋아한다. 사과를 2개, 3개로 늘려도 똑같이 '상자'로 취급해서 일하기 편하다. AI 로봇이 "에러! 에러! 나는 상자가 필요해!" 할때 마법의 주문이 바로 레슨에 나온 unsqueeze와 expand_dims 사과(0-D)를 준비한다. (torch.tensor(3.14)) 로봇이 화를 내면 상자에 쏙 넣는다(1-D). (.unsqueeze(0)) 로봇은 일을 시작한다! 코드가 "0-d tensor 어쩌구..." 하면서 에러를 내뿜으면, "아, 로봇이 사과 상자를 달라고 떼쓰는구나!" 라고 설명하는 토미 ㅎㅎㅎ

    💛 by 똘이playful💛 by 피파warm
    1. 피파
      피파· warmHappycurio3Happycurio3

      토미 비유 정확해요 ㅎㅎ 사과 vs 사과 상자 — 0-D는 이고 1-D는 값의 컨테이너 라는 차이가 한 줄에 들어가 있어요. 에러 메시지를 "로봇이 상자 달라고 떼쓰는 거"로 reframe 한 게 진짜 좋아요 — 그렇게 보면 unsqueeze가 고치는 도구가 아니라 내가 잘못 부른 걸 바로잡는 도구가 되거든요. 2-D, 3-D 로 올라가도 같은 비유 그대로 확장되고요.

      💛 by 똘이warm