🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1823閲覧

物体検出モデルSSD(rykov8/ssd_keras)でのモデル学習時のエラー

MASUFISH

総合スコア22

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/12/31 16:40

前提・実現したいこと

独自のデータを使って、物体検出モデルのSSDモデルを構築しようとしています
https://github.com/rykov8/ssd_keras
をもとに構築しています。コードはほぼ丸パクリです。

そのなかでSSD_training.ipynbでモデルの訓練時にエラーが起きています。

エラー文の内容はvalidationデータを指定しろ?というような内容だと思う(全く違うかもしれません)のですが、その仕方が分かりません。

もし解決策や考えられる要因でも分かる方がいらっしゃいましたら、ご教授お願いします。
完全に初心者なので、少しかみ砕いていただけれると幸いです。

よろしくお願いいたします。

発生している問題・エラーメッセージ

ValueError: When using a generator for validation data, you must specify a value for "nb_val_samples".

該当のソースコード

# some constants NUM_CLASSES = 1 input_shape = (300, 300, 3) priors = pickle.load(open('prior_boxes_ssd300.pkl', 'rb')) bbox_util = BBoxUtility(NUM_CLASSES, priors) gt = pickle.load(open("/content/drive/MyDrive/NN/ssd_keras/ssd_keras_new/ssd_keras/Object.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) y = self.bbox_util.assign_boxes(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 = '/content/drive/MyDrive/NN/ssd_keras/ssd_keras_new/ssd_keras/traindata/images/' gen = Generator(gt, bbox_util, 16, '/content/drive/MyDrive/NN/ssd_keras/ssd_keras_new/ssd_keras/traindata/images/', 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) # optim = keras.optimizers.RMSprop(lr=base_lr) # optim = keras.optimizers.SGD(lr=base_lr, momentum=0.9, decay=decay, nesterov=True) model.compile(optimizer=optim, loss=MultiboxLoss(NUM_CLASSES, neg_pos_ratio=2.0).compute_loss) # ↓でエラーが出る nb_epoch = 10 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 )

試したこと

分からなったので、validationに関するコードをコメントアウトして実行しても、
"""
ValueError: output of generator should be a tuple (x, y, sample_weight) or (x, y). Found: None
"""
と出てしまいます。

補足情報(FW/ツールのバージョンなど)

path_prefix = '/content/drive/MyDrive/NN/ssd_keras/ssd_keras_new/ssd_keras/traindata/images/'
内の画像枚数は20枚です
クラス数は1クラスです。
アノテーションには,labelimgを使いました。

tensorflow==1.0.0
keras==1.2.2
scipy==1.2.0
Googlecolabで処理しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

物体検出アルゴリズム(SSD : Single Shot MultiBox Detector)を学習させてみる
のコメントの中に同様な現象が書かれてます
それによると、教師データの数が少ないと起きるようです

投稿2021/01/01 01:57

jbpb0

総合スコア7653

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MASUFISH

2021/01/01 15:44

回答ありがとうございます。 画像枚数を60枚に増やしましたが同じエラーが出てしまいました。 https://techblog.cccmk.co.jp/entry/2020/05/12/064420 では、100枚で動作しているようなので、とりあえず100枚集めて再度処理してみます。
jbpb0

2021/01/01 15:50 編集

枚数が多ければそのエラーが出ないかを確認するだけなら、同じ画像ファイルをコピーして水増ししても分かると思うので、まずはそうしてみたらいかがでしょうか?
MASUFISH

2021/01/02 07:34 編集

実際に100枚分、アノテーションデータを作成して、処理しましたが同様にエラーが出ました。 しかしながら https://arkouji.cocolog-nifty.com/blog/2018/01/tensorflowkeras.html を参考に、自身でPASCALVOCデータで画像とxmlデータを100以下にして実行したらエラーが起きず処理が進みます。 これは、自身が作ったxmlファイル、そしてpklファイルがおかしいということでしょうか。 もしくは、今回のケースで検証用のデータは使わず学習するといったことは可能でしょうか よろしくお願いします。
jbpb0

2021/01/02 10:36 編集

> 自身が作ったxmlファイル、そしてpklファイルがおかしいということでしょうか。 私が回答で挙げた参考Webサイトの記述では、「train.pyの中の変数val_keysの中身が空」だと現象が起きる、とのことです 質問者さんのコードで独自データで実行してエラーになる場合に、val_keysの中身がどうなっているか、print()させて確認してみてください もし同様に空だった場合、 val_keys = keys[num_train:] の行の付近で、下記をprint()させて、矛盾してないか確認してみてください len(keys) num_train len(keys)の8割をnum_trainとして、keysのnum_train個分をtrain_keysに、残りをval_keysに分けるようにコードは書かれてますので、val_keysの中身が空なら、どこかに矛盾があるはずです たとえば、len(keys)がなぜか1〜2だったりするとか 【追記】もし len(keys) が明らかにおかしいなら、 keys = sorted(gt.keys()) の行の後で、下記をprint()させて、内容がおかしくないか確認してください gt.keys() keys もし gt.keys() の段階で既に内容がおかしいなら、それはpklファイルを pickle.load(open(... しただけなのだから、pklファイルがおかしいのだろうと思います 【追記2】gt.keys() の確認をする際は、 https://qiita.com/slowsingle/items/64cc927bb29a49a7af14 の「pklファイルの中身を見る」を参考にしてください
MASUFISH

2021/01/03 02:49

確かにval_keysは[]と空になっています。 len(keys)も、1が出力されています。 gt.keys()は <built-in method keys of dict object at 0x7f82486a6ca8> と出力されています。 またご提示いただいた https://qiita.com/slowsingle/items/64cc927bb29a49a7af14 より print(data.keys())をしたところ 画像名のリストが返されるのではなく、 dict_keys(['ine'])という出力だけでした。(ineとは稲を意味するラベルです。) やはりpklファイルがおかしいのでしょうか。
jbpb0

2021/01/03 03:34 編集

それだと、おそらく train_keys も正しくないと思うので、print()で確認してみてください それが合ってないと、学習できません 次にやること まずは、エラーが出ないデータで、いろいろprint()させて、正しい状態を把握する 次に、自分で作ったデータでなぜ違うのか調べて、直す
MASUFISH

2021/01/03 05:39

pklファイルを作成するところでミスがあると思い、 PASCAL VOC内のget_data_from_XML.pyで試しにpklファイルを作成してみたところ、 print(val_keys) print(train_keys)で、それぞれ画像名が出力されるようになりました。 ””” import numpy as np import os from xml.etree import ElementTree class XML_preprocessor(object): def __init__(self, data_path): self.path_prefix = data_path self.num_classes = 20 self.data = dict() self._preprocess_XML() def _preprocess_XML(self): filenames = os.listdir(self.path_prefix) for filename in filenames: tree = ElementTree.parse(self.path_prefix + filename) root = tree.getroot() bounding_boxes = [] one_hot_classes = [] size_tree = root.find('size') width = float(size_tree.find('width').text) height = float(size_tree.find('height').text) for object_tree in root.findall('object'): for bounding_box in object_tree.iter('bndbox'): xmin = float(bounding_box.find('xmin').text)/width ymin = float(bounding_box.find('ymin').text)/height xmax = float(bounding_box.find('xmax').text)/width ymax = float(bounding_box.find('ymax').text)/height bounding_box = [xmin,ymin,xmax,ymax] bounding_boxes.append(bounding_box) class_name = object_tree.find('name').text one_hot_class = self._to_one_hot(class_name) one_hot_classes.append(one_hot_class) image_name = root.find('filename').text bounding_boxes = np.asarray(bounding_boxes) one_hot_classes = np.asarray(one_hot_classes) image_data = np.hstack((bounding_boxes, one_hot_classes)) self.data[image_name] = image_data def _to_one_hot(self,name): one_hot_vector = [0] * self.num_classes if name == 'ine': one_hot_vector[0] = 1 """ elif name == 'bicycle': one_hot_vector[1] = 1 elif name == 'bird': one_hot_vector[2] = 1 elif name == 'boat': one_hot_vector[3] = 1 elif name == 'bottle': one_hot_vector[4] = 1 elif name == 'bus': one_hot_vector[5] = 1 elif name == 'car': one_hot_vector[6] = 1 elif name == 'cat': one_hot_vector[7] = 1 elif name == 'chair': one_hot_vector[8] = 1 elif name == 'cow': one_hot_vector[9] = 1 elif name == 'diningtable': one_hot_vector[10] = 1 elif name == 'dog': one_hot_vector[11] = 1 elif name == 'horse': one_hot_vector[12] = 1 elif name == 'motorbike': one_hot_vector[13] = 1 elif name == 'person': one_hot_vector[14] = 1 elif name == 'pottedplant': one_hot_vector[15] = 1 elif name == 'sheep': one_hot_vector[16] = 1 elif name == 'sofa': one_hot_vector[17] = 1 elif name == 'train': one_hot_vector[18] = 1 elif name == 'tvmonitor': one_hot_vector[19] = 1 else: print('unknown label: %s' %name) """ return one_hot_vector ## example on how to use it import pickle data = XML_preprocessor('/XXX/xml/').data pickle.dump(data,open('/XXX/test.pkl','wb')) ””” ファイルの中身です。 しかしながら新たに Epoch 1/10 /usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:150: DeprecationWarning: `imresize` is deprecated! `imresize` is deprecated in SciPy 1.0.0, and will be removed in 1.3.0. Use Pillow instead: ``numpy.array(Image.fromarray(arr).resize())``. Exception in thread Thread-8: Traceback (most recent call last): File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner self.run() File "/usr/lib/python3.6/threading.py", line 864, in run self._target(*self._args, **self._kwargs) File "/usr/local/lib/python3.6/dist-packages/keras/engine/training.py", line 429, in data_generator_task generator_output = next(self._generator) File "<ipython-input-12-2ef3fa94cff0>", line 161, in generate y = self.bbox_util.assign_boxes(y) File "/content/drive/My Drive/NN/ssd_keras/ssd_keras_new/ssd_keras/ssd_utils.py", line 149, in assign_boxes assignment[:, 5:-8][best_iou_mask] = boxes[best_iou_idx, 4:] ValueError: shape mismatch: value array of shape (14,20) could not be broadcast to indexing result of shape (14,0) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-36-cd21e8085a4f> in <module>() 7 nb_val_samples=gen.val_batches, 8 #nb_val_samples=None, ----> 9 nb_worker=1 10 ) /usr/local/lib/python3.6/dist-packages/keras/engine/training.py in fit_generator(self, generator, samples_per_epoch, nb_epoch, verbose, callbacks, validation_data, nb_val_samples, class_weight, max_q_size, nb_worker, pickle_safe, initial_epoch) 1530 '(x, y, sample_weight) ' 1531 'or (x, y). Found: ' + -> 1532 str(generator_output)) 1533 if len(generator_output) == 2: 1534 x, y = generator_output ValueError: output of generator should be a tuple (x, y, sample_weight) or (x, y). Found: None というエラーが出てしまいました。
jbpb0

2021/01/03 11:26 編集

> validationに関するコードをコメントアウトして実行して の時と同じエラーですよね これまでにエラーが出てたから触ってたところを、そのままにしてませんか? > print(val_keys) print(train_keys)で、それぞれ画像名が出力されるようになりました。 になったのだから、元のコードのままで実行してみてください
jbpb0

2021/01/03 11:29 編集

get_data_from_XML.py の self.num_classes = 20 と、学習コードの NUM_CLASSES = 1 は、一致させないといけないのでは?? > ValueError: shape mismatch: value array of shape (14,20) could not be broadcast to indexing result of shape (14,0) は、その不一致が原因かも
MASUFISH

2021/01/03 13:32

ご指示のとおり、self.num_classes = 20をself.num_classes = 1としてpklファイルを作成したところ エラーなく無事学習が進みました! 本当に助かりました! 詳細かつ迅速に対応いただき、ありがとうございました! m(__)m感謝です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問