Keras教程:如何开始使用Keras,Deep Learning和Python
几乎每个介绍Keras"入门"的指南,都会用keras内置的数据集来做例子。往往,我们跟着“指南”学完了教程,仍然无法使用自己的图片数据集来训练自己的模型。所以有了这篇博客Keras Tutorial: How to get started with Keras, Deep Learning, and Python

对于大数据集,可以参考以下博客:

  1. https://medium.com/datadriveninvestor/keras-training-on-large-datasets-3e9d9dbc09d4
  2. https://github.com/keras-team/keras/issues/107#issuecomment-100585794

我的实现

自定义数据生成器

#! -*- coding: utf-8 -*-
from skimage.io import imread
from skimage.transform import resize
from tensorflow import keras as k
from PIL import Image
import numpy as np
import random
import math


class MyGenerator(k.utils.Sequence):
    def __init__(self, filename, batch_size, shuffle, size):
        self.filename = filename
        self.batch_size = batch_size
        self.shuffle = shuffle
        self.size = size
        self._init()

    def _init(self):
        self.items = []
        for line in open(self.filename):
            name, label = line.strip("\n").split()
            self.items.append((name, int(label)))
        if self.shuffle:
            random.shuffle(self.items)

        if isinstance(self.size, int):
            self.size = (self.size, self.size)
        elif isinstance(self.size, tuple) or isinstance(self.size, list):
            assert len(self.size) == 2

    @staticmethod
    def parse_fn(filename):
        image = Image.open(filename)
        image = image.convert("RGB")
        image = np.array(image)
        return image

    def __len__(self):
        return math.ceil(len(self.items) / float(self.batch_size))

    def __getitem__(self, idx):
        item = self.items[idx * self.batch_size: (idx + 1) * self.batch_size]
        batch_x, batch_y = zip(*item)
        # return np.array([resize(imread(filename), self.size) for filename in batch_x]), np.array(batch_y)
        return np.array([self.parse_fn(filename) for filename in batch_x]), np.array(batch_y)

    def on_epoch_end(self):
        """在每个epoch结束时,调用该函数"""
        print(" Epoch_end and reshuffle")
        random.shuffle(self.items)


if __name__ == '__main__':
    gen = MyGenerator("data/fer2013_train.txt", 64, shuffle=True, size=48)
    x, y = next(iter(gen))
    print(x.shape)
    print(y.shape)

xxx.txt内容如下:

/home/zwx/Documents/Data/fer2013/train/0/24441.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/24383.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/22685.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/10511.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/05162.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/18565.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/18715.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/05432.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/11153.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/20802.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/25642.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/19743.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/22733.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/28511.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/28526.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/25897.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/18176.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/12294.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/26549.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/28279.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/25928.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/01123.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/21576.jpg 0
/home/zwx/Documents/Data/fer2013/train/0/06442.jpg 0
....

自定义数据生成器+数据增强

#! -*- coding: utf-8 -*-
from skimage.io import imread
from skimage.transform import resize
from tensorflow import keras as k
from PIL import Image
import numpy as np
import random
import math


class MyGenerator(k.utils.Sequence):
    def __init__(self, filename, batch_size, shuffle, size, aug=None):
        self.filename = filename
        self.batch_size = batch_size
        self.shuffle = shuffle
        self.size = size
        self.aug = aug
        self._init()

    def _init(self):
        self.items = []
        for line in open(self.filename):
            name, label = line.strip("\n").split()
            self.items.append((name, int(label)))
        if self.shuffle:
            random.shuffle(self.items)

        if isinstance(self.size, int):
            self.size = (self.size, self.size)
        elif isinstance(self.size, tuple) or isinstance(self.size, list):
            assert len(self.size) == 2

    def parse_fn(self, filename):
        image = Image.open(filename)
        image = image.resize(self.size)
        image = image.convert("RGB")
        image = np.array(image)
        return image

    def __len__(self):
        return math.ceil(len(self.items) / float(self.batch_size))

    def __getitem__(self, idx):
        item = self.items[idx * self.batch_size: (idx + 1) * self.batch_size]
        batch_x, batch_y = zip(*item)
        # return np.array([resize(imread(filename), self.size) for filename in batch_x]), np.array(batch_y)
        batch_x = np.array([self.parse_fn(filename) for filename in batch_x])
        batch_y = np.array(batch_y)
        if aug:
            batch_x, batch_y = next(aug.flow(batch_x, batch_y))
        return batch_x, batch_y

    def on_epoch_end(self):
        """在每个epoch结束时,调用该函数"""
        print(" Epoch_end and reshuffle")
        random.shuffle(self.items)


if __name__ == '__main__':
    # Data Generator
    aug = k.preprocessing.image.ImageDataGenerator(rotation_range=20,
                                                   zoom_range=0.15,
                                                   width_shift_range=0.2,
                                                   height_shift_range=0.2,
                                                   shear_range=0.15,
                                                   horizontal_flip=True,
                                                   fill_mode="nearest")

    gen = MyGenerator("data/fer2013_train.txt", 64, shuffle=True, size=224)
    x, y = next(iter(gen))
    print(x.shape)
    print(y.shape)

训练模型代码如下

#! -*- coding: utf-8 -*-
from tensorflow import keras as k
from dataset import MyGenerator

TRAIN_FILE = "data/fer2013_train.txt"
VAL_FILE = "data/fer2013_val.txt"
TEST_FILE = "data/fer2013_test.txt"
IMAGE_SIZE = 48
IMAGE_SHAPE = (48, 48, 3)


def main():
    train_gen = MyGenerator(TRAIN_FILE, 64, shuffle=True, size=IMAGE_SIZE)
    val_gen = MyGenerator(VAL_FILE, 128, shuffle=False, size=IMAGE_SIZE)
    # test_gen = MyGenerator(TEST_FILE, 128, shuffle=False, size=IMAGE_SIZE)
    
    # 函数式API定义模型
    inputs = k.Input(shape=(48, 48, 3))
    x = k.layers.Conv2D(32, 5, 2, "SAME", activation="relu", name="conv1")(inputs)
    x = k.layers.BatchNormalization(momentum=0.9)(x)
    print(x.shape)
    x = k.layers.MaxPool2D(2, 2, "SAME", name="pool1")(x)
    print(x.shape)
    x = k.layers.Conv2D(64, 3, 1, "SAME", activation="relu", name="conv2")(x)
    x = k.layers.BatchNormalization(momentum=0.9)(x)
    print(x.shape)
    x = k.layers.MaxPool2D(2, 2, "SAME", name="pool2")(x)
    print(x.shape)
    x = k.layers.BatchNormalization(momentum=0.9)(x)
    x = k.layers.Conv2D(128, 3, 1, "SAME", activation="relu", name="conv3")(x)
    print(x.shape)
    x = k.layers.MaxPool2D(2, 2, "SAME", name="pool3")(x)
    print(x.shape)
    x = k.layers.Flatten(name="flatten")(x)
    print(x.shape)
    x = k.layers.Dense(1024, activation="relu", name="fc1")(x)
    print(x.shape)
    x = k.layers.Dense(7, activation="softmax", name="output")(x)
    print(x.shape)
    model = k.Model(inputs, x)

    model.compile(optimizer=k.optimizers.Adam(0.001),
                  loss=k.losses.sparse_categorical_crossentropy,
                  metrics=["accuracy"])

    model.fit_generator(generator=train_gen,
                        steps_per_epoch=len(train_gen),
                        epochs=100,
                        validation_data=val_gen,
                        validation_steps=len(val_gen),
                        use_multiprocessing=True,
                        max_queue_size=32)


if __name__ == '__main__':
    main()

更新——20190516

快速训练模型,只需要下面的几十行代码

#! -*- coding: utf-8 -*-
from tensorflow import keras as k
# from skimage.io import imread
# from skimage.transform import resize
from PIL import Image
import tensorflow as tf
import numpy as np
import random
import math
import os
import shutil


class Generator(k.utils.Sequence):
    def __init__(self, filename, batch_size, shuffle, image_size):
        self.filename = filename
        self.batch_size = batch_size
        self.shuffle = shuffle
        self.image_size = image_size
        self._init()

    def _init(self):
        self.items = []
        for line in open(self.filename):
            name, label = line.strip("\n").split()
            self.items.append((name, label))
        if self.shuffle:
            random.shuffle(self.items)

    def _parse_fn(self, filename):
        image = Image.open(filename)
        image = image.resize(self.image_size)
        image = np.array(image)
        return image

    def __len__(self):
        return math.ceil(len(self.items) / float(self.batch_size))

    def __getitem__(self, idx):
        print(" ----", idx)
        batch = self.items[idx * self.batch_size: (idx + 1) * self.batch_size]
        names, labels = zip(*batch)
        # x_batch = np.array([resize(imread(filename), self.image_size) for filename in names])  # 效率低
        x_batch = np.array([self._parse_fn(filename) for filename in names])
        return x_batch, np.array(labels)


def mkdir(dir_name, delete):
    if os.path.exists(dir_name):
        if delete:
            shutil.rmtree(dir_name)
            os.makedirs(dir_name)
    else:
        os.makedirs(dir_name)


TRAIN_FILE = "data/train_precision.txt"
VAL_FILE = "data/test_precision.txt"
CHECKPOIN_DIR = "../experiments/spam_normal_v1/checkpoints/weights.{epoch:02d}-{val_loss:.2f}.hdf5"
LOG_DIR = "../experiments/spam_normal_v1/logs/"
mkdir(CHECKPOIN_DIR, delete=False)
mkdir(LOG_DIR, delete=True)

# 全局变量
IMAGE_SIZE = (224, 224)
IMAGE_SHAPE = (224, 224, 3)

# GPU资源配置
gpu_config = tf.GPUOptions(
    allow_growth=True,
    per_process_gpu_memory_fraction=0.95,
)
gpu_config = tf.ConfigProto(
    log_device_placement=False,
    allow_soft_placement=True,
    gpu_options=gpu_config,
)


def main():
    # 配置GPU
    k.backend.set_session(tf.Session(config=gpu_config))

    # 数据生成器
    train_gen = Generator(TRAIN_FILE, 64, True, IMAGE_SIZE)
    val_gen = Generator(VAL_FILE, 128, False, IMAGE_SIZE)

    # 定义模型
    base_model = k.applications.InceptionResNetV2(include_top=False, pooling="avg", input_shape=IMAGE_SHAPE)
    model = k.Sequential([
        base_model,
        k.layers.Dense(2, activation="softmax")
    ])

    # 编译模型
    model.compile(
        optimizer=k.optimizers.Adam(0.001),
        loss=k.losses.sparse_categorical_crossentropy,
        metrics=["accuracy"]
    )

    # 回调函数
    callbacks = [
        k.callbacks.EarlyStopping(monitor="val_loss", patience=5),
        k.callbacks.TensorBoard(LOG_DIR, write_images=True),
        k.callbacks.ModelCheckpoint(CHECKPOIN_DIR, monitor="val_loss", save_best_only=True, save_weights_only=False),
    ]

    # 训练模型
    model.fit_generator(train_gen,
                        epochs=1000,
                        steps_per_epoch=len(train_gen),
                        validation_data=val_gen,
                        validation_steps=len(val_gen),
                        max_queue_size=10,
                        workers=8,
                        use_multiprocessing=True,
                        callbacks=callbacks)


if __name__ == '__main__':
    main()

部署

https://www.pyimagesearch.com/2018/01/29/scalable-keras-deep-learning-rest-api/

run_keras_server.py

#! -*- coding: utf-8 -*-
from tensorflow import keras as k
from PIL import Image
import numpy as np
import base64
import flask
import sys
import io


app = flask.Flask(__name__)
model = None


def load_model():
    global model
    model = k.applications.ResNet50(weights="imagenet")


def prepare_image(image, target):
    if image.mode != 'RGB':
        image = image.convert("RGB")

    image = image.resize(target)
    image = k.preprocessing.image.img_to_array(image)
    image = np.expand_dims(image, axis=0)
    image = k.applications.resnet50.preprocess_input(image)
    return image


def base64_encode_image(image):
    # base64 encode the input NumPy array
    return base64.b64decode(image).decode("utf-8")


def base64_decode_image(image, dtype, shape):
    # if this is Python 3, we need the extra step of encoding the
    # serialized NumPy string as a byte object
    if sys.version_info.major == 3:
        image = bytes(image, encoding="utf-8")

    # convert the string to a NumPy array using the supplied data
    # type and target shape
    image = np.frombuffer(base64.decodebytes(image), dtype=dtype)
    image = image.reshape(shape)
    return image


@app.route("/predict", methods=["POST"])
def predict():
    # initialize the data dictionary that will be returned from the
    # view
    data = {"success": False}

    # ensure an image was properly uploaded to our endpoint
    if flask.request.method == "POST":
        if flask.request.files.get("image"):
            # read the image in PIL format
            image = flask.request.files["image"].read()
            image = Image.open(io.BytesIO(image))

            # preprocess the image and prepare it for classification
            image = prepare_image(image, target=(224, 224))

            # classify the input image and then initialize the list
            # of predictions to return to the client
            preds = model.predict(image)
            results = k.applications.resnet50.decode_predictions(preds)
            data["predictions"] = []

            # loop over the results and add them to the list of
            # returned predictions
            for (imagenetID, label, prob) in results[0]:
                r = {"label": label, "probability": float(prob)}
                data["predictions"].append(r)

            # indicate that the request was a success
            data["success"] = True

    # return the data dictionary as a JSON response
    return flask.jsonify(data)


if __name__ == '__main__':
    print(("* Loading Keras model and Flask starting server..."
           "please wait until server has fully started"))
    load_model()
    app.run(debug=False, threaded=False)

调用服务

Keras教程:如何开始使用Keras,Deep Learning和Python

curl -X POST -F image=@dog.jpg 'http://127.0.0.1:5000/predict'

结果

{
	"predictions": [{
		"label": "beagle",
		"probability": 0.987775444984436
	}, {
		"label": "pot",
		"probability": 0.0020967808086425066
	}, {
		"label": "Cardigan",
		"probability": 0.001351703773252666
	}, {
		"label": "Walker_hound",
		"probability": 0.0012711131712421775
	}, {
		"label": "Brittany_spaniel",
		"probability": 0.0010085132671520114
	}],
	"success": true
}

相关文章:

  • 2021-12-14
  • 2021-10-15
  • 2022-01-09
  • 2021-08-07
  • 2021-06-20
  • 2021-05-19
  • 2021-07-21
猜你喜欢
  • 2021-11-27
  • 2021-06-24
  • 2021-05-30
  • 2022-12-23
  • 2022-12-23
  • 2021-08-09
  • 2021-11-05
相关资源
相似解决方案