/// <summary> /// 垂直方向连接张量,加在下方,外层列数必须一致 /// </summary> /// <param name="down"></param> /// <param name="name"></param> /// <returns></returns> public Tensor VerticalConcat(Tensor down, string name = null) { if (this.DimensionY != down.DimensionY) { throw new Exception("要连接的张量外层维度不一致"); } //Matrix<double>[,] newStorage = new Matrix<double>[this.DimensionX + down.DimensionX, this.DimensionY]; //for (int i = 0; i <= this.DimensionX - 1; i++) //{ // for (int j = 0; j <= this.DimensionY - 1; j++) // { // newStorage[i, j] = this.Storage[i, j]; // } //} //for (int i = 0; i <= down.DimensionX - 1; i++) //{ // for (int j = 0; j <= this.DimensionY - 1; j++) // { // newStorage[i + this.DimensionX, j] = down.Storage[i, j]; // } //} return(TensorBuilder.FromRowMajorIEnumerable(DimensionX + down.DimensionX, DimensionY, Storage.ToRowArray().Concat(down.Storage.ToRowArray()))); //return new Tensor(newStorage, name); //var newStorage = this.Storage.ToRowArray().Concat(down.Storage.ToRowArray()); //return TensorBuilder.FromRowMajorIEnumerable(this.DimensionX + down.DimensionX, this.DimensionY, newStorage); }
public static Tensor operator -(Tensor leftSide, Tensor rightSide) { if ((rightSide.DimensionX != 1 || rightSide.DimensionY != 1) && (leftSide.DimensionX != rightSide.DimensionX || leftSide.DimensionY != rightSide.DimensionY)) { throw new Exception($"张量外层维度错误,左侧为{leftSide.DimensionX}*{leftSide.DimensionY},右侧为{rightSide.DimensionX}*{rightSide.DimensionY}"); } if (rightSide.DimensionX == 1 && rightSide.DimensionY == 1) { Tensor newTensor = TensorBuilder.Empty(leftSide.DimensionX, leftSide.DimensionY); for (int i = 0; i <= newTensor.Storage.Length - 1; i++) { newTensor.Storage[i] = leftSide.Storage[i] - rightSide.Storage[0]; } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); } else { Tensor newTensor = TensorBuilder.Empty(leftSide.DimensionX, leftSide.DimensionY); for (int i = 0; i <= newTensor.Storage.Length - 1; i++) { newTensor.Storage[i] = leftSide.Storage[i] - rightSide.Storage[i]; } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); } }
/// <summary> /// 卷积,外层是乘积法则,内层是卷积 /// </summary> /// <param name="core">卷积核平面</param> /// <param name="mode">卷积模式</param> /// <returns></returns> public Tensor Convolve(Tensor core, ConvolutionMode mode) { if (this.DimensionY != core.DimensionX) { throw new Exception("进行卷积的两个向量外层维度必须符合矩阵乘法规律"); } Tensor newTensor = TensorBuilder.Empty(this.DimensionX, core.DimensionY); //创建一个与后续卷积结果大小相等的0矩阵 Matrix <double> temp = this[0, 0].Convolve(core[0, 0], mode).Map(r => 0.0); for (int i = 0; i <= newTensor.DimensionX - 1; i++) { for (int j = 0; j <= newTensor.DimensionY - 1; j++) { for (int k = 0; k <= this.DimensionY - 1; k++) { temp = temp + this[i, k].Convolve(core[k, j], mode); } newTensor[i, j] = temp; temp = temp.Map(r => 0.0); } } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); }
/// <summary> /// 对张量中的每个矩阵按照下标执行操作 /// </summary> /// <param name="f"></param> /// <param name="keepName"></param> /// <param name="newName"></param> /// <returns></returns> public Tensor MapIndexed(Func <int, int, double, double> f) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY); for (int i = 0; i <= Storage.Length - 1; i++) { newTensor.Storage[i] = this.Storage[i].MapIndexed(f); } return(newTensor); }
/// <summary> /// 最大池化 /// </summary> /// <param name="poolSize"></param> /// <returns>第一个为池化后张量,第二个为掩码表</returns> public Tuple <Tensor, Tensor> MaxPool(int poolSize) { Tensor pooledTensor = TensorBuilder.Empty(DimensionX, DimensionY); Tensor maskTensor = TensorBuilder.Empty(DimensionX, DimensionY); for (int i = 0; i <= this.Storage.Length - 1; i++) { (pooledTensor.Storage[i], maskTensor.Storage[i]) = this.Storage[i].MaxPooling(poolSize); } return(new Tuple <Tensor, Tensor>(pooledTensor, maskTensor)); }
/// <summary> /// 根据下标对张量中的每个矩阵进行整体操作 /// </summary> /// <param name="f"></param> /// <param name="keepName"></param> /// <param name="newName"></param> /// <returns></returns> public Tensor OuterMapIndexed(Func <int, int, Matrix <double>, Matrix <double> > f, bool keepName = true, string newName = null) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY); for (int i = 0; i <= Storage.Length - 1; i++) { newTensor.Storage[i] = f(i / DimensionY, i % DimensionY, this.Storage[i]); } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); }
/// <summary> /// 对张量中的每个矩阵进行整体操作 /// </summary> /// <param name="f"></param> /// <param name="keepName"></param> /// <param name="newName"></param> /// <returns></returns> public Tensor OuterMap(Func <Matrix <double>, Matrix <double> > f) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY); for (int i = 0; i <= Storage.Length - 1; i++) { newTensor.Storage[i] = f(this.Storage[i]); } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); }
public Tensor Stretch() { Tensor newTensor = TensorBuilder.Empty(1, 1); var temp = Storage[0].ToRowMajorArray().AsEnumerable(); for (int i = 1; i <= this.Storage.Length - 1; i++) { temp = temp.Concat(Storage[i].ToRowMajorArray()); } return(TensorBuilder.FromMatrix(Matrix <double> .Build.DenseOfRowMajor(temp.Count(), 1, temp))); }
public static Tensor operator -(Tensor rightSide) { Tensor newTensor = TensorBuilder.Empty(rightSide.DimensionX, rightSide.DimensionY); for (int i = 0; i <= newTensor.Storage.Length - 1; i++) { newTensor.Storage[i] = -rightSide.Storage[i]; } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); }
/// <summary> /// 将每个矩阵转置并乘以一个矩阵 /// </summary> /// <param name="rightSide"></param> /// <returns></returns> public Tensor InnerTransposeAndMultiply(Tensor rightSide) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY); for (int i = 0; i <= this.Storage.Length - 1; i++) { newTensor.Storage[i] = this.Storage[i].TransposeThisAndMultiply(rightSide.Storage[i]); } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); }
/// <summary> /// 对张量中的每个矩阵按照下标执行操作 /// </summary> /// <param name="f"></param> /// <param name="keepName"></param> /// <param name="newName"></param> /// <returns></returns> public Tensor MapIndexed(Func <int, int, double, double> f) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY); for (int i = 0; i <= DimensionX - 1; i++) { for (int j = 0; j <= DimensionY - 1; j++) { newTensor[i, j] = Storage[i, j].MapIndexed(f); } } return(newTensor); }
/// <summary> /// 对张量中的每个矩阵的每个元素执行一个操作 /// </summary> /// <param name="f"></param> /// <returns>新的张量</returns> public Tensor Map(Func <double, double> f, bool keepName = true, string newName = null) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY, keepName ? this.Name : newName); for (int i = 0; i <= DimensionX - 1; i++) { for (int j = 0; j <= DimensionY - 1; j++) { newTensor[i, j] = Storage[i, j].Map(f); } } return(newTensor); }
/// <summary> /// 外层转置 /// </summary> /// <returns></returns> public Tensor OuterTranspose() { var newTensor = TensorBuilder.Empty(this.DimensionY, this.DimensionX); for (int i = 0; i <= DimensionX - 1; i++) { for (int j = 0; j <= DimensionY - 1; j++) { newTensor[j, i] = this[i, j]; } } return(newTensor); }
/// <summary> /// 外层行切片,包括下标stop处的数据 /// </summary> /// <param name="start"></param> /// <param name="stop"></param> /// <param name="step"></param> /// <param name="name"></param> /// <returns></returns> public Tensor RowSlice(int start, int stop, int step, string name = null) { List <Matrix <double> > list = new List <Matrix <double> >(); int x = 0;//记录新张量的外层行数 for (int i = start; i <= stop; i = i + step) { for (int j = 0; j <= DimensionY - 1; j++) { list.Add(Storage[i, j]); } x++; } return(TensorBuilder.FromRowMajorIEnumerable(x, DimensionY, list, name)); }
/// <summary> /// 外层列切片,包括下标stop处的数据 /// </summary> /// <param name="start"></param> /// <param name="stop"></param> /// <param name="step"></param> /// <param name="name"></param> /// <returns></returns> public Tensor ColumnSlice(int start, int stop, int step, string name = null) { List <Matrix <double> > list = new List <Matrix <double> >(); int y = 0;//记录新张量的外层列数 for (int j = start; j <= stop; j = j + step) { for (int i = 0; i <= DimensionX - 1; i++) { list.Add(Storage[i, j]); } y++; } return(TensorBuilder.FromColumnMajorIEnumerable(y, DimensionX, list, name)); }
/// <summary> /// 外层点积,内层矩阵乘法 /// </summary> /// <param name="leftSide"></param> /// <param name="rightSide"></param> /// <returns></returns> public static Tensor operator *(Tensor leftSide, Tensor rightSide) { if (leftSide.DimensionX == rightSide.DimensionX && leftSide.DimensionY == rightSide.DimensionY) { Tensor newTensor = TensorBuilder.Empty(leftSide.DimensionX, leftSide.DimensionY); for (int i = 0; i <= newTensor.Storage.Length - 1; i++) { newTensor.Storage[i] = leftSide.Storage[i] * rightSide.Storage[i]; } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); } else { throw new Exception("维度不符合"); } }
/// <summary> /// 内外部同时点除 /// </summary> /// <param name="rightSide"></param> /// <returns></returns> public Tensor PointDivide(Tensor rightSide) { if (this.DimensionX == rightSide.DimensionX && this.DimensionY == rightSide.DimensionY) { Tensor newTensor = TensorBuilder.Empty(this.DimensionX, this.DimensionY); for (int i = 0; i <= this.Storage.Length - 1; i++) { newTensor.Storage[i] = this.Storage[i].PointwiseDivide(rightSide.Storage[i]); } newTensor.OuterAct(r => r.CoerceZero(1e-15)); return(newTensor); } else { throw new Exception("张量维度不匹配"); } }
public Tensor Fold(int x, int y, int p, int q) { Tensor newTensor = TensorBuilder.Empty(x, y); var temp = this.Storage[0].ToRowMajorArray(); if (this.Storage.Length == 1 && Storage[0].RowCount * Storage[0].ColumnCount == x * y * p * q) { for (int i = 0; i <= x * y - 1; i++) { newTensor.Storage[i] = Matrix <double> .Build.DenseOfRowMajor(p, q, temp.AsSpan().Slice(i *p *q, p *q).ToArray()); } } else { throw new Exception("要折叠的张量必须是1*1"); } return(newTensor); }
/// <summary> /// 水平方向连接张量,加在右方,外层行数必须一致 /// </summary> /// <param name="right"></param> /// <param name="name"></param> /// <returns></returns> public Tensor HorizontalConcat(Tensor right, string name = null) { if (this.DimensionX != right.DimensionX) { throw new Exception("要连接的张量外层维度不一致"); } //Matrix<double>[,] newStorage = new Matrix<double>[this.DimensionX , this.DimensionY+right.DimensionY]; //for (int i = 0; i <= this.DimensionX - 1; i++) //{ // for (int j = 0; j <= this.DimensionY - 1; j++) // { // newStorage[i, j] = this.Storage[i, j]; // } //} //for (int i = 0; i <= this.DimensionX - 1; i++) //{ // for (int j = 0; j <= right.DimensionY- 1; j++) // { // newStorage[i , j+this.DimensionY] = right.Storage[i, j]; // } //} //return new Tensor(newStorage, name); return(TensorBuilder.FromRowMajorIEnumerable(DimensionX, DimensionY + right.DimensionY, Storage.ToRowArray().Concat(right.Storage.ToColumnArray()))); }