共有レイヤーセクションの下にあるKeras [〜#〜] api [〜#〜] のコードを使用してマルチタスク回帰モデルを実装しています。
次のように2つのデータセットがあります。それらをdata_1
およびdata_2
と呼びましょう。
data_1 : shape(1434, 185, 37)
data_2 : shape(283, 185, 37)
data_1
は1434のサンプルで構成され、各サンプルは185文字で、37は一意の文字の総数が37であること、つまりvocab_size
であることを示します。比較的data_2
は283文字で構成されています。
埋め込みレイヤーに渡す前に、次のようにdata_1
とdata_2
を2次元のnumpy配列に変換します。
data_1=np.argmax(data_1, axis=2)
data_2=np.argmax(data_2, axis=2)
これにより、データの形状は次のようになります。
print(np.shape(data_1))
(1434, 185)
print(np.shape(data_2))
(283, 185)
マトリックスの各数値は、インデックス整数を表します。
マルチタスクモデルは次のとおりです。
user_input = keras.layers.Input(shape=((185, )), name='Input_1')
products_input = keras.layers.Input(shape=((185, )), name='Input_2')
shared_embed=(keras.layers.Embedding(vocab_size, 50, input_length=185))
user_vec_1 = shared_embed(user_input )
user_vec_2 = shared_embed(products_input )
input_vecs = keras.layers.concatenate([user_vec_1, user_vec_2], name='concat')
input_vecs_1=keras.layers.Flatten()(input_vecs)
input_vecs_2=keras.layers.Flatten()(input_vecs)
# Task 1 FC layers
nn = keras.layers.Dense(90, activation='relu',name='layer_1')(input_vecs_1)
result_a = keras.layers.Dense(1, activation='linear', name='output_1')(nn)
# Task 2 FC layers
nn1 = keras.layers.Dense(90, activation='relu', name='layer_2')(input_vecs_2)
result_b = keras.layers.Dense(1, activation='linear',name='output_2')(nn1)
model = Model(inputs=[user_input , products_input], outputs=[result_a, result_b])
model.compile(optimizer='rmsprop',
loss='mse',
metrics=['accuracy'])
次に、次のようにモデルを適合させます。
model.fit([data_1, data_2], [Y_1,Y_2], epochs=10)
エラー:
ValueError: All input arrays (x) should have the same number of samples. Got array shapes: [(1434, 185), (283, 185)]
Kerasで2つの異なるサンプルサイズの入力を使用したり、このエラーを回避してマルチタスク回帰の目標を達成するためのトリックを実行したりする方法はありますか?.
これがテストのための最小の作業コードです。
data_1=np.array([[25, 5, 11, 24, 6],
[25, 5, 11, 24, 6],
[25, 0, 11, 24, 6],
[25, 11, 28, 11, 24],
[25, 11, 6, 11, 11]])
data_2=np.array([[25, 11, 31, 6, 11],
[25, 11, 28, 11, 31],
[25, 11, 11, 11, 31]])
Y_1=np.array([[2.33],
[2.59],
[2.59],
[2.54],
[4.06]])
Y_2=np.array([[2.9],
[2.54],
[4.06]])
user_input = keras.layers.Input(shape=((5, )), name='Input_1')
products_input = keras.layers.Input(shape=((5, )), name='Input_2')
shared_embed=(keras.layers.Embedding(37, 3, input_length=5))
user_vec_1 = shared_embed(user_input )
user_vec_2 = shared_embed(products_input )
input_vecs = keras.layers.concatenate([user_vec_1, user_vec_2], name='concat')
input_vecs_1=keras.layers.Flatten()(input_vecs)
input_vecs_2=keras.layers.Flatten()(input_vecs)
nn = keras.layers.Dense(90, activation='relu',name='layer_1')(input_vecs_1)
result_a = keras.layers.Dense(1, activation='linear', name='output_1')(nn)
# Task 2 FC layers
nn1 = keras.layers.Dense(90, activation='relu', name='layer_2')(input_vecs_2)
result_b = keras.layers.Dense(1, activation='linear',name='output_2')(nn1)
model = Model(inputs=[user_input , products_input], outputs=[result_a, result_b])
model.compile(optimizer='rmsprop',
loss='mse',
metrics=['accuracy'])
model.fit([data_1, data_2], [Y_1,Y_2], epochs=10)
新しい回答:
ここでは、TensorFlow 2を使用したソリューションを作成しています。したがって、必要なものは次のとおりです。
データから形をとる動的入力を定義する
平均プーリングを使用して、デンスレイヤーディメンションが入力ディメンションから独立します。
損失を個別に計算する
これが動作するように変更された例です:
## Do this
#pip install tensorflow==2.0.0
import tensorflow.keras as keras
import numpy as np
from tensorflow.keras.models import Model
data_1=np.array([[25, 5, 11, 24, 6],
[25, 5, 11, 24, 6],
[25, 0, 11, 24, 6],
[25, 11, 28, 11, 24],
[25, 11, 6, 11, 11]])
data_2=np.array([[25, 11, 31, 6, 11],
[25, 11, 28, 11, 31],
[25, 11, 11, 11, 31]])
Y_1=np.array([[2.33],
[2.59],
[2.59],
[2.54],
[4.06]])
Y_2=np.array([[2.9],
[2.54],
[4.06]])
user_input = keras.layers.Input(shape=((None,)), name='Input_1')
products_input = keras.layers.Input(shape=((None,)), name='Input_2')
shared_embed=(keras.layers.Embedding(37, 3, input_length=5))
user_vec_1 = shared_embed(user_input )
user_vec_2 = shared_embed(products_input )
x = keras.layers.GlobalAveragePooling1D()(user_vec_1)
nn = keras.layers.Dense(90, activation='relu',name='layer_1')(x)
result_a = keras.layers.Dense(1, activation='linear', name='output_1')(nn)
# Task 2 FC layers
x = keras.layers.GlobalAveragePooling1D()(user_vec_2)
nn1 = keras.layers.Dense(90, activation='relu', name='layer_2')(x)
result_b = keras.layers.Dense(1, activation='linear',name='output_2')(nn1)
model = Model(inputs=[user_input , products_input], outputs=[result_a, result_b])
loss = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.Adam()
loss_values = []
num_iter = 300
for i in range(num_iter):
with tf.GradientTape() as tape:
# Forward pass.
logits = model([data_1, data_2])
loss_value = loss(Y_1, logits[0]) + loss(Y_2, logits[1])
loss_values.append(loss_value)
gradients = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(Zip(gradients, model.trainable_weights))
import matplotlib.pyplot as plt
plt.plot(range(num_iter), loss_values)
plt.xlabel("iterations")
plt.ylabel('loss value')
古い回答:
あなたの問題はコーディングの問題ではなく、機械学習の問題です!データセットをペアにする必要があります。つまり、Kerasモデルを各ラウンドの両方の入力レイヤーにフィードする必要があります。
ソリューションは、両方のデータセットのサイズが同じになるように、より小さなデータセットをアップサンプリングします。そして、その方法は、データセットのセマンティクスに依存します。もう1つのオプションは、より大きなデータセットをダウンサンプリングすることですが、これはお勧めできません。
非常に基本的な状況で、サンプルがi.i.dであると仮定すると、データセット全体で、次のコードを使用できます。
random_indices = np.random.choice(data_2.shape[0],
data_1.shape[0], replace=True)
upsampled_data_2 = data_2[random_indices]
したがって、新しいデータセットの新しいバージョンupsampled_data_2
、これにはいくつかの繰り返しサンプルが含まれていますが、より大きなデータセットと同じサイズです。
あなたがしようとしている場合、それはあなたの質問で明確ではありません:
user
とproduct
を取り、その(user, product)
ペアについて2つのことを予測する単一のモデルを作成します。 user
とproduct
がペアになっていない場合、これが何かを意味していることは明らかではありません(@ matias-valdenegroが指摘したとおり)。他のタイプのランダム要素をペアにする場合( 最初の回答 のように)。各出力が他の入力を無視することを学習することを期待します。これは次と同等です。
埋め込みレイヤーを共有する2つのモデルを作成します(この場合、連結は意味がありません)。 Y1
がdata1
と同じ長さであり、Y2
がdata2
と同じ形状である場合、これはおそらく必要なものです。このように、user
がある場合はuser
モデルを実行でき、product
がある場合はproduct
モデルを実行できます。
あなたは本当に#2が欲しいと思います。それを訓練するためにあなたは次のようなことをすることができます:
for user_batch, product_batch in Zip(user_data.shuffle().repeat(),
product_data.shuffle().repeat()):
user_model.train_on_batch(*user_batch)
product_model.train_on_batch(*product_batch)
step = 1
if step > STEPS:
break
または、両方を組み合わせたモデルでラップします。
user_result = user_model(user_input)
product_result = product_model(product_input)
model = Model(inputs=[user_input , products_input],
outputs=[user_result, product_result])
model.compile(optimizer='rmsprop',
loss='mse',
metrics=['accuracy'])
model.fit([data_1, data_2], [Y_1,Y_2], epochs=10)
使用するトレーニング手順に関係なく、2つのモデルの損失が比較できるように出力範囲を正規化する必要があります。最初の手順では、エポックまたはステップを入れ替えます。 2つ目は、2つの損失の加重和に対して単一の勾配ステップを実行します。どの損失の重み付けが最適かを確認することをお勧めします。
この答えについては、「ユーザーと製品をペアリングするためのルールはありません」、そして単にランダムにサンプリングしたいとします。
これに対する答えはすでにありますが、固定されたペアがあり、ペアを変更する必要があるため、その答えは偏っています。このためには、ジェネレーターが必要です。
_def generator(data_1, data_2, y1, y2, batchSize):
l1 = len(data_1)
l2 = len(data_2)
#extending data 2 to the same size of data 1
sampleRelation = l1 // l2 #l1 must be bigger
if l1 % l2 > 0:
sampleRelation += 1
data_2 = np.concatenate([data_2] * sampleRelation, axis=0)
y2 = np.concatenate([y2] * sampleRelation, axis=0)
data_2 = data_2[:l1]
y2 = y2[:l1]
#batches per Epoch = steps_per_Epoch
batches = l1 // batchSize
if l1 % batchSize > 0:
batches += 1
while True: #keras generators must be infinite
#shuffle indices in every Epoch
np.random.shuffle(data_1)
np.random.shuffle(data_2)
#batch loop
for b in range(batches):
start = b*batchSize
end = start + batchSize
yield [data_1[start:end], data_2[start:end]], [y1[start:end], y2[start:end]]
_
model.fit_generator(generator(data_1, data_2, Y_1, Y_2, batchSize), steps_per_Epoch = same_number_of_batches_as_inside_generator, ...)
を使用してモデルをトレーニングする
私の推測が正しければ、ユーザーと製品の間に関係はなく、単に2つのモデルを同時にトレーニングするだけです。この場合、私はこのアーキテクチャを提案します: