💖 星野アイ (◍•ᴗ•◍)♡ ✧*。
-
Day4 : Deep Learning
📌 Deep Learning란?
퍼셉트론(Perceptron)은 생물학적 뉴런을 수학적으로 모델링한 인공 뉴런 모델로,…
🔧 구조 (Perceptron Structure)
입력(x) → 가중치(w) → 가중합(∑) → 활성화 함수(f) → 출력(y)
🛠️ 작업할 디렉토리 생성 및 환경 설정
# 1. 작업 디렉토리 생성
mkdir F_MNIST # 디렉토리 이름: F_MNIST
cd F_MNIST # 해당 디렉토리로 이동
# 2. 가상 환경 생성 및 활성화
python3 -m venv .fmnist # 가상 환경 생성 (폴더 이름: .fmnist)
source .fmnist/bin/activate # 가상 환경 활성화
# 3. 패키지 설치
pip install -U pip # pip 최신 버전으로 업그레이드
pip install tensorflow # TensorFlow (딥러닝 프레임워크)
pip install matplotlib # Matplotlib (시각화 라이브러리)
pip install PyQt5 # PyQt5 (Matplotlib GUI 백엔드용)
pip install scikit_learn # scikit-learn (머신러닝 및 평가 도구)
# 4. Qt GUI 백엔드 설정 (Wayland 환경에서 필수)
export QT_QPA_PLATFORM=wayland # Qt GUI를 Wayland에서 정상 동작하게 설정
👨💻 실습
💡 Code : Fashion MNIST
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
# dataset load
fashion_mnist = keras.datasets.fashion_mnist
# spilt data (train / test)
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
print(train_images.shape)
print(train_labels.shape)
print(test_images.shape)
print(test_labels.shape)
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
matplotlib.use('Qt5Agg')
NUM=20
plt.figure(figsize=(15,15))
plt.subplots_adjust(hspace=1)
for idx in range(NUM):
sp = plt.subplot(5,5,idx+1)
plt.imshow(train_images[idx])
plt.title(f'{class_names[train_labels[idx]]}')
plt.show()
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()
# 간단한 이미지 전처리 (for ANN)
train_images = train_images / 255.0
test_images = test_images / 255.0
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
plt.figure(figsize=(10,8))
for i in range(20):
plt.subplot(4,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
plt.show()
model = keras.Sequential ([
keras.layers.Flatten(input_shape=(28,28)),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(10, activation='softmax'),
])
model.summary()
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=20)
predictions = model.predict(test_images)
predictions[0]
np.argmax(predictions[0])
test_labels[0]
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array[i], true_label[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions, test_labels)
plt.show()
from sklearn.metrics import accuracy_score
print('accuracy score : ', accuracy_score(tf.math.argmax(predictions, -1), test_labels))
aaaaaa
-
Day3 : Perceptron
Report : Perceptron
1. 퍼셉트론이란?
생물학적 뉴런을 모방한 가장 기본적인 인공신경망
입력 값 × 가중치 + 바이어스를 통해 선형결합을 만들고, 단위 계단 함수(step function) 로 0 또는 1을 출력
간단한 구조지만, 선형 분리 가능한 문제는 완벽하게 해결할 수 있음
하나의 직선으로 나눌 수 있으면 → 선형 분리 가능
단위 계산 함수 : 입력값이 0보다 크면 1을 출력하고, 그 외엔 0을 출력하는 함수
2. 퍼셉트론 학습 방식 (코드 중심)
# AND & OR & NAND & XOR Gate Perceptron
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=10):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
self.errors = []
def activation(self, x):
return np.where(x > 0, 1, 0)
def predict(self, x):
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
def train(self, X, y):
for epoch in range(self.epochs):
total_error = 0
for xi, target in zip(X, y):
prediction = self.predict(xi)
update = self.lr * (target - prediction)
self.weights += update * xi
self.bias += update
total_error += int(update != 0.0)
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
# AND 게이트 데이터 및 학습
X_and = np.array([[0,0],[0,1],[1,0],[1,1]])
y_and = np.array([0,0,0,1])
print(" AND Gate Training")
ppn_and = Perceptron(input_size=2)
ppn_and.train(X_and, y_and)
print("\n AND Gate Test:")
for x in X_and:
print(f"Input: {x}, Predicted Output: {ppn_and.predict(x)}")
# OR 게이트 데이터 및 학습
X_or = np.array([[0,0],[0,1],[1,0],[1,1]])
y_or = np.array([0,1,1,1])
print("\n OR Gate Training")
ppn_or = Perceptron(input_size=2)
ppn_or.train(X_or, y_or)
print("\n OR Gate Test:")
for x in X_or:
print(f"Input: {x}, Predicted Output: {ppn_or.predict(x)}")
# NAND 게이트 데이터 및 학습
X_nand = np.array([[0,0],[0,1],[1,0],[1,1]])
y_nand = np.array([1,1,1,0]) # AND와 반대
print("\n NAND Gate Training")
ppn_nand = Perceptron(input_size=2)
ppn_nand.train(X_nand, y_nand)
print("\n NAND Gate Test:")
for x in X_nand:
print(f"Input: {x}, Predicted Output: {ppn_nand.predict(x)}")
# XOR 게이트 데이터 및 학습
X_xor = np.array([[0,0],[0,1],[1,0],[1,1]])
y_xor = np.array([0,1,1,0]) # 선형 분리 불가능
print("\n XOR Gate Training")
ppn_xor = Perceptron(input_size=2)
ppn_xor.train(X_xor, y_xor)
print("\n XOR Gate Test:")
for x in X_xor:
print(f"Input: {x}, Predicted Output: {ppn_xor.predict(x)}")
2-1. train() 함수 호출
ppn_and.train(X_and, y_and)
X_and: 입력 데이터 배열 (예: [0,0], [1,1] 등)
y_and: 각 입력에 대한 정답 출력값
2-2. 전체 반복 (epoch) 시작
for epoch in range(self.epochs): # 총 10번 반복
한 epoch는 전체 데이터를 한 번 학습하는 주기
총 10번 반복하면서 조금씩 가중치를 조정
2-3. 한 epoch 내 샘플 반복
for xi, target in zip(X, y):
각 데이터 xi와 정답 target을 하나씩 꺼내 순차 학습
2-4. 예측 과정
prediction = self.predict(xi)
predict() 내부에서 다음 순서로 작동:
linear_output = w·x + b
activation() → 0 또는 1 반환
2-5. 오차 계산 및 가중치/바이어스 업데이트
update = self.lr * (target - prediction)
예측이 정답보다 작으면 → update > 0: 가중치 증가
예측이 정답보다 크면 → update < 0: 가중치 감소
예측이 정확하면 → update == 0: 가중치 변화 없음
self.weights += update * xi
self.bias += update
각 입력 값에 따라 가중치 조정
항상 바이어스도 같이 업데이트
2-6. 에러 카운트
total_error += int(update != 0.0)
예측이 틀렸을 때만 에러로 집계
2-7. 학습 결과 출력
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
학습이 진행될수록 Errors가 줄어드는지 확인 가능
하지만 XOR은 줄지 않음 → 선형 분리 불가능 문제
2-8. 최종 예측 결과 확인
각 게이트에 대해 학습이 끝나면 다음을 수행:
for x in X_and:
print(f"Input: {x}, Predicted Output: {ppn_and.predict(x)}")
학습된 가중치로 새로운 입력을 테스트해보는 과정
2-9. 요약: 퍼셉트론 학습 흐름
입력 X, 정답 y
→ 가중합 계산 (w·x + b)
→ 계단 함수로 예측
→ 오차 계산 (target - predict)
→ w, b 업데이트
→ 에러 기록
→ epoch 반복
→ 학습 완료 후 테스트
3. XOR 게이트가 퍼셉트론으로 안 되는 이유
퍼셉트론은 직선 하나로 출력을 나누는 모델
XOR은 어떤 직선으로도 0과 1을 나눌 수 없음
즉, 선형 분리 불가능 문제 → 퍼셉트론 한계
해결책: 다층 퍼셉트론 (MLP)
비선형성을 처리하기 위해 은닉층 + 비선형 활성화 함수 (예: sigmoid, ReLU)를 활용하고,
오차 역전파(Backpropagation)로 학습함
-
Day3 : Perceptron
📌 Perceptron란?
퍼셉트론(Perceptron)은 생물학적 뉴런을 수학적으로 모델링한 인공 뉴런 모델로, 여러 입력 신호를 받아 각 입력에 대한 가중치(Weight)를 곱한 후, 이들의 가중합(Weighted Sum)을 계산하고, 활성화 함수(Activation Function)를 통해 최종 출력을 결정하는 구조이다.
🔧 구조 (Perceptron Structure)
입력(x) → 가중치(w) → 가중합(∑) → 활성화 함수(f) → 출력(y)
입력 (Input): AND, OR 등 논리 연산을 위한 입력 신호.
가중치 (Weight): 입력 신호의 중요도를 결정하며, 학습을 통해 조정됨.
가중합 (Weighted Sum): 각 입력과 그에 대응하는 가중치의 곱을 모두 더한 값.
활성화 함수 (Activation Function): 가중합이 임계값을 넘으면 1, 넘지 못하면 0을 출력하는 함수. 대표적으로 단위 계단 함수 사용.
출력 (Output): 최종 결과값 (보통 0 또는 1의 이진 출력).
🎯 요약
퍼셉트론은 이진 분류 문제를 해결할 수 있는 가장 기본적인 신경망 구조이다.
학습을 통해 입력 신호의 중요도를 나타내는 가중치가 조정된다.
단층 퍼셉트론은 선형 분리 가능한 문제만 해결할 수 있다.
👨💻 실습
💡 Code : AND & OR & NAND & XOR Gate Perceptron
# AND & OR & NAND & XOR Gate Perceptron
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=10):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
self.errors = []
def activation(self, x):
return np.where(x > 0, 1, 0)
def predict(self, x):
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
def train(self, X, y):
for epoch in range(self.epochs):
total_error = 0
for xi, target in zip(X, y):
prediction = self.predict(xi)
update = self.lr * (target - prediction)
self.weights += update * xi
self.bias += update
total_error += int(update != 0.0)
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
# AND 게이트 데이터 및 학습
X_and = np.array([[0,0],[0,1],[1,0],[1,1]])
y_and = np.array([0,0,0,1])
print(" AND Gate Training")
ppn_and = Perceptron(input_size=2)
ppn_and.train(X_and, y_and)
print("\n AND Gate Test:")
for x in X_and:
print(f"Input: {x}, Predicted Output: {ppn_and.predict(x)}")
# OR 게이트 데이터 및 학습
X_or = np.array([[0,0],[0,1],[1,0],[1,1]])
y_or = np.array([0,1,1,1])
print("\n OR Gate Training")
ppn_or = Perceptron(input_size=2)
ppn_or.train(X_or, y_or)
print("\n OR Gate Test:")
for x in X_or:
print(f"Input: {x}, Predicted Output: {ppn_or.predict(x)}")
# NAND 게이트 데이터 및 학습
X_nand = np.array([[0,0],[0,1],[1,0],[1,1]])
y_nand = np.array([1,1,1,0]) # AND와 반대
print("\n NAND Gate Training")
ppn_nand = Perceptron(input_size=2)
ppn_nand.train(X_nand, y_nand)
print("\n NAND Gate Test:")
for x in X_nand:
print(f"Input: {x}, Predicted Output: {ppn_nand.predict(x)}")
# XOR 게이트 데이터 및 학습
X_xor = np.array([[0,0],[0,1],[1,0],[1,1]])
y_xor = np.array([0,1,1,0]) # 선형 분리 불가능
print("\n XOR Gate Training")
ppn_xor = Perceptron(input_size=2)
ppn_xor.train(X_xor, y_xor)
print("\n XOR Gate Test:")
for x in X_xor:
print(f"Input: {x}, Predicted Output: {ppn_xor.predict(x)}")
✅ Result : AND & OR & NAND & XOR Gate Perceptron
AND Gate Training
Epoch 1/10, Errors: 1
Epoch 2/10, Errors: 3
Epoch 3/10, Errors: 3
Epoch 4/10, Errors: 2
Epoch 5/10, Errors: 1
Epoch 6/10, Errors: 0
Epoch 7/10, Errors: 0
Epoch 8/10, Errors: 0
Epoch 9/10, Errors: 0
Epoch 10/10, Errors: 0
AND Gate Test:
Input: [0 0], Predicted Output: 0
Input: [0 1], Predicted Output: 0
Input: [1 0], Predicted Output: 0
Input: [1 1], Predicted Output: 1
OR Gate Training
Epoch 1/10, Errors: 1
Epoch 2/10, Errors: 2
Epoch 3/10, Errors: 1
Epoch 4/10, Errors: 0
Epoch 5/10, Errors: 0
Epoch 6/10, Errors: 0
Epoch 7/10, Errors: 0
Epoch 8/10, Errors: 0
Epoch 9/10, Errors: 0
Epoch 10/10, Errors: 0
OR Gate Test:
Input: [0 0], Predicted Output: 0
Input: [0 1], Predicted Output: 1
Input: [1 0], Predicted Output: 1
Input: [1 1], Predicted Output: 1
NAND Gate Training
Epoch 1/10, Errors: 2
Epoch 2/10, Errors: 3
Epoch 3/10, Errors: 3
Epoch 4/10, Errors: 0
Epoch 5/10, Errors: 0
Epoch 6/10, Errors: 0
Epoch 7/10, Errors: 0
Epoch 8/10, Errors: 0
Epoch 9/10, Errors: 0
Epoch 10/10, Errors: 0
NAND Gate Test:
Input: [0 0], Predicted Output: 1
Input: [0 1], Predicted Output: 1
Input: [1 0], Predicted Output: 1
Input: [1 1], Predicted Output: 0
XOR Gate Training
Epoch 1/10, Errors: 2
Epoch 2/10, Errors: 3
Epoch 3/10, Errors: 4
Epoch 4/10, Errors: 4
Epoch 5/10, Errors: 4
Epoch 6/10, Errors: 4
Epoch 7/10, Errors: 4
Epoch 8/10, Errors: 4
Epoch 9/10, Errors: 4
Epoch 10/10, Errors: 4
XOR Gate Test:
Input: [0 0], Predicted Output: 1
Input: [0 1], Predicted Output: 1
Input: [1 0], Predicted Output: 0
Input: [1 1], Predicted Output: 0
💡 Code : 경계 결정 시각화 함수 (AND, OR, NAND, XOR)
# 경계 결정 시각화 함수 (AND, OR, NAND, XOR)
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
import numpy as np
def plot_decision_boundary(X, y, model, title='Perceptron Decision Boundary'):
cmap_light = ListedColormap(['#FFDDDD', '#DDDDFF']) # 배경 색상
cmap_bold = ListedColormap(['#FF0000', '#0000FF']) # 점 색상
h = .02 # mesh grid 간격
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(6, 5))
plt.contourf(xx, yy, Z, cmap=cmap_light)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
edgecolor='k', s=100, marker='o')
plt.xlabel('Input 1')
plt.ylabel('Input 2')
plt.title(title)
plt.grid(True)
plt.show()
# AND 게이트 결정 경계 시각화
plot_decision_boundary(X_and, y_and, ppn_and, title='AND Gate Decision Boundary')
# OR 게이트 결정 경계 시각화
plot_decision_boundary(X_or, y_or, ppn_or, title='OR Gate Decision Boundary')
# NAND 게이트 결정 경계 시각화
plot_decision_boundary(X_nand, y_nand, ppn_nand, title='NAND Gate Decision Boundary')
# XOR 게이트 결정 경계 시각화
plot_decision_boundary(X_xor, y_xor, ppn_xor, title='XOR Gate Decision Boundary')
✅ Result : 경계 결정 시각화 함수 (AND, OR, NAND, XOR)
💡 Code : # 오류 시각화 (AND, OR, NAND, XOR)
# 오류 시각화 (AND, OR, NAND, XOR)
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(ppn_and.errors) + 1), ppn_and.errors, marker='o', label='AND Gate')
plt.plot(range(1, len(ppn_or.errors) + 1), ppn_or.errors, marker='s', label='OR Gate')
plt.plot(range(1, len(ppn_nand.errors) + 1), ppn_nand.errors, marker='^', label='NAND Gate')
plt.plot(range(1, len(ppn_xor.errors) + 1), ppn_xor.errors, marker='x', label='XOR Gate')
plt.xlabel('Epochs')
plt.ylabel('Number of Errors')
plt.title('Perceptron Learning Error Over Epochs')
plt.legend()
plt.grid(True)
plt.show()
✅ Result : 오류 시각화 (AND, OR, NAND, XOR)
💬 Comment
퍼셉트론: 입력 벡터에 가중치를 곱한 합이 기준(0)을 넘는지 판단하고, 학습 과정에서는 틀린 만큼만 조정하며 선형 분리를 배우는 구조
XOR은 선형 분리 불가능한 문제이기 때문에
단층 퍼셉트론으로는 해결할 수 없다.
이를 해결하려면 다층 퍼셉트론(MLP)이나 비선형 변환이 필요하다.
💡 Code : MLP로 XOR 문제 해결
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
class MultiLayerPerceptron:
def __init__(self, input_size=2, hidden_size=4, output_size=1, lr=0.5, epochs=1000):
self.W1 = np.random.uniform(-1, 1, (input_size, hidden_size))
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.uniform(-1, 1, (hidden_size, output_size))
self.b2 = np.zeros((1, output_size))
self.lr = lr
self.epochs = epochs
self.losses = []
def sigmoid(self, x):
return 1 / (1 + np.exp(-np.clip(x, -250, 250)))
def sigmoid_derivative(self, x):
return x * (1 - x)
def forward(self, X):
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = self.sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.sigmoid(self.z2)
return self.a2
def backward(self, X, y, output):
m = X.shape[0]
dZ2 = output - y
dW2 = (1 / m) * np.dot(self.a1.T, dZ2)
db2 = (1 / m) * np.sum(dZ2, axis=0, keepdims=True)
dZ1 = np.dot(dZ2, self.W2.T) * self.sigmoid_derivative(self.a1)
dW1 = (1 / m) * np.dot(X.T, dZ1)
db1 = (1 / m) * np.sum(dZ1, axis=0, keepdims=True)
self.W2 -= self.lr * dW2
self.b2 -= self.lr * db2
self.W1 -= self.lr * dW1
self.b1 -= self.lr * db1
def train(self, X, y):
for epoch in range(self.epochs):
output = self.forward(X)
loss = np.mean((output - y) ** 2)
self.losses.append(loss)
self.backward(X, y, output)
#if epoch % 200 == 0:
# print(f"Epoch {epoch}/{self.epochs}, Loss: {loss:.6f}")
def predict(self, X):
output = self.forward(X)
return (output > 0.5).astype(int)
def predict_prob(self, X):
return self.forward(X).ravel() # 결정 경계용
# === XOR 데이터 ===
X_xor = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_xor = np.array([[0], [1], [1], [0]])
# === 학습 ===
print("\n=== XOR Gate Multi-Layer Perceptron Training ===")
mlp = MultiLayerPerceptron(input_size=2, hidden_size=2, lr=0.5, epochs=10000)
mlp.train(X_xor, y_xor)
# === 예측 결과 출력 ===
print("\nXOR GATE Test (Multi-Layer Perceptron):")
xor_predictions = mlp.predict(X_xor)
for i, x in enumerate(X_xor):
predicted = xor_predictions[i][0]
actual = y_xor[i][0]
result = "✓" if predicted == actual else "✗"
print(f"Input: {x}, Predicted: {predicted}, Actual: {actual}, {result}")
# === 결정 경계 시각화 함수 ===
def plot_decision_boundary(X, y, model, title="Decision Boundary"):
cmap_light = ListedColormap(['#FFDDDD', '#DDDDFF'])
cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
h = .01
x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
grid = np.c_[xx.ravel(), yy.ravel()]
Z = model.predict_prob(grid)
Z = Z.reshape(xx.shape)
plt.figure(figsize=(6, 5))
plt.contourf(xx, yy, Z > 0.5, cmap=cmap_light)
plt.scatter(X[:, 0], X[:, 1], c=y.ravel(), cmap=cmap_bold,
edgecolor='k', s=120)
plt.title(title)
plt.xlabel("Input 1")
plt.ylabel("Input 2")
plt.grid(True)
plt.show()
# === 결정 경계 시각화 ===
plot_decision_boundary(X_xor, y_xor, mlp, title="XOR MLP Decision Boundary")
# === 손실 곡선 시각화 ===
plt.figure(figsize=(8, 5))
plt.plot(range(mlp.epochs), mlp.losses, color='purple')
plt.title("MLP Training Loss on XOR Problem")
plt.xlabel("Epochs")
plt.ylabel("Mean Squared Error")
plt.grid(True)
plt.show()
✅ Result : MLP로 XOR 문제 해결
=== XOR Gate Multi-Layer Perceptron Training ===
XOR GATE Test (Multi-Layer Perceptron):
Input: [0 0], Predicted: 0, Actual: 0, ✓
Input: [0 1], Predicted: 1, Actual: 1, ✓
Input: [1 0], Predicted: 1, Actual: 1, ✓
Input: [1 1], Predicted: 0, Actual: 0, ✓
-
Day2 : OpenCV
📌 OpenCV란?
OpenCV(Open Source Computer Vision Library)는 실시간 컴퓨터 비전 및 머신러닝을 위한 오픈소스 라이브러리입니다.
다양한 이미지/비디오 처리 기능을 제공하며, Python, C++, Java 등 다양한 언어에서 사용 가능합니다.
🚀 CUDA 모듈의 역할
GPU 가속을 활용한 고속 이미지 처리 수행
OpenCV의 일부 함수들은 CUDA를 통해 병렬 처리되어 성능을 향상시킴
사용 예: cv2.cuda.GpuMat, cv2.cuda.filter2D(), cv2.cuda.resize() 등
🛠️ 작업할 디렉토리 생성 및 환경 설정
# 1. 작업 디렉토리 생성
mkdir opencv # 디렉토리 이름: opencv
cd opencv # 해당 디렉토리로 이동
# 2. 가상 환경 생성 및 활성화
python3 -m venv .env # 가상 환경 생성 (폴더 이름: .env)
source .env/bin/activate # 가상 환경 활성화
# 3. 패키지 설치
pip install opencv-python # OpenCV 기본 기능(core, imgproc 등)
pip install opencv-contrib-python # 추가 모듈(contrib 포함)
pip install -U pip # pip 최신 버전으로 업그레이드
✅ 설치 확인 (Python 인터프리터 실행)
>>> import numpy as np
>>> import cv2
>>> np.__version__
'2.2.6' # 설치된 NumPy 버전 출력
>>> cv2.__version__
'4.11.0' # 설치된 OpenCV 버전 출력
>>> exit() # Python 인터프리터 종료
🎨 색상 정보
🔗 참고 사이트
W3Schools - RGB Colors
🌈 RGB (Red, Green, Blue)
각 색상 채널: 0~255 (8bit)
R (Red): 8bit
G (Green): 8bit
B (Blue): 8bit
픽셀 1개 = 24bit (8bit × 3)
🎨 HSL (Hue, Saturation, Lightness)
H: 색상 (Hue) → 0 ~ 360°
S: 채도 (Saturation) → 0 ~ 100%
L: 밝기 (Lightness) → 0 ~ 100%
🔄 RGB vs HSL 차이점
항목
RGB
HSL
구성
Red, Green, Blue (각 0~255)
Hue (0~360), Saturation & Lightness (0~100%)
직관성
컴퓨터에서 사용하기 적합
사람이 색을 이해하기 쉬움
색 조절
색상 조정이 복잡함
채도/밝기 조절이 용이함
용도
디스플레이, 이미지 처리 등
디자인, 색상 선택 도구 등에 유용
✅ 요약:
RGB는 화면 출력/처리에 적합한 디지털 색 표현 방식
HSL은 색상 구성요소를 분리해 사람이 이해하거나 조절하기 쉬운 방식
📝 메모
vi ex1.py : python 스크립트 생성
python ex1.py : 생성된 스크립트 실행
jpg : 파일이 작고 속도가 빠르며, 주로 사진이나 웹 배경 이미지에 사용
png : 화질 보존, 투명 배경이 필요한 경우 사용
👨💻 실습
💡 Code : 이미지 Read / Write / Display
# ex1.py
import numpy as np
import cv2
# 이미지 파일을 Read
img = cv2.imread("Rengoku.jpg")
# Image 란 이름의 Display 창 생성
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
# Numpy ndarray H/W/C order
print(img.shape)
# Read 한 이미지 파일을 Display
cv2.imshow("image", img)
# 별도 키 입력이 있을때 까지 대기
cv2.waitKey(0)
# ex1_output.jpg 로 읽은 이미지 파일을 저장
cv2.imwrite("ex1_output.jpg", img)
# Destory all windows
cv2.destroyAllWindows()
❓ Quiz: 이미지 Read / Write / Display
1. print(img.shape)의 출력 결과는 무슨 의미일까?
2. 본인이 좋아하는 사진을 web 에서 다운받아서 OpenCV API를 사용해서 Display 및 파일로 저장해보자.
3. 현재는 별도의 키 입력이 있을 때까지 cv2.waitKey(0) 함수에서 대기하게 된다. 코드를 추가해서 소문자 “s” 키를 입력받을 때만 이미지 파일을 저장하고 다른 키가 입력되면 이미지 파일을 저장하지 않게 수정해보자.
💡 Code : RGB/HSV Color Space (색 공간)
# ex2.py
import numpy as np
import cv2
# 이미지 파일을 Read 하고 Color space 정보 출력
color = cv2.imread("Rengoku.jpg", cv2.IMREAD_COLOR)
print(color.shape)
height,width,channels = color.shape
cv2.imshow("Original Image", color)
# Color channel 을 B,G,R 로 분할하여 출력
b,g,r = cv2.split(color)
rgb_split = np.concatenate((b,g,r),axis=1)
cv2.imshow("BGR Channels",rgb_split)
# 색공간을 BGR 에서 HSV 로 변환
hsv = cv2.cvtColor(color, cv2.COLOR_BGR2HSV)
# Channel 을 H,S,V 로 분할하여 출력
h,s,v = cv2.split(hsv)
hsv_split = np.concatenate((h,s,v),axis=1)
cv2.imshow("Split HSV", hsv_split)
❓ Quiz : RGB/HSV Color Space (색 공간)
1. 위 색공간 이미지의 링크로 이동해서 각 색 공간의 표현 방법을 이해해 보자.
2. HSV color space가 어떤 경우에 효과적으로 사용될까?
3. HSV로 변환된 이미지를 BGR이 아닌 RGB로 다시 변환해서 출력해 보자.
4. COLOR_RGB2GRAY를 사용해서 흑백으로 변환해 출력해 보자.
💡 Code : Crop / Resize (자르기 / 크기 조정)
# ex3.py
import numpy as np
import cv2
# 이미지 파일을 Read
img = cv2.imread("Rengoku.jpg")
# Crop 300x400 from original image from (100, 50)=(x, y)
# 세로(y): 100:500 → 500 - 100 = 400픽셀
# 가로(x): 500:1200 → 1200 - 500 = 700픽셀
cropped = img[100:500, 500:1200]
# Resize cropped image from 300x400 to 400x200
resized = cv2.resize(cropped, (800,200))
# Display all
cv2.imshow("Original", img)
cv2.imshow("Cropped image", cropped)
cv2.imshow("Resized image", resized)
cv2.imwrite("ex3_cropped.jpg", cropped)
cv2.imwrite("ex3_resized.jpg", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
❓ Quiz : Crop / Resize (자르기 / 크기 조정)
1. Input image 를 본인이 좋아하는 인물 사진으로 변경해서 적용하자. 그리고 본인이 사용한 input image 의 size 를 확인해 보자.
2. 본인이 사용한 이미지의 얼굴 영역만 crop 해서 display 해 보자.
3. 원본 이미지의 정확히 1.5배만큼 이미지를 확대해서 파일로 저장해 보자.
4. openCV 의 rotate API 를 사용해서 우측으로 90도만큼 회전된 이미지를 출력해 보자.
💡 Code : 역상 (Reverse Image)
# ex4.py
import numpy as np
import cv2
src = cv2.imread("Rengoku.jpg", cv2.IMREAD_COLOR)
dst = cv2.bitwise_not(src)
cv2.imshow("src", src)
cv2.imshow("dst", dst)
cv2.imwrite("ex4_reverse.jpg", dst)
cv2.waitKey()
cv2.destroyAllWindows()
❓ Quiz : 역상 (Reverse Image)
1. AND, OR, XOR 연산에 대해서 확인해 보자.
💡 Code : 이진화 (Binary)
# ex5.py
import numpy as np
import cv2
src = cv2.imread("Rengoku.jpg", cv2.IMREAD_COLOR)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
ret, dst = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
cv2.imshow("dst", dst)
cv2.imwrite("ex5_binary.jpg", dst)
cv2.waitKey()
cv2.destroyAllWindows()
❓ Quiz : 이진화 (Binary)
1. 임계값을 변화시켜 보자.
💡 Code : 흐림효과 (Blur)
# ex6.py
import numpy as np
import cv2
src = cv2.imread("Rengoku.jpg", cv2.IMREAD_COLOR)
dst = cv2.blur(src, (9, 9), anchor=(-1,- 1), borderType=cv2.BORDER_DEFAULT)
cv2.imshow("dst", dst)
cv2.imwrite("ex6_blur.jpg", dst)
cv2.waitKey()
cv2.destroyAllWindows()
❓ Quiz : 흐림효과 (Blur)
1. Kernel Size를 변경하여 보자.
2. borderType을 변경하여 보자.(cv2.BORDER_REFLECT)
💡 Code : 가장자리 검출 (Edge)
# ex7.py
import numpy as np
import cv2
src = cv2.imread("Rengoku.jpg", cv2.IMREAD_COLOR)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, 3)
cv2.imshow("sobel", sobel)
cv2.imwrite("ex7_edge.jpg", sobel)
cv2.waitKey()
cv2.destroyAllWindows()
❓ Quiz : 가장자리 검출 (Edge)
1. Laplacian 변환을 적용해 보자.
2. Canny Edge Detection을 적용해 보자.
💡 Code : 배열 병합 (add Weighted)
# ex8.py
import numpy as np
import cv2
src = cv2.imread("RGB.png", cv2.IMREAD_COLOR)
hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
# 1. Red 마스크 생성
lower_red = cv2.inRange(hsv, (0, 100, 100), (5, 255, 255))
upper_red = cv2.inRange(hsv, (170, 100, 100), (180, 255, 255))
mask_red = cv2.addWeighted(lower_red, 1.0, upper_red, 1.0, 0.0)
# 2. Green 마스크 생성
mask_green = cv2.inRange(hsv, (40, 100, 100), (85, 255, 255))
# 3. Blue 마스크 생성
mask_blue = cv2.inRange(hsv, (100, 100, 100), (130, 255, 255))
# 4. 각 색상 추출 (HSV → BGR 변환 포함)
red = cv2.bitwise_and(hsv, hsv, mask=mask_red)
green = cv2.bitwise_and(hsv, hsv, mask=mask_green)
blue = cv2.bitwise_and(hsv, hsv, mask=mask_blue)
red = cv2.cvtColor(red, cv2.COLOR_HSV2BGR)
green = cv2.cvtColor(green, cv2.COLOR_HSV2BGR)
blue = cv2.cvtColor(blue, cv2.COLOR_HSV2BGR)
# 5. 화면 출력
cv2.imshow("Original", src)
cv2.imshow("Red", red)
cv2.imshow("Green", green)
cv2.imshow("Blue", blue)
cv2.imwrite("ex8_original.png", src)
cv2.imwrite("ex8_red.png", red)
cv2.imwrite("ex8_green.png", green)
cv2.imwrite("ex8_blue.png", blue)
cv2.waitKey()
cv2.destroyAllWindows()
❓ Quiz : 배열 병합 (add Weighted)
1. lower_red 값의 범위를 변경해 보자.
2. upper_red 값의 범위를 변경해 보자.
3. addWeighted의 gamma 값을 변경해 보자.
💡 Code : 채널 분리 및 병합
# ex9.py
import numpy as np
import cv2
# 이미지 읽기
src = cv2.imread("RGB.png", cv2.IMREAD_COLOR)
# 채널 분리
b, g, r = cv2.split(src)
# 채널 순서 변경 (RGB처럼 보이게)
inverse = cv2.merge((r, g, b))
# 화면 출력
cv2.imshow("b", b)
cv2.imshow("g", g)
cv2.imshow("r", r)
cv2.imshow("inverse", inverse)
# 이미지 저장
cv2.imwrite("ex9_blue_gray.png", b)
cv2.imwrite("ex9_green_gray.png", g)
cv2.imwrite("ex9_red_gray.png", r)
cv2.imwrite("ex9_inverse.png", inverse)
cv2.waitKey()
cv2.destroyAllWindows()
❓ Quiz : 채널 분리 및 병합
1. Numpy 형태의 채널 분리를 적용해 보자.
b = src[:, :, 0]
g = src[:, :, 1]
r = src[:, :, 2]
2. 빈 이미지를 적용해 보자.
height, width, channel = src.shape
zero = np.zeros((height, width, 1), dtype=np.uint8)
bgz = cv2.merge((b, g, zero))
💡 Code : 동영상 파일을 읽고 보여주기
# ex10.py
import numpy as np
import cv2
cap = cv2.VideoCapture("son.mp4")
save_count = 1 # 저장할 이미지 번호 초기화
while cap.isOpened():
ret, frame = cap.read()
# (2) 프레임 읽기 실패 → 영상 끝 → 처음부터 다시
if not ret:
print("Restarting video...")
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
continue
# (3) 프레임 크기 50% 축소
resized = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5)
# 출력
cv2.imshow("Resized Frame", resized)
# (1) 고정된 속도로 재생 (약 30fps)
key = cv2.waitKey(90)
# (4) 'c' 키 입력 시 이미지 저장
if key & 0xFF == ord('c'):
filename = f"{save_count:03}.jpg"
cv2.imwrite(filename, resized)
print(f"Saved {filename}")
save_count += 1
# 'q' 키 입력 시 종료
if key & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
❓ Quiz : 동영상 파일을 읽고 보여주기
1. 동영상이 너무 빠르게 재생된다. 이유를 찾아보고 정상적인 속도로 재생될 수 있도록 수정해 보자.
2. 동영상이 끝까지 재생되면 더 이상 frame을 읽지 못해 종료된다. 동영상이 끝까지 재생되면 다시 처음부터 반복될 수 있도록 수정해 보자.
3. 동영상 크기를 반으로 resize해서 출력해 보자.
4. 동영상 재생 중 'c' 키 입력을 받으면 해당 프레임을 이미지 파일로 저장하는 코드를 작성해 보자. 파일 이름은 001.jpg, 002.jpg 등으로 overwrite 되지 않게 하자.
💡 Code : 카메라로부터 input 을 받아 보여주고 동영상 파일로 저장하기
# ex11.py
import numpy as np
import cv2
# Read from the first camera device
cap = cv2.VideoCapture(0)
w = 640 #1280#1920
h = 480 #720#1080
cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
# 성공적으로 video device 가 열렸으면 while 문 반복
while(cap.isOpened()):
# 한 프레임을 읽어옴
ret, frame = cap.read()
if ret is False:
print("Can't receive frame (stream end?). Exiting ...")
break
# Display
cv2.imshow("Camera", frame)
# 1 ms 동안 대기하며 키 입력을 받고 'q' 입력 시 종료
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
❓ Quiz : 카메라로부터 input 을 받아 보여주고 동영상 파일로 저장하기
1. 가지고 있는 카메라의 지원 가능한 해상도를 확인 후 카메라 해상도를 변경해 보자.
2. 카메라 Input을 "output.mp4" 동영상 파일로 저장하도록 코드를 추가해 보자.
📝 메모
sudo apt install v4l-utils : 카메라 지원 해상도 확인용 도구 설치
v4l2-ctl -d /dev/video0 –list-formats-ext : 해당 카메라의 해상도 및 포맷 목록 출력
💡 Code : Text / Line / Ractangle
# ex12.py
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# 동그라미를 그릴 좌표를 저장할 리스트
circle_centers = []
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
# 마우스 왼쪽 버튼 클릭 시 좌표 저장
circle_centers.append((x, y))
cv2.namedWindow("Camera")
cv2.setMouseCallback("Camera", draw_circle)
topLeft = (50+100, 50)
bottomRight = (300+100, 300)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# Line
cv2.line(frame,
(topLeft[0] + 80, topLeft[1]),
(bottomRight[0] + 80, bottomRight[1]),
(0, 255, 0), 3)
# Rectangle
cv2.rectangle(frame,
[pt+80 for pt in topLeft], [pt+50 for pt in bottomRight], (255, 0, 255), 3)
# Text
font = cv2.FONT_ITALIC
cv2.putText(frame, 'hhhong',
[pt-180 for pt in bottomRight], font, 2, (0, 255, 255), 5)
# 저장된 좌표에 동그라미 그리기
for center in circle_centers:
cv2.circle(frame, center, 30, (255, 255, 0), 3) # 반지름 30, 두께 3, 색상 (BGR)
cv2.imshow("Camera", frame)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
❓ Quiz : Text / Line / Ractangle
1. Text 문구 / Font / 색상 / 크기 / 굵기 / 출력위치 등 모든 값을 변경해 보자.
2. 동그라미를 그리는 함수를 찾아서 적용해 보자.
3. 마우스 왼쪽 버튼을 click 하면 해당 위치에 동그라미가 그려지도록 코드를 추가해 보자.
(Reference : cv2.EVENT_LBUTTONDOWN)
💡 Code : Trackbar
# ex13.py
import cv2
topLeft = (50, 50)
bold = 0
r, g, b = 255, 255, 0 # 초기 텍스트 색상: 노란색 (BGR = (0, 255, 255))
# bold 트랙바 콜백
def on_bold_trackbar(value):
global bold
bold = value
global r
r = value
def on_g_trackbar(value):
global g
g = value
def on_b_trackbar(value):
global b
b = value
# 카메라 연결
cap = cv2.VideoCapture(0)
# 윈도우 및 트랙바 생성
cv2.namedWindow("Camera")
cv2.createTrackbar("bold", "Camera", bold, 30, on_bold_trackbar)
cv2.createTrackbar("R", "Camera", r, 255, on_r_trackbar)
cv2.createTrackbar("G", "Camera", g, 255, on_g_trackbar)
cv2.createTrackbar("B", "Camera", b, 255, on_b_trackbar)
# 루프 시작
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# 텍스트 출력 (트랙바에서 받아온 bold, color 값 사용)
cv2.putText(frame, "hhhong",
topLeft,
cv2.FONT_HERSHEY_SIMPLEX,
2,
(b, g, r), # BGR
1 + bold)
# 프레임 출력
cv2.imshow("Camera", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 종료 처리
cap.release()
cv2.destroyAllWindows()
❓ Quiz: Trackbar
1. Trackbar를 control해서 TEXT의 굵기가 변하는 것을 확인해 보자.
2. Trackbar를 추가해서 font size를 변경 / 적용해 보자.
3. R/G/B Trackbar를 각각 추가해서 글자의 font color를 변경해 보자.
-
Touch background to close