import torch
v = torch.tensor([1, 2, 3], dtype=torch.float32)
print(v)tensor([1., 2., 3.])
이론 1장의 사원 경력·연봉 표를 코드로 다룬다. 데이터 한 건과 변수 하나를 구분하고, 입력과 정답을 고르고, 주어진 예측의 오차를 계산한다. 마지막에는 신경망에서 사용할 행렬 곱을 연습한다.
대응 이론: Ch01 데이터와 모형. Python의 변수와 리스트를 배운 학생을 기준으로 하되, PyTorch의 새 문법은 사용 전에 설명한다.
None을 바꾼다. 막히면 힌트를 본다.assert는 조건이 맞는지 확인하고, 틀리면 실행을 멈춘다. 검사 코드를 작성하거나 외우는 것은 학습 목표가 아니다.torch.equal은 값과 모양의 일치를, torch.allclose는 작은 소수 계산 오차를 허용한 값의 일치를 확인한다. 이들은 확인 셀에서 사용한다.| 시간 | 내용 |
|---|---|
| 0–12분 | 모듈·함수·속성 읽기, 텐서 생성 |
| 12–27분 | 데이터 표에서 행·열 고르기 |
| 27–37분 | 사칙연산과 오차 |
| 37–49분 | 합·평균으로 이론의 계산 확인 |
| 49–61분 | 행렬 곱 |
| 61–75분 | 종합 연습·설명·정리 |
Colab에서 노트북을 본인 드라이브에 복사한다. Shift+Enter로 코드 셀을 실행한다. 셀은 위에서 아래로 실행한다. 런타임을 다시 시작하면 변수도 없어지므로 위에서부터 다시 실행한다.
import, 함수 호출, 결과 저장모듈은 관련 기능을 모아둔 것이다. import torch는 PyTorch의 기능을 torch라는 이름으로 사용하게 한다. torch.tensor(...)는 괄호 안의 숫자 목록을 받아 텐서를 반환하는 함수다. 텐서는 숫자를 담고 계산하는 자료형이며, 한 줄짜리 벡터나 표 모양의 행렬을 표현할 수 있다.
| 문법 | 읽는 방법 |
|---|---|
torch.tensor(...) |
torch에 있는 tensor 함수를 호출한다 |
dtype=torch.float32 |
자료형을 지정하는 이름 붙은 인수다. 여기서는 실수 계산용 float32를 사용한다 |
v = ... |
반환된 결과를 변수 v에 담는다 |
print(v) |
v의 내용을 화면에 출력한다 |
v.shape와 v.dtype은 텐서가 가진 속성이다. 이미 가진 정보를 읽으므로 괄호를 붙이지 않는다. 반면 뒤에서 쓸 v.sum()은 텐서의 합을 계산하는 메서드다. 텐서에 소속된 함수를 실행하므로 괄호를 붙인다. 지금은 속성 두 개부터 확인한다.
행렬은 바깥 리스트 안에 행별 리스트를 넣어 만든다. shape의 첫 숫자는 행 수, 둘째 숫자는 열 수다. 다음 결과를 먼저 예상한다.
숫자 [[1, 2], [3, 4], [5, 6]]을 담은 실수 텐서 practice를 만든다. 행과 열의 수를 먼저 말해 본다.
작성 셀
힌트: torch.tensor(숫자 목록, dtype=torch.float32)를 사용한다.
확인 셀 — 작성 후 실행
이론의 사원 8명 자료다. 연봉은 읽기 쉽도록 천 달러 단위로 썼다. 한 행이 사원 한 명, 한 열이 변수 하나다.
인덱스는 0부터 센다. staff[행, 열]로 위치를 고른다. a:b는 a번부터 b번 직전까지, :는 전부라는 뜻이다.
| 코드 | 고르는 것 |
|---|---|
staff[0, 1] |
첫 사원의 연봉 한 값 |
staff[:3] |
앞 세 사원의 전체 행 |
staff[:, 0] |
모든 사원의 경력 값 목록 |
staff[:, 0:1] |
경력 열 하나를 표 형태로 유지 |
tensor(31.)
tensor([[ 1.5000, 31.0000],
[ 2.5000, 39.0000],
[ 4.2000, 43.0000]])
tensor([ 1.5000, 2.5000, 4.2000, 5.1000, 6.7000, 8.3000, 9.5000, 13.0000])
tensor([[ 1.5000],
[ 2.5000],
[ 4.2000],
[ 5.1000],
[ 6.7000],
[ 8.3000],
[ 9.5000],
[13.0000]])
이론에서 경력은 입력 \(X\), 연봉은 정답 \(y\)다. 이번 두 실습에서는 입력과 회귀 정답을 행이 데이터, 열이 변수인 2차원 표로 둔다. 0:1처럼 슬라이스를 쓰면 열 하나도 표로 유지된다. 한 건만 고를 때도 X[:1]로 행을 남긴다.
>=는 이상인지 비교한다. 열의 값들을 비교하면 사원마다 True 또는 False가 나온다. 이 결과를 조건 마스크라 하고 대괄호에 넣으면 True인 행만 남는다.
경력 5년 미만인 사원의 조건 junior_mask, 입력 junior_X, 정답 junior_y를 만든다.
작성 셀
힌트: 조건은 경력 열로 만들고, 같은 조건을 X와 y에 적용한다.
확인 셀 — 작성 후 실행
assert junior_mask is not None and junior_mask.tolist() == [True, True, True, False, False, False, False, False]
assert junior_X is not None and junior_X.shape == (3, 1)
assert torch.allclose(junior_X, torch.tensor([[1.5], [2.5], [4.2]]))
assert junior_y is not None and junior_y.shape == (3, 1)
assert torch.equal(junior_y, torch.tensor([[31.], [39.], [43.]]))
print('통과')설명하기: 입력만 고르고 정답은 그대로 두면 어떤 문제가 생기는가?
+, -, *, /, ** 2는 각각 더하기, 빼기, 곱하기, 나누기, 제곱이다. 텐서에 숫자 하나를 곱하면 모든 원소에 같은 곱셈을 적용한다. 모양이 같은 두 텐서는 같은 위치끼리 계산한다.
tensor([[31000.],
[39000.],
[43000.]])
tensor([[2.5833],
[3.2500],
[3.5833]])
이론의 후보 모형 B는 연봉(천 달러) \(=10+8\times 경력\)이다. 첫 세 사원의 예측값은 22, 30, 43.6이다. 지금은 이 예측값을 주고 정답 − 예측을 계산한다. 예측을 만드는 신경망 부품은 다음 실습에서 배운다.
y_first = y[:3]
pred_B = torch.tensor([[22.], [30.], [43.6]])
error_B = y_first - pred_B
print(error_B) # 약 [9, 9, -0.6]
print(error_B ** 2)tensor([[ 9.0000],
[ 9.0000],
[-0.6000]])
tensor([[81.0000],
[81.0000],
[ 0.3600]])
이론의 후보 C는 앞 세 사원에게 25.5, 32.5, 44.4를 예측한다. pred_C, error_C, squared_C를 작성한다. 세 번째 사원의 오차 부호를 먼저 예상한다.
작성 셀
힌트: 예측 텐서는 정답과 같은 (3, 1)로 만든다.
확인 셀 — 작성 후 실행
assert pred_C is not None and pred_C.shape == y_first.shape
assert torch.allclose(pred_C, torch.tensor([[25.5], [32.5], [44.4]]))
assert error_C is not None and torch.allclose(error_C, torch.tensor([[5.5], [6.5], [-1.4]]), atol=1e-5)
assert squared_C is not None and torch.allclose(squared_C, torch.tensor([[30.25], [42.25], [1.96]]), atol=1e-4)
print('통과')설명하기: 오차가 음수이면 예측이 정답보다 큰가, 작은가?
sum(), mean(), item()| 메서드 | 하는 일 | 반환값 |
|---|---|---|
a.sum() |
전체 원소를 더한다 | 원소 하나인 텐서 |
a.mean() |
전체 원소의 평균을 구한다 | 원소 하나인 텐서 |
a.item() |
원소 하나인 텐서에서 숫자를 꺼낸다 | Python 숫자 |
이론의 잔차 제곱합은 오차를 제곱해서 더한 값이다. 작을수록 주어진 데이터를 더 가깝게 예측한다.
dim은 합치려는 축을 지정한다2차원 표에서 0번 축은 행, 1번 축은 열이다. dim=0은 여러 행을 합쳐 열별 결과, dim=1은 여러 열을 합쳐 행별 결과를 만든다. 인수를 생략하면 전체를 합친다.
아래 두 예측은 사원 8명 전체에 대한 것이다. 각각의 잔차 제곱합 sse_all_B, sse_all_C와 사원 표의 열별 평균 column_mean을 구한다.
작성 셀
힌트: 두 후보를 같은 8명의 정답과 비교한다. 열별 평균은 dim=0이다.
확인 셀 — 작성 후 실행
설명하기: 어느 후보가 더 나은가? 앞 세 사원만 비교했을 때와 결론이 같은가?
A @ B는 왼쪽의 행과 오른쪽의 열을 곱해서 더하는 연산이다. *는 같은 위치끼리 곱하기만 한다. 두 결과는 다르다.
\[(n,p)\ @\ (p,q)\longrightarrow(n,q)\]
왼쪽의 열 수와 오른쪽의 행 수가 같아야 한다. 결과는 왼쪽의 행 수와 오른쪽의 열 수를 갖는다. 아래 A @ B의 첫 값은 \(1\times2+2\times1=4\)다. 나머지 값도 먼저 예상한다.
A = torch.tensor([[1., 2.], [3., 4.]])
B = torch.tensor([[2., 0.], [1., 3.]])
print(A * B)
print(A @ B)
print(A[:1] @ B) # 한 행만 넣어도 계산 순서는 같다tensor([[ 2., 0.],
[ 3., 12.]])
tensor([[ 4., 6.],
[10., 12.]])
tensor([[4., 6.]])
입력 data의 각 행을 B와 곱한 결과를 result에 담는다. 첫 행만 계산한 결과는 one_result에 담는다. 두 결과의 모양을 먼저 예상한다.
작성 셀
힌트: 데이터를 왼쪽, 계산에 쓰는 행렬을 오른쪽에 둔다.
확인 셀 — 작성 후 실행
새 카페 표에서도 같은 문법을 쓸 수 있는지 확인한다. 9분 동안 작성하고, 남은 시간에 결과를 함께 설명한다.
cafe_X, 마지막 열을 정답 cafe_y로 고른다. 둘 다 표 형태로 둔다.feature_mean을 구한다.cafe_pred의 잔차 제곱합 cafe_sse를 구한다.no_ad_mean을 구한다.작성 셀
힌트: 행·열 선택은 2절, 합과 평균은 4절로 돌아가 확인한다.
확인 셀 — 작성 후 실행
assert cafe_X is not None and cafe_X.shape == (4, 2) and torch.equal(cafe_X, cafe[:, :2])
assert cafe_y is not None and cafe_y.shape == (4, 1) and torch.equal(cafe_y, cafe[:, 2:3])
assert feature_mean is not None and feature_mean.shape == (2,)
assert torch.allclose(feature_mean, torch.tensor([2.5, 0.75]))
assert cafe_sse is not None and abs(cafe_sse.item() - 1.) < 1e-5
assert no_ad_mean is not None and abs(no_ad_mean.item() - 10.) < 1e-5
print('통과')설명하기: 매출 열을 입력에 넣으면 왜 안 되는가? 먼저 끝났다면 특정 날짜의 예측을 바꾸고 잔차 제곱합이 커지는지 확인한다.
오늘 익힌 순서는 모듈 가져오기 → 텐서 만들기 → 행·열 선택 → 연산 → 결과 확인이다. shape처럼 정보를 읽는 속성과 sum()처럼 계산하는 메서드를 구분한다.
실습 2에서는 준비한 표를 신경망 부품에 넣어 예측을 만든다.
해설 코드를 해당 작성 셀에 옮긴 후 확인 셀을 실행한다.
cafe_X = cafe[:, :2]
cafe_y = cafe[:, 2:3]
feature_mean = cafe_X.mean(dim=0)
cafe_sse = ((cafe_y - cafe_pred) ** 2).sum()
no_ad_mean = cafe[cafe[:, 1] == 0, 2].mean()후보 비교 해석: 앞 세 사원에서는 C의 잔차 제곱합이 약 74.46으로 B의 162.36보다 작다. 8명 전체에서는 B가 약 607.12, C가 약 816.22로 B가 더 작다. 비교에 사용한 데이터 범위를 함께 봐야 한다.