Skip to content
Rain Hu's Workspace
Go back

[AI] 普適化

Rain Hu

機器學習最重要的兩件事是:

  1. 準確的模型評估
  2. 訓練次數與普適化之間的平衡

普適化(generalization)

overfitting

模糊特徵

就像是下面的三杯一樣的水,由不同的人來 label,也會 label 出不一樣的答案。 wafer

罕見特徵(rare feature)與虛假關聯(spurious correlation)

from tensorflow.keras.datasets import mnist
import numpy as np

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

train_images = train_images.reshape((60000, 28*28))
train_images = train_images.astype("float32") / 255

train_images_with_noise = np.concatenate(
    [train_images, np.random.random((len(train_images), 784))], axis=1
)
train_images_with_zeros = np.concatenate(
    [train_images, np.zeros((len(train_images), 784))], axis=1
)
from tensorflow import keras
from tensorflow.keras import layers

def build_model():
    model = keras.Sequential([
        layers.Dense(512, activation="relu"),
        layers.Dense(10, activation="softmax")
    ])

    model.compile(
        optimizer="rmsprop",
        loss="sparse_categorical_crossentropy",
        metrics=["accuracy"])
    return model

model = build_model()
history_noise = model.fit(train_images_with_noise, train_labels, epochs=10, batch_size=128, validation_split=0.2)
history_zeros = model.fit(train_images_with_zeros, train_labels, epochs=10, batch_size=128, validation_split=0.2)
import matplotlib.pyplot as plt
val_acc_noise = history_noise.history["val_accuracy"]
val_acc_zeros = history_zeros.history["val_accurarc"]
epochs = range(1, 11)
plt.plot(epochs, val_acc_noise, "b-", label="data with noise")
plt.plot(epochs, val_acc_zeros, "r-", label="data with zeros")
plt.title("Effect of noise channels on validtaion accuracy")
plt.xlabel("Epochs")
plt.ylabel("Validation accuracy")
plt.legend()

loss_curve

普適化的本質

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist
import numpy as np
 
(train_images, train_labels), _ = mnist.load_data()
train_images = train_images.reshape((60000, 28*28))
train_images = train_images.astype("float32")/255

random_train_labels = train_labels[:]
np.random.shuffle(random_train_labels)

model = keras.models.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(10, activation="softmax")
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
history = model.fit(train_images, random_train_labels, epochs=100,batch_size=128,validation_split=0.2)

import matplotlib.pyplot as plt
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

random_label_test

流形假說(manifold hypothesis)

流形概念例子
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist

# 載入 MNIST 數據
(x_train, y_train), _ = mnist.load_data()
x_train = x_train.astype('float32') / 255.

# 找出數字 1 和 7 的例子
digit_1 = x_train[y_train == 1][0]
digit_7 = x_train[y_train == 7][0]

# 創建中間過渡圖片
steps = 5
transitions = []
for i in range(steps):
    alpha = i / (steps-1)
    # 簡單的線性混合
    mixed = digit_1 * (1-alpha) + digit_7 * alpha
    transitions.append(mixed)

# 顯示結果
plt.figure(figsize=(12, 3))
for i in range(steps):
    plt.subplot(1, steps, i+1)
    plt.imshow(transitions[i], cmap='gray')
    plt.axis('off')
plt.suptitle('transition of number 1 to 7')
plt.show()

manifold

以內插法作為普適化的基礎

內插法程式
import tensorflow as tf
from tensorflow.keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt

# 載入 MNIST 數據集
(x_train, y_train), _ = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_train_reshaped = x_train.reshape(-1, 28, 28, 1)

# 建立編碼器
encoder_input = tf.keras.Input(shape=(28, 28, 1))
x = tf.keras.layers.Flatten()(encoder_input)
x = tf.keras.layers.Dense(128, activation='relu')(x)
x = tf.keras.layers.Dense(64, activation='relu')(x)
latent = tf.keras.layers.Dense(32, activation='relu')(x)
encoder = tf.keras.Model(encoder_input, latent, name='encoder')

# 建立解碼器
decoder_input = tf.keras.Input(shape=(32,))
x = tf.keras.layers.Dense(64, activation='relu')(decoder_input)
x = tf.keras.layers.Dense(128, activation='relu')(x)
x = tf.keras.layers.Dense(784, activation='sigmoid')(x)
decoder_output = tf.keras.layers.Reshape((28, 28, 1))(x)
decoder = tf.keras.Model(decoder_input, decoder_output, name='decoder')

# 建立完整的自編碼器
autoencoder_input = tf.keras.Input(shape=(28, 28, 1))
encoded = encoder(autoencoder_input)
decoded = decoder(encoded)
autoencoder = tf.keras.Model(autoencoder_input, decoded, name='autoencoder')

# 編譯和訓練
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
history = autoencoder.fit(x_train_reshaped, x_train_reshaped,
                         epochs=20,
                         batch_size=256,
                         shuffle=True,
                         validation_split=0.2)

# 選擇兩張不同的數字圖片
img1 = x_train_reshaped[y_train == 2][0:1]  # 選擇一個 2
img2 = x_train_reshaped[y_train == 7][0:1]  # 選擇一個 7

# 生成線性內插
def linear_interpolation(img1, img2, num_steps=5):
    alphas = np.linspace(0, 1, num_steps)
    images = []
    for alpha in alphas:
        interpolated = img1 * (1 - alpha) + img2 * alpha
        images.append(interpolated[0])
    return np.array(images)

# 生成流形內插
def manifold_interpolation(img1, img2, num_steps=5):
    # 獲取潛在表示
    latent1 = encoder.predict(img1)
    latent2 = encoder.predict(img2)
    
    # 在潛在空間中內插
    alphas = np.linspace(0, 1, num_steps)
    images = []
    for alpha in alphas:
        interpolated_latent = latent1 * (1 - alpha) + latent2 * alpha
        # 使用解碼器重建圖片
        decoded_img = decoder.predict(interpolated_latent)
        images.append(decoded_img[0])
    return np.array(images)

# 生成內插序列
linear_imgs = linear_interpolation(img1, img2)
manifold_imgs = manifold_interpolation(img1, img2)

# 顯示結果
plt.figure(figsize=(15, 6))

# 顯示線性內插
plt.subplot(2, 1, 1)
plt.title('linear interpolation')
for i in range(5):
    plt.subplot(2, 5, i + 1)
    plt.imshow(linear_imgs[i].reshape(28, 28), cmap='gray')
    plt.axis('off')

# 顯示流形內插
plt.subplot(2, 1, 2)
plt.title('manifold interpolation')
for i in range(5):
    plt.subplot(2, 5, i + 6)
    plt.imshow(manifold_imgs[i].reshape(28, 28), cmap='gray')
    plt.axis('off')

plt.tight_layout()
plt.show()
+ 換言之,因為新的資料可以透過現有的資料點內插而得,代表我們可以將新資料點連結到流形上相近的其它點,進而理解這些從未見過的資料點。也就是說我們可以靠空間的有限樣本來理解空間的整體性,做法是透過內插法來填滿其中的空白。以下是我的想像示意圖。 ![imagine](/ai/5_1/imagine.png)

為何深度學習能運作

訓練資料的處理


Share this post on:

Previous
[AI] 評估模型
Next
[AI] 迴歸問題