零基础入门深度学习(2)

还是和上一篇一样的,原文链接:
https://www.zybuluo.com/hanbingtao/note/448086
觉得作者在解那个方程的时候略微有点复杂了,也许是思路不同吧。


线性单元

简单回忆一下感知器的结构,输入,偏置项,权重,计算输出的函数,以及激活函数。


感知器

其中激活函数step function只有01两种状态,所以模型解决的是分类问题。如果结果不是线性可分的那么感知器可能无法收敛,为了解决这个问题需要使用线性的函数来替代激活函数,这种感知器就被叫做线性单元,用来解决回归问题。
这里这个weighted sum就把它叫做输出函数吧,虽然真正的输出函数是激活函数。

假设激活函数是也y=x 那么线性单元如下:

线性单元

Activation function里面就是y = x的图像,相比于感知器上面多出来的这个我觉得是监督模型的监督机制,在代码中我也没有体会到它的存在。
在说模型的时候说的是在输入x的情况下怎么得到y,就是给因变量和自变量找关系了。假设一个人的月薪和工作年限有关则可以得到一个模型

假设参数w为100,b为250,则一个人工作10年后他的月薪就为1250。
这个有很多模型有很多不靠谱的地方,所以需要考虑的因素还有很多。假设和工作年限、行业,公司、职级都有关系,那么可以得到一个新的模型

x为特征工作年限、行业,公司、职级对应的值,w为每个特征的权重。
为了书写方便也b也写成

将w、x写成向量的话



这样子的模型就叫做线性模型,因为那个输出y是输入x的线性组合。

有监督学习和无监督学习

有监督学习模型的输入除了数据之外,还有对应的正确的理想输出,称之为标签吧。模型根据输入计算之后和标签进行比较修改权重。我觉得吧,就是使用数据进行监督的
无监督的学习这种方法的训练样本中只有而没有。模型可以总结出特征的一些规律,但是无法知道其对应的答案。通常只有少部分的续联数据有y。

线性单元的目标函数

就拿上面的来说事吧,
用y表示实际值,用y'表示预测值,则两者之间的误差可以使用下面的式子表:
对训练数据中的所有样本计算误差求和就是模型的误差则

模型误差

由此可见模型的训练就是找出合适的w,这个在数学上称为优化,E(w)称之为目标函数。

梯度下降优化算法

用于求解上面模型误差方程,一般都是使用的求一阶导宁一阶导数为0,然后解出来就得到极值点了,但是吧计算机不会解方程,只有使用这种逼近的方式:
梯度下降

对应的公式:



上面工资的这个例子就可以使用梯度下降优化,梯度下降主要是用于调整参数。

对模型误差两边对w求偏导——复合函数求导法则



将结果带入梯度下降优化中可以得到参数的计算式



向量组表示

由此线性单元的理论基本上是完成了,我觉得好像和感知器的差别也不是太大。

线性单元和感知器的比较

  • 输出函数没有变都是使用向量的计算,这个我觉得是可以变的,所以这次的代码将这个部分提取出来,实现一个复用性强的感知器
  • 激活函数变了,由于激活函数变化,导致那个参数的调整也出现变化,使用梯度下降,求解出权重参数的调整规则。起始参数调整规则也没有变,这个部分在复用性强的感知器中也是应该提取出来。
    其他的就没有什么变化了,下面是本次的线性单元的代码,为了再复习一下感知器,同时提高感知器的复用性感知器实现比较抽象,难于理解的话可以看作者的代码。代码不长,很多都是注释,以及和模型的构建不相关的。

定义一个复用性强的感知器

class Perception(object):
    #定义初始化方法
    def __init__(self,input_num,activor,rate,out_fun,update_weights):
        #权重
        self.weight = [0.0 for _ in range(input_num)]
        #激活函数
        self.activor = activor
        #学习速率
        self.rate = rate
        #计算函数(输出函数)
        self.out_fun = out_fun
        #偏置项
        self.bias = 0.0
        #权重更新函数
        self.update_weights = update_weights

    def __str__(self):
        return  "权重列表 : {0}\n偏置项 : {1}" .format(self.weight,self.bias)

    def predict(self,input_vec):
        return self.out_fun(self,input_vec)

    def train(self,input_vecs,labels,iteration):
        for i in range(iteration):
            for (input_vec,label) in zip(input_vecs,labels):
                delta = label - self.predict(input_vec)
                #更新权重
                self.update_weights(self,input_vec,label,delta)

#------------------上面这个样子貌似感知器就定义完毕了-------------------------------#

#定义相关的操作,为了实现参数调整,激活函数,输出函数 的相关操作
class VectorOP(object):
    #定义向量之间的点乘:对应相乘相加
    @staticmethod
    def dot(x,y):
        return sum(
                [d1 * d2
                 for d1,d2 in zip(x,y)]
        )
    #定义向量的加法
    @staticmethod
    def add(x,y):
        return [d1 + d2 for d1,d2 in zip(x,y)]

    #定义向量乘标量
    @staticmethod
    def mul(v,s):
        return [d * s for d in v]
#-------------------就定义这三个静态方法也貌似够用了--------------------#



#现在来做一个线性的感知器吧
#首先是权重更新函数
def update_weights(sensor,input_vec,label,delta):
    '''
    这里就是真正更新权重的函数,因为随那个啥激活函数的
    不同相应的权重调整也不一定相同,所以把这个函数也当
    参数传递给感知器
    :param sensor: 感知器,计算的时候需要用到权重,偏置项等
    :param input_vec: 输入向量
    :param label: 向量对应的标签
    :param delta: 误差
    :return:   这个厉害呀!没有返回值,也没有引用,权重居然更新了
    '''

    #更新权重
    sensor.weight = VectorOP.add(
            sensor.weight,
            VectorOP.mul(input_vec,sensor.rate * delta)
    )
    #更新偏置项
    sensor.bias += sensor.rate * delta

#其次是那个感知器的计算函数,
#就是权重后面的一个函数,不是激活函数,它的值作为激活函数的参数
def output_fun(sensor,input_vec):
    '''
    预测就是使用的这个方法
    :param sensor: 感知器
    :param input_vec: 待预测的特征(数据)
    :return:
    '''
    return VectorOP.dot(
        sensor.weight,
        input_vec
    )
    + sensor.bias


#最后是那个激活函数
#在预测了之后使用激活函数转换为想要的输出
#这里使用的激活函数是y = x
def activor(x):
    return x

#现在可以构建线性感知器了
line_perception = Perception(4,activor,0.01,output_fun,update_weights)
#---------------------------到这里线性感知器就构造好了------------------------------#

#接下来是训练,以及测试了
#第一步先创建训练数据吧
    #工作年限,行业,公司,职级
input_vecs = [
    [5,1,2,6],
    [3,1,2,6],
    [8,1,2,6],
    [1.4,1,2,6],
    [10.1,1,2,6]
]
    # 期望的输出列表,月薪,注意要与输入一一对应
labels = [5500, 2300, 7600, 1800, 11400]
line_perception.train(input_vecs,labels,10)
#第二步测试感知器

print(line_perception.__str__())

# 测试
print ('Work 3.4 years, monthly salary = %.2f' % line_perception.predict([3.4]))
print ('Work 15 years, monthly salary = %.2f' % line_perception.predict([15]))
print ('Work 1.5 years, monthly salary = %.2f' % line_perception.predict([1.5]))
print ('Work 6.3 years, monthly salary = %.2f' % line_perception.predict([6.3]))
运行结果

你可能感兴趣的:(零基础入门深度学习(2))