#!/usr/bin/env python # coding: utf-8 # **Chương 10 – Giới thiệu về Mạng Nơ-ron Nhân tạo với Keras** # # _Notebook này sẽ chứa tất cả các mã lập trình mẫu và lời giải cho các bài tập trong chương 10._ # # # #
# Open In Colab # # #
# # Cài đặt # Đầu tiên hãy nhập một vài mô-đun thông dụng, đảm bảo rằng Matplotlib sẽ vẽ đồ thị ngay trong notebook, và chuẩn bị một hàm để lưu đồ thị. Ta cũng kiểm tra xem Python phiên bản từ 3.5 trở lên đã được cài đặt hay chưa (mặc dù Python 2.x vẫn có thể hoạt động, phiên bản này đã không còn sử dụng nên chúng tôi rất khuyến khích việc sử dụng Python 3), cũng như Scikit-Learn ≥ 0.20. # In[1]: # Python ≥3.5 is required import sys assert sys.version_info >= (3, 5) # Scikit-Learn ≥0.20 is required import sklearn assert sklearn.__version__ >= "0.20" try: # %tensorflow_version only exists in Colab. get_ipython().run_line_magic('tensorflow_version', '2.x') except Exception: pass # TensorFlow ≥2.0 is required import tensorflow as tf assert tf.__version__ >= "2.0" # Common imports import numpy as np import os # to make this notebook's output stable across runs np.random.seed(42) # To plot pretty figures get_ipython().run_line_magic('matplotlib', 'inline') import matplotlib as mpl import matplotlib.pyplot as plt mpl.rc('axes', labelsize=14) mpl.rc('xtick', labelsize=12) mpl.rc('ytick', labelsize=12) # Where to save the figures PROJECT_ROOT_DIR = "." CHAPTER_ID = "ann" IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, "images", CHAPTER_ID) os.makedirs(IMAGES_PATH, exist_ok=True) def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300): path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension) print("Saving figure", fig_id) if tight_layout: plt.tight_layout() plt.savefig(path, format=fig_extension, dpi=resolution) # # Perceptrons # **Chú ý**: ta thiết lập `max_iter` và `tol` một cách rõ ràng để tránh các cảnh báo là giá trị mặc định của chúng sẽ thay đổi trong các phiên bản tương lai của Scikit-Learn. # In[2]: import numpy as np from sklearn.datasets import load_iris from sklearn.linear_model import Perceptron iris = load_iris() X = iris.data[:, (2, 3)] # petal length, petal width y = (iris.target == 0).astype(np.int) per_clf = Perceptron(max_iter=1000, tol=1e-3, random_state=42) per_clf.fit(X, y) y_pred = per_clf.predict([[2, 0.5]]) # In[3]: y_pred # In[4]: a = -per_clf.coef_[0][0] / per_clf.coef_[0][1] b = -per_clf.intercept_ / per_clf.coef_[0][1] axes = [0, 5, 0, 2] x0, x1 = np.meshgrid( np.linspace(axes[0], axes[1], 500).reshape(-1, 1), np.linspace(axes[2], axes[3], 200).reshape(-1, 1), ) X_new = np.c_[x0.ravel(), x1.ravel()] y_predict = per_clf.predict(X_new) zz = y_predict.reshape(x0.shape) plt.figure(figsize=(10, 4)) plt.plot(X[y==0, 0], X[y==0, 1], "bs", label="Không phải Iris-Setosa") plt.plot(X[y==1, 0], X[y==1, 1], "yo", label="Iris-Setosa") plt.plot([axes[0], axes[1]], [a * axes[0] + b, a * axes[1] + b], "k-", linewidth=3) from matplotlib.colors import ListedColormap custom_cmap = ListedColormap(['#9898ff', '#fafab0']) plt.contourf(x0, x1, zz, cmap=custom_cmap) plt.xlabel("Chiều dài cánh hoa", fontsize=14) plt.ylabel("Chiều rộng cánh hoa", fontsize=14) plt.legend(loc="lower right", fontsize=14) plt.axis(axes) save_fig("perceptron_iris_plot") plt.show() # # Hàm Kích hoạt # In[5]: def sigmoid(z): return 1 / (1 + np.exp(-z)) def relu(z): return np.maximum(0, z) def derivative(f, z, eps=0.000001): return (f(z + eps) - f(z - eps))/(2 * eps) # In[6]: z = np.linspace(-5, 5, 200) plt.figure(figsize=(11,4)) plt.subplot(121) plt.plot(z, np.sign(z), "r-", linewidth=1, label="Hàm Bước") plt.plot(z, sigmoid(z), "g--", linewidth=2, label="Sigmoid") plt.plot(z, np.tanh(z), "b-", linewidth=2, label="Tanh") plt.plot(z, relu(z), "m-.", linewidth=2, label="ReLU") plt.grid(True) plt.legend(loc="center right", fontsize=14) plt.title("Hàm Kích hoạt", fontsize=14) plt.axis([-5, 5, -1.2, 1.2]) plt.subplot(122) plt.plot(z, derivative(np.sign, z), "r-", linewidth=1, label="Hàm Bước") plt.plot(0, 0, "ro", markersize=5) plt.plot(0, 0, "rx", markersize=10) plt.plot(z, derivative(sigmoid, z), "g--", linewidth=2, label="Sigmoid") plt.plot(z, derivative(np.tanh, z), "b-", linewidth=2, label="Tanh") plt.plot(z, derivative(relu, z), "m-.", linewidth=2, label="ReLU") plt.grid(True) #plt.legend(loc="center right", fontsize=14) plt.title("Đạo Hàm", fontsize=14) plt.axis([-5, 5, -0.2, 1.2]) save_fig("activation_functions_plot") plt.show() # In[7]: def heaviside(z): return (z >= 0).astype(z.dtype) def mlp_xor(x1, x2, activation=heaviside): return activation(-activation(x1 + x2 - 1.5) + activation(x1 + x2 - 0.5) - 0.5) # In[8]: x1s = np.linspace(-0.2, 1.2, 100) x2s = np.linspace(-0.2, 1.2, 100) x1, x2 = np.meshgrid(x1s, x2s) z1 = mlp_xor(x1, x2, activation=heaviside) z2 = mlp_xor(x1, x2, activation=sigmoid) plt.figure(figsize=(10,4)) plt.subplot(121) plt.contourf(x1, x2, z1) plt.plot([0, 1], [0, 1], "gs", markersize=20) plt.plot([0, 1], [1, 0], "y^", markersize=20) plt.title("Hàm Kích hoạt: heaviside", fontsize=14) plt.grid(True) plt.subplot(122) plt.contourf(x1, x2, z2) plt.plot([0, 1], [0, 1], "gs", markersize=20) plt.plot([0, 1], [1, 0], "y^", markersize=20) plt.title("Hàm Kích hoạt: sigmoid", fontsize=14) plt.grid(True) # # Xây dựng một bộ Phân loại Hình ảnh # Đầu tiên hãy nạp TensoFlow và Keras. # In[9]: import tensorflow as tf from tensorflow import keras # In[10]: tf.__version__ # In[11]: keras.__version__ # Hãy bắt đầu bằng cách tải tập dữ liệu MNIST thời trang. Keras có một số phương thức để tải các bộ dữ liệu phổ biến trong `keras.datasets`. Tập dữ liệu đã được phân chia thành tập huấn luyện và tập kiểm tra cho chúng ta, nhưng sẽ là hữu ích khi ta chia tập huấn luyện một lần nữa để có được tập kiểm định: # In[12]: fashion_mnist = keras.datasets.fashion_mnist (X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data() # Tập huấn luyện chứa 60,000 ảnh xám, mỗi ảnh có kích thước 28x28 pixel: # In[13]: X_train_full.shape # Cường độ mỗi điểm ảnh được biểu diễn bởi một byte (từ 0 tới 255): # In[14]: X_train_full.dtype # Hãy chia tập huấn luyện đầy đủ thành một tập kiểm định và một tập huấn luyện (nhỏ hơn). Ta cũng tỷ lệ hóa cường độ pixel xuống khoảng 0-1 và chuyển đổi chúng thành kiểu float bằng cách chia cho 255. # In[15]: X_valid, X_train = X_train_full[:5000] / 255., X_train_full[5000:] / 255. y_valid, y_train = y_train_full[:5000], y_train_full[5000:] X_test = X_test / 255. # Ta có thể biểu diễn hình ảnh này sử dụng hàm `imshow()` của Matplotlib, với bản đồ màu `binary`: # In[16]: plt.imshow(X_train[0], cmap="binary") plt.axis('off') plt.show() # Nhãn là ID của lớp (biểu diễn dưới kiểu uint8), từ 0 tới 9: # In[17]: y_train # Dưới đây là tên của các lớp tương ứng: # In[18]: class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"] # Vậy nên hình ảnh đầu tiên trong tập huấn luyện là một cái áo khoác (coat): # In[19]: class_names[y_train[0]] # Tập kiểm định chứa 5.000 hình ảnh và tập kiểm tra chứa 10.000 hình ảnh: # In[20]: X_valid.shape # In[21]: X_test.shape # Hãy xem một ví dụ các hình ảnh trong tập dữ liệu: # In[22]: n_rows = 4 n_cols = 10 plt.figure(figsize=(n_cols * 1.2, n_rows * 1.2)) for row in range(n_rows): for col in range(n_cols): index = n_cols * row + col plt.subplot(n_rows, n_cols, index + 1) plt.imshow(X_train[index], cmap="binary", interpolation="nearest") plt.axis('off') plt.title(class_names[y_train[index]], fontsize=12) plt.subplots_adjust(wspace=0.2, hspace=0.5) save_fig('fashion_mnist_plot', tight_layout=False) plt.show() # In[23]: model = keras.models.Sequential() model.add(keras.layers.Flatten(input_shape=[28, 28])) model.add(keras.layers.Dense(300, activation="relu")) model.add(keras.layers.Dense(100, activation="relu")) model.add(keras.layers.Dense(10, activation="softmax")) # In[24]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[25]: model = keras.models.Sequential([ keras.layers.Flatten(input_shape=[28, 28]), keras.layers.Dense(300, activation="relu"), keras.layers.Dense(100, activation="relu"), keras.layers.Dense(10, activation="softmax") ]) # In[26]: model.layers # In[27]: model.summary() # In[28]: keras.utils.plot_model(model, "my_fashion_mnist_model.png", show_shapes=True) # In[29]: hidden1 = model.layers[1] hidden1.name # In[30]: model.get_layer(hidden1.name) is hidden1 # In[31]: weights, biases = hidden1.get_weights() # In[32]: weights # In[33]: weights.shape # In[34]: biases # In[35]: biases.shape # In[36]: model.compile(loss="sparse_categorical_crossentropy", optimizer="sgd", metrics=["accuracy"]) # Điều này tương đương với: # ```python # model.compile(loss=keras.losses.sparse_categorical_crossentropy, # optimizer=keras.optimizers.SGD(), # metrics=[keras.metrics.sparse_categorical_accuracy]) # ``` # In[37]: history = model.fit(X_train, y_train, epochs=30, validation_data=(X_valid, y_valid)) # In[38]: history.params # In[39]: print(history.epoch) # In[40]: history.history.keys() # In[41]: import pandas as pd pd.DataFrame(history.history).plot(figsize=(8, 5)) plt.grid(True) plt.gca().set_ylim(0, 1) save_fig("keras_learning_curves_plot") plt.show() # In[42]: model.evaluate(X_test, y_test) # In[43]: X_new = X_test[:3] y_proba = model.predict(X_new) y_proba.round(2) # **Cảnh báo**: `model.predict_classes(X_new)` không còn được sử dụng nữa. Nó được thay thế bằng `np.argmax(model.predict(X_new), axis=-1)`. # In[44]: #y_pred = model.predict_classes(X_new) # deprecated y_pred = np.argmax(model.predict(X_new), axis=-1) y_pred # In[45]: np.array(class_names)[y_pred] # In[46]: y_new = y_test[:3] y_new # In[47]: plt.figure(figsize=(7.2, 2.4)) for index, image in enumerate(X_new): plt.subplot(1, 3, index + 1) plt.imshow(image, cmap="binary", interpolation="nearest") plt.axis('off') plt.title(class_names[y_test[index]], fontsize=12) plt.subplots_adjust(wspace=0.2, hspace=0.5) save_fig('fashion_mnist_images_plot', tight_layout=False) plt.show() # # MLP Hồi quy # Hãy tải, phân tách và chia tỷ lệ tập dữ liệu nhà ở California (bản gốc, không phải bản sửa đổi như trong chương 2): # In[48]: from sklearn.datasets import fetch_california_housing from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler housing = fetch_california_housing() X_train_full, X_test, y_train_full, y_test = train_test_split(housing.data, housing.target, random_state=42) X_train, X_valid, y_train, y_valid = train_test_split(X_train_full, y_train_full, random_state=42) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_valid = scaler.transform(X_valid) X_test = scaler.transform(X_test) # In[49]: np.random.seed(42) tf.random.set_seed(42) # In[50]: model = keras.models.Sequential([ keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]), keras.layers.Dense(1) ]) model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) history = model.fit(X_train, y_train, epochs=20, validation_data=(X_valid, y_valid)) mse_test = model.evaluate(X_test, y_test) X_new = X_test[:3] y_pred = model.predict(X_new) # In[51]: plt.plot(pd.DataFrame(history.history)) plt.grid(True) plt.gca().set_ylim(0, 1) plt.show() # In[52]: y_pred # # Functional API # Không phải tất cả các mô hình mạng nơ-ron đều đơn giản là tuần tự. Một số có thể có cấu trúc liên kết phức tạp. Một số có thể có nhiều đầu vào và/hoặc nhiều đầu ra. Ví dụ: mạng nơ-ron Rộng & Sâu (xem [bài báo](https://ai.google/research/pubs/pub45413)) kết nối trực tiếp tất cả hoặc một phần đầu vào với tầng đầu ra. # In[53]: np.random.seed(42) tf.random.set_seed(42) # In[54]: input_ = keras.layers.Input(shape=X_train.shape[1:]) hidden1 = keras.layers.Dense(30, activation="relu")(input_) hidden2 = keras.layers.Dense(30, activation="relu")(hidden1) concat = keras.layers.concatenate([input_, hidden2]) output = keras.layers.Dense(1)(concat) model = keras.models.Model(inputs=[input_], outputs=[output]) # In[55]: model.summary() # In[56]: model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) history = model.fit(X_train, y_train, epochs=20, validation_data=(X_valid, y_valid)) mse_test = model.evaluate(X_test, y_test) y_pred = model.predict(X_new) # Điều gì sẽ xảy ra nếu bạn muốn gửi các tập hợp con khác nhau của các đặc trưng đầu vào thông qua các đường dẫn rộng hoặc sâu? Chúng ta sẽ gửi 5 đặc trưng (đặc trưng 0 đến 4) và 6 thông qua đường dẫn sâu (đặc trưng 2 đến 7). Lưu ý rằng cả ba đặc trưng sẽ đi qua cả hai (đặc trưng 2, 3 và 4). # In[57]: np.random.seed(42) tf.random.set_seed(42) # In[58]: input_A = keras.layers.Input(shape=[5], name="wide_input") input_B = keras.layers.Input(shape=[6], name="deep_input") hidden1 = keras.layers.Dense(30, activation="relu")(input_B) hidden2 = keras.layers.Dense(30, activation="relu")(hidden1) concat = keras.layers.concatenate([input_A, hidden2]) output = keras.layers.Dense(1, name="output")(concat) model = keras.models.Model(inputs=[input_A, input_B], outputs=[output]) # In[59]: model.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) X_train_A, X_train_B = X_train[:, :5], X_train[:, 2:] X_valid_A, X_valid_B = X_valid[:, :5], X_valid[:, 2:] X_test_A, X_test_B = X_test[:, :5], X_test[:, 2:] X_new_A, X_new_B = X_test_A[:3], X_test_B[:3] history = model.fit((X_train_A, X_train_B), y_train, epochs=20, validation_data=((X_valid_A, X_valid_B), y_valid)) mse_test = model.evaluate((X_test_A, X_test_B), y_test) y_pred = model.predict((X_new_A, X_new_B)) # Thêm một đầu ra phụ trợ cho mục đích điểu chuẩn: # In[60]: np.random.seed(42) tf.random.set_seed(42) # In[61]: input_A = keras.layers.Input(shape=[5], name="wide_input") input_B = keras.layers.Input(shape=[6], name="deep_input") hidden1 = keras.layers.Dense(30, activation="relu")(input_B) hidden2 = keras.layers.Dense(30, activation="relu")(hidden1) concat = keras.layers.concatenate([input_A, hidden2]) output = keras.layers.Dense(1, name="main_output")(concat) aux_output = keras.layers.Dense(1, name="aux_output")(hidden2) model = keras.models.Model(inputs=[input_A, input_B], outputs=[output, aux_output]) # In[62]: model.compile(loss=["mse", "mse"], loss_weights=[0.9, 0.1], optimizer=keras.optimizers.SGD(learning_rate=1e-3)) # In[63]: history = model.fit([X_train_A, X_train_B], [y_train, y_train], epochs=20, validation_data=([X_valid_A, X_valid_B], [y_valid, y_valid])) # In[64]: total_loss, main_loss, aux_loss = model.evaluate( [X_test_A, X_test_B], [y_test, y_test]) y_pred_main, y_pred_aux = model.predict([X_new_A, X_new_B]) # # Subclassing API # In[65]: class WideAndDeepModel(keras.models.Model): def __init__(self, units=30, activation="relu", **kwargs): super().__init__(**kwargs) self.hidden1 = keras.layers.Dense(units, activation=activation) self.hidden2 = keras.layers.Dense(units, activation=activation) self.main_output = keras.layers.Dense(1) self.aux_output = keras.layers.Dense(1) def call(self, inputs): input_A, input_B = inputs hidden1 = self.hidden1(input_B) hidden2 = self.hidden2(hidden1) concat = keras.layers.concatenate([input_A, hidden2]) main_output = self.main_output(concat) aux_output = self.aux_output(hidden2) return main_output, aux_output model = WideAndDeepModel(30, activation="relu") # In[66]: model.compile(loss="mse", loss_weights=[0.9, 0.1], optimizer=keras.optimizers.SGD(learning_rate=1e-3)) history = model.fit((X_train_A, X_train_B), (y_train, y_train), epochs=10, validation_data=((X_valid_A, X_valid_B), (y_valid, y_valid))) total_loss, main_loss, aux_loss = model.evaluate((X_test_A, X_test_B), (y_test, y_test)) y_pred_main, y_pred_aux = model.predict((X_new_A, X_new_B)) # # Lưu trữ và Khôi phục # In[68]: np.random.seed(42) tf.random.set_seed(42) # In[69]: model = keras.models.Sequential([ keras.layers.Dense(30, activation="relu", input_shape=[8]), keras.layers.Dense(30, activation="relu"), keras.layers.Dense(1) ]) # In[70]: model.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) history = model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid)) mse_test = model.evaluate(X_test, y_test) # In[71]: model.save("my_keras_model.h5") # In[72]: model = keras.models.load_model("my_keras_model.h5") # In[73]: model.predict(X_new) # In[74]: model.save_weights("my_keras_weights.ckpt") # In[75]: model.load_weights("my_keras_weights.ckpt") # # Sử dụng Callback trong Huấn luyện # In[76]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[77]: model = keras.models.Sequential([ keras.layers.Dense(30, activation="relu", input_shape=[8]), keras.layers.Dense(30, activation="relu"), keras.layers.Dense(1) ]) # In[78]: model.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.h5", save_best_only=True) history = model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb]) model = keras.models.load_model("my_keras_model.h5") # rollback to best model mse_test = model.evaluate(X_test, y_test) # In[79]: model.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) early_stopping_cb = keras.callbacks.EarlyStopping(patience=10, restore_best_weights=True) history = model.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb, early_stopping_cb]) mse_test = model.evaluate(X_test, y_test) # In[80]: class PrintValTrainRatioCallback(keras.callbacks.Callback): def on_epoch_end(self, epoch, logs): print("\nval/train: {:.2f}".format(logs["val_loss"] / logs["loss"])) # In[81]: val_train_ratio_cb = PrintValTrainRatioCallback() history = model.fit(X_train, y_train, epochs=1, validation_data=(X_valid, y_valid), callbacks=[val_train_ratio_cb]) # # TensorBoard # In[82]: root_logdir = os.path.join(os.curdir, "my_logs") # In[83]: def get_run_logdir(): import time run_id = time.strftime("run_%Y_%m_%d-%H_%M_%S") return os.path.join(root_logdir, run_id) run_logdir = get_run_logdir() run_logdir # In[84]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[85]: model = keras.models.Sequential([ keras.layers.Dense(30, activation="relu", input_shape=[8]), keras.layers.Dense(30, activation="relu"), keras.layers.Dense(1) ]) model.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=1e-3)) # In[86]: tensorboard_cb = keras.callbacks.TensorBoard(run_logdir) history = model.fit(X_train, y_train, epochs=30, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb, tensorboard_cb]) # Để khởi động máy chủ TensorBoard, một tùy chọn là sử dụng terminal, nếu cần, hãy kích hoạt virtualenv nơi bạn đã cài đặt TensorBoard, đi tới thư mục của notebook này, sau đó nhập: # # ```bash # $ tensorboard --logdir=./my_logs --port=6006 # ``` # # Sau đó, bạn có thể mở trình duyệt web của mình với địa chỉ [localhost:6006](http://localhost:6006) và sử dụng TensorBoard. Khi bạn đã hoàn tất, hãy nhấn Ctrl-C trong cửa sổ đầu cuối, thao tác này sẽ tắt máy chủ TensorBoard. # # Ngoài ra, bạn có thể tải tiện ích mở rộng Jupyter của TensorBoard và chạy nó như thế này: # In[87]: get_ipython().run_line_magic('load_ext', 'tensorboard') get_ipython().run_line_magic('tensorboard', '--logdir=./my_logs --port=6006') # In[88]: run_logdir2 = get_run_logdir() run_logdir2 # In[89]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[90]: model = keras.models.Sequential([ keras.layers.Dense(30, activation="relu", input_shape=[8]), keras.layers.Dense(30, activation="relu"), keras.layers.Dense(1) ]) model.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=0.05)) # In[91]: tensorboard_cb = keras.callbacks.TensorBoard(run_logdir2) history = model.fit(X_train, y_train, epochs=30, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb, tensorboard_cb]) # Lưu ý cách TensorBoard hiển thị hai lần chạy và bạn có thể so sánh các đường cong học. # Kiểm tra các tùy chọn logging có sẵn khác: # In[92]: help(keras.callbacks.TensorBoard.__init__) # # Tinh chỉnh Siêu tham số # In[93]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[94]: def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]): model = keras.models.Sequential() model.add(keras.layers.InputLayer(input_shape=input_shape)) for layer in range(n_hidden): model.add(keras.layers.Dense(n_neurons, activation="relu")) model.add(keras.layers.Dense(1)) optimizer = keras.optimizers.SGD(learning_rate=learning_rate) model.compile(loss="mse", optimizer=optimizer) return model # In[95]: keras_reg = keras.wrappers.scikit_learn.KerasRegressor(build_model) # In[96]: keras_reg.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid), callbacks=[keras.callbacks.EarlyStopping(patience=10)]) # In[97]: mse_test = keras_reg.score(X_test, y_test) # In[98]: y_pred = keras_reg.predict(X_new) # In[99]: np.random.seed(42) tf.random.set_seed(42) # **Cảnh báo**: cell dưới đây gặp lỗi ở giai đoạn cuối quá trình huấn luyện. Điều này có vẻ là do [issue Keras #13586](https://github.com/keras-team/keras/issues/13586), gây ra bởi một thay đổi gần đây trong Scikit-Learn. [Pull Request #13598](https://github.com/keras-team/keras/pull/13598) dường như đã khắc phục được sự cố, vì vậy vấn đề sẽ sớm được giải quyết. Trong thời gian chờ đợi, tôi đã thêm `.tolist()` và `.rvs(1000).tolist()` làm giải pháp thay thế. # In[100]: from scipy.stats import reciprocal from sklearn.model_selection import RandomizedSearchCV param_distribs = { "n_hidden": [0, 1, 2, 3], "n_neurons": np.arange(1, 100) .tolist(), "learning_rate": reciprocal(3e-4, 3e-2) .rvs(1000).tolist(), } rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3, verbose=2) rnd_search_cv.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid), callbacks=[keras.callbacks.EarlyStopping(patience=10)]) # In[101]: rnd_search_cv.best_params_ # In[102]: rnd_search_cv.best_score_ # In[103]: rnd_search_cv.best_estimator_ # In[104]: rnd_search_cv.score(X_test, y_test) # In[105]: model = rnd_search_cv.best_estimator_.model model # In[106]: model.evaluate(X_test, y_test) # # Lời giải bài tập # ## 1. đến 9. # Tham khảo phụ lục A. # ## 10. # *Bài tập: Huấn luyện MLP sâu trên tập dữ liệu MNIST (bạn có thể tải nó bằng cách sử dụng `keras.datasets.mnist.load_data()`. Hãy xem liệu bạn có thể đạt được độ chính xác trên 98% hay không. Hãy thử tìm kiếm tốc độ học tối ưu bằng cách sử dụng phương pháp được trình bày trong chương này (như là tăng tốc độ học theo cấp số nhân, vẽ đồ thị mất mát và tìm điểm mà tại đó mất mát tăng lên). Hãy thử thêm tất cả các điểm lưu trữ (checkpoint), sử dụng tính năng dừng sớm và vẽ đồ thị đường cong học bằng TensorBoard.* # Nạp tập dữ liệu: # In[107]: (X_train_full, y_train_full), (X_test, y_test) = keras.datasets.mnist.load_data() # Giống như đối với tập dữ liệu Fashion MNIST, tập huấn luyện MNIST chứa 60,000 hình ảnh thang độ xám, mỗi hình ảnh có kích thước 28x28 pixel: # In[108]: X_train_full.shape # Mỗi cường độ pixel cũng được biểu diễn dưới kiểu byte (0 đến 255): # In[109]: X_train_full.dtype # Hãy chia toàn bộ tập huấn luyện thành một tập kiểm định và một tập huấn luyện (nhỏ hơn). Ta cũng tỷ lệ hóa cường độ pixel xuống trong khoảng 0-1 và chuyển đổi chúng thành kiểu float, bằng cách chia cho 255, giống như cách ta đã làm với Fashion MNIST: # In[110]: X_valid, X_train = X_train_full[:5000] / 255., X_train_full[5000:] / 255. y_valid, y_train = y_train_full[:5000], y_train_full[5000:] X_test = X_test / 255. # Hãy biểu diễn một hình ảnh bằng cách sử dụng phương thức `imshow()` của Matplotlib, với bản đồ màu `'nhị phân'`: # In[111]: plt.imshow(X_train[0], cmap="binary") plt.axis('off') plt.show() # Các nhãn là ID lớp (được biểu thị bằng kiểu uint8), từ 0 đến 9. Một điều khá tiện đó là là ID lớp tương ứng với các chữ số được biểu thị trong hình ảnh, vì vậy chúng ta không cần mảng `class_names`: # In[112]: y_train # Tập kiểm định chứa 5,000 hình ảnh và tập kiểm tra chứa 10,000 hình ảnh: # In[113]: X_valid.shape # In[114]: X_test.shape # Hãy xem một mẫu các hình ảnh trong tập dữ liệu: # In[115]: n_rows = 4 n_cols = 10 plt.figure(figsize=(n_cols * 1.2, n_rows * 1.2)) for row in range(n_rows): for col in range(n_cols): index = n_cols * row + col plt.subplot(n_rows, n_cols, index + 1) plt.imshow(X_train[index], cmap="binary", interpolation="nearest") plt.axis('off') plt.title(y_train[index], fontsize=12) plt.subplots_adjust(wspace=0.2, hspace=0.5) plt.show() # Hãy xây dựng một mạng dày đặc đơn giản và tìm tốc độ học tối ưu. Ta sẽ cần một callback để tăng tốc độ học sau mỗi vòng lặp. Nó cũng sẽ ghi lại tốc độ học và mất mát trong mỗi vòng lặp: # In[116]: K = keras.backend class ExponentialLearningRate(keras.callbacks.Callback): def __init__(self, factor): self.factor = factor self.rates = [] self.losses = [] def on_batch_end(self, batch, logs): self.rates.append(K.get_value(self.model.optimizer.learning_rate)) self.losses.append(logs["loss"]) K.set_value(self.model.optimizer.learning_rate, self.model.optimizer.learning_rate * self.factor) # In[117]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[118]: model = keras.models.Sequential([ keras.layers.Flatten(input_shape=[28, 28]), keras.layers.Dense(300, activation="relu"), keras.layers.Dense(100, activation="relu"), keras.layers.Dense(10, activation="softmax") ]) # Ta sẽ bắt đầu với tốc độ học nhỏ là 1e-3 và tăng giá trị này lên 0,5% sau mỗi vòng lặp: # In[119]: model.compile(loss="sparse_categorical_crossentropy", optimizer=keras.optimizers.SGD(learning_rate=1e-3), metrics=["accuracy"]) expon_lr = ExponentialLearningRate(factor=1.005) # Bây giờ hãy huấn luyện mô hình với chỉ 1 epoch: # In[120]: history = model.fit(X_train, y_train, epochs=1, validation_data=(X_valid, y_valid), callbacks=[expon_lr]) # Ta giờ đây có thể biểu diễn mất mát như là một hàm của tốc độ học: # In[121]: plt.plot(expon_lr.rates, expon_lr.losses) plt.gca().set_xscale('log') plt.hlines(min(expon_lr.losses), min(expon_lr.rates), max(expon_lr.rates)) plt.axis([min(expon_lr.rates), max(expon_lr.rates), 0, expon_lr.losses[0]]) plt.grid() plt.xlabel("Tốc độ học") plt.ylabel("Mất mát") # Mất mát bắt đầu tăng trở lại một cách dữ dội khi tốc độ học vượt quá 6e-1, vì vậy hãy thử sử dụng một nửa giá trị đó, ở mức 3e-1: # In[122]: keras.backend.clear_session() np.random.seed(42) tf.random.set_seed(42) # In[123]: model = keras.models.Sequential([ keras.layers.Flatten(input_shape=[28, 28]), keras.layers.Dense(300, activation="relu"), keras.layers.Dense(100, activation="relu"), keras.layers.Dense(10, activation="softmax") ]) # In[124]: model.compile(loss="sparse_categorical_crossentropy", optimizer=keras.optimizers.SGD(learning_rate=3e-1), metrics=["accuracy"]) # In[125]: run_index = 1 # increment this at every run run_logdir = os.path.join(os.curdir, "my_mnist_logs", "run_{:03d}".format(run_index)) run_logdir # In[126]: early_stopping_cb = keras.callbacks.EarlyStopping(patience=20) checkpoint_cb = keras.callbacks.ModelCheckpoint("my_mnist_model.h5", save_best_only=True) tensorboard_cb = keras.callbacks.TensorBoard(run_logdir) history = model.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb, early_stopping_cb, tensorboard_cb]) # In[127]: model = keras.models.load_model("my_mnist_model.h5") # rollback to best model model.evaluate(X_test, y_test) # Ta đã đạt được độ chính xác hơn 98%. Cuối cùng, hãy xem các đồ thị đường cong học bằng TensorBoard: # In[128]: get_ipython().run_line_magic('tensorboard', '--logdir=./my_mnist_logs --port=6006') # In[ ]: