{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    print(dirname)\n    #for filename in filenames:\n        #print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":true,"scrolled":true,"execution":{"iopub.status.busy":"2022-05-05T05:01:20.033723Z","iopub.execute_input":"2022-05-05T05:01:20.034213Z","iopub.status.idle":"2022-05-05T05:01:23.628289Z","shell.execute_reply.started":"2022-05-05T05:01:20.034176Z","shell.execute_reply":"2022-05-05T05:01:23.627507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"---\n## I’m Something of a Painter Myself\n---\n\\* All English explanations have been translated","metadata":{}},{"cell_type":"markdown","source":"## advance preparation | 사전 준비\n---\n\\- set seed : Increase reproducibility   \n\\- Create a folder in which GAN-generated images will be stored   \n\\- I copied the folder and created it separately to use the image separately   \n   \n\\- 시드 설정 : 재현성을 높임   \n\\- GAN으로 생성된 이미지가 저장될 폴더 만들기   \n\\- 이미지를 따로 사용하기 위해 폴더를 복사해서 따로 만들었음   ","metadata":{}},{"cell_type":"code","source":"import numpy as np  # 시드 설정\nimport tensorflow as tf  # 시드 설정\n\n# 이미지가 저장될 폴더가 없다면 만듭니다.\nimport os\nimport shutil\n\nif not os.path.exists(\"/kaggle/working/tmp\"):\n    os.makedirs(\"/kaggle/working/tmp\")\n\nif not os.path.exists(\"/kaggle/working/monet\"):\n    os.makedirs(\"/kaggle/working/monet\")\n\nif not os.path.exists(\"/kaggle/working/photo\"):\n    os.makedirs(\"/kaggle/working/photo\")\n\nif not os.path.exists(\"/kaggle/working/monet/monet_jpg\"):\n    shutil.copytree(\"/kaggle/input/gan-getting-started/monet_jpg\", \"/kaggle/working/monet/monet_jpg\")\n\nif not os.path.exists(\"/kaggle/working/photo/photo_jpg\"):\n    shutil.copytree(\"/kaggle/input/gan-getting-started/photo_jpg\", \"/kaggle/working/photo/photo_jpg\")\n\n# 시드 설정\nseed = 3\nnp.random.seed(seed)\ntf.random.set_seed(seed)\n\nprint(\"seed =\", seed)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-05T05:01:23.629999Z","iopub.execute_input":"2022-05-05T05:01:23.630739Z","iopub.status.idle":"2022-05-05T05:01:23.646756Z","shell.execute_reply.started":"2022-05-05T05:01:23.630692Z","shell.execute_reply":"2022-05-05T05:01:23.645939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## make generator | 생성자 만들기\n---\n\\- input : Use large enough random vectors as inputs.   \n\\- Start with a small image and grow in size.   \n\\- Batch normalization : Normalizes input data. Helps with stable learning.   \n\\- Passes the generated value to the discriminator.   \n\\- no compile   \n   \n\\- 입력 : 충분히 큰 랜덤 벡터 사용   \n\\- 작은 크기로 시작해 크기를 키운다.   \n\\- 배치 정규화 : 입력 데이터를 정규화한다. 안정적인 학습을 도움.   \n\\- 판별자에게 생성된 값을 넘긴다.   \n\\- 생성자는 컴파일 없음.   ","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.layers import Dense, Reshape\nfrom tensorflow.keras.layers import BatchNormalization, Activation, LeakyReLU, UpSampling2D, Conv2D\nfrom tensorflow.keras.models import Sequential, Model\n\n# 생성자 모델을 만듭니다.\ngenerator = Sequential()  # 모델 선언\ngenerator.add(Dense(128 * 32 * 32, input_dim=300, activation=LeakyReLU(0.2)))\n'''\n512 : 임의로 정한 노드의 수. 충분히 있기만 하면 됨\n8 * 8 : 이미지의 최초 크기. 점점 크기를 키울 것이기 때문에 작게 넣음\ninput_dim=300 : 300차원 크기의 랜덤 벡터를 준비해 넣어라\n'''\ngenerator.add(BatchNormalization())  # 배치 정규화 : 입력 데이터를 정규화함. 안정적인 학습을 도움.\ngenerator.add(Reshape((32, 32, 128)))  # 컨볼루션 레이어가 받아들일 수 있는 형태로 바꿈. 인자는 input_shape 형태로 전달\ngenerator.add(UpSampling2D())  # 이미지의 가로 세로 크기를 2배씩 늘림\ngenerator.add(Conv2D(256, kernel_size=5, padding='same'))  # 커널 크기 5 * 5, 패딩으로 크기 유지\n\ngenerator.add(BatchNormalization())\ngenerator.add(Activation(LeakyReLU(0.2)))\ngenerator.add(UpSampling2D())\ngenerator.add(Conv2D(32, kernel_size=5, padding='same'))\n\ngenerator.add(BatchNormalization())  # 배치 정규화\ngenerator.add(Activation(LeakyReLU(0.2)))  # 릭키렐루 : 값이 음수이면 0으로 없애지 말고 전달한 값(0.2)을 곱해라.\ngenerator.add(UpSampling2D())  # 크기 2배\ngenerator.add(Conv2D(3, kernel_size=5, padding='same', activation='tanh'))\n# 컨볼루션. 이후 판별자에게 값을 넘김, 하이퍼볼릭 탄젠트\n# 생성자는 컴파일이 없음\ngenerator.summary()","metadata":{"_kg_hide-output":false,"scrolled":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-05T05:01:23.648154Z","iopub.execute_input":"2022-05-05T05:01:23.648764Z","iopub.status.idle":"2022-05-05T05:01:23.763264Z","shell.execute_reply.started":"2022-05-05T05:01:23.648727Z","shell.execute_reply":"2022-05-05T05:01:23.762574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## make discriminator | 판별자 만들기\n---\n\\- The discriminator should only determine the authenticity and not learn.   \n\\- It actively reduces the size of the image so that the discriminator can grasp only the characteristics.   \n   \n\\- 판별자는 진위판별만 하고 학습은 하면 안 된다.   \n\\- 이미지의 크기를 적극적으로 줄여 판별자가 특징만을 파악하게 한다.   ","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.layers import Input, Dense, Reshape, Flatten, Dropout\nfrom tensorflow.keras.layers import BatchNormalization, Activation, LeakyReLU, UpSampling2D, Conv2D\nfrom tensorflow.keras.models import Sequential, Model\n\n# 판별자 모델을 만듭니다.\n# 진위판별만 하고 학습은 하면 안됨\ndiscriminator = Sequential()  # 모델 선언\ndiscriminator.add(Conv2D(256, kernel_size=5, strides=2, input_shape=(256, 256, 3), padding=\"same\"))\n# 노드 128개, 커널 크기 5 * 5, 커널이 2칸씩 이동, 입력 크기 256 * 256, 흑백, 크기 유지 패딩\n\ndiscriminator.add(Activation(LeakyReLU(0.2)))  # 릭키렐루\ndiscriminator.add(Dropout(0.3))  # 드롭아웃\ndiscriminator.add(Conv2D(128, kernel_size=5, strides=2, padding=\"same\"))\n# 노드 128개, 커널 크기 5 * 5, 커널이 2칸씩 이동, 크기 유지 패딩\n\ndiscriminator.add(Activation(LeakyReLU(0.2)))\ndiscriminator.add(Dropout(0.3))\ndiscriminator.add(Conv2D(128, kernel_size=5, strides=2, padding=\"same\"))\n\ndiscriminator.add(Activation(LeakyReLU(0.2)))\ndiscriminator.add(Dropout(0.3))\ndiscriminator.add(Flatten())  # 플래튼\ndiscriminator.add(Dense(1, activation='sigmoid'))  # 판별 결과 참/거짓\n\n# 판별자 컴파일\ndiscriminator.compile(loss='binary_crossentropy', optimizer='adam')\ndiscriminator.trainable = False  # 학습 금지\ndiscriminator.summary()","metadata":{"_kg_hide-output":false,"scrolled":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-05T05:01:23.765501Z","iopub.execute_input":"2022-05-05T05:01:23.765752Z","iopub.status.idle":"2022-05-05T05:01:23.836497Z","shell.execute_reply.started":"2022-05-05T05:01:23.765711Z","shell.execute_reply":"2022-05-05T05:01:23.835735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## combine generator and discriminator | 생성자와 판별자 합치기\n---\n\\- this is DCGAN.   \n   \n\\- 이것은 DCGAN이다.   ","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.layers import Input\nfrom tensorflow.keras.models import Model\n\n# 생성자와 판별자 모델을 연결시키는 gan 모델을 만듭니다.\nginput = Input(shape=(300,))\n# 랜덤한 100개의 벡터를 집어넣어 생성자의 입력 데이터를 만듦\ndis_output = discriminator(generator(ginput))\n# 생성자 모델에 방금 만든 랜덤 입력 데이터를 넣음, 생성자가 가짜 이미지를 생성하고, 판별자가 진위판별. 그 결과가 변수에 저장됨\ngan = Model(ginput, dis_output)\n# 생성자와 판별자가 합쳐진 새 모델 선언. 랜덤 입력 데이터(x)와 그것으로 만든 가짜 데이터의 진위여부(y)를 넣어 만듦.\n# 생성+판별자 모델 컴파일. 출력은 참 거짓이니 바이너리 사용.\ngan.compile(loss='binary_crossentropy', optimizer='adam')\ngan.summary()  # 이 모델의 요약정보를 보여주세요","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-05T05:01:23.837522Z","iopub.execute_input":"2022-05-05T05:01:23.837704Z","iopub.status.idle":"2022-05-05T05:01:23.911500Z","shell.execute_reply.started":"2022-05-05T05:01:23.837681Z","shell.execute_reply":"2022-05-05T05:01:23.910590Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## execute GAN | GAN 실행하기\n---\nreference : [Load and preprocess images](https://www.tensorflow.org/tutorials/load_data/images)   \n   \n텐서플로우 공식 문서 참고 : [이미지 로드 및 전처리하기](https://www.tensorflow.org/tutorials/load_data/images?hl=ko)   ","metadata":{}},{"cell_type":"code","source":"# 신경망을 실행\n# 4000번 반복되고(+1을 해 주는 것에 주의), 배치 사이즈는 32, 200번 마다 결과가 저장되게 하였습니다.\nepoch = 10000 + 1\nbatch = 30\nsaving_interval = 100  # saving_interval : 몇 번에 한 번 중간과정을 저장할까\nprogress_print_interval = 50  # 학습 과정에서 생성자와 판별자의 오차 출력 간격\nimg_height = 256\nimg_width = 256\n\ntrain_ds = tf.keras.preprocessing.image_dataset_from_directory(\"/kaggle/working/monet/\", seed=seed, image_size=(img_height, img_width), batch_size=batch)\n# test_ds = tf.keras.preprocessing.image_dataset_from_directory(\"/kaggle/working/monet/\", validation_split=0.2, subset=\"validation\", seed=seed, image_size=(img_height, img_width), batch_size=batch)\nphoto_ds = tf.keras.preprocessing.image_dataset_from_directory(\"/kaggle/working/photo/\", seed=seed, image_size=(img_height, img_width), batch_size=batch)\n\nprint(type(train_ds))\n\nnormalization_layer = tf.keras.layers.experimental.preprocessing.Rescaling(1./255)\n# normalization_layer = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset=-1)\n\nnormalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))\nnormal_photo = photo_ds.map(lambda x, y: (normalization_layer(x), y))\n# image_batch, labels_batch = next(iter(normalized_ds))\n# first_image = image_batch[0]\n# Notice the pixels values are now in `[0,1]`.\n# print(first_image)","metadata":{"execution":{"iopub.status.busy":"2022-05-05T05:04:16.667287Z","iopub.execute_input":"2022-05-05T05:04:16.667862Z","iopub.status.idle":"2022-05-05T05:04:17.056280Z","shell.execute_reply.started":"2022-05-05T05:04:16.667805Z","shell.execute_reply":"2022-05-05T05:04:17.055573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt  # 그래프\nimport seaborn as sns\nimport PIL\nimport PIL.Image\n\nep = []  # 에포크\ndl = []  # 판별자 오차\ngl = []  # 생성자 오차\n\ntrue = np.ones((batch, 1))  # batch_size개의 열과 1개의 행을 전부 1로 채운 배열\nfake = np.zeros((batch, 1))  # batch_size개의 열과 1개의 행을 전부 0으로 채운 배열\n\nfor i in range(3):\n    # 실제 데이터를 판별자에 입력하는 부분입니다.\n    image_batch, labels_batch = next(iter(normal_photo))\n    d_loss_real = discriminator.train_on_batch(image_batch, true)\n    \n    plt.imshow(image_batch[0].numpy().astype(\"uint8\"), cmap='hsv')  # 이미지가 새까맣게 나오는데 왜 그렇게 되는지는 모르겠다. 이게 GAN이 잘 안되는 이유인 것 같다.\n    plt.axis(\"off\")\n    plt.show()\n    \n    # img, label = train_generator.next()\n    # d_loss_real = discriminator.train_on_batch(img, true)\n    # 판별자에 넣고 학습한다. 입력은 아까 뽑은 이미지, 클래스는 아까 만든 전부 참 배열.\n    # train_on_batch : 딱 한 번만 학습시키는 함수\n\n    # 가상 이미지를 판별자에 입력하는 부분입니다.\n    noise = np.random.normal(0, 1, (batch, 300))  # 생성자에 집어넣을 랜덤 이미지 만들기\n    # 정수가 아니라서 np.random.normal() 함수 사용. 인자의 의미는 아까와 같음.\n    # (batch_size, 100) : batch_size만큼 100개의 열을 뽑아달라\n    gen_imgs = generator.predict(noise)  # 방금 뽑은 값이 생성자에 들어가 가짜 이미지가 만들어짐\n    d_loss_fake = discriminator.train_on_batch(gen_imgs, fake)\n    # 판별자에 넣고 학습한다. 입력은 아까 만든 가짜 이미지, 클래스는 아까 만든 전부 거짓 배열.\n\n    # 판별자와 생성자의 오차를 계산합니다.\n    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)\n    # 진짜와 가짜의 오차 평균이 판별자의 오차\n    g_loss = gan.train_on_batch(noise, true)\n    # 이건 생성자의 오차.\n\n    # 학습 진행하는 동안 생성자와 판별자의 오차 출력\n    if i % progress_print_interval == 0:\n        print('epoch:%d' % i, ' d_loss:%.4f' % d_loss, ' g_loss:%.4f' % g_loss)\n\n    # 생성자와 판별자의 오차 값을 저장해 데이터 프레임으로 만들고 그래프 그리기\n    ep.append(i)\n    dl.append(d_loss)\n    gl.append(g_loss)\n\n    # 이부분은 중간 과정을 이미지로 저장해 주는 부분입니다.\n    if i % saving_interval == 0:\n        # r, c = 5, 5\n        noise = np.random.normal(0, 1, (25, 300))\n        gan_imgs = generator.predict(noise)\n\n        # Rescale images 0 - 1\n        gan_imgs = 0.5 * gan_imgs + 0.5\n\n        fig, axs = plt.subplots(5, 5)\n        count = 0\n        for j in range(5):\n            for k in range(5):\n                axs[j, k].imshow(gan_imgs[count, :, :, 0], cmap='hsv')\n                axs[j, k].axis('off')\n                count += 1\n        plt.show()\n        fig.savefig(\"tmp/photomonet_%d.png\" % i)","metadata":{"scrolled":true,"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n\nresult_data = {\n    'epoch': ep, \n    'd_loss': dl, \n    'g_loss': gl\n}\n\nhistory = pd.DataFrame(result_data)\n\nsns.set(rc={'figure.figsize':(16, 9)})\n\nsns.set_style(\"white\")\nx = history['epoch']\ny_1 = history['d_loss']\n\nsns.lineplot(x=x, y=y_1, label='d_loss', color='blue', alpha=0.7)\n\nplt.xlabel('epoch', fontsize=20)\nplt.ylabel('loss', fontsize=20)\nplt.title('discriminator loss per epoch', fontsize=25)\n\nplt.grid()\nplt.legend(loc='upper left')\nplt.show()\n\n\nsns.set_style(\"white\")\nx = history['epoch']\ny_2 = history['g_loss']\n\nsns.lineplot(x=x, y=y_2, label='g_loss', color='green', alpha=0.7)\n\nplt.xlabel('epoch', fontsize=20)\nplt.ylabel('loss', fontsize=20)\nplt.title('generator loss per epoch', fontsize=25)\n\nplt.grid()\nplt.legend(loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-05T05:01:24.588255Z","iopub.status.idle":"2022-05-05T05:01:24.588886Z","shell.execute_reply.started":"2022-05-05T05:01:24.588634Z","shell.execute_reply":"2022-05-05T05:01:24.588658Z"},"trusted":true},"execution_count":null,"outputs":[]}]}