图像回归的模型结构

问题描述 投票:0回答:1

我正在尝试构建一个用于分析棋盘游戏的张量流模型,因此我从一个更简单的 2D 数据集开始。我生成了 1000 个黑色半圆图像,如下所示:

我认为尝试恢复平面的角度是一个很好的练习。我将这两个示例图像标记为 210.474° 和 147.593°。

不幸的是,我得到的结果很糟糕。对测试数据的所有预测大约为 180°,大概接近标签的平均值。

任何人都可以给我关于如何改进模型架构或以其他方式改进结果的建议吗?如果所有输入数据都是布尔像素,我需要对其进行标准化吗?

我创建这样的模型:

def build_and_compile_model():
    num_channels = 200
    kernel_size = 3
    image_height = 64
    image_width = 64
    regularizer = regularizers.l2(0.0001)

    model = keras.Sequential(
        [layers.Conv2D(num_channels,
                       kernel_size,
                       padding='same',
                       activation='relu',
                       input_shape=(image_height, image_width, 1),
                       activity_regularizer=regularizer),
         layers.Dense(64, activation='relu'),
         layers.Dense(64, activation='relu'),
         layers.Dense(1)])

    model.compile(loss='mean_absolute_error',
                  optimizer=tf.keras.optimizers.Adam(0.001))
    return model

当我尝试拟合模型时,它会改进几个时期,然后稳定在高误差。

这是完整的示例:

import math
import shutil
import typing
from datetime import datetime
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from PIL import Image, ImageDraw
import tensorflow as tf
from space_tracer import LivePillowImage
from tensorflow import keras
from tensorflow.python.keras import layers, regularizers


def build_and_compile_model():
    num_channels = 200
    kernel_size = 3
    image_height = 64
    image_width = 64
    regularizer = regularizers.l2(0.0001)

    model = keras.Sequential(
        [layers.Conv2D(num_channels,
                       kernel_size,
                       padding='same',
                       activation='relu',
                       input_shape=(image_height, image_width, 1),
                       activity_regularizer=regularizer),
         layers.Dense(64, activation='relu'),
         layers.Dense(64, activation='relu'),
         layers.Dense(1)])

    model.compile(loss='mean_absolute_error',
                  optimizer=tf.keras.optimizers.Adam(0.001))
    return model


def main():
    image_folder = Path(__file__).parent / 'circle_images'
    num_images = 1000
    image_data, label_data = read_input_data(num_images, image_folder)

    # Make NumPy printouts easier to read.
    np.set_printoptions(precision=3, suppress=True)

    image_count = image_data.shape[0]
    image_data = image_data.reshape(image_data.shape + (1, ))

    train_size = math.floor(image_count * 0.8)
    train_dataset = image_data[:train_size, :, :]
    test_dataset = image_data[train_size:, :, :]
    train_labels = label_data[:train_size]
    test_labels = label_data[train_size:]

    test_results = {}

    dnn_model = build_and_compile_model()

    print('training dataset:', train_dataset.shape)
    print('training labels:', train_labels.shape)

    start = datetime.now()
    history = dnn_model.fit(
        train_dataset,
        train_labels,
        validation_split=0.2,
        verbose=0, epochs=25)
    print('Trained for', datetime.now() - start)

    test_results['dnn_model'] = dnn_model.evaluate(test_dataset, test_labels, verbose=0)
    print(pd.DataFrame(test_results, index=['Mean absolute error [game value]']).T)

    test_predictions = dnn_model.predict(test_dataset).flatten()
    print(test_labels[:10])
    print(test_predictions[:10])

    plot_loss(history)


def create_images(num_images: int, image_folder: Path) -> None:
    print(f'Creating {num_images} images.')
    image_folder.mkdir()
    start_angles = np.random.random(num_images)
    start_angles *= 360
    rng = np.random.default_rng()
    rng.shuffle(start_angles)
    for i, start_angle in enumerate(start_angles):
        image_path = image_folder / f'image{i}.png'
        image = create_image(start_angle)
        image.save(image_path)
    label_text = '\n'.join(str(start_angle) for start_angle in start_angles)
    (image_folder / 'labels.csv').write_text(label_text)


def create_image(start_angle: float) -> Image.Image:
    image = Image.new('1', (64, 64))  # B&W 64x64
    drawing = ImageDraw.Draw(image)
    drawing.rectangle((0, 0, 64, 64), fill='white')
    drawing.pieslice(((0, 0), (63, 63)),
                     -start_angle,
                     -start_angle+180,
                     fill='black')
    return image


def read_input_data(num_images: int, image_folder: Path) -> typing.Tuple[
        np.ndarray,
        np.ndarray]:
    """ Read input data from the image folder.

    :returns: (images, labels)
    """
    labels = []
    if image_folder.exists():
        with (image_folder / 'labels.csv').open() as f:
            for line in f:
                labels.append(float(line))
    image_count = len(labels)
    if image_count != num_images:
        # Size has changed, so recreate the input data.
        shutil.rmtree(image_folder, ignore_errors=True)
        create_images(num_images, image_folder)
        return read_input_data(num_images, image_folder)
    label_data = np.array(labels)
    images = np.zeros((image_count, 64, 64))
    for i, image_path in enumerate(sorted(image_folder.glob('*.png'))):
        image = Image.open(image_path)
        bits = np.array(image)
        images[i, :, :] = bits
    return images, label_data


def plot_loss(history):
    plt.plot(history.history['loss'], label='loss')
    plt.plot(history.history['val_loss'], label='val_loss')
    plt.ylim(bottom=0)
    plt.xlabel('Epoch')
    plt.ylabel('Error [angle]')
    plt.legend()
    plt.grid(True)
    plt.show()


def demo():
    image = create_image(226.634)
    LivePillowImage(image).display()


if __name__ == '__main__':
    main()
elif __name__ == '__live_coding__':
    demo()

最后,我看到这个输出:

Trained for 0:00:09.155005
           Mean absolute error [game value]
dnn_model                         92.051697
7/7 [==============================] - 0s 4ms/step
[210.474 147.593 327.796 120.112 163.402 178.04  333.604 342.488 119.694
 240.8  ]
[177.15  181.242 181.242 181.242 181.242 181.242 181.242 181.242 181.242
 181.242]

可以看到所有的预测都接近180°。

python tensorflow machine-learning deep-learning neural-network
1个回答
0
投票

制作更深的模型

model = keras.Sequential(
    [layers.Conv2D(32,
                   3,
                   padding='same',
                   activation='relu',
                   input_shape=(image_height, image_width, 1),
                   activity_regularizer=regularizer),
     layers.Conv2D(64,
                   3,
                   padding='same',
                   activation='relu',
                   input_shape=(image_height, image_width, 1),
                   activity_regularizer=regularizer),
     layers.Dense(128, activation='relu'),
     layers.Dense(64, activation='relu'),
     layers.Dense(1)])
© www.soinside.com 2019 - 2024. All rights reserved.