무냐의 개발일지

[Coursera ML Specialization] C2 Neural Networks / Week1 (개념, Tensorflow 구현법) 본문

Coursera

[Coursera ML Specialization] C2 Neural Networks / Week1 (개념, Tensorflow 구현법)

무냐코드 2024. 2. 18. 18:21

| 목차

Neural Networks

-inference(prediction)

-training

-practival advice for building machine learning systems

-Decision Trees

 


1. Neural Network 가 무엇인가?

| Neurons and the brain

시작 : 인간의 뇌를 모방한 software algorithms 를 만들자!

적용 : speech recognition -> image (computer vision) 에 적용되기 시작했다 -> text (NLP) 까지 오고 있다.

뇌의 작동원리 : 뉴런에서 다른 뉴런으로 전류자극을 보낸다.

생물학적인 motivation을 너무 심각하게 받아들이지 마라

 

 

 

Neural network가 사용되는 예시를 살펴보자!

 

 

| EX1) Demand prediction

input : 티셔츠 가격

output : top seller인지 아닌지 그 확률을 예측

 

 

4개의 feature : T셔츠 가격, shipping cost, marketing, material(소재)

 

3개의 각각의 뉴런을 배치한다 (layer ;  grouping of neurons) - hidden layer

구매가능한가 (price, shipping cost), 품질(material), 인지도(marketing) 등 각 뉴런에 들어가는 feature가 배정된다

 

1개의 output (probability of being a top seller)를 낸다

input layer & hidden layer & output layer

 

hidden layer가 여러개일 수 있다. 몇개의 hidden layer을 놓을 것인지는 architecture의 영역이다.

 

 

| EX2) Image Recognition

사진에서 얼굴을 인식할 때 pixel x pixel 로 이뤄져있다.

 

1000 x 1000 pixel 의 밝기를 학습해서 사람의 얼굴을 인식할 수 있는가?

layer마다 선을 구분 -> 얼굴의 특정 파트(눈, 코, 귀 등)를 구분 -> 얼굴의 더 큰 부분(얼굴형)을 구분 

 


 

2. Neural Network Model

그렇다면 여러개의 layer를 어떻게 만들 것인가!!  layer of neurons 만들기

그 layer들을 만든 다음에 하나의 큰 layer로 합치는거다!

 

hidden layer 1

 

layer 1의 Output = layer 2의 Input

 

activation vector (a)

 

 

좀 더 복잡한 neural network (layer가 여러개 있는거)

 

3번 hidden layer는 a[2]를 입력하고 a[3]을 출력한다

 

activation function

j : j번째 뉴런

g : sigmoid function

 

 

| 이제 이걸 가지고 예측을 어떻게 하나 보자 : forward propagation

 

ex) 손으로 쓴 숫자를 인식하는 방법

1번 25개의 뉴런(유닛)

2번 15개의 뉴런(유닛)

 

x -> a[1] 으로 보내기 (w1~w25, b1~b25까지 있다)

a[1] -> a[2] 으로 보내기 (w1~w15, b1~b15까지 있다)

a[2] -> a[3] 으로 보내기 1개의 레이어가 있다. 

그래서 a[3]이 >= 0.5 인가에 따라 yes면 1, no면 0으로 보낸다 (sigmoid function이니까)

 

왼쪽에서 오른쪽 순방향으로 계산하기 때문에 forward propagation이라고 한다 (<-> backward propagation이라는 것도 있음)

출력레이어에 가까울수록 은닉 유닛(hidden units)이 줄어든다

 


3. Tensor Flow 알아보기 (Pytorch 도 많이 쓴다)

ex) coffee roasting

온도, 지속시간을 가지고 최적의 커피로스팅 조건을 확인하는 것

어떤 조건에서 좋은 커피가 나올 것인지 확인하는 것

 

입력값 : 섭씨 200도, 17분

layer1 = Dense(units=3, activation='sigmoid') <- Dense레이어는 빽뺵한 레이어

a1 = layer_1(x) : 3개의 unit이 있으므로 3개의 값이 나온다

layer2 = Dense(units=1, activation='sigmoid)

a2 = layer_2(a1)

 

if a2 >= 0.5 

yhat =1

else:

yhat =0

 

이런 식으로 결과를 낸다

 

* (정리) Forward prop을 수행하기 위한 절차

1. 데이터 X를 초기화

2. 계층 1을 생성한다, a1을 계산

3. 계층 2를 생성한다, a2를 계산

 

 

| Data in Tensorflow 

그럼 텐서플로우가 데이터를 어떻게 나타낼까?

 

Numpy : 2D로 구성된 행렬

- 행벡터 : np.array([[200, 17]])

- 열벡터): np.array([[200],

                                  [17]])

- 그냥 숫자 1D 벡터 : np.array([200, 17])

 

텐서플로우는 매우 많은 숫자를 다루게 되어있어, 이렇게 행렬(numpy)를 변환하여 계산 효율성이 높다

 

 

tf.Tensor : 효과적인 데이터타입이다 (행렬보다 좀 더 일반적인 개념인데, 텐서를 행렬도 표현하는 방식아록 생각하면 된다)

텐서인 a1을 numpy로 변환하고 싶을 때 a1.numpy로 변환하면 된다.

 

 

| Build a Neural Network in TensorFlow

 

layer 1, layer 2를 생성한다

수동으로 각 layer에 값을 넣어주는 게 아니라,

Sequential 함수를 통해서 layer 1, 2를 합쳐서 neural network를 만들어준다.

(Sequential : 내가 만든 두 개의 layer를 순차적으로 연결해서 신경망을 만들어주세요~ 하는 거)

 

fit : 훈련한다

 

추론 (forward prop) : X_new라는 새로운 데이터가 생겼을 때, 그냥

model.predict(X_new) 를 불러서 예측을 한다 (순방향 추론을 수행한다)

 

보통 layer_1, layer_2 이렇게 명시하지 않고, 바로 층을 만들어 넣는다 (Dense layer처럼)

요런 식으로!! Dense 로 넣는다

 

ex) Digit Classification model

output : probability

 

- model.compile : defines a loss function and specifies a compile optimization.

- model.fit(X, y, epochs=10) : runs gradient descent and fits the weights to the data.

* epochs : entire data set should be applied during training 10 times

 

 


* 코드 구현

1. 레이어 만들어서 묶기

: There are two layers with sigmoid activations as shown below

tf.random.set_seed(1234)  # applied to achieve consistent results
model = Sequential(
    [
        tf.keras.Input(shape=(2,)),
        Dense(3, activation='sigmoid', name = 'layer1'),
        Dense(1, activation='sigmoid', name = 'layer2')
     ]
)

tf.keras.Input(shape=(2,)) :   specifies the expected shape of the input.

 

model.summary()

model.summary() provides a description of the network:

 

L1_num_params = 2 * 3 + 3   # W1 parameters  + b1 parameters
L2_num_params = 3 * 1 + 1   # W2 parameters  + b2 parameters
print("L1 params = ", L1_num_params, ", L2 params = ", L2_num_params  )

# weights and biases 확인하기
W1, b1 = model.get_layer("layer1").get_weights()
W2, b2 = model.get_layer("layer2").get_weights()
print(f"W1{W1.shape}:\n", W1, f"\nb1{b1.shape}:", b1)
print(f"W2{W2.shape}:\n", W2, f"\nb2{b2.shape}:", b2)

 

-결과물

W1(2, 3):
 [[ 0.08 -0.3   0.18]
 [-0.56 -0.15  0.89]] 
b1(3,): [0. 0. 0.]
W2(3, 1):
 [[-0.43]
 [-0.88]
 [ 0.36]] 
b2(1,): [0.]
model.compile(
    loss = tf.keras.losses.BinaryCrossentropy(),
    optimizer = tf.keras.optimizers.Adam(learning_rate=0.01),
)

model.fit(
    Xt,Yt,            
    epochs=10,
)

-결과물

Epoch 1/10
6250/6250 [==============================] - 5s 784us/step - loss: 0.1782
Epoch 2/10
6250/6250 [==============================] - 5s 785us/step - loss: 0.1165
Epoch 3/10
6250/6250 [==============================] - 5s 788us/step - loss: 0.0426
Epoch 4/10
6250/6250 [==============================] - 5s 820us/step - loss: 0.0160
Epoch 5/10
6250/6250 [==============================] - 5s 809us/step - loss: 0.0104
Epoch 6/10
6250/6250 [==============================] - 5s 801us/step - loss: 0.0073
Epoch 7/10
6250/6250 [==============================] - 5s 812us/step - loss: 0.0052
Epoch 8/10
6250/6250 [==============================] - 5s 827us/step - loss: 0.0037
Epoch 9/10
6250/6250 [==============================] - 5s 793us/step - loss: 0.0027
Epoch 10/10
6250/6250 [==============================] - 5s 815us/step - loss: 0.0020
  • The model.compile statement defines a loss function and specifies a compile optimization.
  • The model.fit statement runs gradient descent and fits the weights to the data.
  • epochs was set to 10. This specifies that the entire data set should be applied during training 10 times.

- Epoch 1/10 : which epoch the model is currently running.

(효율성을 위해 training data set is broken into 'batches'. The default size of a batch in Tensorflow is 32.)

(현재 200,000 examples in our expanded data set or 6250 batches.)

(The notation on the 2nd line 6250/6250 [==== : describing which batch has been executed.)

 

 

W1, b1 = model.get_layer("layer1").get_weights()
W2, b2 = model.get_layer("layer2").get_weights()
print("W1:\n", W1, "\nb1:", b1)
print("W2:\n", W2, "\nb2:", b2)

 fit 한 이후에 업데이트된 weights 를 확인한다

 - 결과물 : 

W1:
 [[ -0.13  14.3  -11.1 ]
 [ -8.92  11.85  -0.25]] 
b1: [-11.16   1.76 -12.1 ]
W2:
 [[-45.71]
 [-42.95]
 [-50.19]] 
b2: [26.14]

 

 

 

예측

X_test = np.array([
    [200,13.9],  # positive example
    [200,17]])   # negative example
X_testn = norm_l(X_test)
predictions = model.predict(X_testn)
print("predictions = \n", predictions)


yhat = np.zeros_like(predictions)
for i in range(len(predictions)):
    if predictions[i] >= 0.5:
        yhat[i] = 1
    else:
        yhat[i] = 0
print(f"decisions = \n{yhat}")

yhat = (predictions >= 0.5).astype(int)
print(f"decisions = \n{yhat}")

 

 

4. 파이썬으로 Neural Network 구현하기

(코드를 읽고 이해할 수 있으면 충분하다)

1번 Layer 계산 (3개의 neuron들을 계산)

 

2번 Layer 계산

 

 

 

Dense layer를 만들어준다 (고밀도)

뉴런이 3개고 각각의 계수 w(2개씩)가 있다고 하면, 이걸 스택 (2x3행렬)으로 쌓는다. 상수 b도 마찬가지로 하나의 array [1,2,-1] 이런 식으로 묶는다.

 

* Dense Layer : 앞의 layer의 activation을 받아서 -> w, b 처리 해주고 -> 새로운 activation을 출력한다

Sequential로 dense층을 여러개 묶어준다. 앞의 activation을 받아서, 최종 output을 생성해낸다. (W : matrix를 표현한다)

 

 

Correct. The w parameters of neuron 1 are in column 1. The w parameters of neuron 2 are in column 2, and so on.

 

 


 

5. Artificial General Intelligence (AGI)

| 우리는 과연 AGI를 구현할 수 있을까? 

 

ANI (Narrow) : 특정 분야에서만 잘 작용하는 거 

AGI (General) : 일반 인간이 할 수 있는 모든 걸 할 수 있는 AI

 

 

뉴런이 등장하고, GPU가 발달하면서 똑똑한 뉴런을 닮은 시스템이 구현되고 있다.

1) AI가 훨씬 단순하다 (logistic 회귀 함수를 쓰잖아. 쏘 심플)

2) 우리는 뇌의 작동조차도 아직 다 모른다 

 

인간은 혀로 볼 수도 있다. 여러 감각을 하나의 신체기관으로 감각할 수도 있다는 실험이 밝혀져있다.

 


 

6. Neural Network를 효율적으로 구현하는 방법 (Optional)

신경망을 vectorization을 할 수 있다 ! 

CPU, GPU는 병렬 곱셈을 해서 되게 효율적으로 계산을 할 수 있다

 

 

 

*W : 1,2,3 layer의 가중치

*matmul : Numpy가 행렬 곱셈을 수행하는 방법

*g(Z) : sigmoid 함수

 

- 벡터화된 구현(오른쪽)에서는 2D배열 행렬이 되면서, 연산도 효율화된다.

 

| Matrix Multiplication

행렬곱 (너 아는거야)

Matrix : 벡터를 열 단위로 쌓은 행렬의 집합이다

 

| 신경망의 벡터화 (Matmul) Numpy 활용

 

 

* matmul 혹은 @를 사용해서 연산이 엄청 쉬워짐!