빅데이터 분석 특강 (11주차) 5월16일
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import tensorflow.experimental.numpy as tnp
tf.config.experimental.list_physical_devices()
tnp.experimental_enable_numpy_behavior()
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
y_train # 이 데이터는 클래스의 데이터
x_train.shape
X = tf.constant(x_train.reshape(-1,28,28,1),dtype=tf.float64)
y = tf.keras.utils.to_categorical(y_train)
XX = tf.constant(x_test.reshape(-1,28,28,1),dtype=tf.float64)
yy = tf.keras.utils.to_categorical(y_test)
net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Flatten())
net1.add(tf.keras.layers.Dense(30,activation='relu')) # 30 잘 안 맞는 거 아는데 처음이니까~ 해보자
net1.add(tf.keras.layers.Dense(30,activation='relu'))
net1.add(tf.keras.layers.Dense(10,activation='softmax'))
net1.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net1.fit(X,y,epochs=10)
net1.evaluate(XX,yy)
net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Flatten())
net1.add(tf.keras.layers.Dense(30,activation='relu')) # 30 잘 안 맞는 거 아는데 처음이니까~ 해보자
net1.add(tf.keras.layers.Dense(30,activation='relu'))
net1.add(tf.keras.layers.Dense(10,activation='softmax'))
net1.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net1.fit(X,y,epochs=20,verbose=0)
net1.evaluate(XX,yy)
net가 단순하다보니 정확도 계산에 한계가 있는 거 같다 에폭 20해도 크게 변하지 않음!
net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Flatten())
net1.add(tf.keras.layers.Dense(500,activation='relu'))
net1.add(tf.keras.layers.Dense(500,activation='relu'))
net1.add(tf.keras.layers.Dense(10,activation='softmax'))
net1.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net1.fit(X,y,epochs=10)
net1.evaluate(XX,yy)
net1.summary()
Dense layer로 한계가 있는 것 같으니 다른 방법을 찾아보자
-
두번째 시도
tf.keras.layers.Conv2D
tf.keras.layers.MaxPool2D
net2 = tf.keras.Sequential()
net2.add(tf.keras.layers.Conv2D(30,(2,2)))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Conv2D(30,(2,2)))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Flatten())
net2.add(tf.keras.layers.Dense(10,activation='softmax'))
net2.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net2.fit(X,y,epochs=5)
net2.evaluate(XX,yy)
net2.summary()
dense에 파라메터 뭉쳐있는 이유
- 펼쳐진 노드를 뭉치기 때문에..
- 108010bias10개 = 10810 이렇게 계산되지!
- 정확도만 보면 net2가 낫네?
- 파라메터 수를 보니 첫번째 시도 대비 파라메터를 적게 사용한 모습을 볼 수 있다.
$\therefore$ 파라메터 조금쓰고 정확도 높은 좋은 net2모형!
net2.layers
내가 설계한 네트워크의 순서를 확인해보자
c1,m1,c2,m2,flttn,dns = net2.layers
print(X.shape) # 입력이미지 = 2D # 1은 채널이 하나라는 뜻
print(c1(X).shape) # 2D # 갑자기 채널이 30이 되어버리!
print(m1(c1(X)).shape) # 2D # maxpool 통과했더니 fixel 크기가 줄어들었네?
print(c2(m1(c1(X))).shape) # 2D # 또 줄어들고 채널은 30으로 유지되는데?
print(m2(c2(m1(c1(X)))).shape) # 2D # 모두 퍼져서 12*12*30=4320이 되어버림
print(flttn(m2(c2(m1(c1(X))))).shape) # 2D
print(dns(flttn(m2(c2(m1(c1(X)))))).shape) # 2D
밑에서 배우겠지만 27 ->13 갈때 행/열 하나씩 잘림(기본 옵션) 밑에서 보면 pooling='same;'쓰면 안 잘리고 쓰긴 함
채널 갑자기 믾아진 이유 어느것이든 맞추겠지!
net2 = tf.keras.Sequential()
net2.add(tf.keras.layers.Conv2D(30,(2,2),activation='relu'))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Conv2D(30,(2,2),activation='relu'))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Flatten())
net2.add(tf.keras.layers.Dense(10,activation='softmax'))
net2.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net2.fit(X,y,epochs=5)
net2.evaluate(XX,yy)
m = tf.keras.layers.MaxPooling2D()
XXX = tnp.arange(1*4*4*1).reshape(1,4,4,1)
XXX # observation / color / channel
m(XXX).reshape(1,2,2)
여기로 가는 mapping을 찾아볼까
XXX.reshape(1,4,4) #우리가 생각하는 이미지의 모습
[0,1,4,5] 중 max는 5
[2,3,6,7] 중 max는 7
[8,9,12,13] 중 max는 13
[10,11,14,15] 중 max는 15
-
MaxPool2D layer의 역할: (2,2) 윈도우를 만들고 (2,2) 윈도우에서 max를 뽑아 값을 기록, 윈도우를 움직이면서 반복
XXX = tnp.arange(1*6*6*1).reshape(1,6,6,1)
XXX.reshape(1,6,6) # 흑백 이미지라면 이렇게 보일 것
m(XXX).reshape(1,3,3)
tf.keras.layers.MaxPooling2D??
m = tf.keras.layers.MaxPooling2D(pool_size=(3,3))
XXX = tnp.arange(1*6*6*1).reshape(1,6,6,1)
XXX.reshape(1,6,6) # 흑백 이미지라면 이렇게 보일 것
m(XXX).reshape(1,2,2)
m = tf.keras.layers.MaxPooling2D(pool_size=(2,2))
XXX = tnp.arange(1*5*5*1).reshape(1,5,5,1)
XXX.reshape(1,5,5) # 흑백 이미지라면 이렇게 보일 것
m(XXX).reshape(1,2,2)
애매한 열/행 수를 넣어주니 마지막 열/행은 버려버리네!
- 차원이 안 맞으면 버려버림( 기본 옵션)
m = tf.keras.layers.MaxPooling2D(pool_size=(2,2),padding='same')
XXX = tnp.arange(1*5*5*1).reshape(1,5,5,1)
XXX.reshape(1,5,5) # 흑백 이미지라면 이렇게 보일 것
m(XXX).reshape(1,3,3)
padding ="same"
옵션을 넣어주니 차원을 버리지 않고 다 사용하네?
- 균형을 맞춰 구하진 않음
- 24의 경우 24 하나의 값 중에서 큰 값인 24를 택한 것.
XXX = tnp.arange(2*4*4*1).reshape(2,4,4,1)
XXX.reshape(2,4,4)
m(XXX).reshape(2,2,2)
XXX = tnp.arange(1*4*4*3).reshape(1,4,4,3) # observation 1 channel 3으로 고정
XXX[:,:,:,0]
위 아래 같은 결과..! 생략구문이라 부른다.
XXX[...,0]
m(XXX)[:,:,:,0]
m(XXX)[...,0]
-
레이어 생성
cnv = tf.keras.layers.Conv2D(1,(2,2))
cnv
-
XXX 생성
XXX = tnp.arange(1*4*4*1).reshape(1,4,4,1)
XXX.reshape(1,4,4)
힘든 점:;; 이대로 넣으면 안 돌아간다.
- 데이터 타입이 int가 아니라 float이어야 한다.
cnv(XXX)
XXX = tnp.arange(1*4*4*1,dtype=tf.float64).reshape(1,4,4,1)
XXX.reshape(1,4,4)
cnv(XXX)
- 꼭 4 차원이어야 한다.
XXX = tnp.arange(1*3*3*1,dtype=tf.float64).reshape(1,3,3,1)
XXX.reshape(1,3,3)
cnv(XXX)
XXX = tnp.arange(1*4*4*1,dtype=tf.float64).reshape(1,4,4,1)
XXX.reshape(1,4,4)
cnv(XXX).reshape(1,3,3)
- XXX에서 cnv(XXX)로 가는 맵핑을 찾는 건 쉽지 않아 보인다
- 심지어 랜덤으로 결정되는 부분도 있어보인다.
-
코드 정리
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(2,2))
XXX = tnp.arange(1*4*4*1,dtype=tf.float64).reshape(1,4,4,1)
print(XXX.reshape(1,4,4))
print(cnv(XXX).reshape(1,3,3))
dense 때와 비슷한 상황
cnv.weights
type(cnv.weights)
cnv.weights[0]
tf.reshape(cnv.weights[0],(2,2))
어떻게 유추될까?
0 * -0.13014299 + 1 * -0.23927206 + 4 * -0.20175874 + 5 * -0.6158894 + 0
값이 나왔네
- 원래는 위에서 bias가 들어가야 하지, 위 식에서는 bias가 0임
cnv.get_weights()
2개 나온 모습
type(cnv.get_weights())
type(cnv.get_weights()[0])
type(cnv.get_weights()[1])
cnv.get_weights()[0].shape
cnv.get_weights()[1].shape
w = np.array([1/4,1/4,1/4,1/4],dtype=np.float32).reshape(2,2,1,1)
b = np.array([3],dtype=np.float32)
b는 bias인거 알지? 밑 weights에서 확인 가능
[w,b]
같은 형식으로 나오게 만들었다.
cnv.set_weights([w,b])
cnv.weights
XXX.reshape(1,4,4)
cnv(XXX).reshape(1,3,3)
np.mean([0,1,4,5])+3, np.mean([1,2,5,6])+3, np.mean([2,3,6,7])+3
겹치지 않는 MaxPooling과 달리 겹치는 ConV2D
(1) size=(2,2)인 윈도우를 만듦.
(2) XXX에 윈도우를 통과시켜서 (2,2)크기의 sub XXX 를 얻음. sub XXX의 각 원소에 conv2d.weights[0]의 각 원소를 element-wise하게 곱한다.
- sub XXX의 의미는 위에서 0,1,4,5(XXX.reshape(1,4,4) 결과 중 일부)를 의미
(3) (2)의 결과를 모두 더한다. 그리고 그 결과에 다시 conv2d.weights[1]을 수행
(4) 윈도우를 이동시키면서 반복!
커널을 늘려보자
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(3,3))
XXX = tnp.arange(1*5*5*1,dtype=tf.float64).reshape(1,5,5,1)
XXX.reshape(1,5,5)
cnv(XXX).reshape(1,3,3)
2.7395768
재현 해보기
cnv.weights[1]
bias term은 보통 0이야..
XXX.reshape(1,5,5)
XXX.reshape(1,5,5)[0,:3,:3]
tf.reshape(cnv.weights[0],(3,3))
tf.reduce_sum(XXX.reshape(1,5,5)[0,:3,:3] * tf.reshape(cnv.weights[0],(3,3)))
나왔다.
- 요소끼리 곱
*
쓸 수 있는 거 기억해..
3*0 + 3*1 + 2*2 +0*2 + 0*2 + 1*0 + 3*0 + 1*1 + 2*2
하나만 해보기
내가 한 거!
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(3,3))
XXX = np.array([3,3,2,1,0,0,0,1,3,1,3,1,2,2,3,2,0,0,2,2,2,0,0,0,1]).reshape(1,5,5,1)
XXX.reshape(1,5,5)
XXX.reshape(1,5,5)[0,2:,:3]
_w = np.array([0,1,2,2,2,0,0,1,2],dtype=np.float32).reshape(3,3,1,1)
_b = np.array([0],dtype=np.float32)
cnv
cnv(XXX)
cnv.get_weights()[0]
cnv.set_weights([_w,_b])
cnv.get_weights
tf.reduce_sum(XXX.reshape(1,5,5)[0,2:,:3] * tf.reshape(cnv.weights[0],(3,3)))
-
교수님 부분
XXX = tf.constant([[3,3,2,1,0],[0,0,1,3,1],[3,1,2,2,3],[2,0,0,2,2],[2,0,0,0,1]],dtype=tf.float64).reshape(1,5,5,1)
XXX.reshape(1,5,5)
-
데이터 타입이 float이어야 한다.
-
shape 이 1 5 5 * 1 이어야 한다.
cnv = tf.keras.layers.Conv2D(1,(3,3))
cnv(XXX).reshape(1,3,3)
cnv.weights[0]
_w = tf.constant([[0,1,2,],[2,2,0],[0,1,2]],dtype=tf.float64).reshape(3,3,1,1)
_b = tf.constant([0],dtype=tf.float64)
cnv.set_weights([_w,_b])
cnv.weights
cnv(XXX).reshape(1,3,3)
observation 마다 반복하게 한다?
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(2,2))
XXX = tnp.arange(2*5*5*1,dtype=tf.float64).reshape(2,5,5,1)
XXX.reshape(2,5,5)
cnv.weights
cnv(XXX)
layer 한 번 통과시켜줘야 weights이 나오지
cnv.weights
cnv.set_weights([w,b])
cnv(XXX).reshape(2,4,4)
print(cnv(XXX).reshape(2,4,4))
np.mean([0,1,5,6])+3,np.mean([1,2,6,7])+3,np.mean([25,26,30,31])+3
-
observation이 고정이고 출력 채널이 바뀔때
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(4,(2,2))
XXX = tnp.arange(1*2*2*1,dtype=tf.float64).reshape(1,2,2,1)
cnv = tf.keras.layers.Conv2D(4,(2,2))
여기서 activation ’relu’주면 음의 값이 다 0이 되겠지 뭐~
print(XXX.reshape(1,2,2))
cnv(XXX)
채널이 4개니까 4개의 결과가 출력되었다.
cnv.weights
cnv.weights[0] # (2,2) 커널의 크기 // 1은 XXX의 채널 수 // 4는 Conv(XXX)의 채널 수
cnv.weights[1]
이 값은 0이니 여기서는 신경쓰지 않도록 하자
cnv.weights[0][...,0].reshape(2,2) # Conv(XXX)의 첫번째 채널 출력을 얻기 위해 곱해지는 w
첫 번째 채널을 얻기 위해 나오는 계수 값
- (2,2,1) 차원으로 나옴
tf.reduce_sum(XXX.reshape(1,2,2) * cnv.weights[0][...,0].reshape(2,2))
위 결과와 같은 출력 결과
x의채널이 3개면 컬러 1개면 흑백이었지.
채널이 4개까지 커졌잖아.
채널이 원래 1개 혹은 3개가 있는데 4개?5개?50개로 키워서 relu해 ... 큰 의미가 없.....
채널을 많이 늘려서 의미있는 채널이 있을 것이라고 생각하며 키운 것일뿐!
-
계산결과를 확인하기 위해 쉽게 만든 약간의 트릭
[1]*1*2*2*1
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(4,(2,2))
XXX = tnp.array([1]*1*2*2*1,dtype=tf.float64).reshape(1,2,2,1)
print(XXX.reshape(1,2,2))
- 이렇게 XXX를 설정하면 cnv(XXX)의 결과는 단지 cnv의 weight들의 sum이 된다.
cnv(XXX)
채널이 4개니까 4개의 결과가 출력되었다.
cnv.weights
cnv.weights[0] # (2,2) 커널의 크기 // 1은 XXX의 채널 수 // 4는 Conv(XXX)의 채널 수
cnv.weights[1]
이 값은 0이니 여기서는 신경쓰지 않도록 하자
cnv.weights[0][...,0].reshape(2,2) # Conv(XXX)의 첫번째 채널 출력을 얻기 위해 곱해지는 w
첫 번째 채널을 얻기 위해 나오는 계수 값
- (2,2,1) 차원으로 나옴
tf.reduce_sum(cnv.weights[0][...,0]),tf.reduce_sum(XXX.reshape(1,2,2) * cnv.weights[0][...,0].reshape(2,2)) # 같은 결과!
X의 채널이 여러개 있고, conv의 채널도 여러개 일때
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(4,(2,2))
XXX = tnp.array([1]*1*2*2*3,dtype=tf.float64).reshape(1,2,2,3) # 채널이 3에서 4로 커지는 !
cnv(XXX)
cnv.weights[0] ## (2,2) 는 커널의 사이즈 // 3은 XXX의 채널 // 4는 conv(XXX)의 채널
cnv.weights[0][...,0] ## cnv(XXX)의 첫번째 채널 결과를 얻기 위해서 사용하는 w
tf.reduce_sum(cnv.weights[0][...,0]) # cnv(XXX)의 첫번째 채널의 결과
위와 일치하는 결과
print(tf.reduce_sum(cnv.weights[0][...,0]))
print(tf.reduce_sum(cnv.weights[0][...,1]))
print(tf.reduce_sum(cnv.weights[0][...,2]))
print(tf.reduce_sum(cnv.weights[0][...,3])) ### cnv(XXX)의 결과
cnv(XXX)
똑같이 재현된 모습
cnv.weights[0][...,0] # (2,2,3) 3은 x의 입력 채널에 대응한다.
w_red = cnv.weights[0][...,0][...,0]
w_green = cnv.weights[0][...,0][...,1]
w_blue = cnv.weights[0][...,0][...,2]
XXX[...,0] # X_red
tf.reduce_sum(XXX[...,0] * w_red + XXX[...,1] * w_green + XXX[...,2] * w_blue) # cnv(XXX)의 첫번째 채널의 출력 결과
아래와 같은 흑백이미지가 있다고 하자
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
위의 이미지에 아래와 같은 weight를 가진 필터를 적용하여 convolution 한 결과를 계산하라.(bias는 0으로 가정한다.)
pythin
-1 1
-1 1
cnv = tf.keras.layers.Conv2D(1,(2,2))
XXX = tf.constant([[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1]],dtype=tf.float64).reshape(1,6,6,1)
XXX.reshape(1,6,6)
cnv(XXX).reshape(1,5,5)
cnv.weights[0]
_w = tf.constant([[-1,1],[-1,1]],dtype=tf.float64).reshape(2,2,1,1)
_b = tf.constant([0],dtype=tf.float64)x
cnv.set_weights([_w,_b])
cnv.weights
cnv(XXX).reshape(1,5,5)