C.W.K.
Stream
Lesson 02 of 06 · published

0-D vs 1-D: 첫 주를 갉아먹는 그 버그

~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-D 배열 — shape ()
np.array([5])      # 1-D 배열 — shape (1,)

둘 다 5 로 출력. 둘 다 값 하나. 같은 게 아니야. 0-D 는 배열 옷 입은 스칼라. 1-D 는 list-of-one. AI 라이브러리는 다르게 다뤄 — 그리고 대부분 1-D 를 선호.

둘을 구분해주는 에러

  • 0-D 인덱싱: scalar_in_array[0]IndexError. 인덱스할 축 없음.
  • 0-D 순회: for x in scalar_in_arrayTypeError. 순회할 게 없음.
  • 대부분의 행렬 연산: scalar_in_array @ matrix → 모양 에러. 최소 1축 필요.

1-D 버전은 셋 다 깔끔히 처리. 이거 먼저 설명 안 하는 AI 튜토리얼이 너를 broadcasting 에러로 피흘리게 두는 이유.

universal 해결책

스칼라 있는데 모델/라이브러리/배치 연산에 먹여야 할 때: 먼저 1-D 로 업그레이드. PyTorch 는 scalar.unsqueeze(0). NumPy 는 np.array([scalar]) 또는 np.expand_dims(scalar, 0). 반대 (출력/비교용으로 1-D → 0-D) 는 tensor.squeeze().

의심되면 늘 1-D. 프레임워크는 축 기대. 축 없는 스칼라는 2등 시민; 1-D wrapper 는 비용 0 인데 모든 거 잠금 해제.

피파의 war story

처음 직접 학습 루프 짤 때 스칼라 loss 를 loss.backward() 에 직접 넘겼어. PyTorch 가 받아. 다음 epoch 에서 list 로 로깅하려는데 — "0-d tensor has no len()". 20분 동안 옵티마이저 탓했어. 해결은 .unsqueeze(0) 한 번. 이젠 모든 스칼라가 본능적으로 unsqueeze 돼, 사소해 보여도.

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-D 텐서 만들어. tensor[0] 인덱스 시도 — 에러 노트. 그러고 1-D 로 unsqueeze 후 다시 인덱스 — 작동함. 각 단계 shape 출력.
Hint
torch.tensor(3.14) 가 0-D. .unsqueeze(0) 가 업그레이드. 교훈은 IndexError 느끼는 데 있어 — 그 에러는 우주가 '차원 추가해' 라고 말하는 거.

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