この記事は、の一部として公開されました データサイエンスブログソン
概要
Web 上には、ニューラル ネットワークの構築の基本原理、そのアーキテクチャ、学習戦略などについて説明したチュートリアルやビデオ講義、その他の資料が数多くあります。伝統的に、ニューラル ネットワークは、トレーニング サンプルからの画像パケットをニューラル ネットワークに提示することによってトレーニングされ、バックプロパゲーション法を使用してこのネットワークの係数を補正します。 ニューラル ネットワークを操作するための最も人気のあるツールの XNUMX つは、Google の テンソルフロー としょうかん。
Tensorflow のニューラル ネットワークは、一連の層操作によって表されます。
(行列の乗算、畳み込み、プーリングなど)。 ニューラル ネットワークの各層は、係数を修正する操作とともに、計算グラフを形成します。
この場合、ニューラル ネットワークをトレーニングするプロセスは、ニューラル ネットワークを「提示」することで構成されます。
オブジェクトのパケットのネットワークを作成し、予測されたクラスと真のクラスを比較し、誤差を計算し、ニューラル ネットワーク係数を変更します。
同時に、Tensoflow はトレーニングの技術的な詳細と係数を調整するためのアルゴリズムの実装を隠しており、プログラマーの観点からは、基本的に「予測」を生成する計算グラフについてのみ話すことができます。 グラフを比較してください o
画像1
しかし、Tensorflow がプログラマにできないことは、入力データセットをニューラル ネットワークのトレーニングに便利なデータセットに変換することです。 ライブラリにはかなりの数の「基本ブロック」がありますが。
それらを使用して「パワー」ニューラル ネットワーク入力データの効果的なコンベアを構築する場合と同様に、この記事で説明したいと思います。
問題の例として、 ImageNet このデータセットは、Kaggle でオブジェクト検出コンペティションとして最近公開されました。 XNUMX つのオブジェクト、つまり最大の境界ボックスを持つオブジェクトを検出するようにネットワークをトレーニングします。
準備手順
以下は、あなたが持っていることを前提としています
-
[Python] [python_org] がインストールされており、例では Python 2.7 を使用していますが、Python 3 に移植するのは難しくないはずです。 *
-
ライブラリ [Tensorflow とその Python インターフェイス] [install_tensorflow]
-
Kaggle コンペティションから [dataset] [download_dataset] をダウンロードして解凍しました
ライブラリの従来のエイリアス:
import テンソルフロー as tf import numpy as np
データ前処理
データをロードするには、 作業するためのモジュール Tensorflow のデータセット。
トレーニングと検証には、画像とその説明の両方を含むデータセットが必要です。 ただし、ダウンロードしたデータセットでは、画像と注釈を含むファイルがさまざまなフォルダーにきちんと配置されています。
したがって、対応するペアを反復する反復子を作成します。
ANNOTATION_DIR = os.path.join("注釈", "DET") IMAGES_DIR = os.path.join("データ", "DET") IMAGES_EXT = "JPEG" def image_annotation_iterator(dataset_path, subset="train"): annotations_root = os.path.join(dataset_path, ANNOTATION_DIR, subset) 印刷 annotations_root image_root = os.path.join(dataset_path, IMAGES_DIR, subset) 印刷 画像ルート for ディレクトリパス、_、ファイル名 in os.walk(annotations_root): for 注釈ファイル in file_names: path = os.path.join(dir_path, annotation_file) relpath = os.path.relpath(path, annotations_root) img_path = os.path.join(images_root, os.path.splitext(relpath)[0] + '. ' + IMAGES_EXT ) アサート os.path.isfile(img_path), RuntimeError("ファイル {} が存在しません".format(img_path)) 産出 img_path, path これにより、すでにデータセットを作成し、データセットからファイル名を抽出するなどの「グラフ上の処理」を開始できます。 データセットを作成します: files_dataset = tf.data.Dataset.from_generator( functools.partial(image_annotation_iterator, "./ILSVRC"),output_types=(tf.string, tf.string),output_shapes=(tf.TensorShape([]) 、tf.TensorShape([])))
データセットからデータを取得するには、次のイテレータが必要です。
Make_one_shot_iterator は、データを XNUMX 回繰り返す反復子を作成します。 Iterator.get_next() は、イテレーターからのデータがロードされるテンソルを作成します。 iterator = files_dataset.make_one_shot_iterator() next_elem = iterator.get_next() これで、セッションを作成してテンソルの「値を計算」できるようになりました。 tf.セッション() as セッション: for i in range(10): 要素 = sess.run(next_elem) 印刷 私、要素
しかし、ニューラル ネットワークで使用する場合、ファイル名は必要ありませんが、同じ形状の「XNUMX 層」マトリックスの形式の画像と、「ワンホット」ベクトル形式のこれらの画像のカテゴリが必要です。
画像カテゴリーをエンコードする
注釈ファイルの解析自体はあまり興味深いものではありません。 私が使用したのは、 美しいスープ このためのパッケージ。 ヘルパー クラスは、ファイル パスから初期化し、オブジェクトのリストを保存するためにアノテーション可能です。 まず、cat_max をエンコードするベクトルのサイズを知るためにカテゴリのリストを収集する必要があります。 また、文字列カテゴリを [0..cat_max] の数値にマッピングします。 このようなマップの作成はあまり面白くないので、辞書 cat2id と id2cat には上記の順方向マッピングと逆方向マッピングが含まれていると仮定します。
ファイル名をエンコードされたカテゴリーベクトルに変換する関数。
背景用に別のカテゴリが追加されていることがわかります。一部の画像では、オブジェクトがマークされていません。
def an_file2one_hot(ann_file): annotation = Reader.Annotation("unused", ann_file) category = annotation.main_object().cls result = np.zeros(len(cat2id) + 1) result[cat2id.get(category, len(cat2id) )] = 1 return result データセットに変換を適用しましょう: dataset = file_dataset.map( ラムダ img_file_tensor、ann_file_tensor: (img_file_tensor、tf.py_func(ann_file2one_hot、[ann_file_tensor]、tf.float64)) )
メソッド マップは、元のデータセットの各行に関数が適用された新しいデータセットを返します。 この関数は、結果として得られるデータセットの反復を開始するまで実際には適用されません。
また、関数を tf.py_funcneed でラップしていることにも注目してください。 パラメータとして、テンソルは変換関数に含まれますが、テンソルに含まれる値は含まれません。
文字列を扱うには、このラッパーが必要です。
画像の読み込み
Tensorflow には豊富な機能があります 画像を操作するためのライブラリ。 それを使ってダウンロードしてみましょう。 ファイルを読み取り、行列にデコードし、行列を標準サイズ (平均など) にし、この行列の値を正規化する必要があります。
def 画像パーサー(file_name): image_data = tf.read_file(file_name) image_parsed = tf.image.decode_jpeg(image_data, Channels=3) image_parsed = tf.image.resize_image_with_crop_or_pad(image_parsed, 482, 415) image_parsed = tf.cast(image_parsed, dtype=) tf.float16) image_parsed = tf.image.per_image_standardization(image_parsed) return image_parsed
前の関数とは異なり、ここでは file_nameit はテンソルです。つまり、この関数をラップする必要はなく、前のスニペットに追加する必要があります。
データセット = ファイル_データセット.マップ( ラムダ img_file_tensor, ann_file_tensor: ( image_parser(img_file_tensor), tf.py_func(ann_file2one_hot, [ann_file_tensor], tf.float64) ) )
計算グラフが意味のあるものを生成することを確認してみましょう。
iterator = dataset.make_one_shot_iterator() next_elem = iterator.get_next() 印刷 type(next_elem[0]) tf.セッション() as セッション: for i in range(3): 要素 = sess.run(next_elem) 印刷 i, element[0].shape, element[1].shape 取得する必要があります: 0 (482, 415, 3) (201,) 1 (482, 415, 3) (201,) 2 (482, 415, 3) ) (201,)
原則として、最初はトレーニング/検証/テストのためにデータセットを 2 つまたは 3 つの部分に分割する必要があります。 ダウンロードしたアーカイブからトレーニング データセットと検証データセットに分割して使用します。
計算グラフの設計
確率的勾配降下法に似た方法を使用して畳み込みニューラル ネットワーク (CNN) をトレーニングしますが、改良版を使用します。 アダム。 これを行うには、インスタンスを「パッケージ」(英語ではバッチ) に結合する必要があります。 さらに、マルチプロセッシング (そしてせいぜいトレーニング用の GPU の存在) を利用するために、バックグラウンド データ ページングを有効にすることができます。
BATCH_SIZE = 16 データセット = dataset.batch(BATCH_SIZE) データセット = dataset.prefetch(2)
BATCH_SIZE コピーのパッケージに結合し、そのようなパッケージを 2 つポンプアップします。
トレーニング中に、トレーニングに関係しないサンプルに対して定期的に検証を実行したいと考えています。 したがって、もう XNUMX つのデータセットに対して上記のすべての操作を繰り返す必要があります。
幸いなことに、これらはすべて XNUMX つの関数 (たとえば、dataset_from_file_iterator) に結合して、XNUMX つのデータセットを作成できます。
train_dataset = dataset_from_file_iterator( functools.partial(image_annotation_iterator, "./ILSVRC", subset="train"), cat2id, BATCH_SIZE ) valid_dataset = ... # 同じのみのサブセット = "val"
ただし、トレーニングと検証には引き続き同じ計算グラフを使用したいため、より柔軟なイテレーターを作成します。 再初期化を可能にするもの。
iterator = tf.data.Iterator.from_struct( train_dataset.output_types, train_dataset.output_shapes ) train_initializer_op = iterator.make_initializer(train_dataset) valid_initializer_op = iterator.make_initializer(valid_dataset)
後で、この操作またはその操作を「実行」した後、イテレータを XNUMX つのデータセットから別のデータセットに切り替えることができます。
別。
tf.Session(config=config,graph=グラフ) as sess: sess.run(train_initialize_op) #トレーニング # ... sess.run (valid_initialize_op)
ここではニューラル ネットワークについて説明する必要がありますが、この問題については詳しく説明しません。
関数 semi_alex_net_v1(mages_batch, num_labels) が目的のアーキテクチャを構築し、ニューラル ネットワークによって予測された出力値を含むテンソルを返すと仮定します。
誤差関数と微妙な最適化操作を設定しましょう。
img_batch, label_batch = iterator.get_next() logits = semi_alexnet_v1.semi_alexnet_v1(img_batch, len(cat2id)) loss = tf.losses.softmax_cross_entropy( logits=logits, onehot_labels=label_batch) ラベル = tf.argmax(label_batch, axis=1)予測 = tf.argmax(logits, axis=1) c_predictions = tf.reduce_sum(tf.to_float(tf.equal(labels, precision))) オプティマイザー = tf.train.AdamOptimizer().minimize(loss)
トレーニングと検証のサイクル
これで、学習を開始できます。
tf.セッション() as sess: sess.run(tf.local_variables_initializer()) sess.run(tf.global_variables_initializer()) sess.run(train_initializer_op) カウンタ = tqdm() 合計 = 0。正しい = 0。 試します: while True: opt, l, c_batch = sess.run([optimizer, loss, c_predict]) total += BATCH_SIZE 正しい += c_batch counter.set_postfix({ "loss": "{:.6}".format(l), "精度": 正しい/合計 }) counter.update(BATCH_SIZE) 以下は除く tf.errors.OutOfRangeError: 印刷 「トレーニング終了」
上記では、セッションを作成し、グラフ内のグローバル変数とローカル変数を初期化し、トレーニング データでイテレータを初期化しました。 [tqdm] [tgdm] は学習プロセスではなく、進捗状況を視覚化するための便利なツールにすぎません。
同じセッションのコンテキストで、検証も開始します。検証ループは非常に似ています。 主な違いは、最適化操作が開始されないことです。
tf.セッション() as sess: # トレーニング # ... # カウンタの検証 = tqdm() sess.run(valid_initializer_op) total = 0.correct = 0. 試します: while True: l、正しいバッチ = sess.run([損失, 正しい予測]) 合計 += BATCH_SIZE 正しい += 正しいバッチ counter.set_postfix({ "損失": "{:.6}".format(l), "有効な精度" : 正しい/合計 }) counter.update(BATCH_SIZE) 以下は除く tf.errors.OutOfRangeError: 印刷 「検証が終了しました」
時代とチェックポイント
すべての画像を XNUMX 回単純に通過するだけでは、トレーニングには確かに十分ではありません。 そして、上記のトレーニングと検証のコードをループ内で (XNUMX つのセッション内で) 実行する必要があります。
固定回数の反復を実行するか、トレーニングが役立つ場合に実行します。 データセット全体を通過する XNUMX 回のパスは、伝統的に「エポック」と呼ばれます。
トレーニング中に予期せず停止した場合やモデルをさらに使用するには、モデルを保存する必要があります。 これを行うには、実行グラフの作成時に、Saver クラスのオブジェクトを作成する必要があります。 トレーニング中に、モデルの状態を保存します。
# グラフを作成 # ... saver = tf.train.Saver() # セッションを作成 tf.セッション() as セッション: for i in range(EPOCHS): # トレーニング # ... # 検証 # ... saver.save(sess, "チェックポイント/名前")
まとめ
データセットを作成し、テンソルを操作するための関数や Python で書かれた通常の関数を使用してデータセットを変換する方法を学びました。 画像をメモリにロードしたり、非圧縮形式で保存したりせずに、バックグラウンド ループで画像をロードする方法を学びました。 トレーニングされたモデルを保存する方法も学びました。 上記の手順のいくつかを適用することで、 ダウンロード それらを使用して、画像を認識するプログラムを作成できます。
参考文献:
- https://habrastorage.org/webt/4d/ui/dt/4duidtqhdydft4ys2ahttbj9ysm.png
この記事に示されているメディアは、Analytics Vidhyaが所有しておらず、作成者の裁量で使用されています。
関連記事
PlatoAi。 Web3の再考。 増幅されたデータインテリジェンス。
アクセスするには、ここをクリックしてください。