{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30787,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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    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","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import Conv2D, Conv2DTranspose, BatchNormalization, ReLU, LeakyReLU, Input, Add\nfrom tensorflow.keras.models import Model\nimport os\nimport numpy as np\nfrom PIL import Image\n\n# --- 1. Xử lý Dữ liệu ---\ndef parse_image(filename):\n    \"\"\"Đọc và tiền xử lý ảnh từ file\"\"\"\n    img = tf.io.read_file(filename)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [286, 286])  # Resize lớn hơn để crop ngẫu nhiên\n    img = tf.image.random_crop(img, [256, 256, 3])\n    img = tf.image.random_flip_left_right(img)\n    img = (img / 127.5) - 1  # Chuẩn hóa ảnh về [-1, 1]\n    return img\n\n# Đường dẫn ảnh Monet và Photo\nmonet_paths = tf.data.Dataset.list_files(\"/kaggle/input/gan-getting-started/monet_jpg/*.jpg\")\nphoto_paths = tf.data.Dataset.list_files(\"/kaggle/input/gan-getting-started/photo_jpg/*.jpg\")\n\n# Tạo Dataset với batch size nhỏ hơn\nmonet_dataset = monet_paths.map(parse_image).batch(3).shuffle(buffer_size=1000)\nphoto_dataset = photo_paths.map(parse_image).batch(3).shuffle(buffer_size=1000)\n\n# --- 2. Xây dựng Mô hình ---\ndef residual_block(x, filters):\n    \"\"\"Khối Residual Block\"\"\"\n    shortcut = x\n    x = Conv2D(filters, kernel_size=3, strides=1, padding=\"same\")(x)\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n    x = Conv2D(filters, kernel_size=3, strides=1, padding=\"same\")(x)\n    x = BatchNormalization()(x)\n    return Add()([shortcut, x])\n\ndef build_generator(input_shape):\n    \"\"\"Mạng Generator\"\"\"\n    inputs = Input(shape=input_shape)\n    x = Conv2D(32, kernel_size=7, strides=1, padding=\"same\")(inputs)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n\n    # Downsample\n    x = Conv2D(64, kernel_size=3, strides=2, padding=\"same\")(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n    x = Conv2D(128, kernel_size=3, strides=2, padding=\"same\")(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n\n    # Residual Blocks\n    for _ in range(6):  # Giảm số lượng Residual Blocks\n        x = residual_block(x, 128)\n\n    # Upsample\n    x = Conv2DTranspose(64, kernel_size=3, strides=2, padding=\"same\", output_padding=1)(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n    x = Conv2DTranspose(32, kernel_size=3, strides=2, padding=\"same\", output_padding=1)(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n\n    outputs = Conv2D(3, kernel_size=7, strides=1, padding=\"same\", activation=\"tanh\")(x)\n    return Model(inputs, outputs)\n\ndef build_discriminator(input_shape):\n    \"\"\"Mạng Discriminator\"\"\"\n    inputs = Input(shape=input_shape)\n    x = Conv2D(32, kernel_size=4, strides=2, padding=\"same\")(inputs)  # Số bộ lọc giảm\n    x = LeakyReLU(0.2)(x)\n\n    x = Conv2D(64, kernel_size=4, strides=2, padding=\"same\")(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n\n    x = Conv2D(128, kernel_size=4, strides=2, padding=\"same\")(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n\n    x = Conv2D(256, kernel_size=4, strides=1, padding=\"same\")(x)  # Số bộ lọc giảm\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n\n    outputs = Conv2D(1, kernel_size=4, strides=1, padding=\"same\")(x)\n    return Model(inputs, outputs)\n\n# Tạo các Generator và Discriminator\nG_Monet = build_generator((256, 256, 3))\nG_Photo = build_generator((256, 256, 3))\nD_Monet = build_discriminator((256, 256, 3))\nD_Photo = build_discriminator((256, 256, 3))\n\n# --- 3. Huấn luyện ---\n# Hàm mất mát\nloss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\ndef discriminator_loss(real, generated):\n    real_loss = loss_obj(tf.ones_like(real), real)\n    generated_loss = loss_obj(tf.zeros_like(generated), generated)\n    return (real_loss + generated_loss) * 0.5\n\ndef generator_loss(generated):\n    return loss_obj(tf.ones_like(generated), generated)\n\ndef cycle_consistency_loss(real, cycled):\n    return tf.reduce_mean(tf.abs(real - cycled))\n\ndef identity_loss(real, same):\n    return tf.reduce_mean(tf.abs(real - same))\n\n# Optimizers\nG_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\nD_Monet_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\nD_Photo_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n# Huấn luyện qua epochs\nepochs = 100\nfor epoch in range(epochs):\n    for real_photo, real_monet in zip(photo_dataset, monet_dataset):\n        with tf.GradientTape(persistent=True) as tape:\n            # Sinh ảnh giả và ảnh tái tạo\n            fake_monet = G_Monet(real_photo, training=True)\n            fake_photo = G_Photo(real_monet, training=True)\n\n            cycled_photo = G_Photo(fake_monet, training=True)\n            cycled_monet = G_Monet(fake_photo, training=True)\n\n            same_photo = G_Photo(real_photo, training=True)\n            same_monet = G_Monet(real_monet, training=True)\n\n            # Phân biệt ảnh thật và giả\n            disc_real_monet = D_Monet(real_monet, training=True)\n            disc_fake_monet = D_Monet(fake_monet, training=True)\n\n            disc_real_photo = D_Photo(real_photo, training=True)\n            disc_fake_photo = D_Photo(fake_photo, training=True)\n\n            # Tính loss\n            G_loss = (generator_loss(disc_fake_monet) + generator_loss(disc_fake_photo) +\n                      cycle_consistency_loss(real_photo, cycled_photo) * 10 +\n                      cycle_consistency_loss(real_monet, cycled_monet) * 10 +\n                      identity_loss(real_photo, same_photo) * 5 +\n                      identity_loss(real_monet, same_monet) * 5)\n\n            D_Monet_loss = discriminator_loss(disc_real_monet, disc_fake_monet)\n            D_Photo_loss = discriminator_loss(disc_real_photo, disc_fake_photo)\n\n        # Tính toán và cập nhật gradient\n        G_gradients = tape.gradient(G_loss, G_Monet.trainable_variables + G_Photo.trainable_variables)\n        D_Monet_gradients = tape.gradient(D_Monet_loss, D_Monet.trainable_variables)\n        D_Photo_gradients = tape.gradient(D_Photo_loss, D_Photo.trainable_variables)\n\n        G_optimizer.apply_gradients(zip(G_gradients, G_Monet.trainable_variables + G_Photo.trainable_variables))\n        D_Monet_optimizer.apply_gradients(zip(D_Monet_gradients, D_Monet.trainable_variables))\n        D_Photo_optimizer.apply_gradients(zip(D_Photo_gradients, D_Photo.trainable_variables))\n\n    print(f\"Epoch {epoch+1}/{epochs}, G Loss: {G_loss}, D Monet Loss: {D_Monet_loss}, D Photo Loss: {D_Photo_loss}\")\n\n    # Lưu ảnh và mô hình\n    fake_monet_images = G_Monet(real_photo, training=False)\n    tf.keras.utils.save_img(f'generated_monet_{epoch+1}.png', fake_monet_images[0] * 127.5 + 127.5)\n\n# Lưu mô hình\nG_Monet.save('G_Monet.h5')\nG_Photo.save('G_Photo.h5')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-04T04:41:29.254610Z","iopub.execute_input":"2024-12-04T04:41:29.254969Z","iopub.status.idle":"2024-12-04T10:42:45.088773Z","shell.execute_reply.started":"2024-12-04T04:41:29.254904Z","shell.execute_reply":"2024-12-04T10:42:45.087983Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nfrom tensorflow.keras.models import load_model\nfrom PIL import Image\nimport tensorflow as tf\n\n# Tắt log của TensorFlow\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # Chỉ hiển thị lỗi nghiêm trọng\n\n# Kiểm tra GPU\ndevice = \"/GPU:0\" if tf.config.list_physical_devices('GPU') else \"/CPU:0\"\n\n# Tải mô hình Generator G_Monet đã huấn luyện\nG_Monet = tf.keras.models.load_model('./G_Monet.h5')\n\n# Biến đổi ảnh trước khi đưa vào mô hình\ndef preprocess_image(image_path):\n    \"\"\"Đọc và tiền xử lý ảnh từ file.\"\"\"\n    img = Image.open(image_path).convert(\"RGB\")\n    img = img.resize((256, 256))  # Resize ảnh về đúng kích thước\n    img = np.array(img) / 127.5 - 1  # Chuẩn hóa về [-1, 1]\n    return np.expand_dims(img, axis=0)  # Thêm batch dimension\n\n# Hàm hậu xử lý ảnh sau khi sinh\ndef postprocess_image(image):\n    \"\"\"Chuyển ảnh từ [-1, 1] về [0, 255] và lưu.\"\"\"\n    img = (image[0] + 1) * 127.5  # Loại bỏ batch dimension và chuyển về [0, 255]\n    img = np.clip(img, 0, 255).astype(np.uint8)  # Đảm bảo giá trị hợp lệ\n    return Image.fromarray(img)\n\n# Đường dẫn tới thư mục chứa ảnh gốc (photo_jpg) và thư mục lưu ảnh chuyển phong cách\ninput_dir = '/kaggle/input/gan-getting-started/photo_jpg'\noutput_dir = './styled_photos'\n\n# Tạo thư mục lưu ảnh chuyển phong cách nếu chưa có\nos.makedirs(output_dir, exist_ok=True)\n\n# Hàm để chuyển ảnh thành phong cách Monet và lưu\ndef style_transfer_and_save(input_image_path, output_image_path):\n    # Tiền xử lý ảnh\n    input_image = preprocess_image(input_image_path)\n\n    # Sinh ảnh Monet từ ảnh gốc\n    with tf.device(device):\n        fake_monet = G_Monet.predict(input_image, verbose=0)  # Tắt thông báo của predict()\n\n    # Hậu xử lý và lưu ảnh\n    output_image = postprocess_image(fake_monet)\n    output_image.save(output_image_path)\n\n# Lặp qua tất cả các ảnh trong thư mục `photo_jpg` và chuyển chúng\ntotal_images = len(os.listdir(input_dir))\nfor i, image_name in enumerate(os.listdir(input_dir)):\n    image_path = os.path.join(input_dir, image_name)\n    if os.path.isfile(image_path) and image_name.endswith('.jpg'):\n        # Tạo tên file đầu ra\n        output_image_path = os.path.join(output_dir, f\"{os.path.splitext(image_name)[0]}_monet.png\")\n        \n        # Chuyển phong cách và lưu ảnh\n        style_transfer_and_save(image_path, output_image_path)\n        \n        # In thông báo sau mỗi 1000 ảnh\n        if (i + 1) % 1000 == 0 or (i + 1) == total_images:\n            print(f\"Đã xử lý {i + 1}/{total_images} ảnh.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-04T10:47:14.713032Z","iopub.execute_input":"2024-12-04T10:47:14.713897Z","iopub.status.idle":"2024-12-04T10:59:33.894388Z","shell.execute_reply.started":"2024-12-04T10:47:14.713865Z","shell.execute_reply":"2024-12-04T10:59:33.893354Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo file zip\nimport os\nimport zipfile\nfrom PIL import Image\nfrom io import BytesIO\n\n# Đường dẫn tới thư mục chứa ảnh\nimage_dir = '/kaggle/working/styled_photos'\nzip_path = '/kaggle/working/images.zip'\n\n# Tạo file zip và thêm các ảnh vào đó\nwith zipfile.ZipFile(zip_path, 'w') as zipf:\n    for root, dirs, files in os.walk(image_dir):\n        for file in files:\n            if file.endswith(('.png', '.jpg', '.jpeg')):\n                file_path = os.path.join(root, file)\n                # Thêm tệp ảnh vào file zip\n                zipf.write(file_path, arcname=file)\n\nprint(f'Ảnh đã được nén thành công vào file: {zip_path}')\n\n\ndef count_images_in_zip(zip_path):\n    count = 0\n    with zipfile.ZipFile(zip_path, 'r') as z:\n        for file in z.namelist():\n            if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):\n                count += 1\n    return count\nnum_images = count_images_in_zip(zip_path)\nprint(f'Số lượng ảnh trong file ZIP: {num_images}')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-04T11:07:51.345633Z","iopub.execute_input":"2024-12-04T11:07:51.346589Z","iopub.status.idle":"2024-12-04T11:07:53.805982Z","shell.execute_reply.started":"2024-12-04T11:07:51.346552Z","shell.execute_reply":"2024-12-04T11:07:53.804969Z"}},"outputs":[],"execution_count":null}]}