« カメラ付きのワインセラー”Plum wine system” | トップページ | Lenovo G580が我が家にやってきた »

2018年1月13日 (土)

TensorFlow+KerasでSSDを独自データで使えるようにしてみた

物体検出コードといえば以前「ディープラーニングで一般物体検出する手法”YOLO”のTensorFlow版で独自データセットを使えるようにしてみた: EeePCの軌跡」という記事で紹介したYOLOv1という手法を使えるようにしたのですが、このYOLOv1、精度はいまいち。

ということで、最新のSSD or YOLOv2を使えるようにしたいなぁと考え、何とかこのSSD(Single Shot MultiBox Detector)を使えるようにしました。

コードの入手先はこちら。

GitHub - ryokov8/ssd_keras

参考サイトはこちら。

物体検出アルゴリズム(SSD : Single Shot MultiBox Detector)を学習させてみる - Qiita

準備

まず、このコードは”Keras”というのを使います。

実はこいつが曲者で、最新のKeras(バージョンが2.0以降)を入れると動きません。バージョンは”1.2.2”を入れる必要があります。

> pip install --upgrade keras==1.2.2

とすれば、Windows版Anacondaでもインストールできました。

TensorFlowは1.0以降であればOKのようです。我が家は1.2ですが、動きました。

ただ、環境によってはバックエンドがTensorFlowではない場合があります。その場合は以下を参考にバックエンドをTensorFlowに変更しておいてください。

Keras バックエンドの変更 - Qiita

先のGitHubリンクからコードをゲットします。

Windowsの場合は「GitHub - ryokov8/ssd_keras」をクリックして、その中の「Clone or Download」をクリック、「Download ZIP」をクリックしてZIP形式のファイルを落します。

解凍したのち、そのフォルダ内に「checkpoints」という空フォルダを作っておいてください。

Linuxだと、下記のコマンドで一発ですね。

> git clone https://github.com/rykov8/ssd_keras

さて、とりあえず動かすために、Pascal VOCのデータをダウンロードします。

私はVOC2007を使いました。入手の仕方は「The PASCAL Visual Object Classes Challenge 2007 (VOC2007)」のサイトの中ほどにある「Development Kit」の「 training/validation data 」をクリックします。

これを解凍すると、「VOCdevkit」というフォルダができます。これを、上のSSDのコードのあるところ(ssd_keras-master)にそのまま入れます。

他には学習済みデータを入手する必要があります。

https://mega.nz/#F!7RowVLCL!q3cEVRK9jyOSB9el3SssIA」から「weights_SSD300.hdf5」をダウンロードしてください。右クリックして「ダウンロード」-「標準ダウンロード」で入手できます。これもSSDコードのフォルダ(ssd_keras-master)に入れます。

他に、以下のコードを作っておいてください。参考サイトからほぼそのままいただきました。ファイル名は「train_ssd_keras.py」とでもしておいてください。

import cv2
import keras
from keras.applications.imagenet_utils import preprocess_input
from keras.backend.tensorflow_backend import set_session
from keras.models import Model
from keras.preprocessing import image
import matplotlib.pyplot as plt
import numpy as np
import pickle
from random import shuffle
from scipy.misc import imread
from scipy.misc import imresize
import tensorflow as tf

from ssd import SSD300
from ssd_training import MultiboxLoss
from ssd_utils import BBoxUtility

plt.rcParams['figure.figsize'] = (8, 8)
plt.rcParams['image.interpolation'] = 'nearest'

np.set_printoptions(suppress=True)

# 21
NUM_CLASSES = 21 #4
input_shape = (300, 300, 3)

priors = pickle.load(open('prior_boxes_ssd300.pkl', 'rb'))
bbox_util = BBoxUtility(NUM_CLASSES, priors)

# gt = pickle.load(open('gt_pascal.pkl', 'rb'))
gt = pickle.load(open('VOC2007.pkl', 'rb'))
keys = sorted(gt.keys())
num_train = int(round(0.8 * len(keys)))
train_keys = keys[:num_train]
val_keys = keys[num_train:]
num_val = len(val_keys)

class Generator(object):
    def __init__(self, gt, bbox_util,
                 batch_size, path_prefix,
                 train_keys, val_keys, image_size,
                 saturation_var=0.5,
                 brightness_var=0.5,
                 contrast_var=0.5,
                 lighting_std=0.5,
                 hflip_prob=0.5,
                 vflip_prob=0.5,
                 do_crop=True,
                 crop_area_range=[0.75, 1.0],
                 aspect_ratio_range=[3./4., 4./3.]):
        self.gt = gt
        self.bbox_util = bbox_util
        self.batch_size = batch_size
        self.path_prefix = path_prefix
        self.train_keys = train_keys
        self.val_keys = val_keys
        self.train_batches = len(train_keys)
        self.val_batches = len(val_keys)
        self.image_size = image_size
        self.color_jitter = []
        if saturation_var:
            self.saturation_var = saturation_var
            self.color_jitter.append(self.saturation)
        if brightness_var:
            self.brightness_var = brightness_var
            self.color_jitter.append(self.brightness)
        if contrast_var:
            self.contrast_var = contrast_var
            self.color_jitter.append(self.contrast)
        self.lighting_std = lighting_std
        self.hflip_prob = hflip_prob
        self.vflip_prob = vflip_prob
        self.do_crop = do_crop
        self.crop_area_range = crop_area_range
        self.aspect_ratio_range = aspect_ratio_range

    def grayscale(self, rgb):
        return rgb.dot([0.299, 0.587, 0.114])

    def saturation(self, rgb):
        gs = self.grayscale(rgb)
        alpha = 2 * np.random.random() * self.saturation_var
        alpha += 1 - self.saturation_var
        rgb = rgb * alpha + (1 - alpha) * gs[:, :, None]
        return np.clip(rgb, 0, 255)

    def brightness(self, rgb):
        alpha = 2 * np.random.random() * self.brightness_var
        alpha += 1 - self.saturation_var
        rgb = rgb * alpha
        return np.clip(rgb, 0, 255)

    def contrast(self, rgb):
        gs = self.grayscale(rgb).mean() * np.ones_like(rgb)
        alpha = 2 * np.random.random() * self.contrast_var
        alpha += 1 - self.contrast_var
        rgb = rgb * alpha + (1 - alpha) * gs
        return np.clip(rgb, 0, 255)

    def lighting(self, img):
        cov = np.cov(img.reshape(-1, 3) / 255.0, rowvar=False)
        eigval, eigvec = np.linalg.eigh(cov)
        noise = np.random.randn(3) * self.lighting_std
        noise = eigvec.dot(eigval * noise) * 255
        img += noise
        return np.clip(img, 0, 255)

    def horizontal_flip(self, img, y):
        if np.random.random() < self.hflip_prob:
            img = img[:, ::-1]
            y[:, [0, 2]] = 1 - y[:, [2, 0]]
        return img, y

    def vertical_flip(self, img, y):
        if np.random.random() < self.vflip_prob:
            img = img[::-1]
            y[:, [1, 3]] = 1 - y[:, [3, 1]]
        return img, y

    def random_sized_crop(self, img, targets):
        img_w = img.shape[1]
        img_h = img.shape[0]
        img_area = img_w * img_h
        random_scale = np.random.random()
        random_scale *= (self.crop_area_range[1] -
                         self.crop_area_range[0])
        random_scale += self.crop_area_range[0]
        target_area = random_scale * img_area
        random_ratio = np.random.random()
        random_ratio *= (self.aspect_ratio_range[1] -
                         self.aspect_ratio_range[0])
        random_ratio += self.aspect_ratio_range[0]
        w = np.round(np.sqrt(target_area * random_ratio))
          h = np.round(np.sqrt(target_area / random_ratio))
        if np.random.random() < 0.5:
            w, h = h, w
        w = min(w, img_w)
        w_rel = w / img_w
        w = int(w)
        h = min(h, img_h)
        h_rel = h / img_h
        h = int(h)
        x = np.random.random() * (img_w - w)
        x_rel = x / img_w
        x = int(x)
        y = np.random.random() * (img_h - h)
        y_rel = y / img_h
        y = int(y)
        img = img[y:y+h, x:x+w]
        new_targets = []
        for box in targets:
            cx = 0.5 * (box[0] + box[2])
            cy = 0.5 * (box[1] + box[3])
            if (x_rel < cx < x_rel + w_rel and
                y_rel < cy < y_rel + h_rel):
                xmin = (box[0] - x_rel) / w_rel
                ymin = (box[1] - y_rel) / h_rel
                xmax = (box[2] - x_rel) / w_rel
                ymax = (box[3] - y_rel) / h_rel
                xmin = max(0, xmin)
                ymin = max(0, ymin)
                xmax = min(1, xmax)
                ymax = min(1, ymax)
                box[:4] = [xmin, ymin, xmax, ymax]
                new_targets.append(box)
        new_targets = np.asarray(new_targets).reshape(-1, targets.shape[1])
        return img, new_targets

    def generate(self, train=True):
        while True:
            if train:
                shuffle(self.train_keys)
                keys = self.train_keys
            else:
                shuffle(self.val_keys)
                keys = self.val_keys
            inputs = []
            targets = []
            for key in keys:
                img_path = self.path_prefix + key
                img = imread(img_path).astype('float32')
                y = self.gt[key].copy()
                if train and self.do_crop:
                    img, y = self.random_sized_crop(img, y)
                img = imresize(img, self.image_size).astype('float32')

                if train:
                    shuffle(self.color_jitter)
                    for jitter in self.color_jitter:
                        img = jitter(img)
                    if self.lighting_std:
                        img = self.lighting(img)
                    if self.hflip_prob > 0:
                        img, y = self.horizontal_flip(img, y)
                    if self.vflip_prob > 0:
                        img, y = self.vertical_flip(img, y)
                #
                #print(y)
                y = self.bbox_util.assign_boxes(y)
                #print(y)
                inputs.append(img)
                        targets.append(y)
                if len(targets) == self.batch_size:
                    tmp_inp = np.array(inputs)
                    tmp_targets = np.array(targets)
                    inputs = []
                    targets = []
                    yield preprocess_input(tmp_inp), tmp_targets

path_prefix = './VOCdevkit/VOC2007/JPEGImages/'
gen = Generator(gt, bbox_util, 4, path_prefix,
                train_keys, val_keys,
                (input_shape[0], input_shape[1]), do_crop=False)

model = SSD300(input_shape, num_classes=NUM_CLASSES)
model.load_weights('weights_SSD300.hdf5', by_name=True)

freeze = ['input_1', 'conv1_1', 'conv1_2', 'pool1',
          'conv2_1', 'conv2_2', 'pool2',
          'conv3_1', 'conv3_2', 'conv3_3', 'pool3']#,
#           'conv4_1', 'conv4_2', 'conv4_3', 'pool4']

for L in model.layers:
    if L.name in freeze:
        L.trainable = False

def schedule(epoch, decay=0.9):
    return base_lr * decay**(epoch)

callbacks = [keras.callbacks.ModelCheckpoint('./checkpoints/weights.{epoch:02d}-{val_loss:.2f}.hdf5',
                                             verbose=1,
                                             save_weights_only=True),
             keras.callbacks.LearningRateScheduler(schedule)]

base_lr = 3e-4
optim = keras.optimizers.Adam(lr=base_lr)
model.compile(optimizer=optim,
              loss=MultiboxLoss(NUM_CLASSES, neg_pos_ratio=2.0).compute_loss)

nb_epoch = 100
history = model.fit_generator(gen.generate(True), gen.train_batches,
                              nb_epoch, verbose=1,
                              callbacks=callbacks,
                              validation_data=gen.generate(False),
                              nb_val_samples=gen.val_batches,
                              nb_worker=1)

inputs = []
images = []
img_path = path_prefix + sorted(val_keys)[0]
img = image.load_img(img_path, target_size=(300, 300))
img = image.img_to_array(img)
images.append(imread(img_path))
inputs.append(img.copy())
inputs = preprocess_input(np.array(inputs))

preds = model.predict(inputs, batch_size=1, verbose=1)
results = bbox_util.detection_out(preds)

for i, img in enumerate(images):
    # Parse the outputs.
    det_label = results[i][:, 0]
    det_conf = results[i][:, 1]
    det_xmin = results[i][:, 2]
    det_ymin = results[i][:, 3]
    det_xmax = results[i][:, 4]
    det_ymax = results[i][:, 5]

    # Get detections with confidence higher than 0.6.
    top_indices = [i for i, conf in enumerate(det_conf) if conf >= 0.6]

    top_conf = det_conf[top_indices]
    top_label_indices = det_label[top_indices].tolist()
    top_xmin = det_xmin[top_indices]
    top_ymin = det_ymin[top_indices]
    top_xmax = det_xmax[top_indices]
    top_ymax = det_ymax[top_indices]

    colors = plt.cm.hsv(np.linspace(0, 1, NUM_CLASSES)).tolist()

    plt.imshow(img / 255.)
    currentAxis = plt.gca()

    for i in range(top_conf.shape[0]):
        xmin = int(round(top_xmin[i] * img.shape[1]))
        ymin = int(round(top_ymin[i] * img.shape[0]))
        xmax = int(round(top_xmax[i] * img.shape[1]))
        ymax = int(round(top_ymax[i] * img.shape[0]))
        score = top_conf[i]
        label = int(top_label_indices[i])
        # label_name = voc_classes[label - 1]
        display_txt = '{:0.2f}, {}'.format(score, label)
        coords = (xmin, ymin), xmax-xmin+1, ymax-ymin+1
        color = colors[label]
        currentAxis.add_patch(plt.Rectangle(*coords, fill=False, edgecolor=color, linewidth=2))
        currentAxis.text(xmin, ymin, display_txt, bbox={'facecolor':color, 'alpha':0.5})

    plt.show()

コードのあるフォルダ(ssd_keras-master)の中にある「testing_utils」の中の「videotest.py」というコードは、一部修正が必要です。

87、88行目にある以下のコードを

        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)
        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)

以下のように変えます。

        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)

これで、準備完了です。

学習

まず最初に「PASCAL_VOC」というフォルダに「get_data_from_XML.py」というコードがあるはずです。これを一つ上のフォルダ(ssd_keras-master)に移動し、実行します。

> python get_data_from_XML.py

すると「VOC2007.pkl」というファイルができるはずです。

これができたら、いよいよ実行です。

> python train_ssd_keras.py

これで「VOC2007」のデータを使って、学習がはじまるはずです。

100 epochs実行するのに、うちの環境(Corei3 3220 3.3GHz + GeForce 1050Ti 4GB)では約12時間かかりました。

終わると、「checkpoints」というフォルダに学習済みデータが入っているはずです(10 epochs毎)。

これを使って、いよいよ動画の”物体検出”を実行します。

検出(動画)

ここでは、動画を使ったリアルタイム検出を行います。

まず「testing_utils」というフォルダに、物体検出させたい動画を入れます(ホームビデオなど)。

続いて、「videotest_example.py」を開きます。18行目の「model.load_weights('~')」の' '内に学習済みデータのファイル名(ex. ../checkpoints/weights.96-2.83.hdf5)を入れて、24行目の「vid_test.run('~')」の' '内には動画ファイル名を入れます。

以下のような画像が出てくるはずです。

Ssdtest01

うちの環境では、7FPS程度しか出ません。

不思議と元データ「weights_SSD300.hdf5」を使うと、13FPS出るんですけどね。学習データによって倍もフレームレートが変わるという理由がよくわかりませんね。

ともかく、精度はまあまあありそうです。

独自データでの学習

さて、これまVOC2007のデータを使った話。独自データを使うにはどうするのか?

まずは、独自データとなる画像を集めます。これは必須。

続いて、「AnnotationTool.exe」をダウンロードします。

私がとりあえず作った、Windows上で動かすアノテーションデータ作成ソフトです。

使い方は以下。

-----------------------------------------------------------------------

Annotation00

① まずアノテーションファイル(*.xmlと”trainval.txt”)を保存するフォルダ(作業フォルダ)を作りドラッグ&ドロップ

② アノテーションを作成したい画像ファイルをドラッグ&ドロップ

③ 画像ファイルが出てくるので、物体をマウスで囲みます

④ ”ラベル名”のテキストボックスに物体の名前を書きます(半角英数) 

⑤ ”ラベル作成”をクリックすると登録

同一画像内で認識させたい物体の数だけ③~⑤を繰り返します。

⑥ 一通り終わったら「Annotation追加」をクリック

次の画像ファイルを読み込むため、再び②で別の画像を読み込み、⑥までを繰り返します。

すべての画像ファイルのアノテーション登録が終わったら

⑦ ”終了”をクリック

-----------------------------------------------------------------------

これを実行すると、画像ファイル分の「~.xml」ファイルと、「trainval.txt」ができているはずです。

これを、以下のように「VOCdevkit/VOC2007」に反映。

・ 「Annotations」フォルダには作成されたxmlファイルを全部入れます

・ 「ImageSets/Main」にある「trainval.txt」に、上で作られた「trainval.txt」の中身を追記します。

・ 「JPEGImages」フォルダに、独自データの画像ファイルをすべて入れます

そのあと、「get_data_from_XML.py」の中身を書き換えます。

42行目「if name == 'aeroplane':」以降に並んだ20個のラベルを、独自データ分のラベルと置き換えます。

例えば「イノシシ」と「鹿」と「馬」の画像ファイルを加えて、それぞれラベルを「inoshishi」、「shika」、「uma」としたいとします。その場合、42行目以降のコードは

        if name == 'inoshishi':
            one_hot_vector[0] = 1
        elif name == 'shika':
            one_hot_vector[1] = 1
        elif name == 'uma':
            one_hot_vector[2] = 1
         elif name == 'boat':
            one_hot_vector[3] = 1
        elif name == 'bottle':
         ・
         ・
         ・

となります(赤の部分が変更部位)。 ('uma'は'horse'じゃないのか等のツッコミはなしでお願いします)

この状態で

> python get_data_from_XML.py

を実行。

独自データ版の「VOC2007.pkl」ができるはずです。

この状態で、上の「学習」手順に基づき、学習コード(train_ssd_keras.py)を実行。

動画から物体検出させる場合は「testing_utils」の「videotest_example.py」の12行目を、上と同じラベルに書き換えます。あとは「検出(動画)」手順そのまま。

これで、独自データの検出が可能になるはず・・・です。

実は私自身、これを書いている時点ではまだ実行していないのですが、VOC2007のデータを使った学習ができているので、多分可能なはずです。

こちらのサイトでは、実際に動作に成功しているようです。

物体検出用SSD_Kerasで使える学習モデルの作成方法 | AI coordinator

とりあえず、これでSSDを実装することができました。

あとはネットワークを深層化したりしてやれれば万々歳なのですが、まだそこまでは試しておりません。

あと、どういうわけかこのコード、会社では同じようにやっても動かないんですよね。Keras 1.2.2にダウングレードしたのに、Keras 2.0.6で動かしたときのエラーが出ます。理由は不明。

Kerasというのはコードが書きやすくなる半面、学習データがブラックボックス化されるというか、どういう形式で書きこんでいるのかがわからなくなりますね。さらに、1.xから2.0に変えた時の変化点が大きすぎです。おかげで、Kerasのことはあまり好きになれません。

とはいえ、手軽に使える便利なコードなので、このSSD_Keras、おすすめです。

初めてのTensorFlow 数式なしのディープラーニング

« カメラ付きのワインセラー”Plum wine system” | トップページ | Lenovo G580が我が家にやってきた »

数値解析系」カテゴリの記事

コメント

過去記事への投稿失礼します。

非常にためになる記事をありがとうございます。
一通り動いたのですが、気づいたことがあるのでご連絡させていただきます。

独自データでのget_data_from_XML.py実行時にエラーになったので調べてみたところ、
AnnotationTool.exeを実行してできる .xml ファイルの3行目がとなっていますが、
の誤りではないでしょうか?(全て置換したところうまく動きました)
ご確認いただけたらと思いますし、可能であれば修正版をリリースいただけると、
非常に助かるので、ご検討いただければ幸いです。

こんにちは、機会学習勉強中さん。

ご指摘ありがとうございます。ただ、今ちょうど出先でして、なんとか今夜中に対応したいと思います。それまでお待ちいただけますか?

ご連絡いただきありがとうございます。
また、ご対応いただけるとのことで、大変ありがとうございます!
昨日のコメント内で肝心な部分が消えていたので、今更ですが念のため改めて書かせていただきます。
3行目のspirceとなっている箇所ですが、正しくはsourceかと思いますので、ご確認いただければ幸いです。

こんにちは、機械学習勉強中 さん。

たった今、アップいたしました。おっしゃる通り、”source”が”spirce”になってますね。ソースを直し、修正できていることを確認いたしました。

世の中にあるAnnotationツールに比べると、ずいぶんと雑な造りで申し訳ありません。他にも、ラベル無しでAnnotation書き込みを行うと例外エラーを起こしたりと、いろいろ不具合はあります。また、ラベルを付けた部分の枠線が画像中に残るようにできなかったり、不具合だらけですね。Linux環境であれば、もっといいツールがあるんですけどね・・・だれか、Windows版で作ってくれませんかねぇ。

お礼が遅くなってしまって申し訳ありません。
返信したつもりでしたが、投稿が反映されていませんでした。
この度はご対応いただきありがとうございました!
早速使わせていただいております。
短いですがお礼まで。

こんにちは、機械学習勉強中さん。

いえいえ、ご迷惑をおかけしました。会社で作ったコードを印刷して打ち込み、動いたのでそのままにしちゃいました。ちゃんとチェックしなきゃいけませんね。

ところで、このコードはkeras 1.2.2でないと動きません。最新のkeras(今は2.2.0)で使いたいときは、下記のサイトが参考になります。

http://d.hatena.ne.jp/natsutan/touch/20170318/1489851945

tensorflowも最新(1.8.0)にすればちゃんと動きました。本当は本文に書かないといけないのですが、この場を借りて紹介しておきます。ご参考まで。

質問失礼いたします。

VOC2007.pklというファイルが作成されません。
> python ・・・/get_data_from_XML.pyを入力してみたところ何もエラーなどは出ていないんですが、VOC2007.pklというファイルはできませんでした。
どうすれば解決できますか。

こんにちは、大学生さん。

コマンドの実行ですが、「PASCAL_VOC」フォルダと同じ階層に「get_data_from_XML.py」を移動後、「python get_data_from_XML.py」と実行されてますか?それとも、絶対パスで実行しているんでしょうか?

このコードの94行目付近にある以下のコード

pickle.dump(data,open('VOC2007.pkl','wb'))

を見る限り、実行したパスに「VOC2007.pkl」ができるはずですですが・・・あるいは、そのあたりを何か、いじられましたかね?

ssd_keras-masterはどこに置けばいいですか?

こんにちは、大学生さん。

特に決まりはありません。Linuxであれば、home/(ユーザー) の下に置いていただければいけるはずです。

もし、うちと同じWindows + Anaconda という環境なら、日本語名フォルダの下でなければいけるはず。会社のPCではc:\dl\の下に置いてます。

>Kerasというのはコードが書きやすくなる半面、学習データがブラックボックス化されるというか、どういう形式で書きこんでいるのかがわからなくなりますね。

ここは、kerasのせいではないと思いますが...
この最初のソースを書いた人の設計であり、フレームワークは関係してないですね。

自分的には、kerasは、keras自体のデータの入力形式も方法もわかりやすい方だと思いますが...

get_data_from_XML.pyの90行目に
# pickle.dump(data,open('VOC2007.p','wb')) と書いてありました。

これは、VOC2007.pklと書き換えた方がいいのですか?

こんにちは、大学生さん。

返信遅れました。コードを確認する間がなかったので……

書き忘れてましたが、まず88〜90行目のシャープ(#)を消してください。それで動くはずです。

私の方では、特にVOC2007.pのままでやってますが、そこもVOC2007.pklとしておいた方がいいかもしれません。記憶にないですが、多分私は後でファイル名を変えたようです。

質問失礼します。

Deeplearning素人なのですが、動画ではなく画像から物体を検出するための手順を教えていただけませんか?

こんにちは、大学生さん。

上記記事中で「検出(動画)」の項にある、「videotest_example.py」の中の「vid_test(‘〜‘)」の〜のところに動画のファイル名を入れるように書いてますが、あそこに静止画のファイル名を入れるといけます。

ただし、一瞬で結果が表示されて消えてしまうため、なんらか画像ファイルを出力するようにした方がよさそうです。

ありがとうごさいます。

独自データを作成しようとしたところ、

unknown label: aeroplane
unknown label: aeroplane
unknown label: aeroplane
unknown label: aeroplane
・・・

となってしまいます。

Deeplearning素人なので申し訳ありませんが、おしえていただけないでしょうか?

こんにちは、大学生さん。

上の「独自データでの学習」の項目の、「get_data_from_XML.py 」のラベルは書き換えましたでしょうか?

どこかでラベルを書き忘れているために出るエラーかと思われます。一度ご確認ください。

def _to_one_hot(self,name):
one_hot_vector = [0] * self.num_classes
if name == 'aeroplane': ←aeroplaneを書き換えました。
one_hot_vector[0] = 1
elif name == 'bicycle':
one_hot_vector[1] = 1

元々あったAnotationsに入っているaeroplaneのxmlファイルは削除したほうがいいですか?

こんにちは、大学生さん。

そのままでも大丈夫です。VOC2007のデータには、今回学習に使う20のラベル以外の名前の書かれたxmlファイルはたくさんありますが、プログラム中に記述したラベル以外は無視するため、いちいち削除したところであまり意味はありません。そのままでいいです。

こんにちは。
大変ためになる記事、ありがとうございます。

質問なのですが、
model.load_weights('weights_SSD300.hdf5', by_name=True)
となっている箇所は独自データ(pascal VOCに含まれていないような物体)を検出したい際の学習においても変更しなくても大丈夫でしょうか。

変更が必要な場合はどのようにして重みを出力すればよいかも教えていただけると幸いです。

こんにちは、毎日カレーさん。

最初の学習では、weight.SSD300.hdf5を使うしかないので、そのままご使用ください。ただ、一度独自データで学習すると、checkpointsというフォルダに〜.hdf5という学習器が生成されるため、その後独自データでの転移学習(画像の追加や新たなラベルでの学習)されるときは、その中から適当な学習器を選んで置き換えてください。

このコード自体が、0からの学習ができない仕様のため、最初はなんらかの学習器を読み込んで使うしかありません。最近公開されているディープラーニングのプログラムコードはこういうものが多いです。ですが、これでまあまあ上手くいくので、一度お試しください。

返信ありがとうございます。

やはり最初はそのまま使うしかないのですね。
一度学習して、画像を追加するなりしながら試していこうと思います。

こんにちは、毎日カレーさん。

この手の技術は、少しづつ試すしかないですね。頑張ってください。私もかれこれ1年半ほどディープラーニングに関わってますが、実際に使ってみると理解が早いと思います。オープンソースでこれほどのコードが手に入る時代です。試してみるに限ると思います。

こんにちは!この記事を参考にgithubから構築をしています。
windows10でanacondaを用いており、各バージョンは、Keras==1.2.2, Opencv==3.1.0, tensorflow==1.2.0を使用して行いました。その結果、CPUでのtrain_ssd_keras.pyの実行は可能になりました。
しかし、私はGPUでの実行を行いたいため、上記のバージョンのtensorflowをアンインストールし、tensorflow-gpu==1.2.0をインストールした結果、実行をすることができなくなってしまいました。
このSSD_KerasをGPUで動作させるには、どのようにすれば良いか教えていただきたいです。よろしくお願いします。

こんにちは、リーさん。

おそらくですが、Kerasも再インストールが必要かと思われます。kerasをアンインストールして、再インストールすると使えると思います。

今だと、1.9以上のTensorFlow、Kerasは2以上にするのがいいかもしれません。私も会社の環境で最新のkerasと1.9のTensorFlowにしたうえで、

http://d.hatena.ne.jp/natsutan/touch/20170318/1489851945

を参考にコードを書き換えたところ、使えました。

最新版のTensorFlowやKerasの方が実行効率がやや上がっていたり、不具合が減っているようなので、なるべくなら細心にしたいところですね。ご参考まで。

arkoujiさん返信ありがとうございます!

kerasも再インストールを行ってみましたが、実行の結果、No Module tensorflowとなってしまい、実行できませんでした涙  
もちろん、tensorflow==1.2.0はアンインストールしtensorflow-gpu==1.2.0はインストール行ってます、、、

できれば、arkoujiさんがgpu環境で実行できた時のインストール環境(ex. tensorflow-gpu==1.9.0 , matplotlib==... など)を一覧で教えていただくことはできないでしょうか??

こんにちは、リーさん。

返信遅れました。とりあえず、pip listでの表示を張り付けておきます。
(自宅のWindows版Anaconda3 4.4.0です)
absl-py 0.2.2
appdirs 1.4.0
astor 0.6.2
bleach 1.5.0
boto 2.48.0
boto3 1.7.39
botocore 1.10.39
bz2file 0.98
certifi 2017.11.5
chardet 3.0.4
cmake 0.6.0
colorama 0.3.9
cycler 0.10.0
Cython 0.25.2
decorator 4.1.2
docutils 0.14
entrypoints 0.2.3
gast 0.2.0
gensim 3.4.0
grpcio 1.12.1
h5py 2.7.0
html5lib 0.9999999
idna 2.6
ipykernel 4.6.1
ipython 6.1.0
ipython-genutils 0.2.0
ipywidgets 6.0.0
Janome 0.3.6
jedi 0.10.2
Jinja2 2.9.6
jmespath 0.9.3
jsonschema 2.6.0
jupyter 1.0.0
jupyter-client 5.0.1
jupyter-console 5.1.0
jupyter-core 4.3.0
Keras 2.2.0
Keras-Applications 1.0.2
Keras-Preprocessing 1.0.1
lxml 3.8.0
Markdown 2.6.11
MarkupSafe 1.0
matplotlib 2.0.2
mistune 0.7.4
nbconvert 5.2.1
nbformat 4.3.0
networkx 1.11
notebook 5.0.0
numpy 1.13.3
olefile 0.44
packaging 16.8
pandas 0.20.3
pandocfilters 1.4.1
pickleshare 0.7.4
Pillow 4.2.1
pip 10.0.1
prompt-toolkit 1.0.14
protobuf 3.6.0
Pygments 2.2.0
pyparsing 2.2.0
pystan 2.17.1.0
python-dateutil 2.6.1
pytz 2017.2
PyWavelets 0.5.2
PyYAML 3.12
pyzmq 16.0.2
qtconsole 4.3.0
requests 2.18.4
s3transfer 0.1.13
scikit-image 0.13.0
scikit-learn 0.18.1
scipy 1.0.0
selectivesearch 0.4
setuptools 34.0.1
simplegeneric 0.8.1
six 1.11.0
smart-open 1.5.7
tensorboard 1.8.0
tensorflow 0.12.0rc1
tensorflow-gpu 1.8.0
termcolor 1.1.0
testpath 0.3.1
tflearn 0.3.2
Theano 1.0.1
tornado 4.5.1
tqdm 4.19.5
traitlets 4.3.2
urllib3 1.22
wcwidth 0.1.7
webencodings 0.5.1
Werkzeug 0.14.1
wheel 0.29.0
widgetsnbextension 2.0.0
win-unicode-console 0.5

ほとんどAnacondaについていたものばかりで、自分でインストールしたものはほとんどありません。
また、見ていただくとわかりますが、CPU版TensorFlowを残したまま(0.12.0rc1)、GPU版TensorFlow-gpu(ここでは1.8.0)をインストールしております。これでも動いてますね。

なお、会社では1.9.0を使っております。

初めまして。この記事を参考に独自データをつかってやっているものです。
質問なのですが、train_ssd_keras.pyを実行することはできたのですが、
Epoch1/30 4086/4087の時点で以下のようなエラーがはいてしまいました。
ValueError: Error when checking input: expected input_1 to have shape (300, 300, 3) but got array with shape (300, 300, 4)
これはどういうことなのでしょうか。もしなにかわかるならば教えていただきたいです。
ちなみに独自で集めた画像のサイズはバラバラでやっていまして、もしかしたら影響があるのでしょうか。

こんにちは、taguseiさん。

うーん、よくわかりませんが、以下のIssue が近いですかね?

https://github.com/rykov8/ssd_keras/issues/84

どうやら、グレースケールの画像を使ってるとこうなるようなことが書かれてるっぽいですが……とりあえず、こちらでは起こったことのないエラーですね。

ちなみに、ばらばらのサイズは問題ないはずです。こちらでも経験済みですが、特にエラーになったことはないです。ただ、小さすぎる画像は不具合を起こすことがあったような……すいません、あまりちゃんとした回答はできませんね。

arkoujiさん、返信ありがとうございます。
もう一度やり直して、手順の通りやっていると返信していただいたようなエラーが起きました。
解決策の通り行ってみると、画像ファイルがjpgとpngが混ざっていたのが問題だったような気がします。ちなみに私はpngの画像データはすべて消して、jpgの画像データだけで行うと無事成功しました。助かりました、ありがとうございました。
このデータを使ってカメラからの認識ができれば思っています。
もし、またなにかわからないことがでてきたら教えていただきたいです。

こんにちは、taguseiさん。

ああ、そういえばこのコードはjpgオンリーでしたね。予めpngファイルは変換が必要です。

一応、カメラ画像からの認識コードは付いていました。使ったことがないので、なんとも言えませんが……

ところで、SSDに対抗意識を燃やすyoloもバージョン3を出しています。tensorflow+keras版も出ているので、そちらも検討してみるといいかもしれません。確かに認識速度と数は多いですが、条件次第ではSSDの方が良かったり、yoloの方が良かったり……ただ、手法を2種類くらい持っておくのは便利です。

はじめまして。
この記事にある検出(動画)の項目の

「ここでは、動画を使ったリアルタイム検出を行います。
まず「testing_utils」というフォルダに、物体検出させたい動画を入れます(ホームビデオなど)。
続いて、「videotest_example.py」を開きます。18行目の「model.load_weights('~')」の' '内に学習済みデータのファイル名(ex. ../checkpoints/weights.96-2.83.hdf5)を入れて、24行目の「vid_test.run('~')」の' '内には動画ファイル名を入れます。」

までは行えたのですが、その次の

「以下のような画像が出てくるはずです。」

の部分がわかりません。
なんのプログラムを実行したらそうなるのでしょうか?

こんにちは、benkyoさん。

言われてみれば、抜けてますね。まさに編集中のコードを実行します。

python videotest_example.py

そうすると、物体検出の画像が出てきます。お試しください。

ご返信ありがとうございます。
うまくいきました。
このブログのおかげもあり、これから物体認識についてどんどん取り組んでいこうと思います。
ありがとうございました。

たびたびの質問すみません
画像からの学習が終了し、動画からの検出を行おうと思って上記のようにvideotest_example.pyを実行したのですが、以下のようなエラーが出てしまい、解決できません...
どうすればよいのでしょうか?

Dimension 3 in both shapes must be equal, but are 60 and 63. Shapes are [3,3,512,60] and [3,3,512,63]. for 'Assign_43' (op: 'Assign') with input shapes: [3,3,512,60], [3,3,512,63].

こんにちは、benkyoさん。

うーん、よくわかりませんね。以下のissueがよく似てますけど、こちらもよくわかりませんでした。

https://github.com/rykov8/ssd_keras/issues/136

なんとなくですが、ニューラルネットワークのどこかが崩れちゃったんですかね?でもこのコードでは、そういうのはできない気がしますが。

返信ありがとうございます。
これはpythonやkeras、tensorflow、をインストールしなおしたほうが良いんでしょうか...?

こんにちは、benkyoさん。

そういうレベルのものではないと思います。多分、同じコードを別のPCに持っていっても起こる類のことのように思います。

video_example.pyで読み込ませる学習器を「weights_SSD300.hdf5」に戻しても、同じエラーが出ますか?もし出ないようなら、独自データで学習させて作った学習器(weights_〜.hdf5)がおかしいと分かるので、対処のしようがあるかもしれません。

返信ありがとうございます。

weights_SSD300.hdf5でやってみたものの、やはり同じエラーが出てしまいます。
これは対処が難しいでしょうか?

こんにちは、benkyoさん。

どこかコードをいじってしまってますね。もう一度Githubからオリジナルのコードを持ってきた方が良さそうです。今わかるのは、それくらいでしょうか。

返信ありがとうございます。

この件に関しまして、無事解決しましたのでご報告させていただきます。
エラーの理由はおそらくvideotext_example.pyの中身の
class_name =
以降にある最初の
"background"
を誤って削除したからだと思われます。

お騒がせしてすみませんでした。

こんにちは、benkyoさん。

あ…それでエラーが出てたんですね。なるほど、私も勉強になります。

ところで、今まさに物体検出を会社でトライ中です。このコードも使えないか、検討中。これはこれでよくできたコードなので、便利ですね。

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/510034/66219107

この記事へのトラックバック一覧です: TensorFlow+KerasでSSDを独自データで使えるようにしてみた:

« カメラ付きのワインセラー”Plum wine system” | トップページ | Lenovo G580が我が家にやってきた »

当ブログ内検索

  • カスタム検索

スポンサード リンク

ブログ村

無料ブログはココログ