오늘부로 AI 파트가 모두 끝났다. 어제에 이어서 여러 모델들을 구현해보았다. 단일 선형 회귀처럼 간단한 모델은 상대적으로 쉬워서 이해하면서 코드 구현을 했었는데, 복잡한 모델을 구현하니까 이해는 둘째 치고 코드를 따라 치는 것도 벅찼던 것 같다. 코드를 계속 보면서 조금씩 이해해보려 해야겠다.
nn.Sequential() : 복잡한 모델 구현을 간단하게 표현 가능class LinearRegression(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Linear(1,10),
nn.ReLU(),
nn.Linear(10,10),
nn.ReLU(),
nn.Linear(10,1)
)
def forward(self, x):
return self.model(x)
x = torch.linspace(0,10,100).view(-1,1)
y = 3 * x + 2 + torch.randn(100, 1) * 2
# Train / Test set 분리 (8:2로 분리)
num_train = int(len(x) * 0.8)
indices = torch.randperm(len(x))
train_idx, test_idx = indices[:num_train], indices[num_train:]
x_train, y_train = x[train_idx], y[train_idx]
x_test, y_test = x[test_idx], y[test_idx]
class LinearRegressionModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(1,1)
def forward(self, x):
return self.linear(x)
model = LinearRegressionModel()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
epochs = 500
losses = []
# 트레이닝 데이터로 학습
for epoch in range(epochs):
optimizer.zero_grad()
outputs = model(x_train)
loss = criterion(outputs, y_train)
loss.backward()
optimizer.step()
losses.append(loss.item())
if (epoch + 1) % 100 == 0:
print(f"Eporch [{epoch+1} / {epochs}], Loss : {loss.item() : .4f}")
# 테스트 데이터 평가
with torch.no_grad():
test_output = model(x_test)
test_loss = criterion(test_output, y_test)
print(f"최종 Test Loss : {test_loss.item(): .4f}")
plt.figure(figsize=(10,5))
plt.subplot(1, 2, 1)
plt.plot(losses)
plt.title("Loss over Epochs")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.grid()
plt.subplot(1, 2, 2)
plt.scatter(x_train.numpy(), y_train.numpy(), label="Training Data")
plt.scatter(x_test.numpy(), y_test.numpy(), label="Test Data", color="g")
plt.plot(x.numpy(), model(x).detach().numpy(), color="r", label="Fitted Line")
plt.title("Linear Regression Fit")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()
# 데이터 정의 (10개 샘플)
X = torch.tensor([[50.0, 25.0, 30.0],
[10.0, 20.0, 25.0],
[5.0, 22.0, 30.0],
[30.0, 26.0, 28.0],
[40.0, 15.0, 28.0],
[60.0, 35.0, 40.0],
[70.0, 30.0, 35.0],
[20.0, 15.0, 20.0],
[25.0, 18.0, 22.0],
[45.0, 28.0, 30.0]], dtype=torch.float32)
y = torch.tensor([[22.1], [10.4], [9.3], [18.5], [12.9],
[25.0], [27.5], [13.0], [15.0], [20.5]], dtype=torch.float32)
# 모델 정의
class MultipleLinearRegression(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Linear(3, 1)
)
def forward(self, X):
return self.model(X)
model = MultipleLinearRegression()
# 손실함수 정의
criterion = nn.MSELoss()
# 가중치 업데이트
optimizer = optim.SGD(model.parameters(), lr=0.0001)
epochs = 1000
losses = []
for epoch in range(epochs):
optimizer.zero_grad()
outputs = model(X)
loss = criterion(outputs, y)
loss.backward()
optimizer.step()
losses.append(loss.item())
if (epoch + 1) % 100 == 0:
print(f"Epoch [{epoch+1} / {epochs}], Loss : {loss.item(): .4f}")
# 결과 시각화
plt.figure(figsize=(10,5))
# 손실 감소 그래프
plt.subplot(1, 2, 1)
plt.plot(losses)
plt.title("Training Loss over Epochs")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.grid()
# 데이터와 예측 결과
predicted = model(X).detach().numpy()
actual = y.numpy()
plt.subplot(1, 2, 2)
plt.scatter(range(len(actual)), actual, color="b", label="Actual")
plt.scatter(range(len(predicted)), predicted, color="r", label="Predicted")
plt.grid()
plt.title("Actual vs Predicted Sales")
plt.xlabel("Data index")
plt.ylabel("Sales")
plt.legend()
plt.show()
# Weight / Bias 값 출력
# 방법 1
weight = model.model[-1].weight.data
bias = model.model[-1].bias.data
print("\n학습된 모델의 파라미터")
print(f"Weight : {weight}")
print(f"Bias : {bias}")
# 방법 2
model_layer_idx = len(model.model) - 1
params = dict(model.named_parameters())
w = params[f"model.{model_layer_idx}.weight"].data
b = params[f"model.{model_layer_idx}.bias"].data
print(w)
print(b)
from torch.autograd import Variablemultivariate_normal(평균, 공분산, 점의 수)np.random.seed(42) # 시드 고정
num_samples = 1000
# 평균 및 공분산 설정
mean_1 = np.array([1., 1.])
cov_1 = np.array([[1,0], [0,1]])
mean_2 = np.array([-1., -1.])
cov_2 = np.array([[1,0], [0,1]])
# 데이터 생성
data_1 = np.random.multivariate_normal(mean_1, cov_1, num_samples // 2)
data_2 = np.random.multivariate_normal(mean_2, cov_2, num_samples // 2)
# 데이터 확인
plt.scatter(data_1[:, 0], data_1[:, 1], color="b", label="Class1")
plt.scatter(data_2[:, 0], data_2[:, 1], color="r", label="Class0")
plt.legend()
plt.show()
# 데이터 정의 및 텐서로 변환
data = np.vstack((data_1, data_2))
labels = np.ones(num_samples)
labels[num_samples // 2:] = 0
data = torch.from_numpy(data).float()
labels = torch.from_numpy(labels).float()
labels = labels.view(-1, 1)
num_samples, num_features = data.shape
class LogisticRegression(nn.Module):
def __init__(self, input_dim, output_dim):
super().__init__()
self.linear = nn.Linear(input_dim, output_dim)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
out = self.linear(x)
out = self.sigmoid(out)
return out
model = LogisticRegression(2, 1)
criterion = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
epochs = 1000
losses = []
for epoch in range(epochs):
inputs = Variable(data)
targets = Variable(labels)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
losses.append(loss.item())
if (epoch + 1) % 100 == 0:
print(f"Epoch [{epoch+1} / {epochs}], Loss : {loss.item(): .4f}")
plt.plot(losses)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.grid()
plt.show()
# 결정 경계 그리기
w = model.linear.weight.data.numpy()
b = model.linear.bias.data.numpy()
x_plot = np.array([-2,2])
y_plot = (-b - w[0][0] * x_plot / w[0][1]) # 결정 경계 함수
plt.plot(x_plot, y_plot, color="g", label="Decision Boundary")
plt.scatter(data_1[:, 0], data_1[:, 1], color="b", label="Class1")
plt.scatter(data_2[:, 0], data_2[:, 1], color="r", label="Class0")
plt.legend()
plt.show()
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
transform = transforms.ToTensor() # 이미지 데이터를 Tensor로 변환
# 트레이닝 테이터 정의
train_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=transform
)
# 테스트 데이터 정의
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=transform
)
# 데이터 로더 정의
batch_size = 64 # 미니 배치 경사 하강법
train_dataloader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=batch_size, shuffle=False)
class MultiClassificationModeel(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.model = nn.Sequential(
nn.Linear(28*28, 512),
nn.BatchNorm1d(512),
nn.ReLU(),
nn.Linear(512, 256),
nn.BatchNorm1d(256),
nn.ReLU(),
nn.Linear(256, 64),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.flatten(x)
out = self.model(x)
return out
model = MultiClassificationModeel()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
epochs = 10
# 학습 루프
def train_loop(dataloader, model, criterion, optimizer):
model.train() # 학습 모드
size = len(dataloader.dataset)
running_loss = 0.
# x = 데이터 y = 정답 batch = idx
for batch, (x, y) in enumerate(dataloader):
optimizer.zero_grad() # 초기화
outputs = model(x) # 순전파
loss = criterion(outputs, y) # 손실 계산
loss.backward() # 역전파
optimizer.step() # 가중치 업데이트
running_loss += loss.item() * x.size(0) # loss에 batch size를 곱함
if (batch+1) % 100 == 0:
current = batch * len(x)
print(f"[batch : {batch+1: 4d}], Loss : {loss.item():>7f} ({current:>5d} / {size:>5d})")
epoch_loss = running_loss / size
return epoch_loss
# 테스트 루프
def test_loop(dataloader, model, criterion):
model.eval() # 평가 모드
size = len(dataloader.dataset)
num_batches = len(dataloader)
test_loss = 0.
correct = 0
with torch.no_grad():
for x, y in dataloader:
outputs = model(x)
loss = criterion(outputs, y)
test_loss += loss.item()
correct += (outputs.argmax(1) == y).sum().item()
avg_loss = test_loss / num_batches
accuracy = correct / size
print(f"Test - Accuracy : {100*accuracy:>5.1f}%, Avg_loss : {avg_loss:>8f}")
return avg_loss, accuracy
# 학습 실행
for epoch in range(epochs):
print(f"\n[Epoch] {epoch+1} / {epochs}")
train_loss = train_loop(train_dataloader, model, criterion, optimizer)
val_loss, val_acc = test_loop(test_dataloader, model, criterion)
print("\n완료!")
label_tags = {
0: "T-Shirt", 1: "Trouser", 2: "Pullover", 3: "Dress", 4: "Coat", 5: "Sandal", 6: "Shirt", 7: "Sneaker", 8: "Bag", 9: "Ankle Boot"
}
rows, columns = 6, 6
fig = plt.figure(figsize=(15,15))
model.eval()
for i in range(1, rows * columns + 1):
data_idx = np.random.randint(len(test_data))
img_tensor, trus_label = test_data[data_idx]
with torch.no_grad():
x = img_tensor.unsqueeze(0) # 데이터 변형
output = model(x)
pred_idx = output.argmax(1).item()
pred_class = label_tags[pred_idx] # 예측한 태그
true_class = label_tags[trus_label] # 정답 태그
is_correct = (pred_idx == int(trus_label))
title = f"{pred_class}, Correct!" if is_correct else f"{pred_class}, Incorrect! answer : {true_class}"
cmap = "Blues" if is_correct else "Reds"
ax = fig.add_subplot(rows, columns, i)
ax.imshow(img_tensor.squeeze(0).numpy(), cmap=cmap)
ax.set_title(title, fontsize=10)
ax.axis("off")
plt.tight_layout()
plt.show()
내일부터는 새로운 프로젝트를 시작하는데, 그동안 배웠던 OpenCV와 AI 기능을 활용한 프로젝트인 것 같은데 어떤 주제일지 전혀 감이 안 잡힌다. 최근에 배웠던 내용들이 꽤 까다로운 내용들이 많아서 살짝 걱정이 앞서는 것 같다.