tensorflow 2系 GPUの使用メモリ上限を設定する(CUDA_ERROR_OUT_OF_MEMORY: out of memory)

AutoKerasで学習を実行していると、GPUメモリの確保に失敗したというエラーが発生しました。


W tensorflow/core/framework/op_kernel.cc:1767] OP_REQUIRES failed at cwise_ops_common.h:120 : Resource exhausted: OOM when allocating tensor with shape[32,128,98,98] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc
I tensorflow/stream_executor/cuda/cuda_driver.cc:775] failed to allocate 5.33G (5717907200 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory




GPUメモリ上限の指定はこちら
https://www.tensorflow.org/guide/gpu

7GBに制限してみます。
ソースコードの先頭に以下の記載を追加。


  1. gpus = tf.config.experimental.list_physical_devices('GPU')
  2. if gpus:
  3. # Restrict TensorFlow to only allocate 1GB of memory on the first GPU
  4. try:
  5.     tf.config.experimental.set_virtual_device_configuration(
  6.         gpus[0],
  7.         [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024*7)])
  8.     logical_gpus = tf.config.experimental.list_logical_devices('GPU')
  9.     print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
  10. except RuntimeError as e:
  11.     # Virtual devices must be set before GPUs have been initialized
  12.     print(e)




これで最後まで処理が実行できるようになりました。

AutoKeras モデルのロード時に「ValueError: Unknown optimizer: Custom>AdamWeightDecay」

AutoKerasで作成したモデルをロードする際、こんなエラーが発生しました。


Traceback (most recent call last):
File "check.py", line 36, in <module>
    model = tf.keras.models.load_model('model.h5')
File "/home/baranche/.local/lib/python3.8/site-packages/tensorflow/python/keras/saving/save.py", line 182, in load_model
    return hdf5_format.load_model_from_hdf5(filepath, custom_objects, compile)
File "/home/baranche/.local/lib/python3.8/site-packages/tensorflow/python/keras/saving/hdf5_format.py", line 193, in load_model_from_hdf5
    model.compile(**saving_utils.compile_args_from_training_config(
File "/home/baranche/.local/lib/python3.8/site-packages/tensorflow/python/keras/saving/saving_utils.py", line 211, in compile_args_from_training_config
    optimizer = optimizers.deserialize(optimizer_config)
File "/home/baranche/.local/lib/python3.8/site-packages/tensorflow/python/keras/optimizers.py", line 865, in deserialize
    return deserialize_keras_object(
File "/home/baranche/.local/lib/python3.8/site-packages/tensorflow/python/keras/utils/generic_utils.py", line 346, in deserialize_keras_object
    (cls, cls_config) = class_and_config_for_serialized_keras_object(
File "/home/baranche/.local/lib/python3.8/site-packages/tensorflow/python/keras/utils/generic_utils.py", line 296, in class_and_config_for_serialized_keras_object
    raise ValueError('Unknown ' + printable_module_name + ': ' + class_name)
ValueError: Unknown optimizer: Custom>AdamWeightDecay



こちらが参考になります。
How do I load a keras saved model with custom Optimizer


モデルをロードする処理


  1. # 出力したモデルの読み込み
  2. model = tf.keras.models.load_model('model.h5')



こちらに引数を追加


  1. # 出力したモデルの読み込み
  2. model = tf.keras.models.load_model('model.h5', compile=False)




これでモデルがロードできるようになりました。

AutoKeras Image Regressionを用いた画像解析サンプル(年齢判定)

AutoKerasの画像解析には
・Image Classification
・Image Regression
の2つがあります。

Classificationは画像の分類で、よく見るMNISTの手書き数字が何であるかの判定に用いられています。
Regressionは直訳すると「回帰」で、どういった場面で使えるのかよくわかっていませんでした。


Image Regression(画像の回帰)



非常に参考になったのがこちらの記事です。

きゅうり画像で回帰問題を解いてみた
顔画像から年齢を予測

特に「顔画像から年齢」という用例が非常にしっくり来ました。
「犬、猫、馬のどれか」という問題ではなく、段階的に変化していく「年齢」や「サイズ」、「家の築年数」といった用途で使用できそうです。



AutoKerasでのサンプル



Image Regression
こちらのサンプルと、
顔画像から年齢を予測
こちらのサンプルを参考に、顔画像から年齢を判定するプログラムをAutoKerasを用いて作成してみます。

データはこちらから取得しました。
https://susanqq.github.io/UTKFace/

「Aligned&Cropped Faces」の「UTKFace.tar.gz」を使用します。
顔の画像が200x200ピクセルで切り出されたものが23,708ファイルあります。
ファイル名の先頭が年齢になっているので、ラベルとして使用します。

UTKFace.tar.gzを展開せずに中身の画像データを使用しました。
Python tar.gzファイルを解凍せずに中身の画像ファイルを読み込む

・sample.py


  1. import os
  2. import random
  3. import tarfile
  4. import numpy as np
  5. from PIL import Image
  6. # from sklearn.model_selection import train_test_split
  7. import tensorflow as tf
  8. import autokeras as ak
  9. train_images = []
  10. train_labels = []
  11. test_images = []
  12. test_labels = []
  13. with tarfile.open(name='UTKFace.tar.gz', mode='r') as tar:
  14.     for info in tar.getmembers():
  15.         if not info.isfile():
  16.             continue
  17.         # ファイル名から年齢を取得し、ラベルに採用
  18.         # UTKFace/82_0_2_20170111210110290.jpg.chip.jpg -> 82
  19.         print(info.name)
  20.         age = os.path.basename(info.name).split('_')[0]
  21.         # 内容をio.BufferedReaderで取り出し
  22.         f = tar.extractfile(info)
  23.         img = Image.open(f)
  24.         # メモリに乗らないのでリサイズ
  25.         img = img.resize((64, 64))
  26.         # 学習用とテスト用に分割
  27.         if random.randint(1, 10) <= 1:
  28.             test_images.append(np.asarray(img))
  29.             test_labels.append(int(age))
  30.             img.save(os.path.join('test', os.path.basename(info.name)))
  31.         else:
  32.             train_images.append(np.asarray(img))
  33.             train_labels.append(int(age))
  34.         
  35. train_images = np.array(train_images,dtype=np.float32)
  36. train_labels = np.array(train_labels)
  37. test_images = np.array(test_images,dtype=np.float32)
  38. test_labels = np.array(test_labels)
  39. # メモリーエラーで強制終了したので、自前で分割
  40. # x_train, x_test, y_train, y_test = train_test_split(images, labels, test_size=0.1, shuffle = False)
  41. print(len(train_images))
  42. print(len(train_labels))
  43. print(len(test_images))
  44. print(len(test_labels))
  45. print(test_images.shape)
  46. reg = ak.ImageRegressor(
  47.     overwrite=True,
  48.     max_trials=3)
  49. reg.fit(train_images, train_labels, epochs=10)
  50. predicted_y = reg.predict(test_images)
  51. print(predicted_y)
  52. print(reg.evaluate(test_images, test_labels))
  53. # モデルの保存
  54. model = reg.export_model()
  55. model.save('model.h5')




200x200の画像そのままだとメモリにデータが乗らず、プログラムが強制終了しました。
64x64の画像にリサイズして解析に利用しています。

トレーニングとテストデータに分割するのによく用いられる「train_test_split」も
メモリ使用量が大きいため、自前で適当に分割しています。

テストに分類した画像は、後の確認用に保存しておきました。


出来上がったモデルの内容を見てみます。


  1. import tensorflow as tf
  2. # 出力したモデルの読み込み
  3. model = tf.keras.models.load_model('model.h5')
  4. # 内容出力
  5. print(model.summary())




Layer (type)                 Output Shape             Param #
=================================================================
input_1 (InputLayer)         [(None, 64, 64, 3)]     0        
_________________________________________________________________
resizing (Resizing)         (None, 71, 71, 3)         0        
_________________________________________________________________
xception (Functional)        (None, 3, 3, 2048)        20861480
_________________________________________________________________
flatten (Flatten)            (None, 18432)             0        
_________________________________________________________________
regression_head_1 (Dense)    (None, 1)                 18433    
=================================================================
Total params: 20,879,913
Trainable params: 20,825,385
Non-trainable params: 54,528
_________________________________________________________________
None



ポイントは最終的なアウトプットが(None, 1)になっている点でしょうか。
Classificationでは解析対象とした年齢分の出力となるはずです。



簡単な評価プログラム



出力したモデルを用いて年齢を判定してみます。

・check.py


  1. import os
  2. import tkinter as tk
  3. import numpy as np
  4. from PIL import Image, ImageTk
  5. import tensorflow as tf
  6. # 画像ファイルの読み込み
  7. face_files = [
  8.     'test/14_1_0_20170109204321875.jpg.chip.jpg',
  9.     'test/25_0_4_20170117193004258.jpg.chip.jpg',
  10.     'test/41_0_0_20170117140625076.jpg.chip.jpg',
  11.     'test/54_1_0_20170104235918548.jpg.chip.jpg',
  12.     'test/64_1_1_20170112233355207.jpg.chip.jpg',
  13.     'test/80_0_0_20170111205541652.jpg.chip.jpg'
  14. ]
  15. images = []
  16. ages = []
  17. train_images = []
  18. for face_file in face_files:
  19.     img = Image.open(face_file)
  20.     images.append(img)
  21.     ages.append(os.path.basename(face_file).split('_')[0])
  22.     train_images.append(np.array(img))
  23. train_images = np.array(train_images,dtype=np.float32)
  24. # 出力したモデルの読み込み
  25. model = tf.keras.models.load_model('model.h5')
  26. # 解析実行
  27. predicted_y = model.predict(train_images)
  28. print(predicted_y)
  29. # 結果を表示
  30. root = tk.Tk()
  31. root.geometry('500x200')
  32. root.title('face image')
  33. tk_images = []
  34. for i in range(len(face_files)):
  35.     tk_images.append(ImageTk.PhotoImage(images[i]))
  36. for i in range(len(face_files)):
  37.     label = tk.Label(root, image = tk_images[i])
  38.     label.grid(column=i, row=0)
  39.     
  40.     label = tk.Label(root, text = 'real:%s' % (ages[i]))
  41.     label.grid(column=i, row=1)
  42.     label = tk.Label(root, text = 'predict:%.1f' % (predicted_y[i]))
  43.     label.grid(column=i, row=2)
  44. root.mainloop()



そこまで学習に時間をかけていないモデルとしては、とんでもないハズレもなくそれなりの結果が出たのではないかと思います。

a34_01.png



【参考URL】

きゅうり画像で回帰問題を解いてみた
顔画像から年齢を予測
https://susanqq.github.io/UTKFace/
Image Regression

Python tar.gzファイルを解凍せずに中身の画像ファイルを読み込む

複数の画像ファイルを圧縮したtar.gz。
データ解析に使用したいのですが、取り回しが楽なので圧縮ファイルのまま処理したい。


ファイル名の取得



こちらを参考にしました。
tarfile --- tar アーカイブファイルの読み書き

まず、中に存在するファイル名の列挙から始めてみます。
とりあえず、最初の1ファイルだけ表示。

・sample.py


  1. import tarfile
  2. with tarfile.open(name='UTKFace.tar.gz', mode='r') as tar:
  3.     for info in tar.getmembers():
  4.         print(info.name)
  5.         break



ファイル名が取得できました。

$ python3 sample.py
UTKFace/82_0_2_20170111210110290.jpg.chip.jpg





データの取り出し



こちらが参考になりました。
pythonスクリプトでtarファイルの内容を展開せずに読み込む

extractfileで内容を取得します。

・sample.py


  1. import tarfile
  2. with tarfile.open(name='UTKFace.tar.gz', mode='r') as tar:
  3.     for info in tar.getmembers():
  4.         # ファイル名
  5.         print(info.name)
  6.         # 内容をio.BufferedReaderで取り出し
  7.         f = tar.extractfile(info)
  8.         # 確認用にファイルへ出力
  9.         with open('check.jpg', 'wb') as c:
  10.             c.write(f.read())
  11.         
  12.         # とりあえず1件のみ処理
  13.         break



これでtar.gzファイルを回答せず中身のファイル名、画像が取り出せました。




【参考URL】
tarfile --- tar アーカイブファイルの読み書き

pythonスクリプトでtarファイルの内容を展開せずに読み込む


AutoKeras 作成したモデルを用いての画像分類

AutoKerasで学習したモデルの保存と読み込みを試してみました。
AutoKeras 作成したモデルの保存と呼び出し、モデルの内容確認

今回はモデルを読み込んで画像の分類を試してみます。

テストデータの判定



作成したモデルを読み込み分類してみます。


  1. import tensorflow as tf
  2. from tensorflow.keras.datasets import cifar10
  3. import numpy as np
  4. import tkinter as tk
  5. from PIL import Image, ImageTk
  6. (x_train, y_train), (x_test, y_test) = cifar10.load_data()
  7. # 出力したモデルの読み込み
  8. model = tf.keras.models.load_model('model.h5')
  9. # 最初のテスト画像を判定
  10. predicted_y = model.predict(x_test[1])
  11. print(predicted_y)
  12. # 確信度が最大値のインデックス表示
  13. print(np.argmax(predicted_y))
  14. # 判定した画像を表示
  15. root = tk.Tk()
  16. root.geometry('200x200')
  17. root.title('cifar10 image')
  18. canvas = tk.Canvas(
  19.     root,
  20.     width=128,
  21.     height=128
  22. )
  23. canvas.place(x=0, y=0)
  24. #PILでjpgを使用
  25. img = Image.fromarray(np.uint8(x_test[1]))
  26. img = img.resize((128, 128)) # 画像を拡大表示
  27. tk_img = ImageTk.PhotoImage(img)
  28. canvas.create_image(
  29.     0,
  30.     0,
  31.     image=tk_img,
  32.     anchor=tk.NW
  33. )
  34. root.mainloop()




実行結果


[[3.22687876e-04 8.15596506e-02 1.15753856e-07 3.03708219e-07
2.27200161e-08 5.22791144e-09 1.87353741e-08 4.26373497e-08
9.17966664e-01 1.50418127e-04]]
8



a33_01.png

分類は「8(ship:船)」です。
正しく認識できているようです。




画像ファイルを読み込んでの判定



用意されたデータセットからではなく、画像ファイルを読み込んで判定を行ってみます。
まず、先程表示した船の画像をファイルに保存。
Python mnistデータセットの内容を画像ファイルに出力する(pillow使用)


  1. import numpy as np
  2. from PIL import Image
  3. from tensorflow.keras.datasets import cifar10
  4. (x_train, y_train), (x_test, y_test) = cifar10.load_data()
  5. img = Image.fromarray(np.uint8(x_test[1]))
  6. img.save('ship.png')



以下の画像が出力できました。

a33_02.png

この画像を読み込んで判定を行ってみます。


  1. import tensorflow as tf
  2. from PIL import Image
  3. import numpy as np
  4. img = np.array(Image.open('ship.png'))
  5. # 出力したモデルの読み込み
  6. model = tf.keras.models.load_model('model.h5')
  7. # テスト画像を判定
  8. predicted_y = model.predict(img)
  9. print(predicted_y)
  10. # 確信度が最大値のインデックス表示
  11. print(np.argmax(predicted_y))



実行結果


[[3.22687876e-04 8.15596506e-02 1.15753856e-07 3.03708219e-07
2.27200161e-08 5.22791144e-09 1.87353741e-08 4.26373497e-08
9.17966664e-01 1.50418127e-04]]
8



先ほどと同じく、「8(ship:船)」という分類になりました。




【参考URL】

Python, NumPyで画像処理(読み込み、演算、保存)

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
Symfoware まとめ

PR




検索フォーム

月別アーカイブ