오늘의 학습 리스트
-
Generative Modelling
- 여태까지의 분류기는 Discrimitive Modelling으로 볼 수 있음
-
모델 1) Pix2Pix
- 한 이미지를 다른 이미지로 픽셀 단위로 변환한다는 뜻의 Pixel to Pixel을 딴 Pix2Pix
- 단순화된 input image와 ground truth 가 쌍을 이루는 형태로 학습
- 그래서 그 단순화된 input image가 들어가면 최대한 비슷하게 ground truth와 같은 predicted image 반환하도록 훈련
-
모델 2) Cycle GAN
- Pix2Pix는 한 방향으로만 이미지 변환 가능한데, 양방향 가능
- 즉 실사를 그림으로 그림을 실사로
- Pix2Pix처럼 쌍을 이루지 않아도 됨.
- 모델이 스스로 각각의 스타일을 학습해서 서로 다른 곳에 적용 가능
- 이렇게 paired 데이터가 아니어도 학습 가능하다는 건 labelling cost가 없어지는 것이니 큰 장점
-
모델 3) Neural Style Transfer
- Base image와 Style image 두 장을 놓고 새로운 이미지를 만들어 냄
-
plt.imshow()
에 객체로서 2차원(가로, 세로) array만 들어가는 게 아니라 3차원(가로, 세로, 채널) 들어가도 됨
-
한번 0 ~ 255
값의 이미지 어레이를 -1 ~ 1
말고 0 ~ 2
로 해도 plt.imshow()
로 읽을 수 있는지 해보니 된다.
-
GAN
- 이것도 나름 모델의 이름임
- Ian Goodfellow가 만들었음
- 여기서 Generator는 아무 의미 없는 노이즈로부터 신경망에서의 연산을 통해 이미지 벡터를 만들어낸다고 함.
-
"we want the model distribution to match the true data distribution in the space of images"
- DCGAN 글에서 퍼온 것인데, 나름 유의미한 정보를 주는 것 같다.
- distribution...
- 즉, 실제 이미지들을 공간에 놓았을 때 그들이 위치하는 곳(분포)에 맞게 noise 데이터를 맞춰가도록 한다.
-
이미지넷의 경우 120만개 256 256 * 3개 채널이면 약 200GB의 데이터인데, 이것을 보통 약 1억개의 파라미터로 학습해서 표현하려는 것이다.
- 감이 안오지만, 여튼 욱여넣는 것이고
- 이 비유는 '그래서 파라미터는 실제 이미지들의 가장 실제적인 특징을 추출하도록 학습되겠구나' 라고 생각하면 되는 것 같다.
model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
model.add(layers.BatchNormalization())
model.add(layers.LeakyReLU())
-
위와 같이 있으면 레이어가 3개인 것 같은데 사실 Dense layer하나인 것 같다.
- BN은 해당 레이어의 가중치들을 정규화해주는 것 같고
- LeakyReLU는 그 레이어층 끝단에 있는 활성화함수이다.
-
Transpose Convolution 레이어는 사실 Deconvolution은 아니란다.
-
GAN의 loss function
- 판별자는 이진 분류(실제인지 아닌지)를 해야하므로 binary_crossentropy를 사용
- 판별자는 real 값이 1이 나오고, fake 값이 0이 나오도록 훈련
- 생성자는 만들어낸 fake값이 1이 나오도록 훈련
- (이런 점에서 약간 모델 세팅이 복잡하다... 하나는 loss가 2개, 하나는 loss가 1개 계산된다...)
tf.keras.losses.BinaryCrossentropy()
에서 input으로 오는 값이 실수니까(sigmoid를 거쳐서 0~1로 정규화되지 않은) 이 경우엔 from_logts=True
설정해줘야 함
-
tf.reduce_mean()
- mean 값 반환
- axis를 넣을 수 있음(그러면 차원이 하나만 감소)
- 아니면 차원이 다 감소되고 스칼라 값의 전체에서의 mean이 나옴
-
@tf.function
- 만약 tensorflow를 통해 계산 과정에서 computational graph 등을 그려야 한다면 이용되는 인풋 객체가 tf 자료형이어야 하나보다.
- 어떤 함수에 numpy 어레이를 넣으면 그냥 그거로 계산되는데,
- 위에 저 데코레이터를 붙이면 그 어레이(인풋)도 tf 자료형으로 바뀌고, 계산 결과도 tf 자료형으로 반환된다.
-
데코레이터
- 지금도 살짝 헷갈린다.
- 근데 정리하자면,
@decorate하고 싶은 함수 B
로 함수 A 위에 올리면
- 함수 A는 B함수에 가서
- B 함수 안에 있는 wrapper를 거치게 되고(기능 추가)
- B 함수는 그렇게 기능 추가된 A함수를 다시 내뱉는다.
- 즉,
@ 의미 : A함수야 저기 가서 B함수가 가진 기능 추가하고 와
-
tf.train.Chekcpoint()
-
display.clear_output(wait=True)
-
with
구문 이해 안가면 링크(https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=wideeyed&logNo=221653260516)
-
plt.imshow()
의 input array 픽셀 값 range
- (M, N, 3): an image with RGB values (0-1 float or 0-255 int)
- (M, N): an image with scalar data. The values are mapped to colors using normalization and a colormap. See parameters norm, cmap, vmin, vmax.
-
from_tensor_slices()
- 차원 1개를 줄인 텐서를 만든단다.
- 근데 그렇다고 나머지 데이터가 날라가는 건 아닌 것 같다.
- The given tensors are sliced along their first dimension. This operation preserves the structure of the input tensors, removing the first dimension of each tensor and using it as the dataset dimension. All input tensors must have the same size in their first dimensions.
- 링크(https://www.tensorflow.org/api_docs/python/tf/data/Dataset#from_tensor_slices)
미니프로젝트
DCGAN 구조를 이용해서 CIFAR-10 데이터 생성하기
- 그전에 실습 때 한 것을 순서별로 정리해보자...
- 데이터셋 불러오기
- 데이터 전처리
- GAN은 y_train 같은 라벨 데이터는 필요 없다.
- 픽셀값을
-1 ~ 1
로 맞춰줬다.
- 이는 추후 생성한 이미지 어레이의 요소들 값을
tanh
함수로 출력해서 -1 ~ 1
로 맞춰줄 건데, 즉 tanh를 거치는 fake 이미지도 같은 픽셀값을 갖게끔 해주는 것 같다.
- 데이터셋은 그 후
.shuffle()
, .batch()
를 통해 모델에 넣어줄 수 있는 준비를 한다.
- 모델 설계
- generator 설계
- 노이즈 어레이 인풋으로 받으면
reshape
, Conv2DTranspose()
등을 통해 실제 이미지 shape으로 upsampling
- discriminator 설계
- 이미지 데이터 shape로 인풋 받기
- 출력값은
Dense(1)
로 값 하나
- 그런데 여기에 sigmoid 같은 거 하지 않았음.(하지만 추후
tf.keras.BinaryCrossentropy(from_logits=True)
loss 계산을 통해 0~1 사이 값으로 바뀌긴 함.
- loss function 만들기
- 일단 loss가 두 개 필요하다.(곰곰히 생각해보면 generator를 위한, discriminator를 위한 것 각각 필요하다)
- 어떤 loss function이 되어야 하는지 생각해야 함
- 여기서는 이진 분류이다.
- 그리고 generator는 이미지 어레이를 내고,
- discriminator는 확률 값을 낸다.
- 그래서 여기서 사용한 방법은
- generator의 이미지 어레이도 discriminator에 넣어서 확률 값으로 만든다.
- 그리고 generator : fake image의 확률값은 1일때의 loss를 계산한다.(그 값이 작아져야 한다.)
- 반면 discriminator : 2개를 계산해서 더한다.
- fake image의 확률이 0일 때의 loss
- real image의 확률이 1일 때의 loss
- accuracy 계산 함수 만들기
- 이것도 2개 만든다.(real의 accuracy, fake의 accuracy를 따로 측정한다)
- real -> real의 확률 값이 0.5 이상일 때의 갯수를 데이터셋으로 들어온 크기(아마 배치인듯)로 나눈 게 accuracy
- fake -> fake의 확률 값이 0.5 밑일 때의 갯수를 데이터셋으로 들어온 크기로 나눈 게 accuracy
- optimizer 만들기
train 함수
만들기
- 여기서 GPU 사용 등을 설정한다.
- 위에 만든 모델 2개(함수 형태)에 이미지랑 노이즈 들어가게 하고
- loss 값 계산
tf.GradientTape().gradient(로스값, trainable_parameters)
넣어줘서 gradient 구하기
- optimizer에
.apply_gradients(gradient값, 파라미터들)
메소드로 업데이트 시켜주기
- 위의 accuracy도 계산해서 loss, accuracy 둘 다 real, fake 각각 반환
- 중간에 시각화할 함수 만들기
- 에포크, 혹은 몇 번의 iteration마다(
i % == 0
으로 설정 가능) 그래프 그리기 등
- Checkpoint 만들기
- 모든 함수 다 합친
최종 train 함수
만들기
- 고정 seed 노이즈 설정
- for loop으로 에포크만큼
최종 train 함수
돌리기
- 저장된 이미지들 GIF로 만들어보기
- 실제 프로젝트는 위의 과정을 거쳐서 CIFAR-10 이미지와 비슷한 이미지 생성하는 모델 만들어보기!