TensorFlow - Softmax
flyfish
公式
sigma(z)j=ezj∑Kk=1ezksigma(z)j=ezj∑k=1Kezk
解释 K表示K维向量
类似一个向量里面有K个实数值,通过Softmax函数输出另一个向量,另一个向量也K个实数值,每一个实数都是0到1之间的数,并且它们的和是1
将公式用代码表示
import math
z = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
z_exp = [math.exp(i) for i in z]
print([round(i, 2) for i in z_exp])
sum_z_exp = sum(z_exp)
softmax = [round(i / sum_z_exp, 3) for i in z_exp]
print(softmax)
print(sum(softmax))
输出结果
[2.72, 7.39, 20.09, 54.6, 148.41, 403.43, 1096.63]
[0.002, 0.004, 0.012, 0.032, 0.086, 0.233, 0.633]
1.002
代码解释
round()方法
返回浮点数x的四舍五入值。
语法:round( x [, n] )
参数
x – 数值表达式。
n – 数值表达式。
round(80.23456, 2) : 80.23
round(100.000056, 3) : 100.0
round(-100.000056, 3) : -100.0
exp() 函数
导入 math 模块,通过静态对象调用该方法
exp() 方法返回x的指数,e的x次方。
语法
import math
math.exp(x)
参数
x – 数值表达式。
sum函数
l = range(10) # 创建一个整数列表从 0 开始到 9
print(sum(l))
print(sum([2, 5, 8], 1))
print(sum([2, 5, 8], 2))
print(sum((2, 3, 4), 1))
45
16
17
10
Sigmod是分两类,Softmax是分多类
numpy表达方式 可使用张量
import numpy as np
import math
def softmax(x):
x_exp = np.exp(x) # (n,m)
x_sum = np.sum(x_exp, axis = 1, keepdims = True) # (n,1)
s = x_exp / x_sum # (n,m)
return s
z = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0,7.0])
z=z.reshape((1, 7))
print(softmax(z))
#[[0.0015683 0.00426308 0.01158826 0.03150015 0.0856263 0.2327564 0.6326975 ]]
print(np.sum(softmax(z)))
#1.0
验证一下
e1 =math.e ** 1
e2 =math.e ** 2
e3 =math.e ** 3
e4 =math.e ** 4
e5 =math.e ** 5
e6 =math.e ** 6
e7 =math.e ** 7
print( (e6 )/ (e1+e2+e3+e4+e5+e6+e7) )
#0.2327564043022802
TensorFlow中的Softmax 代码示例 以及对代码的解释
摘自《TensorFlow for Machine Intelligence》
# Softmax example in TF using the classical Iris dataset
# Download iris.data from https://archive.ics.uci.edu/ml/datasets/Iris
import tensorflow as tf
import os
# this time weights form a matrix, not a column vector, one "weight vector" per class.
W = tf.Variable(tf.zeros([4, 3]), name="weights")
# so do the biases, one per class.
b = tf.Variable(tf.zeros([3], name="bias"))
def combine_inputs(X):
return tf.matmul(X, W) + b
def inference(X):
return tf.nn.softmax(combine_inputs(X))
def loss(X, Y):
return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(combine_inputs(X), Y))
def read_csv(batch_size, file_name, record_defaults):
filename_queue = tf.train.string_input_producer([os.path.dirname(__file__) + "/" + file_name])
reader = tf.TextLineReader(skip_header_lines=1)
key, value = reader.read(filename_queue)
# decode_csv will convert a Tensor from type string (the text line) in
# a tuple of tensor columns with the specified defaults, which also
# sets the data type for each column
decoded = tf.decode_csv(value, record_defaults=record_defaults)
# batch actually reads the file and loads "batch_size" rows in a single tensor
return tf.train.shuffle_batch(decoded,
batch_size=batch_size,
capacity=batch_size * 50,
min_after_dequeue=batch_size)
def inputs():
sepal_length, sepal_width, petal_length, petal_width, label =\
read_csv(100, "iris.data", [[0.0], [0.0], [0.0], [0.0], [""]])
# convert class names to a 0 based class index.
label_number = tf.to_int32(tf.argmax(tf.to_int32(tf.pack([
tf.equal(label, ["Iris-setosa"]),
tf.equal(label, ["Iris-versicolor"]),
tf.equal(label, ["Iris-virginica"])
])), 0))
# Pack all the features that we care about in a single matrix;
# We then transpose to have a matrix with one example per row and one feature per column.
features = tf.transpose(tf.pack([sepal_length, sepal_width, petal_length, petal_width]))
return features, label_number
def train(total_loss):
learning_rate = 0.01
return tf.train.GradientDescentOptimizer(learning_rate).minimize(total_loss)
def evaluate(sess, X, Y):
predicted = tf.cast(tf.arg_max(inference(X), 1), tf.int32)
print sess.run(tf.reduce_mean(tf.cast(tf.equal(predicted, Y), tf.float32)))
# Launch the graph in a session, setup boilerplate
with tf.Session() as sess:
tf.initialize_all_variables().run()
X, Y = inputs()
total_loss = loss(X, Y)
train_op = train(total_loss)
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
# actual training loop
training_steps = 1000
for step in range(training_steps):
sess.run([train_op])
# for debugging and learning purposes, see how the loss gets decremented thru training steps
if step % 10 == 0:
print "loss: ", sess.run([total_loss])
evaluate(sess, X, Y)
coord.request_stop()
coord.join(threads)
sess.close()
借助对数几率回归,可对Yes-No型问题的回答进行建模。现在,希望能够回答具有多个选项的问题,如“你的出生地是波士顿、伦敦还是悉尼?”
对于这样的问题,可使用softmax函数,它是对数几率回归在C个可能不同的值上的推广。
该函数的返回值为含C个分量的概率向量,每个分量对应于一个输出类别的概率。由于各分量为概率,C个分量之和始终为1,这是因为softmax的公式要求每个样本必
须属于某个输出类别,且所有可能的样本均被覆盖。如果隐藏的类别;若各分量之和大于1,则说明每个样本可能同时属于多个类别。
可以证明,当类别总数为2时,所得到的输出概率与对数几率回归模型的输出完全相同。
为实现该模型,需要将之前的模型实现中变量初始化部分稍做修改。由于模型需要计算C个而非1个输出,所以需要C个不同的权值组,每个组对应一个可能的输出。因
此,会使用一个权值矩阵而非一个权值向量。该矩阵的每行都与一个输入特征对应,而每列都对应于一个输出类别。
在尝试softmax分类时,我们准备使用经典的鸢尾花数据集Iris(下载链接https://archive.ics.uci.edu/ml/datasets/Iris)。该数据集中包含4个数据特征及3个
可能的输出类(不同类型的鸢尾花),因此权值矩阵的维数应4×3。
变量初始化代码如下所示:
# this time weights form a matrix, not a column vector, one "weight vector" per class.
W = tf.Variable(tf.zeros([4, 3]), name="weights")
# so do the biases, one per class.
b = tf.Variable(tf.zeros([3], name="bias"))
正如所期望的那样,TensorFlow提供了一个softmax函数的内嵌实现:
这里写代码片
def inference(X):
return tf.nn.softmax(combine_inputs(X))
对数几率回归中对损失计算的考虑也同样应用于拟合一个候选损失函数,因为这里的输出也是概率值。准备再次使用交叉熵,并对其进行改造以适应多类情形。
对于单个训练样本i,交叉熵的形式变为:
将每个输出类别在训练样本上的损失相加。注意,对于训练样本的期望类别,yc应当为1,对其他情形应为0,因此实际上这个和式中只有一个损失值被计入,它度量
了模型为真实类别预测的概率的可信度。
为计算训练集上的总损失值,我们将每个训练样本的损失相加:
在代码层面,TensorFlow为softmax交叉熵函数提供了两个实现版本:一个版本针对训练集中每个样本只对应单个类别专门做了优化。例如,训练数据可能有一个类别
值或者是“dog”,或者是“person”或“tree”。这个函数是tf.nn.sparse_softmax_cross_entropy_with_logits。
def loss(X, Y):
return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(combine_inputs(X), Y))
另一个版本允许用户使用包含每个样本属于每个类别的概率信息的训练集。例如,可使用像“60%被询问的人认为这幅图片与狗有关,25%认为与树有关,其余人认
为与人有关”的训练数据,该函数是tf.nn.softmax_cross_entropy_with_logits。在一些真实用例中,可能需要这样的函数,但对于正在考虑的简单问题,并不需要
它。在可能的情况下,稀疏版本是更好的选择,因为它的计算速度非常快。注意,模型的最终输出将总是单个类别值,这个版本只是为了支持更灵活的训练数据。
下面定义输入方法。我们将复用来自对数几率回归示例中的read_csv函数,但在调用时会使用数据集中的默认值,它们都是数值型的。
为了使用sparse_softmax_cross_entropy_with_logits,无须将每个类别都转换成它自己的变量,但需要将值转换为范围是0~2的整数,因为总的类别数为3。在数据
集文件中,类别是一个来自“Iris-setosa”、“Iris-versicolor”和“Iris-virginica”的字符串。为对其进行转换,可用tf.pack创建一个张量,并利用tf.equal
将文件输入与每个可能的值进行比较。然后,利用tf.argmax找到那个张量中值为真的位置,从而有效地将各对于训练函数,内容完全相同。
为了评估模型的准确率,需要对sigmoid版本稍做修改:
def evaluate(sess, X, Y):
predicted = tf.cast(tf.arg_max(inference(X), 1), tf.int32)
print sess.run(tf.reduce_mean(tf.cast(tf.equal
(predicted, Y), tf.float32)))
推断过程将计算各测试样本属于每个类别的概率。可利用tf.argmax函数来选择预测的输出值中具有最大概率的那个类别。最后,把tf.equal与期望的类别进行比较,
并像之前sigmoid的例子中那样运用tf.reduce_mean计算准确率。
运行上述代码,可以获得约95%的准确率。