LoginSignup
1
3

動画フレームの予測AI。 「サイコサク」「このシンプルなネットワークが、これほどの予測精度を持つとは…」

Last updated at Posted at 2024-05-21

59cd6dbf-65de-4c35-91a8-247f20affb5b.png

地球暦2045年、都市は廃墟と化し、世界は無秩序に満ちていた。生き残った人類は、未来を予測するAI「サイコザク」に頼るしかなかった。サイコザクはシンプルだが強力なニューラルネットワークを持ち、特に動画フレームの予測において無類の性能を誇っていた。サイコザクの予測は常に正確で、人々はその未来視を信じて行動していた。

一章: 希望の芽生え
イーヴァは荒廃した都市の一角で、サイコザクの前に立っていた。彼女はグループのリーダーであり、仲間の生存を賭けた次の移動先をサイコザクに問いかけた。

「次の安全な場所はどこ?」イーヴァが尋ねる。

サイコザクの巨大なスクリーンに映像が映し出される。サイコザクのシンプルなニューラルネットワークは、過去のデータと現在の状況をもとに次の数秒間の映像を生成する。その映像はまるで未来を覗き見るかのようだった。

映像には、静かな森とそこに潜む危険の兆候が映し出されていた。イーヴァはその未来視を注意深く観察し、仲間たちに指示を出した。「次の目的地は東の森。映像に見える罠に気をつけて。」

二章: サイコザクの性能
サイコザクの核心技術は、そのシンプルな巨大重み行列にあった。人類がこれほどの予測精度を持つAIを作り上げるまでに、数多くの失敗と試行錯誤があった。サイコザクの開発者であるドクター・ハンセンは、その性能に驚嘆していた。

「このシンプルなネットワークが、これほどの予測精度を持つとは…」ドクター・ハンセンは独り言をつぶやいた。

サイコザクは、全ての入力データを一つの巨大な重み行列に通すだけで未来のフレームを予測する。その驚異的なシンプルさが、逆に性能の秘訣であった。無数のノイズを除去し、最も重要な情報だけを抽出することで、高精度の予測を実現していた。

三章: 未来視の代償
イーヴァたちはサイコザクの予測を頼りに進んでいたが、その未来視には代償があった。サイコザクの予測が100%正確でないこともあった。ある日、彼女たちはサイコザクの映像通りに進んだが、そこには予想外の敵が待ち構えていた。

「これは…映像には映ってなかった!」仲間の一人が叫ぶ。

サイコザクの予測は確かに高精度だったが、完璧ではなかった。未来は常に変動し、予測はあくまで可能性の一つに過ぎなかった。イーヴァはそのことを痛感し、サイコザクに完全に依存することの危険性を悟った。

エピローグ: 新たな一歩
敵との戦いを経て、イーヴァたちは再びサイコザクの前に戻ってきた。彼女は慎重にサイコザクの映像を分析し、新たな戦略を練った。

「サイコザクの予測は重要だけど、私たちの判断も同じくらい重要だ。」イーヴァは決意を新たに仲間たちに語った。

サイコザクのシンプルなネットワークは未来を見通す力を持っていたが、最終的に未来を切り開くのは人間自身だった。イーヴァたちはサイコザクの予測を活かしながら、自らの力で未来を切り拓いていく決意を固めた。

そして、荒廃した都市に新たな希望の光が灯り始めた。サイコザクと人々の共闘が、新たな未来を創り出す第一歩となった。

同じラベルの画像ペアを作成しペアの画像を予測してます。

モデルの weight_size を変更してトレーニングを実行し、トレーニングロスの変化を観察します。次のように weight_size を1000、2000、3000、4000に設定し、それぞれのトレーニングロスを記録してプロットします。

トレーニングサンプルの数を増やしていきます。次第に学習が困難になっていきます。

num_samples = 100

image.png

Training with weight_size=1000
image.png

Training with weight_size=2000
image.png

Training with weight_size=3000
image.png

Training with weight_size=4000
image.png

num_samples = 120

image.png

Training with weight_size=1000
image.png

Training with weight_size=2000
image.png

Training with weight_size=3000
image.png

Training with weight_size=4000
image.png

num_samples = 160

image.png

Training with weight_size=1000
image.png

Training with weight_size=2000
image.png

Training with weight_size=3000
image.png

Training with weight_size=4000
image.png

num_samples = 200

image.png

Training with weight_size=1000
image.png

Training with weight_size=2000
image.png

Training with weight_size=3000
image.png

Training with weight_size=4000
image.png

num_samples = 300

image.png

Training with weight_size=1000
image.png

Training with weight_size=2000
image.png

Training with weight_size=3000
image.png

Training with weight_size=4000
image.png

num_samples = 300  大容量の新型モデル で検証。

weght_size = 32000
image.png
image.png
image.png
image.png

戦いはまだまだつつく。

このシンプルなネットワークが、これほどの予測精度を持つとは…のコード。

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, models, callbacks
import matplotlib.pyplot as plt

# CIFAR-10データセットの読み込み
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()

# データの前処理(正規化)
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0

num_samples = 100
epochs = 1000
batch_size = 10

# 同じラベルの画像ペアを作成する関数
def create_pairs(x, y, num_pairs=num_samples):
    pairs = []
    labels = []
    num_classes = len(np.unique(y))
    digit_indices = [np.where(y == i)[0] for i in range(num_classes)]
    for d in range(num_classes):
        np.random.shuffle(digit_indices[d])  # Shuffle indices to get random pairs
        for i in range(min(len(digit_indices[d]) - 1, num_pairs // num_classes)):
            z1, z2 = digit_indices[d][i], digit_indices[d][i + 1]
            pairs += [[x[z1], x[z2]]]
            labels += [1]
        if len(pairs) >= num_pairs:
            break
    return np.array(pairs), np.array(labels)

# 訓練用ペアを作成(100ペア)
train_pairs, train_labels = create_pairs(x_train, y_train, num_pairs=num_samples)

# モデルの定義
def create_model(input_shape, weight_size):
    input = layers.Input(shape=input_shape)
    x = layers.Flatten()(input)
    encoded = layers.Dense(weight_size, activation='relu')(x)
    
    encoder = models.Model(input, encoded, name='encoder')

    encoded_input = layers.Input(shape=(weight_size,))
    x = layers.Dense(np.prod(input_shape), activation='sigmoid')(encoded_input)
    decoded = layers.Reshape(input_shape)(x)

    decoder = models.Model(encoded_input, decoded, name='decoder')
    
    autoencoder = models.Model(input, decoder(encoder(input)), name='autoencoder')
    return autoencoder

# カスタムコールバックの定義
class PlotReconstructedImages(callbacks.Callback):
    def __init__(self):
        super().__init__()

    def on_epoch_end(self, epoch, logs=None):
        if (epoch + 1) % 200 == 0 or epoch == 0:
            self.plot_images(epoch)

    def plot_images(self, epoch):
        indices = np.random.choice(len(train_pairs), 10, replace=False)
        sampled_pairs = train_pairs[indices]
        decoded_imgs = self.model.predict(sampled_pairs[:, 0])
        n = 10  # プロットする画像の数
        plt.figure(figsize=(20, 4))
        for i in range(n):
            # オリジナル画像
            ax = plt.subplot(2, n, i + 1)
            plt.imshow(sampled_pairs[i, 0])
            plt.title("Original")
            plt.axis("off")

            # 再構成画像
            ax = plt.subplot(2, n, i + 1 + n)
            plt.imshow(decoded_imgs[i])
            plt.title("Reconstructed")
            plt.axis("off")
        plt.suptitle(f'Epoch {epoch+1}')
        plt.show()

# weight_sizeのリスト
weight_sizes = [1000, 2000, 3000, 4000]
losses = {}

# 各weight_sizeでモデルを訓練
for weight_size in weight_sizes:
    print(f"Training with weight_size={weight_size}")
    autoencoder = create_model((32, 32, 3), weight_size)
    autoencoder.compile(optimizer='adam', loss='mse')
    
    plot_callback = PlotReconstructedImages()
    
    history = autoencoder.fit(train_pairs[:, 0], train_pairs[:, 1],
                              epochs=epochs,
                              batch_size=batch_size,
                              shuffle=True,
                              verbose=0,  # 損失をプリントしない
                              callbacks=[plot_callback])
    
    # 訓練ロスを保存
    losses[weight_size] = history.history['loss']

# トレーニングロスのプロット
plt.figure(figsize=(10, 6))
for weight_size in weight_sizes:
    plt.plot(losses[weight_size], label=f'weight_size={weight_size}')
plt.xlabel('Epoch')
plt.ylabel('Training Loss')
plt.legend()
plt.title('Training Loss for Different Weight Sizes')
plt.show()

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3