32, 일반적으로 32나 64 사용)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Input, Dense, Flatten
from tensorflow.keras.optimizers import SGD, Adam
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 모델 1: sigmoid + SGD
model1 = Sequential()
model1.add(Input(shape=(28,28)))
model1.add(Flatten())
model1.add(Dense(units=64, activation='sigmoid'))
model1.add(Dense(units=128, activation='sigmoid'))
model1.add(Dense(units=256, activation='sigmoid'))
model1.add(Dense(units=128, activation='sigmoid'))
model1.add(Dense(units=64, activation='sigmoid'))
model1.add(Dense(units=10, activation='softmax'))
model1.compile(
optimizer=SGD()
, loss="sparse_categorical_crossentropy"
, metrics=["accuracy"]
)
h1 = model1.fit(X_train, y_train, validation_split=0.2, epochs=20, batch_size=64)
# 모델 2: : ReLU + SGD → default 값으로 학습 시 보폭이 너무 커 제대로 학습하지 못함 → 하이퍼 파라미터 조정
model2 = Sequential()
model2.add(Input(shape=(28,28)))
model2.add(Flatten())
model2.add(Dense(units=64, activation='relu'))
model2.add(Dense(units=128, activation='relu'))
model2.add(Dense(units=256, activation='relu'))
model2.add(Dense(units=128, activation='relu'))
model2.add(Dense(units=64, activation='relu'))
model2.add(Dense(units=10, activation='softmax'))
model2.compile(
optimizer=SGD(learning_rate=0.001) # 0.01일 때 loss가 None으로 출력됨 → learning rate=0.01이 너무 높다는 뜻
, loss="sparse_categorical_crossentropy"
, metrics=["accuracy"]
)
h2 = model2.fit(X_train, y_train, validation_split=0.2, epochs=20, batch_size=64)
# 모델 3: ReLU + Adam
model3 = Sequential()
model3.add(Input(shape=(28,28)))
model3.add(Flatten())
model3.add(Dense(units=64, activation='relu'))
model3.add(Dense(units=128, activation='relu'))
model3.add(Dense(units=256, activation='relu'))
model3.add(Dense(units=128, activation='relu'))
model3.add(Dense(units=64, activation='relu'))
model3.add(Dense(units=10, activation='softmax'))
model3.compile(
optimizer=Adam() # Adam의 default learning_rate는 0.001 cf. SGD는 default 0.01
, loss="sparse_categorical_crossentropy"
, metrics=["accuracy"]
)
h3 = model3.fit(X_train, y_train, validation_split=0.2, epochs=20, batch_size=64)
# 시각화: accuracy
plt.figure(figsize=(8,3))
plt.plot(h1.history["accuracy"], label="sig+sgd acc")
plt.plot(h2.history["accuracy"], label="relu+sgd acc")
plt.plot(h3.history["accuracy"], label="relu+adam acc")
plt.plot(h1.history["val_accuracy"], label="sig+sgd acc_val")
plt.plot(h2.history["val_accuracy"], label="relu+sgd acc_val")
plt.plot(h3.history["val_accuracy"], label="relu+adam acc_val")
plt.legend()
plt.show()

# 시각화: loss
plt.figure(figsize=(8,3))
plt.plot(h1.history["loss"], label="sig+sgd loss")
plt.plot(h2.history["loss"], label="relu+sgd loss")
plt.plot(h3.history["loss"], label="relu+adam loss")
plt.plot(h1.history["val_loss"], label="sig+sgd loss_val")
plt.plot(h2.history["val_loss"], label="relu+sgd loss_val")
plt.plot(h3.history["val_loss"], label="relu+adam loss_val")
plt.legend()
plt.show()

서로에게 맞는 최적화 함수와 활정화 함수가 있음!
→ 다양한 조합과 다양한 파라미터로 학습을 진행하기
modelcheckpointearlystopping모델을 중간 중간 저장하는 습관 들이기
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
# 모델 저장
# 경로 설정
model_path = "/content/drive/MyDrive/Colab Notebooks/DeepLearning_basic/data/model_save/model_{epoch:02d}_{val_accuracy:.3f}.keras"
# 모델 저장 객체 생성 → 학습할 때 사용
mc = ModelCheckpoint(
filepath=model_path # 모델을 저장할 경로
, monitor="val_accuracy" # 모델의 성능을 확인하는 기준(최고점(최고 성능) 판단 기준)
, verbose=1 # 진행 과정 출력 여부(0→미출력, 1→출력)
, save_best_only=True # 모델이 최고 성능을 갱신할 때만 저장 (False → 모든 epoch마다 저장): 메모리를 아끼기 위해서 꼭 True로
)
# 조기학습 중단 객체 생성
es = EarlyStopping(
monitor="val_accuracy" # 중단할 기준
, verbose=1 # 로그 출력 여부
, patience=20 # 모델 성능 개선을 기다리는 횟수
)
# 모델 1: sigmoid + SGD
model1 = Sequential()
model1.add(Input(shape=(28,28)))
model1.add(Flatten())
model1.add(Dense(units=64, activation='sigmoid'))
model1.add(Dense(units=128, activation='sigmoid'))
model1.add(Dense(units=256, activation='sigmoid'))
model1.add(Dense(units=128, activation='sigmoid'))
model1.add(Dense(units=64, activation='sigmoid'))
model1.add(Dense(units=10, activation='softmax'))
# 학습 방법
model1.compile(
optimizer=SGD()
, loss="sparse_categorical_crossentropy"
, metrics=["accuracy"]
)
# 학습
h1 = model1.fit(
X_train
, y_train
, validation_split=0.2
, epochs=100
, batch_size=64
, callbacks = [mc,es]
)
# 콜백 함수를 사용한 결과 → acc, val_acc 그래프 그려보기
plt.figure(figsize=(10,6))
plt.plot(h1.history["accuracy"], label="acc")
plt.plot(h1.history["val_accuracy"], label="val_acc")
plt.show()

from tensorflow.keras.models import load_model
model_loaded = load_model("/content/drive/MyDrive/Colab Notebooks/DeepLearning_basic/data/model_save/model_89_0.890.keras")
model_loaded.summary()

# 설치 확인 및 버전 확인
import torch, torchvision
print(torch.__version__)
print(torchvision.__version__)
print(torch.cuda.is_available()) # 구글 코랩 기본 설정은 CPU라 런타임 유형 설정 안 바꾸고 하면 False가 뜹니다.
# 컴퓨팅 자원을 아껴두기 위해 CPU로 설정하고 진행해 주세요.
2.6.0+cu124
0.21.0+cu124
False
하드웨어 가속기를 T4 GPU로 변경하면:
import torch
# 텐서 생성
torch.tensor([[1, 2],
[3, 4]])
tensor([[1, 2],
[3, 4]])





[2, 4, 4]| PyTorch 타입 이름 | 실제 자료형(dtype) | 설명 |
|---|---|---|
FloatTensor | torch.float32 | 32비트 실수형(32-bit floating point) |
DoubleTensor | torch.float64 | 64비트 실수형 |
HalfTensor | torch.float16 | 16비트 실수형 |
BFloat16Tensor | torch.bfloat16 | 16비트 실수형 |
IntTensor | torch.int32 | 32비트 정수형 |
LongTensor | torch.int64 | 64비트 정수형 |
ShortTensor | torch.int16 | 16비트 정수형 |
CharTensor | torch.int8 | 8비트 정수형 |
ByteTensor | torch.uint8 | 8비트 부호 없는 정수형 |
BoolTensor | torch.bool | Boolean |

# 실수형 텐서 생성
t_float = torch.FloatTensor([[1, 2], [3, 4]])
t_long = torch.LongTensor([[1, 2], [3, 4]])
print(t_float.dtype)
print(t_long.dtype)
torch.float32
torch.int64
torch.rand(), torch.randn()# 32비트 실수형 데이터를 갖는 임의의 텐서 생성
torch.FloatTensor(2, 3) # 메모리에 남아 있던 찌꺼기 값(초기화되지 않은 메모리 값)
tensor([[2.0758e-16, 0.0000e+00, 1.6180e-16],
[0.0000e+00, 7.0414e-17, 0.0000e+00]])
# 랜덤 값으로 (2,3)의 텐서 생성하기
torch.rand(2,3) # 사용할 수 있는 실수 값 생성
tensor([[0.3889, 0.1263, 0.8998],
[0.0140, 0.8352, 0.9881]])
| 항목 | torch.FloatTensor(2, 3) | torch.rand(2, 3) |
|---|---|---|
| 값의 의미 | 초기화되지 않은 메모리 쓰레기값 | 0 이상 1 미만의 무작위 실수 (균등분포) |
| 난수 생성 여부 | ❌ 아님 (난수 아님) | ✅ 진짜 난수 |
| 실전에서의 사용 | 거의 안 씀 (조심해야 함) | 자주 씀 (초기화, 랜덤 샘플 등) |
# 정규분포 난수값을 가지는 텐서 생성
torch.randn(2,3)
tensor([[ 1.0045, -1.1222, 0.1809],
[-0.4668, 0.3108, 1.5698]])
# numpy에서 특정 값으로 배열 생성
import numpy as np
# 1로 채운 넘파이 배열 생성
np.ones((2, 3))
print('np.random.rand\n', np.random.rand(2, 3))
# 0과 1 사이의 균일 분포 난수로 채워진 행렬을 생성
print('np.random.randn\n', np.random.randn(2, 3))
# 표준 정규 분포 (평균 0, 분산 1)를 따르는 난수로 채워진 행렬을 생성
print('np.random.randint\n', np.random.randint(0, 10, size=(2, 3)))
# 지정된 범위 (low 이상 high 미만)의 정수 난수로 채워진 행렬을 생성
print('np.random.choice\n', np.random.choice([1, 2, 3, 4, 5], size=(2, 3), replace=True, p=None))
# 지정된 범위 (low 이상 high 미만)의 정수 난수로 채워진 행렬을 생성
# replace=True는 복원 추출 (중복 허용)을 의미하고, replace=False는 비복원 추출 (중복 불가)을 의미
# cf. 파이썬 random 모듈
import random
print('random.randint\n', random.randint(0, 10))
print('random.sample\n', random.sample(range(1, 101), 5))
np.random.rand
[[0.05471568 0.2818698 0.20810544]
[0.87613291 0.51560773 0.35518498]]
np.random.randn
[[-0.95464116 -0.39966631 -1.39070909]
[-0.14523821 1.73774026 1.94933784]]
np.random.randint
[[1 7 6]
[2 9 2]]
np.random.choice
[[5 3 4]
[5 1 4]]
random.randint
4
random.sample
[88, 58, 72, 56, 7]
torch.randint(), torch.randperm()# (시작범위, 끝범위+1, 텐서의 크기)
torch.randint(1, 50+1, size=(1,6))
tensor([[42, 17, 20, 19, 9, 33]])
# randperm 함수: 0부터 n-1까지 정수를 하나씩 섞어서 임의의 배열을 생성
# 데이터 세트를 랜덤으로 shuffle
torch.randperm(10)
tensor([1, 9, 3, 4, 2, 5, 0, 8, 7, 6])
arr = np.array([[1, 2], [3, 4]])
ten = torch.tensor([[1, 2], [3, 4]])
# ndarray → tensor
torch.from_numpy(arr)
# tensor → ndarray
ten.numpy()
# 리스트
[1, 2, 3] + [1, 2, 3] # 출력: [1, 2, 3, 1, 2, 3]
# 넘파이 ndarray
np.array([1, 2, 3])+np.array([1, 2, 3]) # 출력: array([2, 4, 6])
# 파이토치 tensor
torch.tensor([1, 2, 3])+torch.tensor([1, 2, 3]) # 출력: tensor([2, 4, 6])
# (4, 4) 크기로 정규 분포를 갖는 랜덤 텐서 생성
t_randn = torch.randn(4,4)
# 랜덤 텐서 long 형태로 변환
t_long = t_randn.long()
print(t_long)
print(type(t_long))
# 텐서를 numpy로 변환
arr = t_long.numpy()
print(arr)
print(type(arr))
# numpy → 텐서로 변환
ten = torch.from_numpy(arr)
print(ten)
print(type(ten))
# 크기, 차원 출력
print(ten.shape, ten.size(), ten.ndim, sep="\n")
tensor([[ 0, 0, 0, 0],
[ 0, -1, 0, 1],
[ 0, 2, 0, -1],
[ 0, 0, 0, 1]])
<class 'torch.Tensor'>
[[ 0 0 0 0]
[ 0 -1 0 1]
[ 0 2 0 -1]
[ 0 0 0 1]]
<class 'numpy.ndarray'>
tensor([[ 0, 0, 0, 0],
[ 0, -1, 0, 1],
[ 0, 2, 0, -1],
[ 0, 0, 0, 1]])
<class 'torch.Tensor'>
torch.Size([4, 4])
torch.Size([4, 4])
2
# Byte 타입의 5개 크기로 임의의 텐서를 생성하고 랜덤으로 섞는다
# 1. ByteTensor 생성
t_bt=torch.ByteTensor(5)
print(t_bt)
# 2. size 함수를 사용하여 데이터의 개수 파악
s = t_bt.size()
print(s[0])
# 3. torch.randperm을 사용하여 랜덤하게 인덱스 생성
t_idx = torch.randperm(s[0])
print(t_idx)
# 4. torch.randperm이 가지는 숫자를 인덱스로 지정
# 5. 인덱스 번호 순서대로 정렬(인덱싱) → 월화수목금 가져오는 원리와 동일
result = t_bt[t_idx]
print(result)
# 한 줄로도 가능
torch.ByteTensor(5)[torch.randperm(torch.ByteTensor(5).size()[0])]
tensor([ 96, 157, 148, 73, 169], dtype=torch.uint8)
5
tensor([1, 3, 4, 0, 2])
tensor([157, 73, 169, 96, 148], dtype=torch.uint8)
tensor([240, 0, 46, 44, 82], dtype=torch.uint8)
# (3,3) 크기의 임의로 1~10 사이의 정수형 텐서를 생성하고 랜덤으로 섞어서 출력
# 다양한 방법으로 해 보기
# 1. 임의의 3,3 크기의 텐서를 생성 (랜덤 수)
ten_3by3 = torch.randint(1, 10+1, size=(3,3))
print(ten_3by3)
# 2. 반복문을 활용하여 사이즈 추출 (1행, 2행, 3행)
for i in range(ten_3by3.size()[0]):
idx = torch.randperm(ten_3by3[i].size()[0])
ten_3by3[i] = ten_3by3[i][idx]
# 3. torch.randperm을 인덱스처럼 활용하여 재배열
# print(임의의 3,3 텐서)
# print(결과)
print(ten_3by3)
# 다른 풀이 1
t_rand = torch.randint(1, 11, size=(3,3))
t_rand_size = t_rand.size() # [3,3]
n_flat = t_rand.numpy().flatten()
row = t_rand_size[0]
col = t_rand_size[1]
n_arr = n_flat[torch.randperm(row*col)]
t_arr = torch.from_numpy(n_arr)
result = t_arr.reshape(row, col)
result
# 다른 풀이 2
data_org = torch.randint(1, 11, (3,3))
print(data_org)
data = data_org.reshape(-1)
idx = torch.randperm(data.shape[0])
data = data[idx]
data = data.reshape(data_org.shape[0], data_org.shape[1])
print(data)
# 다른 풀이 3
t_int = torch.randint(1, 11, (3,3))
print(t_int)
for idx, row in enumerate(t_int):
size = row.size()
t_int[idx] = row[torch.randperm(size[0])]
print(t_int)
# 다른 풀이 4
ten_org = torch.randint(1, 10+1, size=(3,3))
print(ten_org)
row_num = ten_org.shape[0]
col_num = ten_org.shape[1]
ten_shuffled = []
for i in range(row_num):
idx = torch.randperm(col_num)
ten_shuffled.append(ten_org[i][idx])
ten_shuffled = torch.stack(ten_shuffled)
result = ten_shuffled[torch.randperm(row_num)]
print(result)
# 다른 풀이 5
t_rand3 = torch.randint(1, 10+1, size=(3,3))
print(t_rand3)
rand_rows = t_rand3[torch.randperm(t_rand3.size(0))]
print(rand_rows)
rand_tensor = t_rand3.view(-1)[torch.randperm(9)].reshape(3,3)
print(rand_tensor)
# 강사님 풀이
# (3,3) 크기의 임의로 1~10 사이의 정수형 텐서를 생성하고 / 랜덤으로 섞어서 출력
# 1. 임의의 3,3 크기의 텐서를 생성 (랜덤수)
rand_int = torch.randint(1,11,size=(3,3))
print(rand_int)
# 2. 반복문을 활용하여 사이즈 추출 (1행,2행,3행)
for i in range(rand_int.shape[0]):
s = rand_int[i].size(0)
idx = torch.randperm(s)
rand_int[i] = rand_int[i][idx]
# 3. torch.randperm 을 인덱스처럼 활용하여 재배열
print(rand_int)
# print(임의의 3,3 텐서)
# print(결과)
# 또 다른 방법
t_int = torch.randint(1,11,(3,3))
print('원본')
print(t_int)
for dim in range(t_int.ndim):
perm = torch.randperm(t_int.size(dim))
t_int = t_int[perm] if dim == 0 else t_int[:, perm]
print('변환')
print(t_int)