質問するログイン新規登録

回答編集履歴

3

d

2018/11/10 16:37

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -109,4 +109,66 @@
109
109
 
110
110
  # 計算した値が numpy と TensorFlow で一致するか
111
111
  print(np.allclose(loss1, loss2))
112
+ ```
113
+
114
+ ## 追記
115
+
116
+ 各処理がなにをやっているのか簡単な例を追加しました。
117
+ TensorFlow のテンソルに対して、numpy の indexing のような操作ができないようなので、少々わかりづらいやり方を取らざる得なくなっています。
118
+
119
+ ```python
120
+ import tensorflow as tf
121
+
122
+ with tf.Session() as sess:
123
+ label_dim = 6
124
+ labels = tf.constant([[1, 2, 3, 4, 5, 6],
125
+ [7, 8, 9, 10, 11, 12],
126
+ [13, 14, 15, 16, 17, 18]])
127
+
128
+ # ラベルから Y_true を抽出する。
129
+ mask = tf.tile([True, True, False], (label_dim // 3,))
130
+ print(mask.eval()) # [ True True False True True False]
131
+
132
+ # 各サンプルの 1, 2, 4, 5 列目を抜き出している。
133
+ Y_true = tf.boolean_mask(labels, mask, axis=1)
134
+ print(Y_true.eval())
135
+ # [[ 1 2 4 5]
136
+ # [ 7 8 10 11]
137
+ # [13 14 16 17]]
138
+
139
+ # ラベルから重み係数を抽出する。
140
+ mask = tf.math.logical_not(mask)
141
+ print(mask.eval()) # [False False True False False True]
142
+
143
+ # 各サンプルの 3, 6 列目を抜き出している。
144
+ coeff = tf.boolean_mask(labels, mask, axis=1)
145
+ print(coeff.eval())
146
+ # [[ 3 6]
147
+ # [ 9 12]
148
+ # [15 18]]
149
+
150
+ # 末尾に次元を1つ追加している。ones のほうも同様
151
+ print(tf.shape(coeff).eval()) # [3 2]
152
+ print(tf.shape(coeff[..., tf.newaxis]).eval()) # [3 2 1]
153
+
154
+ # 次元を1つ増やし、axis=-1 で結合している。
155
+ ones = tf.ones_like(coeff)
156
+ concat = tf.concat([ones[..., tf.newaxis], coeff[..., tf.newaxis]], axis=-1)
157
+ print(concat.eval())
158
+ # [[[ 1 3]
159
+ # [ 1 6]]
160
+ # [[ 1 9]
161
+ # [ 1 12]]
162
+ # [[ 1 15]
163
+ # [ 1 18]]]
164
+
165
+ # [3 2 2] を [3, 4] に戻している。
166
+ W = tf.reshape(concat, [tf.shape(ones)[0], -1])
167
+ print(tf.shape(concat).eval()) # [3 2 2]
168
+ print(tf.shape(W).eval()) # [3 4]
169
+
170
+ print(W.eval())
171
+ # [[ 1 3 1 6]
172
+ # [ 1 9 1 12]
173
+ # [ 1 15 1 18]]
112
174
  ```

2

d

2018/11/10 16:37

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -3,66 +3,110 @@
3
3
 
4
4
  ## 問題設定
5
5
 
6
- 簡単にするため、バッチ次元及び最後の2つの次元は除いています。
6
+ BatchSize=30, LabelDim=75, OutputDim=50
7
7
 
8
- モデルの入力データ X: (InputDims) numpy 配列
8
+ モデルの入力 data: (BatchSize, 16, 16, 1) の配列
9
- モデルの出力データ Y_pred: (InputDims // 3 * 2) の numpy 配列
9
+ モデルの出力 Y_pred: (BatchSize, OutputDim) の配列
10
+ ラベル labels: (BatchSize, LabelDim) の配列
10
11
 
11
- まず入力データ X を MSE を計算する際の正解データと重み係数に分解します。
12
- 配列 X のうち、1, 2, 4, 5, 7, 8, ... というように3の倍数以外のインデックスの要素を抽出した部分配列を作り、
13
- これを Y_true とします。
12
+ ## サンプルコード
14
- また配列 X のうち、3, 6, 9, ... というように3の倍数のインデックスの要素を抽出した部分配列を作り、W とします。
15
13
 
16
- W の要素に w_1, w_2, w_3, ... に交互に1を加えて、
17
- W = [1, w_1, 1, w_2, ...] とします。
14
+ ### テスト用に入力及びラベルを作成
18
15
 
16
+ ```python
19
- すると、サンプル1つの損失関数は以下のように表せます。
17
+ import numpy as np
20
18
 
21
- mean((Y_true - Y_pred) ** 2 * W)
19
+ batch_size = 30 # バッチサイズ
20
+ input_shape = (16, 16, 1) # モデルの入力サイズ
21
+ label_dim = 75 # ラベルの次元数
22
+ output_dim = 50 # 出力の次元数
22
23
 
23
- ## numpy サンプルコ
24
+ # ダミー入力デタ及びラベルを作成する。
25
+ data = np.random.randn(batch_size, *input_shape) # データ
26
+ labels = np.random.randn(batch_size, label_dim) # ラベル
27
+ print('data.shape', data.shape) # data.shape (30, 16, 16, 1)
28
+ print('labels.shape', labels.shape) # labels.shape (30, 75)
29
+ ```
24
30
 
31
+ ### テスト用に簡単なモデルを作成する。
32
+
25
33
  ```python
26
- batch_size = 30
27
- input_dim = 75
34
+ import tensorflow as tf
28
- assert 75 % 3 == 0 # input_dim は3で割り切れないとおかしい
35
+ from keras.models import Sequential
29
- output_dim = input_dim // 3 * 2
36
+ from keras.layers import Conv2D, GlobalMaxPooling2D
30
37
 
31
- # ダミーの入力データ及び出力データを作成する。
32
- input_tensor = np.random.randn(batch_size, input_dim, 1, 1)
38
+ # 入力が (BatchSize, 16, 16, 1) で出力が (BatchSize, 50) のダミーのモデルを作成する。
33
- Y_pred = np.random.randn(batch_size, output_dim, 1, 1)
39
+ model = Sequential()
34
- print('input_tensor.shape', input_tensor.shape) # input_tensor.shape (30, 75, 1, 1)
40
+ model.add(Conv2D(output_dim, kernel_size=(3, 3), input_shape=input_shape))
35
- print('Y_pred.shape', output_tensor.shape) # Y_pred.shape (3, 8, 1, 1)
41
+ model.add(GlobalMaxPooling2D())
42
+ model.summary()
43
+ ```
36
44
 
45
+ ```
37
- # 入力データ X を MSE を計算する際の正解データと重み係数に分解
46
+ _________________________________________________________________
38
- ##############################################################
47
+ Layer (type) Output Shape Param #
48
+ =================================================================
49
+ conv2d_1 (Conv2D) (None, 14, 14, 50) 500
50
+ _________________________________________________________________
51
+ global_max_pooling2d_1 (Glob (None, 50) 0
52
+ =================================================================
53
+ Total params: 500
54
+ Trainable params: 500
55
+ Non-trainable params: 0
56
+ _________________________________________________________________
57
+ ```
39
58
 
40
- # 1, 2, 4, 5, 7, 8, ... というように3の倍数以外が True のマスク
41
- Y_true_indices = np.mod(np.arange(input_dim) + 1, 3) != 0
42
- print(Y_true_indices)
59
+ ### 損失関数の定義
43
- # [ True True False True True False True True False True True False]
44
60
 
45
- # 3, 6, 9, ... というように3の倍数が True のマスク
61
+ ```python
46
- W_indices = np.logical_not(Y_true_indices)
62
+ def custom_loss(labels, Y_pred):
63
+ # ラベルから Y_true を抽出する。
47
- # [False False True False False True False False True False False True]
64
+ mask = tf.tile([True, True, False], (label_dim // 3,))
48
- print(W_indices)
65
+ Y_true = tf.boolean_mask(labels, mask, axis=1)
49
66
 
67
+ # ラベルから重み係数を抽出する。
50
- Y_true = input_tensor[:, Y_true_indices, ...]
68
+ mask = tf.math.logical_not(mask)
51
- coeff = input_tensor[:, W_indices, ...]
69
+ coeff = tf.boolean_mask(labels, mask, axis=1)
52
- print('Y_true.shape', Y_true.shape) # Y_true.shape (30, 50, 1, 1)
53
- print('coeff.shape', coeff.shape) # coeff.shape (30, 25, 1, 1)
54
70
 
71
+ # 重み係数を作成する。
72
+ ones = tf.ones_like(coeff)
73
+ W = tf.reshape(
74
+ tf.concat([ones[..., tf.newaxis], coeff[..., tf.newaxis]], axis=-1),
75
+ [tf.shape(ones)[0], -1])
76
+
77
+ return tf.reduce_mean((Y_true - Y_pred) ** 2 * W)
78
+ ```
79
+
80
+ ### 損失関数の値計算
81
+
82
+ ```
83
+ model.compile(loss=custom_loss, optimizer='adam')
84
+ model.fit(data, labels, epochs=3)
85
+ loss1 = model.evaluate(data, labels)
86
+ print(loss1) # 0.6780742406845093
87
+ ```
88
+
89
+ ### numpy での計算
90
+
91
+ ```
92
+ # モデルの出力
93
+ Y_pred = model.predict(data)
94
+
95
+ # ラベルから Y_true を抽出する。
96
+ mask = np.ones(labels.shape[1], dtype=bool)
97
+ mask[2::3] = False
98
+ Y_true = labels[:, mask]
99
+
100
+ # ラベルから重み係数を抽出する。
101
+ mask = np.logical_not(mask)
102
+ coeff = labels[:, mask]
103
+
55
104
  # 重み係数を作成する。
56
105
  W = np.ones_like(Y_true)
57
- W[:, 1::2, ...] = coeff
106
+ W[:, 1::2] = coeff
58
- print('W.shape', W.shape) # W.shape (30, 50, 1, 1)
59
107
 
60
- # 重み付き2乗誤差
61
- loss = np.mean((Y_true - Y_pred) ** 2 * W)
108
+ loss2 = np.mean((Y_true - Y_pred) ** 2 * W)
62
- print(loss)
63
- ```
64
109
 
65
- ## Keras でこれと同じことを行うには
66
-
67
- Keras Lambda 関数内では TensorFlow の関数を利用きま
110
+ # 計算した値が numpy TensorFlow で一致るか
68
- numpy でできることは TensorFlow の関数を使ってもできるので、同じ方針で作りましょう。
111
+ print(np.allclose(loss1, loss2))
112
+ ```

1

d

2018/11/10 14:24

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -1,7 +1,7 @@
1
1
  Python では数値計算を行うための for 文は基本的に遅くなるため NG です。
2
2
  for 文を使わないで計算できるようにしましょう。
3
3
 
4
- ## 問題設定とその理解
4
+ ## 問題設定
5
5
 
6
6
  簡単にするため、バッチ次元及び最後の2つの次元は除いています。
7
7