我了解,如果我的分类输入有多个可能的值(例如国家或地区),则可以使用onehot张量(表示为多个0且只有一个1)。
我还了解到,如果变量具有许多可能的值(例如成千上万的邮政编码或学校ID),单热点张量可能无效,我们应该使用其他表示形式(基于哈希?)。但是我还没有找到文档或有关如何使用JavaScript版本的TensorFlow进行操作的示例。
有任何提示吗?
更新 @edkeveked给了我有关使用嵌入的正确建议,但是现在我需要一些有关如何在tensorflowjs中实际使用嵌入的帮助。
让我尝试一个具体的例子:
让我们假设我有一些人的记录,这些人的年龄(整数),州(0到49之间的整数)和风险(0或1)。
const data = [
{age: 20, state: 0, risk: 0},
{age: 30, state: 35, risk: 0},
{age: 60, state: 35, risk: 1},
{age: 75, state: 17, risk: 1},
...
]
当我想使用tensorflowjs创建一个分类器模型时,我会将状态编码为单热张量,将风险-标签-设为单热张量(风险:01,无风险10),然后使用密集层,如下所示:
const inputTensorAge = tf.tensor(data.map(d => d.age),[data.length,1])
const inputTensorState = tf.oneHot(data.map(d => d.state),50)
const labelTensor = tf.oneHot(data.map(d => d.risk),2)
const inputDims = 51;
const model = tf.sequential({
layers: [
tf.layers.dense({units: 8, inputDim:inputDims, activation: 'relu'}),
tf.layers.dense({units: 2, activation: 'softmax'}),
]
});
model.compile({loss: 'categoricalCrossentropy', "optimizer": "Adam", metrics:["accuracy"]});
model.fit(tf.concat([inputTensorState, inputTensorAge],1), labelTensor, {epochs:10})
(顺便说一句...我是tensorflow的新手,所以可能有更好的方法...但这对我有用)
现在...我的挑战。如果我想要一个类似的模型,但是现在我有一个邮政编码而不是状态(假设该邮政编码有10000个可能的值):
const data = [
{age: 20, postcode: 0, risk: 0},
{age: 30, postcode: 11, risk: 0},
{age: 60, postcode: 11, risk: 1},
{age: 75, postcode: 9876, risk: 1},
...
]
如果我想使用嵌入来表示邮政编码,那么我知道我应该使用嵌入层,例如:
tf.layers.embedding({inputDim:10000, outputDim: 20})
因此,如果我仅使用邮政编码作为输入并省略了年龄,则模型将为:
const model = tf.sequential({
layers: [
tf.layers.embedding({inputDim:10000, outputDim: 20})
tf.layers.dense({units: 2, activation: 'softmax'}),
]
});
如果我将输入张量创建为
inputTensorPostcode = tf.tensor(data.map(d => d.postcode);
然后尝试 model.fit(inputTensorPostcode,labelTensor,{epochs:10})
这行不通...所以我显然做错了。
关于如何创建模型以及如何使model.fit嵌入的任何提示?
也...如果我想组合多个输入(例如邮政编码和年龄),该怎么办?
答案 0 :(得分:2)
对于分类数据,可以使用单热编码来解决该问题。一键式编码的问题在于,它通常会导致稀疏的数据具有很多零。
处理分类数据的另一种方法是减小输入数据的维数。此技术称为embeddings。要创建涉及分类数据的模型,可以使用Js API中提供的embedding layer。
编辑: 数据不是真正的分类数据,尽管可以这样构建,也没有理由这样做。用于推荐系统的经典分类数据的示例是包含用户是否观看过的电影的数据。数据如下所示:
________________________________________________
| moovie 1 | moovie 2 | moovie 3| --- | moovie n|
|__________|__________|_________|______|_________|
user 1 | 0 | 1 | 1 | --- | 0 |
user 2 | 0 | 0 | 1 | --- | 0 |
user 3 | 0 | 1 | 0 | --- | 0 |
. | . | . | . | --- | . |
. | . | . | . | --- | . |
. | . | . | . | --- | . |
此处的输入维数是Moovies n
的数量。这样的数据可能非常稀疏,带有很多零。因为数据库可能包含成千上万的电影,而普通用户几乎看不到超过一千的电影。在这种情况下,将有一千个字段包含1,所有其余字段都包含0。需要使用embeddings
来聚合这样的数据,以便将维数从n
减小到较小。
情况并非如此。输入数据只有2个特征age
和postcode
。输入数据维为2,输出(标签)始终为一维(此处的标签为risk
属性)。但是由于有两个类别,因此输入维度的大小为2。邮政编码值的范围不会影响我们的分类
const data = [
{age: 20, state: 0, risk: 0},
{age: 30, state: 35, risk: 0},
{age: 60, state: 35, risk: 1},
{age: 75, state: 17, risk: 1}
]
const model = tf.sequential()
model.add(tf.layers.dense({inputShape: [2], units: 10, activation: 'relu'}))
model.add(tf.layers.dense({activation: 'softmax', units: 2}))
const x = tf.tensor2d(data.map(e => [e.age, e.state]), [data.length, 2])
const y = tf.oneHot(tf.tensor1d(data.map(e => e.risk), "int32"), 2)
model.compile({optimizer: 'adam', loss: 'categoricalCrossentropy' })
model.fit(x, y, {epochs: 10}).then(() => {
// prediction will look like [p, 1-p] with 0 <= p <= 1
// predictions [p, 1-p] such that p > 0.5 are in one category
// predictions [p, 1-p] such that 1-p > 0.5 are in the 2 category
// prediction for age 30 and postcode 35 is the same with age 0 and postcode 35
// (they both will either have p > 0.5 or p < 0.5)
// the previous prediction will be different for age 75 postcode 17
model.predict(tf.tensor2d([[30, 35], [0, 20], [75, 17]])).print()
})
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.13.0"> </script>
</head>
<body>
</body>
</html>