Python从零开始(库的安装与初步使用3+习题1.6)

本文记录了Python初学者在安装和使用库时遇到的问题,包括pyyaml的安装,以及在神经网络实验中遇到的文件操作、数据处理、matplotlib画图库的使用。此外,还探讨了Python的缩进语法、字符串处理、运算符优先级等特性,并提出了一些关于Keras库的疑问,例如损失函数、学习率衰减等。
摘要由CSDN通过智能技术生成

前言:

这个MarkDown编辑器真纠结,我以为上面的保存到线上草稿箱就是保存到我的草稿箱,结果MarkDown的草稿箱就只有一个,相当于缓存,会自动覆盖上一个,也就是说不能同时进行两个笔记。之前写了好多都没了,又得从新写。

正文:
上次的问题解决了,它说wheel pyyaml出了错,我自己去http://www.lfd.uci.edu/~gohlke/pythonlibs/下一个pyyaml装上就好了(这个连接要复制粘贴到地址框,不能从csdn转过去,{额外问题1}):
这里写图片描述

我查了一下,pyyaml是用于Python的Yaml(一种语言)解析器和发射器(emitter 是什么意思?{问题1})。wheel是用来代替egg的压缩包。不过为什么它需要执行这一部而不是直接安装呢{问题2}?

之后做《神经。。。》那本书上的1.5实验,具体细节我在阅读笔记上说明。

首先是样本数据生成,我计划训练样本和测试样本各生成2个文件,一个数据一个标签:

import random
import math
#打开文件
training_sample=open("training_sample.txt",'w')
training_label=open("training_label.txt",'w')
test_sample=open("test_sample.txt",'w')
test_label=open("test_label.txt",'w')
#下面是样本数据生成算法
#三个参数
r=10
w=6
d=0
#进入循环
i=1
while  i<3000+1:
    #在方形空间中随机生成一点
    x=random.uniform(-(w/2)-r,2*r+(w/2))
    y=random.uniform(-(w/2)-r-d,r+(w/2))
    #如果此点在任一半月形区域内,则写入相应文件,i加1,否则抛弃并从新生成
    if (r-(w/2))**2<=x**2+y**2<=(r+(w/2))**2 and y>0:
        if i>1000: 
            test_sample.write(str(x)+' '+str(y)+'\n')
            test_label.write('1\n')
        else:
            training_sample.write(str(x)+' '+str(y)+'\n')
            training_label.write('1\n')
        i=i+1
    else: 
        if (r-(w/2))**2<=(x-r)**2+(y+d)**2<=(r+(w/2))**2 and y<-d:
            if i>1000: 
                test_sample.write(str(x)+' '+str(y)+'\n')
                test_label.write('-1\n')
            else:
                training_sample.write(str(x)+' '+str(y)+'\n')
                training_label.write('-1\n')
            i=i+1  
#保存并关闭文件
training_sample.close()
training_label.close()
test_sample.close()
test_label.close()

这个过程我发现了Python的一些特点。
一,缩进也是语法,这和C++就不一样了,C++用{}来分块,而Python则用缩进分块。参考了http://www.cnblogs.com/zxf330301/articles/5415750.html
二,逗号的运用,详见http://www.cnblogs.com/wzjbg/p/6211957.html

另外,我试着用了C++里的文件操作,竟然成功了,看来Python的文件操作几乎和C++一样,这里的文件打开模式为写“w”。写入字符串时先用str()把数值转换成字符串,官网又上不去了,所以我就参考了http://www.cnblogs.com/Joseph-AMI/p/4713003.html

字符串中空格代表向量的下一维,换行代表下一向量。

Python的运算符优先级:

运算符 描述
lambda Lambda表达式
or 布尔“或”
and 布尔“与”
not x 布尔“非”
in,not in 成员测试
is,is not 同一性测试
<,<=,>,>=,!=,== 比较
| 按位或
^ 按位异或
& 按位与
<<,>> 移位
+,- 加法与减法
*,/,% 乘法、除法与取余
+x,-x 正负号
~x 按位翻转
** 指数
x.attribute 属性参考
x[index] 下标
x[index:index] 寻址段
f(arguments…) 函数调用
(experession,…) 绑定或元组显示
[expression,…] 列表显示
{key:datum,…} 字典显示
‘expression,…’ 字符串转换

以上来自https://www.cnblogs.com/xiehui/p/4146690.html,想看工整排版的可以点。

还有,Python的单引号’和双引号”扩起来的都表示无结尾符的字符串,不像C,C里单引号扩起来的是单个字符,双引号扩起来的是有结尾符的字符串。具体参考http://blog.csdn.net/wanghai__/article/details/6285310

之后检测一下数据:

import matplotlib.pyplot as plt
import numpy as np
training_sample=np.loadtxt("training_sample.txt")
plt.scatter(training_sample[:,0],training_sample[:,1])
plt.show()

matplotlib是一个画图库,需要安装一下,scatter用来画散点图,其中有两个必要参数,分别是坐标x和y的数组。另外关于numpy的元素操作可参考http://blog.csdn.net/Savinger/article/details/52880078

结果显示数据正常:
这里写图片描述

接下来是建模训练:

import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from keras import backend, metrics

#创建了新类,继承SGD
class SGD_c(SGD):
    #添加了一个参数linear_decay
    def __init__(self, lr=0.01, momentum=0., decay=0.,linear_decay=0.,
                 nesterov=False, **kwargs):
        self.linear_decay = linear_decay
        super(SGD_c, self).__init__(lr, momentum, decay,
                 nesterov, **kwargs)

    #先处理线性衰减,之后进入父类函数
    def get_updates(self, loss, params):
        lr_t = self.lr
        if self.linear_decay > 0:
            self.lr -= self.linear_decay * backend.get_value(self.iterations)
        self.updates = super(SGD_c, self).get_updates(loss, params)
        self.lr = lr_t
        return  self.updates

#读入数据
training_sample=np.loadtxt("training_sample.txt")
training_label=np.loadtxt("training_label.txt",'int')
test_sample=np.loadtxt("test_sample.txt")
test_label=np.loadtxt("test_label.txt",'int')
#建立模型
model=Sequential()
#添加一层全连接层,一个节点,输入向量的维度为2,激活函数为tanh
model.add(Dense(1, input_dim=2, activation='tanh'))
#损失就是书中的MSE,优化器为自己改的SGD,其参数为初始学习率和和线性衰减
model.compile(loss='mean_squared_error', optimizer=SGD_c(lr=0.1, linear_decay=(0.1-0.00001)/50), metrics=[metrics.binary_accuracy])
#model.get_layer(index=1).set_weights([np.array([[0],[1]]), np.array([0])])
#训练模型,反复50次
model.fit(training_sample, training_label, epochs=50, batch_size=1000)
#评估模型,打印评估结果
print(model.evaluate(test_sample, test_label, batch_size=2000))
#打印决策边界
print(model.get_layer(index=1).get_weights())

结果如下:
前几次迭代:
这里写图片描述

最后几次迭代,加上评估结果与决策边界:
这里写图片描述
(最后的决策边界为:-0.01782304x+1.84150457y+0.00046315=0,接近x轴)

我注意到个小细节,loadtxt会把[[a],[b],[c]….]1*n这种数据读成一维的数据串。我在官方文档看到了其dtype 参数的介绍:
dtype : data-type, optional
Data-type of the resulting array; default: float. If this is a structured data-type, the resulting array will be 1-dimensional, and each row will be interpreted as an element of the array. In this case, the number of columns used must match the number of fields in the data-type.
上面说当读入的是结构化数据时,结果会转换成一维数据,各行会变为一维数组的各元素。

我在Keras官网文档看了一圈,没找到阈值激活函数,我就先用tanh代替了,之前的题目也证明了其效果。
并且也没有书中的损失函数:
这里写图片描述
Keras里所有可用loss的参数都是真实分类结果与预测分类结果。没办法,就用均方差代替吧。

优化器中也没有书中所说的批梯度下降,但是有一个随机梯度下降(SGD),我在https://www.cnblogs.com/eniac1946/p/7423865.html中大概了解了一下,发现也可以用来代替,但是要把batch_size设置成总样本数。

另外关于decay的具体作用,我搜到了https://stats.stackexchange.com/questions/211334/keras-how-does-sgd-learning-rate-decay-work,上面说可以直接查看源码,每次更新学习率如下:

    def get_updates(self, loss, params):
        grads = self.get_gradients(loss, params)
        self.updates = [K.update_add(self.iterations, 1)]

        lr = self.lr
        if self.initial_decay > 0:
            lr *= (1. / (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))

cast的作用是把iterations转换成decay的格式。可以看到在第一次计算学习率时衰减已经计算在内了。以每次学习的学习率为中介,线性衰减值的计算如下:
这里写图片描述
其中,i为当前学习的次数(即当前是第i次迭代),ηi为第i次学习的学习率,m为最大学习次数(50),d为衰减值。转换后得:
这里写图片描述

但是如果要修改代码的话就不需要这样再转换一下,就像程序里的一样。
我看了源码,用于计算和返回的是函数里的局部lr,所以我就干脆先把self.lr改了,等它计算完再改回来。

关于继承,可以用super或直接self.parent。我参考了https://www.cnblogs.com/wjx1/p/5084980.html,总结一下就是用super 的话可以保证其每个父类只运行一次。

结语:

有几点还是没明白:
1,官方文档说evaluate()的batch_size默认是32,可是评估要这个是做什么用的?{问题3}

2,用vs调试Python代码时,调试到断点后各种变量的值我看不懂,因为本次已经耽误了很久了,所以我也没有搞的很明白,变量都是用print等函数打印出来看的。Python变量的储存方法还是要研究研究。{问题4}

3,可以看到我在代码中一段注释掉的代码:

model.get_layer(index=1).set_weights([np.array([[0],[1]]), np.array([0])])

这行代码是用来设置初始权值的,可以把初始的决策边界设置成y=0(即x轴)。因为我之前生成数据时没有生成边界数据,所以如果这样设置了,理论上应该是分类正确率应该是1,但为什么总差一点呢?{问题5}而且一共有2000个测试样本,理论上正确率应该是0.0005的整数倍,而不是像上面那样这么多小数位。

4,如上,我把初始的决策边界设置成y=0,把标签改成1和0,并且激活函数改用sigmoid,之后正确率就正常地为1了。改了标签之后,sigmoid和tanh不应该是一样的吗,为什么有区别?{问题6}

终于告一段落了,接下来就要好好琢磨《神经网络。。。》的第二章了。

欢迎回答我留下的问题。不过如果有问题也欢迎来向我提问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值