본문 바로가기
Others/한여름 머신러닝

8월 19일의 머신러닝

by ju_nope 2021. 1. 25.

여전히 여러 기업들과 연구소에서는 인공지능 소스들이 TensorFlow 1 으로 작성되어 있다. 그래서 우리는 만일을 대비하여 TensorFlow 1에서부터 공부를 시작해야 한다.

케라스에서 작성한 코드와 비교해가면서 학습하면 도움이 된다. 많은 내용들이 함축되어있는 케라스를 공부할때는 미처 몰랐던 부분까지 직접 코드로 제어해보며, 머신러닝의 프로세스에 익숙해진다.

1. TensorFlow 1 example 실습

원 핫 인코딩 된 x 데이터

# [털 , 날개] 잇으면 1 없으면 0
x_data = np.array( [ [0,0], [1,0], [1,1], [0,0],[0,0],[0,1]])

원 핫 인코딩 된 y 데이터

y_data = np.array([
    [1,0,0], [0,1,0], [0,0,1], [1,0,0],[1,0,0],[0,0,1]
])

X Y 데이터를 placeholder에 둔다. placeholder는 빈칸인데, 나중에 채워진다.

굳이 이렇게 해주는 이유는 처음부터 데이터가 있는게 아니라, 나중에 fitting 과정에서 훈련시켜줄때 데이터를 가져와서 이 placeholder라는 빈 상자에 넣기 위함이다.

쉽게 말해서 일단 식판을 준비하고, 점심 시간이 되면 음식을 받아오는 것이다.

X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

그 다음 가중치를 정의하고 초기화해준다. argument는 주석으로 설명한 것과 같다. 2*10 행렬 가중치 W1이 생성된다.

W1 = tf.Variable(tf.random_uniform([2, 10], -1. , 1.))
# [들어오는 특성(feature)의 개수, 뉴런의 숫자], 왼쪽 경계, 오른쪽 경계 
# -1부터 1까지 균등하게 랜덤 분포

아래 케라스 코드를 보자. 이 케라스 코드와 의미상으로 같은 코드가 바로 위 텐서플로 코드이다.

# Keras
model.add( Dense(10, activation='relu', input_shape=(2,)) )

여기서 가중치가 어떻게 작용하는지 짚고 넘어가야한다.

X_data는 1*2 matrix 이고 , W는 2*10 matrix이다. X_data와 W 사이의 행렬곱을 한다는 것은 무슨 의미일까?

그림으로 그려놓았으니 아래 첨부 사진을 참고 바란다.

두번째 뉴런층의 가중치인 W2도 만들어준다.

W2 = tf.Variable(tf.random_uniform([10,3], -1.,1.))
# [이전 뉴런의 개수, 나가는 개수.] 텐서플로의 약속이다.

y = Wx +b 에서 가중치인 W를 만들어줬으니, b도 정의해준다.

b1 = tf.Variable(tf.zeros([10]))
# W1의 개수만큼 b1 도 만들어 줘야 해서 10
# 1개 짜리 0을 채워주겠다는 의미

b2 =tf.Variable(tf.zeros([3]))

이제 가중치, X, bias( y 절편) 을 모두 준비했다.

일차함수를 만들어주자.

L1 = tf.add(tf.matmul(X,W1), b1) # X*W1 + b1

TensorFlow는 Keras에 비해 불편한 점이 많다. 덧셈, 곱셈 모두 tf.add(), tf.matmul() 함수를 이용해서 해준다.

다음은 Activation 함수 지정이다. Activation 국룰인 Relu 함수를 사용하겠다.

L1 = tf.nn.relu(L1)

1번째 Layer에서 넘어온 값들은, 두번째 Layer에서 다시 가중치를 곱하고 바이어스를 더해준다.

model = tf.add(tf.matmul(L1, W2), b2)

원래 두번째 레이어라서 L2라는 이름으로 만들어야 하지만, 이번 예제에선 레이어가 총 2개라서 마지막 레이어를 의미하는 model이라는 변수명을 할당했다.

자 그러면 마지막 단계인 Activation 함수와 비용함수를 정해준다. 분류 문제이므로 softmax를 쓰고, 비용은 크로스 엔트로피 이다.

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=Y, logits=model))

다음은 Optimizer 지정이다. Adam을 사용해준다. optimizer train 까지 시켜준다.

optimizer = tf.train.AdamOptimizer(learning_rate=0.01)
train_op = optimizer.minimize(cost)

그 다음으로 세션을 만들어서 초기화까지 시켜준다. 이해가 안되면 일단 외운다.

sess = tf.Session()
sess.run(tf.global_variables_initializer()) 
# 초기화

자 그러면, 훈련을 시켜준다. epochs를 100으로 설정해주는 것이므로 for 문을 돌려준다. keras에서 fit과 같다.

# 반복문을 돌려서 학습시켜준다. 
for step in range(100):
    sess.run(train_op, feed_dict={X: x_data, Y: y_data})
    if(step+1)%10 ==0: #10번 단위로 비용출력 
        print(step+1, sess.run(cost, feed_dict={X: x_data, Y: y_data}))
#feed_dict : 사전을 제공하는 함수
# 출력결과
10 0.85478014
20 0.6882488
30 0.55313975
40 0.44251204
50 0.3464333
60 0.26295754
70 0.19406633
80 0.14101486
90 0.10164076
100 0.07410798

훈련을 시켰으니, prediction 을 해보자 .

prediction = tf.argmax(model,axis=1)
target = tf.argmax(Y, axis=1)

print("prediction:",sess.run(prediction, feed_dict={X:x_data}))
print("target:", sess.run(target, feed_dict={Y:y_data}))

실행을 시키기 위해서는 반드시 sess.run()을 해줘야 한다.

#출력결과 
prediction: [0 1 2 0 0 2]
target: [0 1 2 0 0 2]

위에서 argmax를 해주는 이유는 , 이 문제가 다중분류 문제이기 때문이다. 항목별로 몇 %의 확률로 정답일지 나오기 때문에, 가장 높은 확률의 항목을 뽑아주어야 한다.

score까지 해본다. (정확도)

is_correct = tf.equal(prediction, target)
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

print("정확도: {:.2f}".format(sess.run(accuracy*100,feed_dict={X: x_data, Y: y_data})))

is_correct 변수에는 prediction 과 target이 같은 곳은 True 다른곳은 False인 값이 들어간다.

이후 accuracy 변수에는 위의 is_correct를 cast한 0과 1의 값이 들어간다. true false를 1, 0으로 바꿔주는 것이 cast이다.

reduce_mean()은 뒤에오는 객체의 argument들의 산술 평균을 구하는 method인데, accuracy 변수에 들어있는 0과 1의 평균을 구하면 자동적으로 정확도가 소수점으로 표현된다. (ex. 0.98 ⇒ 98%)

여기에 100을 곱하면 백분율로 나타낸 정확도가 된다. (정확도 = tp+tf/전체)

#출력결과 
정확도: 100.00

케라스에서는 위의 score 과정을 evaluate 하나로 해준다.

다 끝난뒤에는 세션을 닫아준다. 꼭

sess.close()

아래는 우리가 day08에 작성했던 Keras DNN 코드이다. 위의 TensorFlow 코드와 비교해가며 읽어보자

# Keras DNN 코드
# model 생성
model = Sequential() #건물
model.add( Dense(10, activation='relu', input_shape=(2,)) ) 
# 건물 1층에 사무실 10개가 있고, 2층 올라가는 계단의 종류는 relu, 입구에는 2명씩 들어온다 (input_shape는 x축 y축 2개) 
# 무 친 설 명 
model.add(Dense(10, activation ='relu'))
# 건물 1층에 사무실 10개가 있고, 3층 올라가는 계단의 종류는 relu, 입구는 1층에만 있다. 
model.add(Dense(10, activation='relu'))
# 건물 1층에 사무실 10개가 있고, 4층 올라가는 계단의 종류는 relu, 역시 입구는 따로 없다. 
model.add(Dense(10, activation='relu'))
# 마찬가지 
model.add(Dense(2,activation='softmax'))
# 마지막 5층에는 사무실이 2개, 다중 분류용 softmax인데 이진에서도 쓰인다. 
model.summary()

# 비용 함수와 옵티마이저 설정 
model.compile(loss='categorical_crossentropy', optimizer='sgd')

# One Hot Encoding
# 현재 Y는 true false 값이다 
# 이 녀석을 이대로 두는게 아니라 One hot encoding 해야 한다. 
Y_onehot = np_utils.to_categorical(Y)
Y_onehot
# True => [0,1]
# False => [1,0]

#훈련
model.fit(X,Y_onehot,epochs=200)

#예측
pred = model.predict(pred_x)
pred
 
#시각화
# 다시 초기 상황 보기 위해
plt.scatter(x,sine)
plt.scatter(X[:,0][Y==0], X[:,1][Y==0])
plt.scatter(X[:,0][Y==1], X[:,1][Y==1])
plt.show()

TensorFlow 1. x mnist example 손글씨 숫자 DNN 실습

우선 필요한 모듈들을 import한다. 기본적인 모듈은 생략했다.

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

우리가 사용할 mnist 데이터를 읽어서 변수에 할당한다. 원 핫 인코딩을 True로 설정한다.

mnist = input_data.read_data_sets('mnist/data', one_hot=True)

X와 Y Placeholder를 준비한다.

X = tf.placeholder(tf.float32, [None, 784])
# 데이터의 개수는 아직 지정하지 않아서 None
# 손글씨 데이터 28*28(=784) 이미지를 1차원 으로 핀 것 (DNN 이니까)
Y = tf.placeholder(tf.float32, [None,10])

가중치를 준비하고, X 와 곱해준다.

W1 = tf.Variable(tf.random_normal([784, 256], stddev = 0.01))
L1 = tf.nn.relu(tf.matmul(X, W1))

random normal로 난수를 발생시켜서 초기화 해주는데, 이때 표준편차를 0.01로 준비한다. 데이터는 784개로 들어와서 256개로 나간다.

위 두개 코드는 케라스에서 아래 코드와 같다.

# 케라스에서
model.add(Dense(128, activation = 'relu', input_shape=(784,)))

두번째 가중치도 준비해 준다. Layer 1의 결과값과 곱해준다. 256개 뉴런이 들어와서 다시 256개의 뉴런으로 나간다.

W2 = tf.Variable(tf.random_normal([256,256], stddev=0.01))
L2 = tf.nn.relu(tf.matmul(L1,W2))

세번째 가중치를 준비해준다. 마지막 뉴런을 준비해준다. 마지막 뉴런층의 이름은 model 이다.

W3 = tf.Variable(tf.random_normal([256,10], stddev=0.01))
#최종 뉴런의 개수는 10개이다. 0~9가 10개 니까
model = tf.matmul(L2,W3)

Activation 과 비용 함수를 정해준다. 다중분류니까 softmax에 cross entropy 일게 뻔하다.

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))

# model.add(Dense(10, activation = 'softmax')) 케라스

Optimizer도 정해주자. Adam 을 쓰겠다.

optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)
# 케라스 코드 라면 ... (정확히 같지는 않음)
# model.compile(loss="sparse_categorical_crossentropy", optimizer = 'adam', metrics=['accuracy'])

그러면 Train을 해줄 준비를 해보자. 우선 한번에 메모리에 올릴 이미지의 장수인 batch size를 정해주자. 100장을 정해주도록 하자.

batch_size = 100 # 한번에 올리는 이미지 100장
total_batch = int(mnist.train.num_examples / batch_size ) # 훈련데이터 개수 / 한번에 올릴 이미지의 양

전체 5만 5천개의 이미지를 100장씩 처리하므로 550번 돌려야 트레이닝 데이터를 한번 돌릴수 있다.

다 준비되었으니 학습을 시작한다. 역시나 반복문을 이용해 학습해준다.

학습횟수만큼 total_batch를 반복해준다.

for epoch in range(15): #학습횟수는 15번
    total_cost = 0 
    for i in range(total_batch): #학습 1번당 550번을 돌린다. 
        batch_xs, batch_ys = mnist.train.next_batch(batch_size) # 100개씩 xs ys에 할당
        _, cost_val = sess.run([optimizer, cost], feed_dict={X:batch_xs, Y:batch_ys})
        # cost만 궁금하다는 뜻
        total_cost += cost_val
    print('epoch : {:04d}, cost : {:.3f}'.format((epoch+1) , (total_cost/total_batch) ))
print("train finish!")

#출력결과
epoch : 0001, cost : 0.010
epoch : 0002, cost : 0.011
epoch : 0003, cost : 0.013
epoch : 0004, cost : 0.004
epoch : 0005, cost : 0.007
epoch : 0006, cost : 0.009
epoch : 0007, cost : 0.008
epoch : 0008, cost : 0.004
epoch : 0009, cost : 0.007
epoch : 0010, cost : 0.011
epoch : 0011, cost : 0.005
epoch : 0012, cost : 0.004
epoch : 0013, cost : 0.005
epoch : 0014, cost : 0.011
epoch : 0015, cost : 0.004
train finish!

TensorFlow 1. mnist CNN 으로 구현하기

우선 필요한 모듈 import와 데이터 download 진행

from tensorflow.examples.tutorials.mnist import input_data
from tensorflow import nn

mnist = input_data.read_data_sets("mnist/data", one_hot=True)

plt.imshow(mnist.train.images[0].reshape((28,28)), cmap=plt.cm.gray)

X, Y Placeholder를 준비한다. 이젠 어느정도 외운듯하다.

X = tf.placeholder(tf.float32, [None, 28, 28,1]) # CNN 이기 때문에 가로, 세로 ,흑백
Y = tf.placeholder(tf.float32, [None,10]) # 10 = 0~9
keep_prob = tf.placeholder(tf.float32)

keep_prob 역할은 기억이 안난다.

W1 으로 필터를 첫번째 필터그룹(?)을 생성해준다.

# [3,3,1,32] => 3 by 3 filters , gray , 32 filters 
W1 = tf.Variable(tf.random_normal([3,3,1,32], stddev=0.01))

layer를 지정해준다. 이후 pooling 까지 진행해준다. pooling은 절반으로 해준다.

L1 = nn.conv2d(X, W1, strides=[1,1,1,1], padding='SAME')
L1 = nn.relu(L1)
L1 = nn.max_pool(L1,ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
# 1,2,2,1 에서 양끝 두개 1은 아무 의미 없음. (2,2)로 생각해도 됨. 
# ksize = kernel size.

stride는 (2,2) 즉 옆으로 2칸씩, 아래로 2칸씩 이동하는 필터를 사용한다는 의미이다.

두번째 가중치(기울기, 뉴런층)도 정의해준다.

# 3 by 3 filters , gray, 32 filters
W2 = tf.Variable(tf.random_normal([3,3,32,64], stddev=0.01))

두번째 Layer도 정의해준다. 아까와 마찬가지로 Activation function과 pooling stride를 정해준다.

L2 = nn.conv2d(L1,W2, strides=[1,1,1,1], padding='SAME')
L2 = nn.relu(L2)
L2 = nn.max_pool(L2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
L2 = nn.dropout(L2, keep_prob)

마지막 레이어에서 1차원 데이터로 만들어 주어야 한다. 우리는 세번째 가중치 W3를 정의할때, 데이터를 1차원 array로 만들어줄 것이다.

W3 = tf.Variable(tf.random_normal([7*7*64, 256], stddev=0.01))

keras 에서는 Flatten() 이라는 method로 펴주었다.

총 정리 해보자면, 처음 28*28 이미지 1개가 첫 번째 Max pooling 에 의해 14*14짜리 이미지 32개가 되었다.

이후 다시 32개의 14*14 이미지들이 두번째 Max pooling에 의해 7*7짜리 64장의 이미지가 된다.

마지막으로 세번째 레이어(W3)를 만난 이미지들은 3136(=7*7*64) 사이즈의 1차원 데이터가 된다.

tf.random_normal method의 상세설명을 보면 다음과 같다.

Outputs random values from a normal distribution.

  • 무작위의 정규분포 value가 출력됩니다.
  • arg: shape: A 1-D integer Tensor or Python array. The shape of the output tensor. (shape:
  • 첫번째 arg인 shape은 출력의 shape을 의미합니다. (size)

박사님께 설명을 들은 바에 따르면, [7*7*64, 256] 의 의미는, 먼저 7*7*64는 들어오는 뉴런의 개수, 그리고 256은 나가는 뉴런의 개수라고 한다.

알듯 말듯.

Layer L3를 정의해준다.

L3 = tf.reshape(L2,[-1,7*7*64])
L3 = tf.matmul(L3,W3)
L3 = nn.relu(L3)
L3=nn.dropout(L3, keep_prob)

L2 를 1차원 배열로 바꿔준다.

W4를 정의해준다.

W4 = tf.Variable(tf.random_normal([256,10], stddev=0.01))

마지막 Layer 인 model을 정의해준다.

model = tf.matmul(L3, W4)

이전에 적었던 케라스 코드와 비교해보자

model = Sequential()

# 첫번째
model.add(Conv2D(32,(3,3), activation='relu', padding= 'same', input_shape=(28,28,1)))
# 32 filters(3 by 3)
model.add(Conv2D(32,(3,3), activation = 'relu', padding ='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
# 두번 conv 후 풀링(2,2)
model.add(Dropout(0.25))
# overfitting 방지 Dropout

# 두번째
model.add(Conv2D(64,(3,3), activation='relu', padding= 'same'))
# 32 filters(3 by 3)
model.add(Conv2D(64,(3,3), activation = 'relu', padding ='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
# 두번 conv 후 풀링(2,2)
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(123, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

cost와 activation 지정해준다.

cost = tf.reduce_mean(nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))

훈련을 시키기에 앞서 Session 을 열어준다. 초기화도 시켜준다.

sess = tf.Session()
sess.run(tf.global_variables_initializer())

한번에 처리할 이미지의 개수인 batch size를 설정하고, 그에 따라 몇번 처리 해야하는지 total_batch 값을 구해준다.

batch_size=100
total_batch = int( mnist.train.num_examples / batch_size) #55000 / 100 => 550

훈련을 시작한다. 반복문을 열고 epochs 만큼 반복해준다.

이번에는 특별히 fprint라는 python 3.5 이상에서만 작동하는 새로운 print문을 써보았다. {}.format 형태를 단축하여 쓸 수 있는 문법이다.

#내코드 에러남/
for epoch in trange(15):
    total_cost = 0 
    for i in range(total_batch) : # batch
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        batch_xs = batch_xs.reshape(-1,28,28,1)
        _, cost_val = sess.run([optimizer, cost], feed_dict={X:batch_xs, Y:batch_ys, keep_prob:0.7}) # 30% dropout
        total_cost += total_cost
    print(f"epoch : {epoch:04d} avg. cost: {(total_cost/total_batch):.3f}")
print("train finish!")

#박사님 코드 
%%time
for epoch in trange(15):
    total_cost = 0
    for i in range(total_batch): # 550
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        batch_xs = batch_xs.reshape(-1, 28, 28, 1)
        _, cost_val = sess.run([optimizer, cost],
                              feed_dict={X:batch_xs, Y:batch_ys, keep_prob:0.7})
        total_cost += cost_val
    print(f"epoch : {epoch:04d} avg. cost: {(total_cost/total_batch):.3f}")
print("train finish!!!")
# epoch : 0014 avg. cost: 0.028
# train finish!!!

정확도를 계산해준다. 위의 코드는 에러가 나서, 박사님의 코드로 실행시켰다.

is_correct = tf.equal(tf.argmax(model, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

print("test acc: {:.3f}".format(
    sess.run(accuracy,
            feed_dict={X:mnist.test.images.reshape(-1,28,28,1),
                      Y:mnist.test.labels,
                      keep_prob: 1})))
# test acc: 0.992

'Others > 한여름 머신러닝' 카테고리의 다른 글

8월 24일의 머신러닝  (5) 2021.01.25
8월 21일의 머신러닝  (1) 2021.01.25
8월 20일의 머신러닝  (0) 2021.01.25

댓글