リスト 3.3 は、第 1 層と第 3 層の畳み込み層にパディング (padding リスト 3.3 : /srcnn/model/mode1915_svs. py # coding: UTF—8 ' m0de1915 svs' NAME INPUT SIZE 33 OUTPUT SIZE INPUT_SIZE CHANNELS 1 def inference(lr—images) : を設定しています。 convl convl conv2 conv2 conv3 conv3 conv2d( 'convl' input—layer=lr—images, weights—shape=[9, 9 , CHANNELS, 64 ] , biases—shape=C32] , biases_vatue=@.@, weight—stddev=le-l, weights—shape=[l, 1 , 64 , 32 ] , input—tayer=convl, conv2d( 'conv2' tf. nn. retu(convl) padding='SAME' ) st ri des= [ 1 , 1 , 1 , 1 ] , biases—shape=[64] , biases_value=@ . @, weight—stddev=le—l, st ri des= [ 1 , 1 , 1 , 1 ] , padding='VAL 工 D') tf. nn . relu(conv2) conv2d( 'conv3' input—Iayer=conv2, weights—shape=[5, 5 , 32 , weight—stddev=1e-3, biases—shape=[CHANNELS] , st ri des= [ 1 , 1 , 1 , 1 ] , padding='SAME') tf. nn . retu(conv3) CHANNELS] , biases_value=@ . 0, return conv3 この場合、モデルの入力サイズ (INPUT_SIZE) と出力サイズ (OUTPUT_SIZE) は同じに なります。 第 3 章超解像奮闘記 45
biases_vatue=@ . 0, biases—shape=[32] , strides=[l, 1 , 1 padding='VALID') tf. nn . reIu(conv2) conv2 conv2d( 'conv3' input_Iayer=conv2, weights—shape= [ 5 , 5 , 32 , CHANNELS] , weight—stddev=1e—3, biases—shape=[CHANNELS] , biases vatue=@. @, st ri des= [ 1 , 1 , 1 , 1 ] , padding='VALID') tf. nn . retu(conv3) conv3 conv3 return conv3 共通する処理は、 modet ー base. py にまとめています ( リスト 2.2 ) 。 リスト 2.2 : srcnn/model/model_base. py # coding: UTF-8 from future from future_ from future import absotute_import import division import print_function import tensorflow as tf def variable_on_cpu(name, shape, initializer, trainabIe=True) : wi th tf. devi ce ( ' / cpu : @ ' ) : tf. get_variable(name, shape, initializer=initiatizer, var trainable=trainabte) return var def _get—weights(shape, stddev=l. の : variabte—on—cpu( var shape, 'weights' tf. truncated—normal_initiatizer(stddev=stddev) ) return var def —get—biases(shape, value=@. の : 24 第 2 章 CNN で超解像
weights—shape=[5, 5 , 64 , 32 ] , weight—stddev=le-l, biases—shape=[32] , biases—vatue=@ . @, st ri des= [ 1 , 1 , 1 , 1 ] , padding='VALID') tf. nn . reIu(conv2) conv2d( 'conv3' input_Iayer=conv2, weights—shape=[5, 5 , 32 , weight—stddev=1e—3, biases—shape=[CHANNELS] , st ri des= [ 1 , 1 , 1 , 1 ] , padding='VAL 工 D') tf. nn . sigmoid(conv3) 1 ( グレースケール ) conv3 conv3 conv2 図 42 は、表 4.1 の条件で学習した場合の誤差の変化です。 return conv3 CHANNELS] , biases value=@ . @, 表 4.1 : 学習条件 条件 画像の倍率 (scale) 学習率 (learning-rate) ニバッチサイズ (batch_size) ステップ数 (max_step) チャンネル数 (CHANNELS) 図 4.2 誤差の変化 (smoothing=O. 9) 000 5 ℃ 00e -3 0.018 0.0150 0.02C0 0025 つ 00 三 ) ン 値 0. 開 1 128 300 , 開 0 1 CC :. 150. 28 し 250. ⅸ 第 4 章 3 〔 00 ス . さまざまなモデル 61
図 3.8 超解像処理をした画像 第第 1 かなり良くなりましたが、一定間隔で黒い点が表示されているのが気になります。 どうやら 処理するプロックの境界にノイズが出ているようです。 tf. nn . conv2d が追加するパディングは「 0 パディング ( = 黒のピクセル ) 」です 周辺領域 の特徴を多く取り込むために追加したパディングが、学習結果に影響を与えたと考えられます。 画像の読み込み処理 こでもう一度、第 2 章で作成した学習時の画像の読み込み処理 ( リスト 3.4 ) を見てみま しよう。 リスト 3.4 : s ℃ nn/image 」 oader_svs. py def load_image(file_list, input_size, output_size, channels=l, scaIe=2, batch_size=l) : with tf. name_scope( 'image_loader—svs' ) : filename—queue = tf. train. string_input_producer(fite_list, shuffte=True) tf. WholeFiIeReader() reader. read(filename_queue) reader value tf. image. decode—jpeg(vatue, channels=channels) 1 mage 第 3 章超解像奮闘記 47
リスト 1 .15 : NumPy のプロードキャスティング import numpy as np 3 , 4 ] ) arrayl vaIue1 result np. a r ray ( [ 1 , 2 , 3 5 arrayl + vaIueI print(result) [ 6 7 8 9 ] TensorFlow にもプロードキャスティングの仕組みがあり、形の違う配列同士で演算するこ リスト 1 . 16 : TensorFlow のプロードキャスティング とができます ( リスト 1.16 ) 。 import tensorflow as tf arrayl vatuel result tf. constant([l, 2 , tf. constant(5) arrayl + valuel with tf. Session() as sess: print(sess . run(result)) [ 6 7 8 9 ] TensorBoard によるグラフの可視化 TensorFlow には、強力な可視イヒッール「 TensorBoard 」が搭載されています。 TensorBoard を使えばグラフを可視化して、 Web プラウザ上で見ることができます。 TensorBoard で読み込める形式でデータを出力します。 グラフの書き出し 第 1 章 TensorFIow の基礎 19
print(var2. name) scopel/varl:@ scope2—I/scope2—2/var2:@ スコープ内で宣言した変数は、変数名の前にスコープ名が付加されます。入れ子のスコープ の場合、区切り文字 ( / ) で連結されます。 tf. Variable と tf. get_variable 変数は tf. Variable に加えて tf. get_variabte でも宣言できます リスト 1.9 を見てみましよう。 tf. va ri a ble は、同じスコープ、同じ名前で何度でも変数を としています。 ただ変数を宣言するだけの tf. variabte に対し tf. get_variable は、変数の共有を目的 with tf. variable_scope('scopel') : リスト 1 .9 : tf. VariabIe による変数の宣言 ( 利用 ) 宣言できます。 varl 1 varl 2 tf. Variab1e(name="varI" tf. Variab1e(name="varI" initial_value=l . @) initiat_vatue=l . @) print(varl_l . name) print(varI_2. name) scopel/varl:@ scopel/varl_l:@ 一方、 tf. get_variabte は、もし同じ名前の変数が宣言されていた場合工ラーになります。 リスト 1 . 1 0 : tf. get_variable による変数の宣言 ( 利用 ) with tf. variabte_scope('scopel') : tf. get—variable( var1 1 shape=[] , ' va r 1 ' initializer=tf. constant_initializer(l .@)) tf. get—variable( var1 2 shape=[] , ' va r 1 ' initializer=tf. constant_initiatizer(l .@)) 第 1 章 TensorFlow の基礎 15
var variable_on_cpu('biases' shape, tf. constant_initializer(value)) return var def conv2d(name, input_layer, weights—shape, weight—stddev, biases_shape, biases value, strides=(), 1 , 1 , 1 ) , padding='VALID'): with tf. variabte_scope(name) as scope: —get—weights(weights—shape, stddev=weight—stddev) weights conv = tf. nn. conv2d(input_Iayer, weights, strides, padding=padding) if biases_shape is not None: —get—biases(biases—shape, value=biases—value) biases CO n V tf. nn . bias_add(conv, biases) 図 2.3 ConvolutionaI NeuraI Network return conv 33X33X1 ( 0 nv 1 9X9X64 ReLU conv2 1XIX32 ReLU conv3 5X5X1 21X21X1 ReLU 図 2.3 は、モデルを図示したものです。 うにするには、モデルに低解像度の画像を入力すると、高解像度の画像を出力するように「学 モデルを定義しただけでは、期待するとおりの機能 ( 超解像 ) は果たしません。目的に適うよ 学習 のものでも超解像を実現できます。 は、深層化の傾向を深めている昨今から見れば小さいモデルですが、正しく使えば、この規模 3 層の畳み込み層 (ConvolutionaI Layer) で構成される CNN (ConvoIutionaI NeuraI Network) いるモデルです。 これは論文「 lmage Super-Resolution Using Deep Convolutional Networksl 」で紹介されて 習」させる必要があります。 学習は、次の手順で行います。 第 2 章 CNN で超解像 25
saver . restore(sess, checkpoint. model_checkpoint_path) tf. train . start_queue_runners(sess=sess, coord=coord) threads 表 2.1 の条件で学習した場合の誤差の変化が図 2.4 です。 coord . join(threads) # Wait for threads to finish . coord. request—stop() finally: epoch limit reached ' ) print('Done training except tf. errors. OutOfRangeError: break saver. save(sess, checkpoint—path, global_step=step) print('step limit %d reached' % FLAGS. max_step) if FLAGS. max_step > 0 and FLAGS. max_step く = step: saver. save(sess, checkpoint—path, global_step=step) if (step % 1@@@@ , 。 (step, loss—value)) p ri nt ( ' Step : 96d LOSS : %. 6f , 。 , if step % 1@@@ N a N ' 'ModeI diverged with toss assert not np . isnan(loss_value) , \ [train—op, global—step, toss] sess . run( step, toss—value while not coord . should_stop() : 表 2.1 : 学習条件 条件 画像の倍率 (scale) 学習率 (learning-rate) 、ニバッチサイズ (batch_size) ステップ数 (max_step) チャンネル数 (CHANNELS) 値 0. 開 1 128 100 開 0 1 ( グレースケール ) 第 2 章 CNN で超解像 31
filename—queue = tf. train. string_input_producer(file tist, shuffte=True) tf. WhoteFileReader() reader value reader. read(filename_queue) tf. image. decode—jpeg(value, channels=channels) 1 mage lr_images ground_truths for i in range(batch—size) : tf. random—crop( cropped—image image, (input—size, input—size, channets)) lr_image = tf. image . resize—images( cropped—image' (input—size / / scate, input_size / / scate) , method=tf. image . ResizeMethod . BICUBIC) lr_image = tf. image . resize_images( lr_image, (input—size, input_size) , method=tf. image . ResizeMeth0d . BICUBIC) offset_teft (input_size ー output_size) / / 2 offset_top (input_size output—size) / / 2 ground—truth tf. image. crop—to—bounding—box( cropped—image, offset—top, offset—left, output—size, output_size) lr—images ・ append(lr—image) ground—truths . append(ground—truth) tf. stack(lr_images, axis=@) images tf. stack(ground—truths, axis=@) ground_truths return tr_images / 255 , ground_truths / 255 また、 evat. py でプロックに分割するときのスライド幅 (stride) を、 MODEL. INPUT_SIZE から MODEL. OUTPUT_SIZE に変更します ( リスト 3.6 ) 。 50 第 3 章超解像奮闘記
if biases_shape is not None: —get—biases(biases—shape, value=biases_value) biases conv = tf. nn . bias—add(conv, biases) return conv 畳み込み層は、入力に対して「フィルターによるスキャン」と「バイアスの加算」を行います。 入力とは、 2 次元の画像 + チャンネルの 3 階テンソル [ height , width, channet]lo 厳 密に言えば、、ニバッチのサイズを併せた [batch, height, width, channet] の形をし た 4 階テンソルです。 オペレーション tf. nn . conv2d は、指定した形と枚数 (weights-shape で定義されます ) のフィルターを使って、畳み込み処理をします。 畳み込み処理とは、フィルターをスライドさせて、入力をスキャンすることを言います。 図 3.2 は、フィルターが入力をスキャンする ( 畳み込む ) 様子を図示したものです。 図 3.2 33X33 の入力を、フィルターサイズ 9X9 、スライド幅 1 でスキャンした場合 編第彦第ド 第■・第第を第 第・・第第物当置 を、第を・・をー第 ■日 0 材を ・宿第画ーをー宿 を宿い 置第第重第第宿こ 第第ををき ・をー第 スキャンは左上から開始します。フィルターが右端に到達すると下にスライドして、もう一 度左端からスキャンします。これを繰り返して、次の層への出力マップを作成します。スキャ ン一回分の結果が、出力マップの 1 マスに当たります。 42 ー第 3 章超解像奮闘記