导入数据
网上有很多的关于鸢尾花分类的博客都是从sklearn中直接导入的,因为上课的需要,需要用自己的数据来导入。我的数据是放在txt文件中的,首先看看大概的数据:
这里的前4列是花的特征,且我的数据只有100行,且只有两种花(最后一列独热编码只有0,1),当然3种花的做法和两种花的做法是一样的。后面用softmax来进行分类时会用到150行的数据,且有3种花。
导入数据的代码:
def log_re(path,*batch):
# 从文件夹中读取数据
data = np.loadtxt(path, dtype='float32', delimiter=None)
# 总的数据的80%用于训练,其余的用于测试
length = int(len(data)*0.8)
# 注意这里的x_trian,y_train都是二阶的,特别注意y_train
x_train = []
y_train = []
# 当输入的batch的参数个数为1个时,表示会随机的输出batch个数据
if len(batch)> 0 and len(batch) < 2:
# 随机的得到0到length之间的batch[0]个数,这里的batch[0]就是你输出的那个数
ran = random.sample(range(0,length),batch[0])
for i in ran:
x = []
y = []
for j in range(len(data[0]) - 1):
x.append(data[i][j])
if data[i][-1] == 0:
y.append(1)
y.append(0)
if data[i][-1] == 1:
y.append(0)
y.append(1)
# y.append(data[i][-1])
x_train.append(x)
y_train.append(y)
return x_train,y_train
# 假如batch个数等于0,表示没有输入,即随机输出length个数
elif len(batch) == 0:
batch1=length
ran = random.sample(range(0, length), batch1)
for i in ran:
x = []
y = []
for j in range(len(data[0]) - 1):
x.append(data[i][j])
if data[i][-1] == 0:
y.append(1)
y.append(0)
if data[i][-1] == 1:
y.append(0)
y.append(1)
# y.append(data[i][-1])
x_train.append(x)
y_train.append(y)
return x_train,y_train
else:
print("参数错误,请从新输出两个参数")
return x_train,y_train
这里得到的数据是总的数据的80%,这是用于训练的,并且每次输出都是随机的一个batch,batch的大小就是这个函数的第二个参数,这里默认的是batch=80,所以x_train和y_train的shape是(80,4)和(80,2)。
这里是直接把y_train变成了独热编码:
这里建议从在导入自己txt数据时用np.loadtxt(),个人觉得很好用。
建立模型
首先是定义参数和占位符:
input_n = 4 #输入维度是4
output_n = 2 #输出维度是2
learn_rate = 0.5 #学习率
epoch = 20 #迭代次数,个人实验之后发现15次迭代之后就会有比较好的效果
x1 = tf.placeholder(tf.float32,shape=[None,input_n])
y = tf.placeholder(tf.float32,shape=[None,output_n])
w1 = tf.Variable(tf.ones([input_n,output_n]),name='weight1')
b1 = tf.Variable(tf.zeros([output_n]),name='base1')
#下面的两句代码的功能相同
y_pre = tf.matmul(x1,w1) + b1
#y_pre = tf.nn.bias_add(tf.matmul(x1,w1),b1)
#这里仅仅使用sigmoid函数和交叉熵来求解,没有用到softmax。
loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=y_pre, name='loss')
#这里用tf.reduce_mean()函数,表示的是平均的损失值
cross_entropy = tf.reduce_mean(loss)
train_step = tf.train.GradientDescentOptimizer(learn_rate).minimize(cross_entropy)
#tfarg_max()函数得到的是一行中最大的数的下标,tf.equal()函数是比较两个矩阵或向量是不是相同的,如果相同就是True
#不是就是False,
correct_prediction = tf.equal(tf.arg_max(y_pre, 1), tf.arg_max(y, 1))
#tf.cast()函数是转化类型的,这里就是转化为tf.float32类型,因为这里转化之后的值不是1就是0,所以用tf.reduce_mean()
#函数之后得到的就是正确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
启动会话
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
for i in range(epoch):
x,y_ = log_re(path)
sess.run(train_step,feed_dict={x1:x , y:y_})
cross_entr,acc = sess.run([cross_entropy,accuracy],feed_dict={x1:x,y:y_})
y_pred,corr = sess.run([y_pre,correct_prediction],feed_dict={x1:x,y:y_})
print("第%d次迭代,cross_entropy=%f" % (i,cross_entr))
print("第%d次迭代,acc=%f" % (i,acc))
# 通过验证大概在迭代15次左右就能达到很好的效果,甚至是100%的效果,所以还以存在过拟合的
# 当输出的值是一个向量或者矩阵时,建议用format来输出,这样可以整个输出矩阵或向量的值
print("第{}次迭代,correct_pre={}" .format(i,corr))
print("第{}次迭代,correct_pre={}" .format(i,y_pred))
第一次迭代的结果:
从第一次迭代结果可以看出正确率比较小的,从correct_pre中就可以看出,里面的True和False有很多
第15次迭代结果:
从15次迭代看出,correct_pre全部都为True,猜想可能是出现过拟合,当然从另一方面看正确率确实是变高了。