最近学习了神经网络算法,学的过程全部是用python实现的,我平时用java较多,所以我就尝试使用java来实现这个算法,完整代码在我的github地址,java没有numpy,所以我自己实现了一个类专门进行矩阵计算
package com.network.array;
/**
* 此类主要解决矩阵运算方面的数学问题(仅支持2维的运算)
* @author root
*/
public class Array {
// 需要进行运算的数据对象
private double[] data ;
// 矩阵的维度 行
private int h ;
// 矩阵的维度 列
private int w ;
// 用于随即产生矩阵
public static Random random = Random.random ;
// 用于产生一个全部为0的矩阵
public static Zero zero = Zero.zero ;
//给定维度和数据大小创建矩阵
public Array(int w , int maxLength) {
this.w = w ;
this.h = 0 ;
this.data = new double[maxLength] ;
}
// 给定维度创建矩阵
public Array(int w) {
this.w = w ;
this.h = 0 ;
this.data = new double[100] ;
}
// 扩大数组容量
private double[] copyArr(double[] source , int len) {
double[] target = new double[len] ;
System.arraycopy(source, 0, target, 0, source.length);
return target ;
}
// 获取矩阵结构
public int[] shape() {
int[] temp = new int[] {w , h} ;
return temp ;
}
// 重置矩阵结构
public void reshape(int w , int h) {
this.w = w ;
this.h = h ;
}
// 此方法时给矩阵乘法提供的 默认时操作矩阵的最后一位
public void push(int w_index , int h_index , double a) {
// 判断数组大小是否足够
if((h_index)*w + w_index + 1 >= data.length) {
data = copyArr(data, (w*h + 2)*2) ;
}
data[h_index*w + w_index] = a ;
h = h_index+1 ;
}
// 往矩阵中添加数据
public void push(double[] a) throws Exception {
if(a.length != this.w) {
throw new Exception("维度不匹配");
}
// 判断数组大小是否足够
if(w*h + a.length >= data.length) {
data = copyArr(data, (w*h + a.length)*2) ;
}
for(int i=0 ; i<a.length ; i++) {
data[w*h+i] = a[i] ;
}
h++ ;
}
// 往矩阵中添加数据
public void push(Array arr) throws Exception {
int target_w = arr.shape()[0] ;
int target_h = arr.shape()[1] ;
if(target_w != this.w) {
throw new Exception("维度不匹配");
}
double[] target = arr.getData() ;
int size = this.w*this.h ;
// 判断数组大小是否足够
if(w*h + target_w*target_h >= data.length) {
data = copyArr(data, (w*h + target_w*target_h)*2) ;
}
// 将目标数组填入
for(int i = 0 , len = target_w*target_h ; i < len ; i++) {
this.data[size+i] = target[i] ;
}
h += target_h ;
}
// 矩阵点乘
public Array dot(Array arr) throws Exception {
// 判断两个矩阵是否能够相乘
int target_w = arr.shape()[0] ;
int target_h = arr.shape()[1] ;
if(this.w != target_h) {
throw new Exception("矩阵无法相乘");
}
// 当前对象的矩阵数据
double[] source = this.data ;
// 目标对象的矩阵数据
double[] target = arr.getData() ;
// 创建相乘后的矩阵
Array result = new Array(target_w) ;
for(int i = 0 , len = this.h * target_w ; i < len ; i++) {
int temp_w = i%target_w ;
int temp_h = i/target_w ;
// 计算1矩阵i行和2矩阵j列的乘积
double d = 0 ;
for(int j = 0 ; j < this.w ; j++) {
d += source[temp_h*this.w+j]*target[temp_w+j*target_w] ;
}
result.push(temp_w , temp_h , d);
}
return result ;
}
// 矩阵某个维度求和
public Array sum(int axios) {
Array result = null ;
int lenX ;
int lenY ;
if (axios == 0) {
result = new Array(this.w) ;
lenX = this.w ;
lenY = this.h ;
}else {
result = new Array(1) ;
lenX = this.h ;
lenY = this.w ;
}
for(int i = 0 ; i < lenX ; i++) {
double sum = 0 ;
for(int j = 0 ; j < lenY ; j++) {
sum += this.data[axios == 0 ? j*this.w+i : i*this.w+j] ;
}
result.push(axios == 0 ? i : 0 , axios == 0 ? 0 : i , sum);
}
return result ;
}
。。。。。。
代码总共有400多行,所以只粘贴了一部分,完整代码请到我的github下载
上面是神经网络所需要的数学工具类,然后我们来写神经网络算法
// 训练数据
Array batch_x = xTrain.I(batchMask) ;
// 数据标记
Array batch_t = tTrain.I(batchMask) ;
// 1.前向传播
Array a1 = batch_x.dot(this.w1).add(this.b1) ;
//激活函数sigmoid
Array z1 = a1.sigmoid() ;
Array a2 = z1.dot(this.w2).add(this.b2) ;
//激活函数softmax
Array y = a2.softmax() ;
// 2.反向传播
// 2.1求softmax函数的反向传播(y - t)
Array dy = y.sub(batch_t).div(batch_x.shape()[1]) ;
// 矩阵点乘的反向传播 输入信号的转置点乘后端传过来的矩阵
Array dw2 = z1.T().dot(dy) ;
Array db2 = dy.sum(0) ;
// 求dx
Array dx = dy.dot(this.w2.T()) ;
// 2.2求sigmoid的反向传播 (1 - y)*y
Array dz = z1.sub(1).mul(-1).mul(z1).mul(dx) ;
Array dw1 = batch_x.T().dot(dz) ;
Array db1 = dz.sum(0) ;
// 更新权值
this.w1 = this.w1.sub(dw1.mul(this.learningRate)) ;
this.b1 = this.b1.sub(db1.mul(this.learningRate)) ;
this.w2 = this.w2.sub(dw2.mul(this.learningRate)) ;
this.b2 = this.b2.sub(db2.mul(this.learningRate)) ;
以上就是核心代码了