前面的线性分类器是,x是一个列向量,W把结果变成10个元素的列向量
神经网络不同,例如一个简单二层网络,里面是和上面一样的线性处理,得到中间变量,假设是100维的,然后做非线性处理,然后得到最后的10维列向量。非线性不会和线性的合并,所以才分了层。
参数通过训练,随机梯度下降和反向传播学到
对单个神经元建模
每个神经元都对它的输入和权重进行点积,然后加上偏差,最后使用非线性函数(或称为激活函数)。
本例中使用的是sigmoid函数
一些常见的激活函数:
激活函数的操作概括起来就是,输入一个数字,把它限定在一定范围,比如(0,1)或者>0之类的
sigmoid函数,把神经元输出压缩在(0,1),即限定在0完全不激活和1完全激活,激活这个词代表这个神经元对后面的影响,如果激活函数输出为0,对于后面的神经元来说,这个神经元相当于睡过去了,完全没影响。
sigmoid函数的缺点,梯度消失和非0中心
输入层, 隐层 ,输出层的概念
当我们说N层神经网络的时候,我们没有把输入层算入。和神经网络中其他层不同,输出层的神经元一般是不会有激活函数的。
每个隐层的权重存储隐层和下一层的连接,比如第3行的第2个权重值为0,就代表下一层的第3个神经元和该隐层的第2个神经元无连接,因为前面的神经元无论怎么变化,传到后面的神经元的数都是0。
先是初始化,然后计算scores,loss和grad
f = lambda x: np.maximum(0, x)
H1 = f(np.dot(X, W1) + b1)
OUT = np.dot(H1, W2) + b2
scores = OUT
train_num = X.shape[0]
scores -= np.max(scores, axis=1, keepdims=True)
#loss -= np.log(np.exp(scores[range(train_num),y]) / np.sum(np.exp(scores), axis=1))
scores = np.exp(scores) / np.sum(np.exp(scores), axis=1, keepdims=True)
loss -= np.log(scores[range(train_num),y])
loss = np.sum(loss)
ds = np.copy(scores)
ds[range(train_num),y] -= 1
ds /= train_num
db2 = np.sum(ds)
dW2 = np.dot(H1.T, ds) + reg * 2 * W2
dh1 = np.dot(ds, W2.T) * (H1 > 0)
db1 = np.sum(dh1)
dW1 = np.dot(X.T, dh1) + reg * 2 * W1
loss /= train_num
loss += reg * np.sum(W1*W1) + reg * np.sum(W2*W2)
其中为什么ds和loss都有/=train_num这一步呢,这样得到的都是相对于单个输入的,如果更换了batch_size也能用。
反向传播的时候,先把计算图画好,然后把每层神经元数量和各个变量的维数写清楚,就比较不容易错
input(4),hidden(10),output(3)
X1(5*4) H1(5*10) OUT(5*3)
W1(4*10) W2(10*3)
b1(10,) b2(3,)
训练曲线
num_iters=1000, batch_size=200,迭代1000次,每次200个
每个Epoch会衰减一次学习率
learning_rate *= learning_rate_decay
每个Epoch处理的数据的数量等于所有训练集数量,但是是通过多次minibatch迭代做的
比如这个例子是49000个训练样本,每次迭代200个,每245次迭代后衰减学习率
SGD就会比原始方法更快更新权重值,快245倍
上面的图能看出来loss大致是线性衰减的,这说明学习率设低了
图还能看出来,训练和验证的准确性没有差异,说明模型性能低,要加深扩大模型来更加过拟合一些。
python中的lambda argument_list: expression,即lambda 参数列表:单行表达式
这里就是定义了一个函数f,输入x,输出sigmoid
有研究证明,神经网络可以近似任何连续函数,虽然在理论上深层网络(使用了多个隐层)和单层网络的表达能力是一样的,但是就实践经验而言,深度网络效果比单层网络好。
另外,在实践中3层的神经网络会比2层的表现好,然而继续加深(做到4,5,6层)很少有太大帮助。卷积神经网络的情况却不同,在卷积神经网络中,对于一个良好的识别系统来说,深度是一个极端重要的因素,因为图像拥有层次化结构。
最后,不应该因为害怕出现过拟合而使用小网络。相反,应该进尽可能使用大网络,然后使用正则化技巧来控制过拟合,因为训练一个大的网络,你将发现许多不同的解决方法,但是最终损失值的差异将会小很多。这就是说,所有的解决办法都差不多,而且对于随机初始化参数好坏的依赖也会小很多。