実行結果に、プレースホルダーに与えた値が反映されています。 なお、プレースホルダーに値を与えずに関連したオペレーションを実行すると、必要なデー タがないため工ラーになります。必須でないプレースホルダーを示すため、あらかじめ初期値 を指定する tf. placeholder-with-default もあります。 演算子のオーバーロード これまで演算オペレーションとして tf. add や tf. multiply を使ってきました。これらは 一般的な演算子に書き換えることができます ( リスト 1.14 ) 。 リスト 1 .14 . tf. add と演算子 + は同じ意味 varl ニ tf. constant(l) var2 = tf. constant(2) tf. add(varl, var2) varl 十 var2 resuIt1 resuIt2 print(resutt2) with tf. Session() as sess: print(sess . run(resultl)) print(sess . run(resuIt2)) dtype=int32) shape=() , Tensor("add_1:@" 3 3 resuttl と result2 の結果は同じになりました 一度目の print(resuIt2) で表示されるのが Tensor("add-1:@" shape=(), dtype = int32 ) であることに注意してください。演算子 + はオーバーロードで tf. add に置き 換えられています。そのため、オペレーションを実行するまで値は得られません。 プロードキャスティング プロードキャスティング (Broadcasting) は、 NumPy5 で一般的な機能です。プロードキャス ティングを使うと、形の異なる配列同士を自動的に変換して計算できます。 リスト 1.15 のように、本来、一次元配列の arrayl とスカラーの vatuel は、そのままでは t 算できませんが、プロードキャスティングにより計算が可能になります。 一三ロ 18 第 1 章 TensorFlow の基礎
OS . path . join(dir, MODEL. NAME) dir if not os . path . exists(dir) : os . mkdir(dir) OS . path . j 0i n ( di r , 96s—96dx ・ png OS . path . j Oi n ()i r , '96s-96dx—resuIt. png padded_fite % (name, scate)) resutt file % (name, scale)) lmage . open(image—path) 1 mage image. resize( resized_image (image. width ☆ scale, image . height ☆ scale) , lmage . BICUBIC) if MODEL . CHANNELS resized image resized_image . convert('L') calc—padding(resized—image, stride) padding —pad(resized—image, padding=padding) resized_image —save—image(resized—image, padded—file, padding=padding) extract_btocks(resized—image, stride) btocks —process(blocks, train—dir) btocks —reconstruct(btocks) resutt_image normalize(result_image) ☆ 255 result_image round((MODEL. INPUT_SIZE MODEL . OUTPUT_SIZE) / 2 ) pad pad padding[INDEX_PADDING_LEFT] pad paddingCINDEX_PADDING_TOP] padding[INDEX_PADDING_RIGHT] + = pad padding[INDEX_PADDING_BOTTOM] + = pad —save_image(result image, result—fite, padding=padding) file, padded—file return result 平価 一平価用の画像として、縦横 510PX5 の画像を用意しました ( 図 2.5 ) 。 三ロ 38 第 2 章 CNN で超解像
リスト 3.6 : srcnn/eval.py def _srcnn(image—path, scale, # スライド幅を変更 stride (MODEL. OUTPUT_SIZE, train_dir): MODEL. OUTPUT_SIZE) name, ext = OS. path. sptitext(os. path. basename(image_path)) dir OS . path . dirname(image_path) dir OS . path. join(dir, MODEL . NAME) if not os . path . exists(dir): os . mkdir(dir) padded_fite result fite OS . path . j Oi n ()i r , 96s—96dx ・ png % (name, scale)) OS . path . join(dir, '96s—96dx—resuIt ・ png % (name, scale)) lmage ・ open(image—path) 1 mage resized_image image . resize( (image. width 大 scale, image ・ height ☆ scale) , 工 mage. BICUBIC) if MODEL . CHANNELS resized image 1 : resized—image. convert('L') padding calc—padding(resized—image, stride) resized_image —pad(resized—image, padding=padding) —save—image(resized—image, padded—fite, padding=padding) blocks blocks extract_blocks(resized—image, stride) —process(btocks, train—dir) resutt_image result_image —reconstruct(blocks) _normalize(resutt_image) ☆ 255 # パディングの再計算 pad round ( (MODEL. INPUT_SIZE MODEL. OUTPUT_S 工 (E) / 2 ) padding[ 工 NDEX_PADDING_LEFT] pad padding[ 工 NDEX—PADDING_TOP] pad padding[INDEX_PADDING_RIGHT] + = pad padding[INDEX_PADDING_BOTTOM] + ニ pad —save—image(resutt—image, result—file, padding=padding) 第 3 章超解像奮闘記 51
result [@ for i in range(h_num)] for j in range(v_num) for row in range(v_num) : for C01 in range(h_num) : block sess. run(logits, feed_dict={ image—ptacehotder: blocks[row] [ C01 ] result[row] [ C01 ] btock[@] return result プロックの再構成 リスト 2.11 の関数 __reconstruct は、 変換可能な形にします。 リスト 2.1 1 : s ℃ nn/eval.py def —reconstruct(blocks) : ー process で処理したプロックを連結して、画像に V num h num resutt ten(blocks) ten(btocks[@]) None for row in range(v_num) : horizontal None for C01 in range(h_num) : if horizontal is None: np . hstack((horizontal, horizontat etse: blocks[row] [ C01 ] horizontal btocks[row] [col] ) ) if resutt is None: horizontal result etse: resutt np . vstack((result, return result horizontat) ) 36 第 2 章 CNN で超解像
図 3.13 評価用画像 ( 拡大 ) LOW Resolution Super ResoIution 活性化関数 ノイズの原因を探るため、プロックを再構築した直後の NumPy Array の最大値 (np. argmax を確認すると、 1 . @ 以上の値が含まれていることがわかりました リスト 3.8 : result_image の最大・最小値を表示 extract_blocks(resized_image, stride) btocks —process(btocks, train—dir) btocks —reconstruct(blocks) result np . argmax(result—image) amax np. argmin(result_image) print(' ・ 0'f . , 0 ・ O'f 0 / , 0 (amax, amin)) amax . ′ 0 resutt image ☆ 255 result 1 .120654 , amnn: amax : ピクセルの値域である 0-255 を超過した箇所か 1 . @ を超える値に 255 を積算しているため、 54 第 3 章超解像奮闘記
図 1 .1 グラフを構成するオペレーション tf. add constl const2 今回の場合、 const1,const2,add—op は、 Python プログラム上では変数ですが、 TensorFlow ではデータフローグラフを構成するノード、つまり「オペレーション」です 2 。 そのため print で中身を見ようとしても「 Tensor 」としか表示されません。 グラフの実行 構築したグラフの処理結果を得るには、セッション (tf. session) の中で、結果を得たい オペレーションを実行 (run) する必要があります。 run は、オペレーションが指定されると、そのオペレーションに接続されているグラフを処 リスト 1.3 は、オペレーション add ー op を実行しています。 理して、結果を NumPy の ndarray オプジェクトとして返します。 リスト 1 .4 : rrul_op と add_op を実行 ともできます。 また、 ru n の引数にオペレーションのリストを渡せば、複数のオペレーションを実行するこ print(result) resutt sess . run(add—op) sess = tf. Session() リスト 1 .3 : d ー op を実行 constl const2 add—op mul—op tf. constant(2) tf. constant(3) tf. add(constl, const2) tf. multiply(add—op, const2) with tf. Session() as sess: sess . run( 10 mut resutt, add_result 第 1 章 TensorFIow の基礎 —op, add—op])
リスト 1 .17 : Tenso 「 Boa 「 d にデータを書き出す constl const2 add—op mul—op tf. constant(2) tf. constant(3) tf. add(constl, const2) tf. muttiply(add—op, const2) with tf. Session() as sess: mul_result, add_resutt print(mul—result) print(add—result) sess . run( [mul—op, add—op] ) tf. summary. FiIeWriter(' . /, sess ・ graph) リスト 1.17 を実行すると、スクリプトと同じディレクトリに TensorBoard 用のファイル 6 が作 成されます。 Tenso 「 Boa 「 d の起動 次に、 TensorBoard を起動します。 TensorFIow がインストールされていれば、コマンド tensorboard で起動できます 引数ーー logdir には、 tf. summary. Filewriter に指定した出力先のディレクトリを指定 します。 $ tensorboard ー logdir ニ [ TensorBoard 用のファイルがあるディレクトリ ] Starting TensorBoard b ' 47 ' at http : / / 0.0.0.0 : 6006 (Press CTRL + C to quit) プラウザで http.//10Ca1h0St:6006 にアクセスして、上部メニューから「 GRAPH 」を選択する と、構築したグラフ画像が表示されます。画像を見れば、オペレーション同士がどう結びつい ているのか視覚的に確認することができます。 20 第 1 章 TensorFlow の基礎
VaIueError: VariabIe scopel/varl already exists, disallowed . reuse=True in VarScope? OriginaIIy defined at: FiIe " く stdin>" Iine 2 , in く module> Did you mean tO set 変数を宣言した状態で、既にある変数を利用するには、 スコープ宣言で reuse=True を指定 します。 リスト 1 .1 1 : 一度宣言した変数を取得 with tf. variable_scope('scopel') : tf. get—variable( varl shape=[] , 'varl initiatizer=tf. constant_initializer(l . @)) tf. assign(varl, ー 1 . の varl with tf. Session() as sess: sess . run(tf. globat—variabtes_initializer()) varl_result = sess . run(varl) print('varl , 。 varl_result) with tf. variabte_scope('scopel' var2 = tf. get—variable( shape=[] , ' va r 1 ' initializer=tf. constant_initializer(l . @)) var2 result sess. run(var2) print('var2 % var2—resuIt) reuse=True) : ー 1 .000000 varl var2 scopel/varl は、一度目も二度目も、初期値として 1.0 を指定しています。しかし、二度目 の get-variabte で取得した scopel/var の値は、一度目に宣言した後に代入した値 -1.0 と なっています プレースホルダー プレースホルダー (placeholder) はデータが格納される予定地です。データは未定のままグ ラフを構築し、具体的な値は実行するときに与えます。 プレースホルダーを利用するケースとして、ファイルから読み込んだデータをグラフに与え て処理する場合が考えられます。 16 第 1 章 TensorFlow の基礎
print(mul—result) print(add—resuIt2) リスト 1.4 では、加算した結果に const2 を積算するオペレーション mut ー op を実行していま tf. add tf. multiply 図 1 .2 tf. multiply に tf. add と const2 を入力 す。このオペレーションを図にすると図 1.2 のようになります。 constl const2 実行結果は次の通りです。 15 5 このように、セッションの中でグラフを構成するいすれかのオペレーションを実行して結果 を取り出すことができます。 テンソル (Tensor) たとえば画像データを表す場合、 Tensor の Rank は [ 3 ] 、 Shape は [width, height, にはデータ型 (Type) があります ( 表 1.2 ) 。 Rank は「テンソルの階数」、 Shape は「テンソルの形」を意味します ( 表 1.1) 。また、 Tensor Rank と Shape, Type 差し支えありません。 扱います。以後、 Tens 。 rFl 。 w の文脈で触れる「 Tensor 」は、「 n 次元の多次元配列」と考えて TensorFIow は、グラフを構成するすべてのオペレーションを「 Tensor ( テンソル ) 」として channel] 、データ型は tf. uint83 となります。 第 1 章 TensorFIow の基礎 11
リスト 1 . 1 2 : プレースホルダーの宣 tf.Variabte(@) varl hotder2 tf. placeholder(tf. int32) add—op = tf. add(varl, h0tder2) update_varl tf. assign(varl, add—op) mut—op = tf. multiply(add_op, update_varl) リスト 1.12 では、プレースホルダー hotder2 を作成しています。しかし、定数や変数のとき 図 1 .4 プレースホルダーを追加したグラフ のように初期値を与えていません。型として tf. int32 を指定しているだけです。 tf. add va 「 1 Va 「 iables tf. multiply va 「 1 tf. assign va 「 1 holde 「 2 プレースホルダーの値は、オペレーションの実行時に feed ー dict を通じて与えます。 ト 1.13 では、 holder2 の値として「 5 」を与えています。 リスト 1 . 1 3 : プレースホルダーに値を与える with tf. Session() as sess: sess . run(tf. global—variables—initializer()) sess . run(mut—op, feed—dict={ 5 result hotder2 print(resutt) 25 第 1 章 TensorFlow の基礎 リス 17