#include "AllShader.hpp" const char* shader_MetalReLU6_metal = "struct Param {\n" " float minV;\n" " float maxV;\n" " int size;\n" " int remain;\n" "};\n" "kernel void relu6(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant Param &p [[buffer(2)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if (gid.x(float)height || x<-1.0f || x>(float)width) {\n" " return M4(0);\n" " }\n" " y=max(y,0.0f);\n" " x=max(x,0.0f);\n" " int y0=(int)y;\n" " int x0=(int)x;\n" " int y1,x1;\n" " if (y0 >= height-1) {\n" " y1=y0=height-1;\n" " y=(float)y0;\n" " } else {\n" " y1=y0+1;\n" " }\n" " if (x0 >= width-1) {\n" " x1=x0=width-1;\n" " x=(float)x0;\n" " } else {\n" " x1=x0+1;\n" " }\n" " float dy=y-(float)y0;\n" " float dx=x-(float)x0;\n" " float dy1=1.0f-dy;\n" " float dx1=1.0f-dx;\n" " // w1=dy1*dx1 (top-left),w2=dy1*dx (top-right),w3=dy*dx1 (bottom-left),w4=dy*dx (bottom-right)\n" " M4 v1=data[y0*width+x0];\n" " M4 v2=data[y0*width+x1];\n" " M4 v3=data[y1*width+x0];\n" " M4 v4=data[y1*width+x1];\n" " M4 result=M4((float4)v1*dy1*dx1 +\n" " (float4)v2*dy1*dx +\n" " (float4)v3*dy*dx1 +\n" " (float4)v4*dy*dx);\n" " return result;\n" "}\n" "kernel void roi_align_avg(const device M4 *in [[buffer(0)]],\n" " const device M *roi [[buffer(1)]],\n" " device M4 *out [[buffer(2)]],\n" " constant roi_align_shape &s [[buffer(3)]],\n" " const device int *batch_idx_buf [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x >= s.output_width || (int)gid.y >= s.output_height) return;\n" " int ob=gid.z % s.num_roi; // ROI index\n" " int iz=gid.z/s.num_roi; // slice index (C/4)\n" " // Read ROI data\n" " int ib;\n" " float x1,y1,x2,y2;\n" " if (s.has_batch_indices) {\n" " auto b_roi=roi+ob*4;\n" " ib=batch_idx_buf[ob];\n" " x1=(float)b_roi[0];\n" " y1=(float)b_roi[1];\n" " x2=(float)b_roi[2];\n" " y2=(float)b_roi[3];\n" " } else {\n" " auto b_roi=roi+ob*5;\n" " ib=(int)b_roi[0];\n" " x1=(float)b_roi[1];\n" " y1=(float)b_roi[2];\n" " x2=(float)b_roi[3];\n" " y2=(float)b_roi[4];\n" " }\n" " float offset=s.aligned ? -0.5f : 0.0f;\n" " x1=x1*s.spatial_scale+offset;\n" " y1=y1*s.spatial_scale+offset;\n" " x2=x2*s.spatial_scale+offset;\n" " y2=y2*s.spatial_scale+offset;\n" " float roi_w=x2-x1;\n" " float roi_h=y2-y1;\n" " if (!s.aligned) {\n" " roi_w=max(roi_w,1.0f);\n" " roi_h=max(roi_h,1.0f);\n" " }\n" " float bin_size_w=roi_w/(float)s.output_width;\n" " float bin_size_h=roi_h/(float)s.output_height;\n" " int sampling_ratio_w=s.sampling_ratio>0 ? s.sampling_ratio : (int)ceil(roi_w/(float)s.output_width);\n" " int sampling_ratio_h=s.sampling_ratio>0 ? s.sampling_ratio : (int)ceil(roi_h/(float)s.output_height);\n" " sampling_ratio_w=max(sampling_ratio_w,1);\n" " sampling_ratio_h=max(sampling_ratio_h,1);\n" " float sampling_bin_w=bin_size_w/(float)sampling_ratio_w;\n" " float sampling_bin_h=bin_size_h/(float)sampling_ratio_h;\n" " // Pointer to the correct slice of input: [iz*batch+ib]*(H*W)\n" " auto z_in=in+(ib+iz*s.input_batch)*s.input_size;\n" " int pw=(int)gid.x;\n" " int ph=(int)gid.y;\n" " float sampling_start_w=x1+pw*bin_size_w;\n" " float sampling_start_h=y1+ph*bin_size_h;\n" " float4 sum=float4(0.0f);\n" " int count=sampling_ratio_h*sampling_ratio_w;\n" " for (int i=0; i= s.output_width || (int)gid.y >= s.output_height) return;\n" " int ob=gid.z % s.num_roi;\n" " int iz=gid.z/s.num_roi;\n" " int ib;\n" " float x1,y1,x2,y2;\n" " if (s.has_batch_indices) {\n" " auto b_roi=roi+ob*4;\n" " ib=batch_idx_buf[ob];\n" " x1=(float)b_roi[0];\n" " y1=(float)b_roi[1];\n" " x2=(float)b_roi[2];\n" " y2=(float)b_roi[3];\n" " } else {\n" " auto b_roi=roi+ob*5;\n" " ib=(int)b_roi[0];\n" " x1=(float)b_roi[1];\n" " y1=(float)b_roi[2];\n" " x2=(float)b_roi[3];\n" " y2=(float)b_roi[4];\n" " }\n" " float offset_val=s.aligned ? -0.5f : 0.0f;\n" " x1=x1*s.spatial_scale+offset_val;\n" " y1=y1*s.spatial_scale+offset_val;\n" " x2=x2*s.spatial_scale+offset_val;\n" " y2=y2*s.spatial_scale+offset_val;\n" " float roi_w=x2-x1;\n" " float roi_h=y2-y1;\n" " if (!s.aligned) {\n" " roi_w=max(roi_w,1.0f);\n" " roi_h=max(roi_h,1.0f);\n" " }\n" " float bin_size_w=roi_w/(float)s.output_width;\n" " float bin_size_h=roi_h/(float)s.output_height;\n" " int sampling_ratio_w=s.sampling_ratio>0 ? s.sampling_ratio : (int)ceil(roi_w/(float)s.output_width);\n" " int sampling_ratio_h=s.sampling_ratio>0 ? s.sampling_ratio : (int)ceil(roi_h/(float)s.output_height);\n" " sampling_ratio_w=max(sampling_ratio_w,1);\n" " sampling_ratio_h=max(sampling_ratio_h,1);\n" " float sampling_bin_w=bin_size_w/(float)sampling_ratio_w;\n" " float sampling_bin_h=bin_size_h/(float)sampling_ratio_h;\n" " auto z_in=in+(ib+iz*s.input_batch)*s.input_size;\n" " int pw=(int)gid.x;\n" " int ph=(int)gid.y;\n" " float sampling_start_w=x1+pw*bin_size_w;\n" " float sampling_start_h=y1+ph*bin_size_h;\n" " float4 max_val=float4(-FLT_MAX);\n" " for (int i=0; i= cst.output_width || (int)gid.y >= cst.output_height || (int)gid.z >= cst.slice*cst.batch) return;\n" " \n" " int oz=gid.z/cst.batch;\n" " int offset_x=(int)gid.x*cst.stride_x-cst.pad_x;\n" " int offset_y=(int)gid.y*cst.stride_y-cst.pad_y;\n" " int sx=max(0,(UP_DIV(-offset_x,cst.dilation_x)));\n" " int ex=min(cst.kernel_x,UP_DIV(cst.input_width-offset_x,cst.dilation_x));\n" " int sy=max(0,(UP_DIV(-offset_y,cst.dilation_y)));\n" " int ey=min(cst.kernel_y,UP_DIV(cst.input_height-offset_y,cst.dilation_y));\n" " offset_x += sx*cst.dilation_x;\n" " offset_y += sy*cst.dilation_y;\n" " auto z_wt=wt+(int)oz*cst.kernel_size;\n" " auto z_in=in+(int)gid.z*cst.input_size;\n" " auto z_out=out+(int)gid.z*cst.output_size+(int)gid.y*cst.output_width+(int)gid.x;\n" " FLOAT4 result=FLOAT4(biasTerms[oz]);\n" " for (auto ky=sy,y=offset_y; ky= cst.output_width || (int)gid.y >= cst.output_height || (int)gid.z >= cst.oz_size) return;\n" " \n" " int idx_w=gid.x;\n" " int idx_h=gid.y;\n" " int idx_c=gid.z/cst.batch;\n" " int idx_b=gid.z % cst.batch;\n" " \n" " int offset_x=(int)idx_w*cst.stride_x-cst.pad_x;\n" " int offset_y=(int)idx_h*cst.stride_y-cst.pad_y;\n" " int sx=max(0,(UP_DIV(-offset_x,cst.dilation_x)));\n" " int ex=min(cst.kernel_x,UP_DIV(cst.input_width-offset_x,cst.dilation_x));\n" " int kw=ex-sx;\n" " int sy=max(0,(UP_DIV(-offset_y,cst.dilation_y)));\n" " int ey=min(cst.kernel_y,UP_DIV(cst.input_height-offset_y,cst.dilation_y));\n" " int kh=ey-sy;\n" " offset_x += sx*cst.dilation_x;\n" " offset_y += sy*cst.dilation_y;\n" " \n" " auto z_in=in+idx_b*cst.input_size+offset_y*cst.input_width+offset_x;\n" " auto z_wt=wt+idx_c*cst.input_slice*cst.kernel_size+sy*cst.kernel_x+sx;\n" " auto z_out=out+idx_b*cst.output_size+(int)idx_c*cst.batch*cst.output_size+(int)gid.y*cst.output_width+(int)gid.x;\n" " int dilation_h=cst.input_width*cst.dilation_y;\n" " FLOAT4 result=FLOAT4(biasTerms[idx_c]);\n" " for (auto z=0; z= cst.output_width || (int)gid.y >= cst.output_height) return;\n" " \n" " int idx_w=gid.x << 1;\n" " int idx_h=gid.y;\n" " int idx_c=gid.z/cst.batch;\n" " int idx_b=gid.z % cst.batch;\n" " int4 uz=idx_c*CONV_UNROLL+int4(0,1,2,3);\n" " bool3 valids=uz.yzw=cst.input_width || offset_y<0) ? (M4)0.f : *(z_in+0*cst.input_width+1);\n" " auto in02=(offset_x+2>=cst.input_width || offset_y<0) ? (M4)0.f : *(z_in+0*cst.input_width+2);\n" " auto in03=(offset_x+3>=cst.input_width || offset_y<0) ? (M4)0.f : *(z_in+0*cst.input_width+3);\n" " auto in10=(offset_x<0 || offset_y+1>=cst.input_height) ? (M4)0.f : *(z_in+1*cst.input_width+0);\n" " auto in11=(offset_x+1>=cst.input_width || offset_y+1>=cst.input_height) ? (M4)0.f : *(z_in+1*cst.input_width+1);\n" " auto in12=(offset_x+2>=cst.input_width || offset_y+1>=cst.input_height) ? (M4)0.f : *(z_in+1*cst.input_width+2);\n" " auto in13=(offset_x+3>=cst.input_width || offset_y+1>=cst.input_height) ? (M4)0.f : *(z_in+1*cst.input_width+3);\n" " \n" " auto in20=(offset_x<0 || offset_y+2>=cst.input_height) ? (M4)0.f : *(z_in+2*cst.input_width+0);\n" " auto in21=(offset_x+1>=cst.input_width || offset_y+2>=cst.input_height) ? (M4)0.f : *(z_in+2*cst.input_width+1);\n" " auto in22=(offset_x+2>=cst.input_width || offset_y+2>=cst.input_height) ? (M4)0.f : *(z_in+2*cst.input_width+2);\n" " auto in23=(offset_x+3>=cst.input_width || offset_y+2>=cst.input_height) ? (M4)0.f : *(z_in+2*cst.input_width+3);\n" " \n" " auto z_wt=z_flt;\n" " auto k00=z_wt[0],k01=z_wt[1],k02=z_wt[2];\n" " auto k10=z_wt[3],k11=z_wt[4],k12=z_wt[5];\n" " auto k20=z_wt[6],k21=z_wt[7],k22=z_wt[8];\n" " CONV_MUL_PACK_W2(result0,result4);\n" " if (valids[0]) {\n" " CONV_NEXT_FLT;\n" " CONV_MUL_PACK_W2(result1,result5);\n" " }\n" " if (valids[1]) {\n" " CONV_NEXT_FLT;\n" " CONV_MUL_PACK_W2(result2,result6);\n" " }\n" " if (valids[2]) {\n" " CONV_NEXT_FLT;\n" " CONV_MUL_PACK_W2(result3,result7);\n" " }\n" " }\n" " /* true */ *z_out=activate(M4(result0+FLOAT4(biasTerms[uz[0]])),cst.activation);\n" " if(valid_x) {\n" " *(z_out+1)=activate(M4(result4+FLOAT4(biasTerms[uz[0]])),cst.activation);\n" " }\n" " if (valids[0]) {\n" " z_out += cst.output_size;\n" " *z_out=activate(M4(result1+FLOAT4(biasTerms[uz[1]])),cst.activation);\n" " if(valid_x) {\n" " *(z_out+1)=activate(M4(result5+FLOAT4(biasTerms[uz[1]])),cst.activation);\n" " }\n" " }\n" " if (valids[1]) {\n" " z_out += cst.output_size;\n" " *z_out=activate(M4(result2+FLOAT4(biasTerms[uz[2]])),cst.activation);\n" " if(valid_x) {\n" " *(z_out+1)=activate(M4(result6+FLOAT4(biasTerms[uz[2]])),cst.activation);\n" " }\n" " }\n" " if (valids[2]) {\n" " z_out += cst.output_size;\n" " *z_out=activate(M4(result3+FLOAT4(biasTerms[uz[3]])),cst.activation);\n" " if(valid_x) {\n" " *(z_out+1)=activate(M4(result7+FLOAT4(biasTerms[uz[3]])),cst.activation);\n" " }\n" " }\n" "}\n" "kernel void conv_s1d1p0_w2(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv_constants& cst [[buffer(2)]],\n" " const device M4x4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*2 >= cst.output_width || (int)gid.y >= cst.output_height || (int)gid.z >= cst.oz_size) return;\n" " \n" " int idx_w=gid.x << 1;\n" " int idx_h=gid.y;\n" " int idx_c=gid.z/cst.batch;\n" " int idx_b=gid.z % cst.batch;\n" " if (idx_b >= cst.batch || idx_c >= cst.output_slice) return;\n" " bool valid=(idx_w+1= cst.output_width || (int)gid.y >= cst.output_height || (int)gid.z >= cst.oz_size) return;\n" " \n" " int idx_w=gid.x << 2;\n" " int idx_h=gid.y;\n" " int idx_c=gid.z/cst.batch;\n" " int idx_b=gid.z % cst.batch;\n" " \n" " if (idx_b >= cst.batch || idx_c >= cst.output_slice) return;\n" " int3 uz=idx_w+int3(1,2,3);\n" " bool3 valids=uz.xyz= cst.output_width || (int)gid.y >= cst.output_height) return;\n" " \n" " int idx_w=gid.x;\n" " int idx_h=gid.y;\n" " int idx_c=gid.z/cst.batch;\n" " int idx_b=gid.z % cst.batch;\n" " if (idx_b >= cst.batch || idx_c*4 >= cst.output_slice) return;\n" " int4 uz=idx_c*CONV_UNROLL+int4(0,1,2,3);\n" " bool3 valids=uz.yzw= cst.output_width || (int)gid.y >= cst.output_height) return;\n" " \n" " int idx_w=gid.x;\n" " int idx_h=gid.y;\n" " int idx_c=gid.z/cst.batch;\n" " int idx_b=gid.z % cst.batch;\n" " if (idx_b >= cst.batch || idx_c*2 >= cst.output_slice) return;\n" " int2 uz=idx_c*2+int2(0,1);\n" " bool valids=uz.y= s.inside_size || (int)gid.y >= s.outside_size) return;\n" " \n" " auto axis_off=gid.y*s.axis_length*s.inside_size+gid.x;\n" " auto axis_in=in+axis_off;\n" " auto axis_out=out+axis_off;\n" " \n" " // get max\n" " float max1=-FLT_MAX;\n" " for (int i=0; i= s.inside_size || (int)gid.y >= s.outside_size) return;\n" " \n" " auto axis_off=gid.y*s.axis_length*s.inside_size+gid.x;\n" " auto axis_in=in+axis_off;\n" " auto axis_out=out+axis_off;\n" " // get max\n" " auto max4=softmax_filter(float4(axis_in[0]),0,s.flat_length);\n" " for (int i=1; i= s.inside_size || (int)gid.y >= s.outside_size) return;\n" " auto axis_off=gid.y*s.axis_length*s.inside_size+gid.x;\n" " auto axis_in=in+axis_off;\n" " auto axis_out=out+axis_off;\n" " // get max\n" " auto max4=axis_in[0];\n" " for (int i=1; i= cst.inside || (int)gid.y >= cst.outside) {\n" " return;\n" " }\n" " auto in_data=in+gid.y*cst.inside;\n" " auto out_data=out+gid.y*cst.inside;\n" " float mean;\n" " float sum=0.0f;\n" " float square_sum=0.0f;\n" " \n" " for(int i=0; i= cst.inside/4 || (int)gid.y >= cst.outside) {\n" " return;\n" " }\n" " auto in_data=in+gid.y*cst.inside/4;\n" " auto out_data=out+gid.y*cst.inside/4;\n" " float mean;\n" " float sum=0.0f;\n" " float square_sum=0.0f;\n" " \n" " for(int i=0; i= cst.inside || (int)gid.y >= cst.outside) {\n" " return;\n" " }\n" " auto in_data=in+gid.y*cst.inside;\n" " auto out_data=out+gid.y*cst.inside;\n" " float square_sum=0.0f;\n" " \n" " for(int i=0; i= cst.inside/4 || (int)gid.y >= cst.outside) {\n" " return;\n" " }\n" " auto in_data=in+gid.y*cst.inside/4;\n" " auto out_data=out+gid.y*cst.inside/4;\n" " float square_sum=0.0f;\n" " for(int i=0; i= 0 && y >= 0 ? input[x+y*cst.input_shape.x] : 0;\n" "}\n" "kernel void winograd_transform_source2_5_1(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant winograd_constants &cst [[buffer(2)]],\n" " constant int &batch_idx [[buffer(3)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " auto pos=int3(gid);\n" " if (pos.x= cst.output_width || (int)gid.y >= cst.output_height || (int)gid.z >= cst.batch*cst.output_slice) return;\n" " \n" " int b=gid.z % cst.batch;\n" " int o=gid.z/cst.batch;\n" " FLOAT4 result=FLOAT4(biasTerms[o]);\n" " int oy=(int)gid.y+cst.pad_y;\n" " int ox=(int)gid.x+cst.pad_x;\n" " int max_sy=min((cst.input_height-1)*cst.stride_y,oy/cst.stride_y*cst.stride_y);\n" " int max_sx=min((cst.input_width-1)*cst.stride_x,ox/cst.stride_x*cst.stride_x);\n" " int min_ky=UP_DIV(oy-max_sy,cst.dilation_y);\n" " int min_kx=UP_DIV(ox-max_sx,cst.dilation_x);\n" " \n" " if ((oy-min_ky*cst.dilation_y) % cst.stride_y == 0 && (ox-min_kx*cst.dilation_x) % cst.stride_x == 0) {\n" " int min_sy=max(0,ROUND_UP(oy+cst.dilation_y-cst.kernel_y*cst.dilation_y,cst.stride_y));\n" " int min_sx=max(0,ROUND_UP(ox+cst.dilation_x-cst.kernel_x*cst.dilation_x,cst.stride_x));\n" " int max_ky=(oy-min_sy)/cst.dilation_y;\n" " int max_kx=(ox-min_sx)/cst.dilation_x;\n" " int min_iy=(oy-max_ky*cst.dilation_y)/cst.stride_y;\n" " int min_ix=(ox-max_kx*cst.dilation_x)/cst.stride_x;\n" " \n" " auto o_wt=wt+o*cst.input_slice*cst.kernel_size;\n" " auto b_in=in+b*cst.input_size;\n" " for (auto z=0; z= min_ky; ky -= cst.delta_ky,iy += cst.delta_iy) {\n" " for (auto kx=max_kx,ix=min_ix; kx >= min_kx; kx -= cst.delta_kx,ix += cst.delta_ix) {\n" " auto wt4=o_wt[z*cst.kernel_size+ky*cst.kernel_x+kx];\n" " auto in4=b_in[z*cst.input_size*cst.batch+iy*cst.input_width+ix];\n" " result += FLOAT4(in4*wt4);\n" " }\n" " }\n" " }\n" " }\n" " out[(int)gid.z*cst.output_size+(int)gid.y*cst.output_width+(int)gid.x]=activate(M4(result),cst.activation);\n" "}\n" "kernel void deconv_depthwise(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant deconv_constants& cst [[buffer(2)]],\n" " const device M4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x >= cst.output_width || (int)gid.y >= cst.output_height || (int)gid.z >= cst.batch*cst.output_slice) return;\n" " int oz=(int)gid.z/cst.batch;\n" " FLOAT4 result=FLOAT4(biasTerms[oz]);\n" " \n" " int oy=(int)gid.y+cst.pad_y;\n" " int ox=(int)gid.x+cst.pad_x;\n" " int max_sy=min((cst.input_height-1)*cst.stride_y,oy/cst.stride_y*cst.stride_y);\n" " int max_sx=min((cst.input_width-1)*cst.stride_x,ox/cst.stride_x*cst.stride_x);\n" " int min_ky=UP_DIV(oy-max_sy,cst.dilation_y);\n" " int min_kx=UP_DIV(ox-max_sx,cst.dilation_x);\n" " \n" " if ((oy-min_ky*cst.dilation_y) % cst.stride_y == 0 && (ox-min_kx*cst.dilation_x) % cst.stride_x == 0) {\n" " int min_sy=max(0,ROUND_UP(oy+cst.dilation_y-cst.kernel_y*cst.dilation_y,cst.stride_y));\n" " int min_sx=max(0,ROUND_UP(ox+cst.dilation_x-cst.kernel_x*cst.dilation_x,cst.stride_x));\n" " int max_ky=(oy-min_sy)/cst.dilation_y;\n" " int max_kx=(ox-min_sx)/cst.dilation_x;\n" " int min_iy=(oy-max_ky*cst.dilation_y)/cst.stride_y;\n" " int min_ix=(ox-max_kx*cst.dilation_x)/cst.stride_x;\n" " \n" " auto z_wt=wt+oz*cst.kernel_size;\n" " auto z_in=in+(int)gid.z*cst.input_size;\n" " for (auto ky=max_ky,iy=min_iy; ky >= min_ky; ky -= cst.delta_ky,iy += cst.delta_iy) {\n" " for (auto kx=max_kx,ix=min_ix; kx >= min_kx; kx -= cst.delta_kx,ix += cst.delta_ix) {\n" " auto wt4=z_wt[ky*cst.kernel_x+kx];\n" " auto in4=z_in[iy*cst.input_width+ix];\n" " result += FLOAT4(in4*wt4);\n" " }\n" " }\n" " }\n" " out[(int)gid.z*cst.output_size+(int)gid.y*cst.output_width+(int)gid.x]=activate(M4(result),cst.activation);\n" "}\n" ; const char* shader_MetalPooling_metal = "struct pooling_sizes {\n" " int input_width;\n" " int input_height;\n" " int output_width;\n" " int output_height;\n" " int slice;\n" " int kernel_width;\n" " int kernel_height;\n" " int stride_width;\n" " int stride_height;\n" " int pad_width;\n" " int pad_height;\n" "};\n" "kernel void pooling_max(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant pooling_sizes& s [[buffer(2)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if (any(gid >= uint3(s.output_width,s.output_height,s.slice))) return;\n" " \n" " int off_x=gid.x*s.stride_width-s.pad_width;\n" " int off_y=gid.y*s.stride_height-s.pad_height;\n" " int x_max=s.input_width-1;\n" " int y_max=s.input_height-1;\n" " int ex=off_x+s.kernel_width;\n" " int ey=off_y+s.kernel_height;\n" " \n" " auto z_in=in+(int)gid.z*s.input_width*s.input_height;\n" " auto result=M4(z_in[clamp(off_y,0,y_max)*s.input_width+clamp(off_x,0,x_max)]);\n" " for (int y=off_y; y= uint3(s.output_width,s.output_height,s.slice))) return;\n" " \n" " int off_x=gid.x*s.stride_width-s.pad_width;\n" " int off_y=gid.y*s.stride_height-s.pad_height;\n" " int sx=off_x+max(0,-off_x);\n" " int sy=off_y+max(0,-off_y);\n" " int ex=off_x+min(s.kernel_width,s.input_width-off_x);\n" " int ey=off_y+min(s.kernel_height,s.input_height-off_y);\n" " \n" " FLOAT4 result=0;\n" " auto z_in=in+(int)gid.z*s.input_width*s.input_height;\n" " for (int y=sy; y0 ? 1.f/count : 1;\n" " out[(int)gid.z*s.output_width*s.output_height+(int)gid.y*s.output_width+(int)gid.x]=M4(result*div);\n" "}\n" ; const char* shader_MetalROIPooling_metal = "struct ROI_shape {\n" " int input_width;\n" " int input_height;\n" " int input_size;\n" " int input_batch;\n" " int output_width;\n" " int output_height;\n" " int output_size;\n" " int batch;\n" " float spatial_scale;\n" "};\n" "kernel void ROI_pooling(const device M4 *in [[buffer(0)]],\n" " const device M *roi [[buffer(1)]],\n" " device M4 *out [[buffer(2)]],\n" " constant ROI_shape &s [[buffer(3)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x >= s.output_width || (int)gid.y >= s.output_height) return;\n" " \n" " int ob=gid.z % s.batch;\n" " int iz=gid.z/s.batch;\n" " \n" " auto b_roi=roi+ob*5;\n" " int ib=int(b_roi[0]);\n" " int x1=round(float(b_roi[1])*s.spatial_scale);\n" " int y1=round(float(b_roi[2])*s.spatial_scale);\n" " int x2=round(float(b_roi[3])*s.spatial_scale);\n" " int y2=round(float(b_roi[4])*s.spatial_scale);\n" " \n" " int roi_w=max(x2-x1+1,1);\n" " int roi_h=max(y2-y1+1,1);\n" " float bin_size_w=(float)roi_w/(float)s.output_width;\n" " float bin_size_h=(float)roi_h/(float)s.output_height;\n" " \n" " int w_start=clamp(x1+(int)floor(gid.x*bin_size_w) ,0,s.input_width);\n" " int w_end=clamp(x1+(int)ceil((gid.x+1)*bin_size_w),0,s.input_width);\n" " int h_start=clamp(y1+(int)floor(gid.y*bin_size_h) ,0,s.input_height);\n" " int h_end=clamp(y1+(int)ceil((gid.y+1)*bin_size_h),0,s.input_height);\n" " \n" " int is_empty=(h_end <= h_start) || (w_end <= w_start);\n" " auto z_in=in+(ib+iz*s.input_batch)*s.input_size;\n" " auto max4=is_empty ? 0 : z_in[h_start*s.input_width+w_start];\n" " for (int y=h_start; y= cst.output_size || (int)gid.y >= cst.output_slice || (int)gid.z >= cst.batch) return;\n" " \n" " int rx=gid.x*CONV_UNROLL;\n" " int uz=gid.y;\n" " auto xy_wt=wt+uz*cst.input_slice;\n" " auto xy_in0=in+(int)gid.z*cst.input_size+rx+0;\n" " auto xy_out=out+(int)gid.z*cst.output_size+uz*cst.output_size*cst.batch+rx;\n" " auto biasValue=FLOAT4(biasTerms[uz]);\n" " FLOAT4 result0=biasValue,result1=biasValue,result2=biasValue,result3=biasValue;\n" " int computeSize=min(cst.output_size-rx,CONV_UNROLL);\n" " for (auto z=0; z1) {xy_out[1]=activate(M4(result1),cst.activation); }\n" " if (computeSize>2) {xy_out[2]=activate(M4(result2),cst.activation); }\n" " if (computeSize>3) {xy_out[3]=activate(M4(result3),cst.activation); }\n" "}\n" "kernel void conv1x1_g1z4_w8(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv1x1_constants& cst [[buffer(2)]],\n" " const device MNN::char4x4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " const device M4 *dequantScale [[buffer(5)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*CONV_UNROLL >= cst.output_size || (int)gid.y >= cst.output_slice || (int)gid.z >= cst.batch) return;\n" " int rx=gid.x*CONV_UNROLL;\n" " int uz=gid.y;\n" " auto xy_wt=wt+uz*cst.input_slice;\n" " auto xy_in0=in+(int)gid.z*cst.input_size+rx+0;\n" " auto xy_out=out+(int)gid.z*cst.output_size+uz*cst.output_size*cst.batch+rx;\n" " auto biasValue=FLOAT4(biasTerms[uz]);\n" " FLOAT4 result0=biasValue,result1=biasValue,result2=biasValue,result3=biasValue;\n" " int computeSize=min(cst.output_size-rx,CONV_UNROLL);\n" " int block=(cst.input_slice+cst.block_size-1)/cst.block_size;\n" " for (int bi=0; bi1 ? (FLOAT4)*(xy_in0+1) : (FLOAT4)0.0;\n" " auto in42=computeSize>2 ? (FLOAT4)*(xy_in0+2) : (FLOAT4)0.0;\n" " auto in43=computeSize>3 ? (FLOAT4)*(xy_in0+3) : (FLOAT4)0.0;\n" " auto w=xy_wt[z];\n" " FLOAT4x4 w_fp32=FLOAT4x4(FLOAT4(w[0]),FLOAT4(w[1]),FLOAT4(w[2]),FLOAT4(w[3]));\n" " FLOAT4x4 w_dequant;\n" " for (int i=0; i<4; ++i) {\n" " w_dequant[i]=w_fp32[i]*scale[i]+dequant_bias[i];\n" " }\n" " result0 += FLOAT4(in40*w_dequant);\n" " result1 += FLOAT4(in41*w_dequant);\n" " result2 += FLOAT4(in42*w_dequant);\n" " result3 += FLOAT4(in43*w_dequant);\n" " xy_in0 += cst.input_size*cst.batch;\n" " }\n" " }\n" " /* true */ \n" " xy_out[0]=activate(M4(result0),cst.activation);\n" " if (computeSize>1) {xy_out[1]=activate(M4(result1),cst.activation); }\n" " if (computeSize>2) {xy_out[2]=activate(M4(result2),cst.activation); }\n" " if (computeSize>3) {xy_out[3]=activate(M4(result3),cst.activation); }\n" "}\n" "kernel void conv1x1_g1z4_w4(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv1x1_constants& cst [[buffer(2)]],\n" " const device MNN::uchar4x2 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " const device M4 *dequantScale [[buffer(5)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*CONV_UNROLL >= cst.output_size || (int)gid.y >= cst.output_slice || (int)gid.z >= cst.batch) return;\n" " int rx=gid.x*CONV_UNROLL;\n" " int uz=gid.y;\n" " auto xy_wt=wt+uz*cst.input_slice;\n" " auto xy_in0=in+(int)gid.z*cst.input_size+rx+0;\n" " auto xy_out=out+(int)gid.z*cst.output_size+uz*cst.output_size*cst.batch+rx;\n" " auto biasValue=FLOAT4(biasTerms[uz]);\n" " FLOAT4 result0=biasValue,result1=biasValue,result2=biasValue,result3=biasValue;\n" " int computeSize=min(cst.output_size-rx,CONV_UNROLL);\n" " int block=(cst.input_slice+cst.block_size-1)/cst.block_size;\n" " for (int bi=0; bifloat */\n" " //FLOAT4x4 w_fp32=FLOAT4x4(FLOAT4(w[0]),FLOAT4(w[1]),FLOAT4(w[2]),FLOAT4(w[3]));\n" " FLOAT4x4 w_dequant;\n" " for (int i=0; i<4; ++i) {\n" " // M4 w4=M4(w_fp32[i]);\n" " FLOAT4 w4=FLOAT4((float)(w_int4[i][0] >> 4)-8,(float)(w_int4[i][0] & 15)-8,(float)(w_int4[i][1] >> 4)-8,(float)(w_int4[i][1] & 15)-8);\n" " FLOAT4 res=w4*scale[i]+dequant_bias[i];\n" " w_dequant[i]=res;\n" " }\n" " result0 += FLOAT4(in40*w_dequant);\n" " result1 += FLOAT4(in41*w_dequant);\n" " result2 += FLOAT4(in42*w_dequant);\n" " result3 += FLOAT4(in43*w_dequant);\n" " xy_in0 += cst.input_size*cst.batch;\n" " }\n" " }\n" " \n" " /* true */ \n" " xy_out[0]=activate(M4(result0),cst.activation);\n" " if (computeSize>1) {xy_out[1]=activate(M4(result1),cst.activation); }\n" " if (computeSize>2) {xy_out[2]=activate(M4(result2),cst.activation); }\n" " if (computeSize>3) {xy_out[3]=activate(M4(result3),cst.activation); }\n" "}\n" "kernel void conv1x1_g1z8(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv1x1_constants& cst [[buffer(2)]],\n" " const device M4x4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*CONV_UNROLL_L >= cst.output_size || (int)gid.y >= cst.output_slice || (int)gid.z >= cst.batch) return;\n" " int rx=gid.x*CONV_UNROLL_L;\n" " int uz=gid.y;\n" " auto xy_wt=wt+uz*cst.input_slice;\n" " auto xy_in0=in+(int)gid.z*cst.input_size+rx+0;\n" " auto xy_out=out+(int)gid.z*cst.output_size+uz*cst.batch*cst.output_size+rx;\n" " auto biasValue=FLOAT4(biasTerms[uz]);\n" " FLOAT4 result0=biasValue,result1=biasValue,result2=biasValue,result3=biasValue;\n" " FLOAT4 result4=biasValue,result5=biasValue,result6=biasValue,result7=biasValue;\n" " int computeSize=min(cst.output_size-rx,CONV_UNROLL_L);\n" " for (auto z=0; z1) {xy_out[1]=activate(M4(result1),cst.activation); }\n" " if (computeSize>2) {xy_out[2]=activate(M4(result2),cst.activation); }\n" " if (computeSize>3) {xy_out[3]=activate(M4(result3),cst.activation); }\n" " if (computeSize>4) {xy_out[4]=activate(M4(result4),cst.activation); }\n" " if (computeSize>5) {xy_out[5]=activate(M4(result5),cst.activation); }\n" " if (computeSize>6) {xy_out[6]=activate(M4(result6),cst.activation); }\n" " if (computeSize>7) {xy_out[7]=activate(M4(result7),cst.activation); }\n" "}\n" "kernel void conv1x1_w4h4(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv1x1_constants& cst [[buffer(2)]],\n" " const device M4x4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*16 >= cst.output_width || (int)gid.y >= cst.batch*cst.output_slice) return;\n" " int idx_w=gid.x << 4;\n" " int idx_h=0;\n" " int idx_c=gid.y/cst.batch;\n" " int idx_b=gid.y % cst.batch;\n" " auto xy_wt=wt+idx_c*cst.input_slice;\n" " auto xy_in0=in+(int)idx_b*cst.input_size+idx_h*cst.output_width+idx_w;\n" " auto xy_out=out+(int)idx_b*cst.output_size+idx_c*cst.output_size*cst.batch+idx_h*cst.output_width+idx_w;\n" " auto biasValue=FLOAT4(biasTerms[idx_c]);\n" " FLOAT4 result00=biasValue,result01=biasValue,result02=biasValue,result03=biasValue;\n" " FLOAT4 result10=biasValue,result11=biasValue,result12=biasValue,result13=biasValue;\n" " FLOAT4 result20=biasValue,result21=biasValue,result22=biasValue,result23=biasValue;\n" " FLOAT4 result30=biasValue,result31=biasValue,result32=biasValue,result33=biasValue;\n" " for (auto z=0; z1) {xy_out[1]=activate(M4(result01),cst.activation); }\n" " if (widthSize>2) {xy_out[2]=activate(M4(result02),cst.activation); }\n" " if (widthSize>3) {xy_out[3]=activate(M4(result03),cst.activation); }\n" " if (widthSize>4) {xy_out[4]=activate(M4(result10),cst.activation); }\n" " if (widthSize>5) {xy_out[5]=activate(M4(result11),cst.activation); }\n" " if (widthSize>6) {xy_out[6]=activate(M4(result12),cst.activation); }\n" " if (widthSize>7) {xy_out[7]=activate(M4(result13),cst.activation); }\n" " if (widthSize>8) {xy_out[8]=activate(M4(result20),cst.activation); }\n" " if (widthSize>9) {xy_out[9]=activate(M4(result21),cst.activation); }\n" " if (widthSize>10) {xy_out[10]=activate(M4(result22),cst.activation); }\n" " if (widthSize>11) {xy_out[11]=activate(M4(result23),cst.activation); }\n" " if (widthSize>12) {xy_out[12]=activate(M4(result30),cst.activation); }\n" " if (widthSize>13) {xy_out[13]=activate(M4(result31),cst.activation); }\n" " if (widthSize>14) {xy_out[14]=activate(M4(result32),cst.activation); }\n" " if (widthSize>15) {xy_out[15]=activate(M4(result33),cst.activation); }\n" "}\n" "kernel void conv1x1_w2c2(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv1x1_constants& cst [[buffer(2)]],\n" " const device M4x4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*2 >= cst.output_width || (int)gid.y*2 >= cst.batch*cst.output_slice) return;\n" " int channel_pack=(cst.output_channel+7) >> 3;\n" " int idx_w=gid.x << 1;\n" " int idx_h=0;\n" " int idx_c=(gid.y % channel_pack) << 1;\n" " int idx_b=gid.y/channel_pack;\n" " \n" " if(idx_b >= cst.batch || idx_c >= cst.output_slice) return;\n" " auto xy_wt=wt+idx_c*cst.input_slice;\n" " auto xy_in0=in+(int)idx_b*cst.input_size+idx_h*cst.output_width+idx_w;\n" " auto xy_out=out+(int)idx_b*cst.output_size+idx_c*cst.output_size*cst.batch+idx_h*cst.output_width+idx_w;\n" " auto biasValue0=FLOAT4(biasTerms[idx_c]);\n" " auto biasValue1=FLOAT4(biasTerms[idx_c+1]);\n" " FLOAT4 result0=biasValue0,result1=biasValue0;\n" " FLOAT4 result4=biasValue1,result5=biasValue1;\n" " for (auto z=0; z1) {xy_out[1]=activate(M4(result1),cst.activation); }\n" " \n" " int channelSize=min(cst.output_slice-idx_c,2);\n" " if(channelSize>1) {\n" " /* true */ {xy_out[cst.output_size*cst.batch +0]=activate(M4(result4),cst.activation); }\n" " if (widthSize>1) {xy_out[cst.output_size*cst.batch +1]=activate(M4(result5),cst.activation); }\n" " }\n" "}\n" "kernel void conv1x1_w4c2(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant conv1x1_constants& cst [[buffer(2)]],\n" " const device M4x4 *wt [[buffer(3)]],\n" " const device M4 *biasTerms [[buffer(4)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x*4 >= cst.output_width || (int)gid.y*2 >= cst.batch*cst.output_slice) return;\n" " int channel_pack=(cst.output_channel+7) >> 3;\n" " int idx_w=gid.x << 2;\n" " int idx_h=0;\n" " int idx_c=(gid.y % channel_pack) << 1;\n" " int idx_b=gid.y/channel_pack;\n" " if(idx_b >= cst.batch || idx_c >= cst.output_slice) return;\n" " auto xy_wt=wt+idx_c*cst.input_slice;\n" " auto xy_in0=in+(int)idx_b*cst.input_size+idx_h*cst.output_width+idx_w;\n" " auto xy_out=out+(int)idx_b*cst.output_size+idx_c*cst.output_size*cst.batch+idx_h*cst.output_width+idx_w;\n" " auto biasValue0=FLOAT4(biasTerms[idx_c]);\n" " auto biasValue1=FLOAT4(biasTerms[idx_c+1]);\n" " FLOAT4 result0=biasValue0,result1=biasValue0;\n" " FLOAT4 result4=biasValue0,result5=biasValue0;\n" " FLOAT4 result2=biasValue1,result3=biasValue1;\n" " FLOAT4 result6=biasValue1,result7=biasValue1;\n" " for (auto z=0; z1) {xy_out[1]=activate(M4(result1),cst.activation); }\n" " if (widthSize>2) {xy_out[2]=activate(M4(result4),cst.activation); }\n" " if (widthSize>3) {xy_out[3]=activate(M4(result5),cst.activation); }\n" " \n" " int channelSize=min(cst.output_slice-idx_c,2);\n" " if(channelSize>1) {\n" " /* true */ xy_out[cst.output_size*cst.batch]=activate(M4(result2),cst.activation);\n" " if (widthSize>1) {xy_out[cst.output_size*cst.batch +1]=activate(M4(result3),cst.activation); }\n" " if (widthSize>2) {xy_out[cst.output_size*cst.batch +2]=activate(M4(result6),cst.activation); }\n" " if (widthSize>3) {xy_out[cst.output_size*cst.batch +3]=activate(M4(result7),cst.activation); }\n" " }\n" "}\n" ; const char* shader_MetalConvolutionGEMM_metal = "struct matmul4x4_const {\n" " int output_width;\n" " int output_height;\n" " int multi_length;\n" " int group;\n" "};\n" "template \n" "static inline void matmul4x4_template(const device IType *in,\n" " device OType *out,\n" " const device IType *kt,\n" " constant matmul4x4_const &cst,\n" " uint3 gid) {\n" " if ((int)gid.x(in,out,kt,cst,gid);\n" "}\n" ; const char* shader_MetalResize_metal = "struct resize_shape {\n" " int input_width;\n" " int input_height;\n" " int input_size;\n" " int output_width;\n" " int output_height;\n" " int output_size;\n" " int sliceMap;\n" "};\n" "kernel void resize_nearest(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant resize_shape &c [[buffer(2)]],\n" " constant float4& s [[buffer(3)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x >= c.output_width || (int)gid.y >= c.output_height || (int)gid.z >= c.sliceMap) return;\n" " \n" " float srcX=gid.x*s.x+s.y,srcY=gid.y*s.z+s.w;\n" " int left=floor(srcX);\n" " int top=floor(srcY);\n" " \n" " auto in_z=in+gid.z*c.input_size;\n" " auto in_top=in_z+top*c.input_width;\n" " out[int(gid.z)*c.output_size+int(gid.y)*c.output_width+int(gid.x)]=in_top[left];\n" "}\n" "kernel void resize_bilinear(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant resize_shape &c [[buffer(2)]],\n" " constant float4& s [[buffer(3)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x >= c.output_width || (int)gid.y >= c.output_height || (int)gid.z >= c.sliceMap) return;\n" " \n" " float srcX=gid.x*s.x+s.y,srcY=gid.y*s.z+s.w;\n" " int srcXInt=int(floor(srcX));\n" " int srcYInt=int(floor(srcY));\n" " int left=clamp(srcXInt,0,c.input_width-1);\n" " int right=clamp(srcXInt+1,0,c.input_width-1);\n" " int top=clamp(srcYInt,0,c.input_height-1);\n" " int bottom=clamp(srcYInt+1,0,c.input_height-1);\n" " float x2_factor=srcX-float(srcXInt);\n" " float y2_factor=srcY-float(srcYInt);\n" " float x1_factor=1-x2_factor;\n" " float y1_factor=1-y2_factor;\n" " \n" " auto in_z=in+gid.z*c.input_size;\n" " auto in_top=in_z+top*c.input_width;\n" " auto in_bottom=in_z+bottom*c.input_width;\n" " auto tl=float4(in_top[left])*x1_factor*y1_factor;\n" " auto tr=float4(in_top[right])*x2_factor*y1_factor;\n" " auto bl=float4(in_bottom[left])*x1_factor*y2_factor;\n" " auto br=float4(in_bottom[right])*x2_factor*y2_factor;\n" " out[int(gid.z)*c.output_size+int(gid.y)*c.output_width+int(gid.x)]=M4(tl+tr+bl+br);\n" "}\n" "static inline float4 resize_cubic_interpolation(float4 A,float4 B,float4 C,float4 D,float factor) {\n" " float4 a=(B-C)+0.5f*(B-A)+(D-C)*0.5f;\n" " float4 b=C-((B-A)+(B-C))-(B+D)*0.5f;\n" " float4 c=(C-A)*0.5f;\n" " float4 d=B;\n" " return ((a*factor+b)*factor+c)*factor+d;\n" "}\n" "kernel void resize_cubic(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant resize_shape &c [[buffer(2)]],\n" " constant float4& s [[buffer(3)]],\n" " uint3 gid [[thread_position_in_grid]]) {\n" " if ((int)gid.x >= c.output_width || (int)gid.y >= c.output_height || (int)gid.z >= c.sliceMap) return;\n" " float x=gid.x*s.x+s.y,y=gid.y*s.z+s.w;\n" " \n" " float x_factor=x-floor(x);\n" " float y_factor=y-floor(y);\n" " \n" " int4 xp=int4(int(x)-1,int(x)+0,int(x)+1,int(x)+2);\n" " xp=clamp(xp,0,c.input_width-1);\n" " \n" " int4 yp=int4(int(y)-1,int(y)+0,int(y)+1,int(y)+2);\n" " yp=clamp(yp,0,c.input_height-1);\n" " \n" " auto in_z=in+gid.z*c.input_size;\n" " float4x4 ABCD;\n" " for (int i=0; i<4; i++) {\n" " auto in_y=in_z+yp[i]*c.input_width;\n" " float4 A=float4(in_y[xp[0]]);\n" " float4 B=float4(in_y[xp[1]]);\n" " float4 C=float4(in_y[xp[2]]);\n" " float4 D=float4(in_y[xp[3]]);\n" " ABCD[i]=resize_cubic_interpolation(A,B,C,D,x_factor);\n" " }\n" " \n" " auto val=M4(resize_cubic_interpolation(ABCD[0],ABCD[1],ABCD[2],ABCD[3],y_factor));\n" " out[int(gid.z)*c.output_size+int(gid.y)*c.output_width+int(gid.x)]=val;\n" "}\n" ; const char* shader_MetalPReLU_metal = "struct prelu_shape {\n" " int size;\n" " int slice;\n" " int batch;\n" "};\n" "kernel void prelu(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " constant float &slope [[buffer(2)]],\n" " uint gid [[thread_position_in_grid]]) {\n" " auto v4=in[int(gid)];\n" " out[int(gid)]=select(v4,M4(slope)*v4,signbit(v4));\n" "}\n" "kernel void prelu_slopes(const device M4 *in [[buffer(0)]],\n" " device M4 *out [[buffer(1)]],\n" " const device float4 *slope [[buffer(2)]],\n" " constant prelu_shape& s [[buffer(3)]],\n" " uint3 gid [[thread_position_in_grid]]) { // size,slice,batch\n" " if ((int)gid.x >= s.size || (int)gid.y >= s.slice) return;\n" " \n" " int z=gid.z+gid.y*s.batch;\n" " auto v4=in[z*s.size+int(gid.x)];\n" " out[z*s.size+int(gid.x)]=select(v4,M4(slope[int(gid.y)])*v4,signbit(v4));\n" "}\n" ; const char* shader_MetalDefine_metal = "using namespace metal;\n" "// –––––––––––––––––––––––––––––––––––––––––––––––––––\n" "// Macro\n" "// –––––––––––––––––––––––––––––––––––––––––––––––––––\n" "#define UP_DIV(x,y) ( ((x)+(y)-1)/(y) )\n" "#define ROUND_UP(x,y) ( ((x)+(y)-1)/(y)*(y) )\n" "// whether computer with float32 when store with float16\n" "#define MNN_METAL_FLOAT32_COMPUTER 1 //\n" "#if MNN_METAL_FULL_PRECISION\n" "typedef float M;\n" "typedef float2 M2;\n" "typedef float3 M3;\n" "typedef float4 M4;\n" "typedef float2x2 M2x2;\n" "typedef float2x3 M2x3;\n" "typedef float2x4 M2x4;\n" "typedef float3x2 M3x2;\n" "typedef float3x3 M3x3;\n" "typedef float3x4 M3x4;\n" "typedef float4x2 M4x2;\n" "typedef float4x3 M4x3;\n" "typedef float4x4 M4x4;\n" "#else\n" "typedef half M;\n" "typedef half2 M2;\n" "typedef half3 M3;\n" "typedef half4 M4;\n" "typedef half2x2 M2x2;\n" "typedef half2x3 M2x3;\n" "typedef half2x4 M2x4;\n" "typedef half3x2 M3x2;\n" "typedef half3x3 M3x3;\n" "typedef half3x4 M3x4;\n" "typedef half4x2 M4x2;\n" "typedef half4x3 M4x3;\n" "typedef half4x4 M4x4;\n" "#endif\n" "#if MNN_METAL_FLOAT32_COMPUTER\n" "typedef float FLOAT;\n" "typedef float2 FLOAT2;\n" "typedef float3 FLOAT3;\n" "typedef float4 FLOAT4;\n" "typedef float2x2 FLOAT2x2;\n" "typedef float2x3 FLOAT2x3;\n" "typedef float2x4 FLOAT2x4;\n" "typedef float3x2 FLOAT3x2;\n" "typedef float3x3 FLOAT3x3;\n" "typedef float3x4 FLOAT3x4;\n" "typedef float4x2 FLOAT4x2;\n" "typedef float4x3 FLOAT4x3;\n" "typedef float4x4 FLOAT4x4;\n" "#else\n" "typedef half FLOAT;\n" "typedef half2 FLOAT2;\n" "typedef half3 FLOAT3;\n" "typedef half4 FLOAT4;\n" "typedef half2x2 FLOAT2x2;\n" "typedef half2x3 FLOAT2x3;\n" "typedef half2x4 FLOAT2x4;\n" "typedef half3x2 FLOAT3x2;\n" "typedef half3x3 FLOAT3x3;\n" "typedef half3x4 FLOAT3x4;\n" "typedef half4x2 FLOAT4x2;\n" "typedef half4x3 FLOAT4x3;\n" "typedef half4x4 FLOAT4x4;\n" "#endif\n" "namespace MNN {\n" " \n" " // –––––––––––––––––––––––––––––––––––––––––––––––––––\n" " // Number Limit\n" " // –––––––––––––––––––––––––––––––––––––––––––––––––––\n" "#define INT8_MAX 127\n" "#define INT8_MIN -128\n" "#define INT16_MAX 32767\n" "#define INT16_MIN -32768\n" "#define INT32_MAX 2147483647\n" "#define INT32_MIN -2147483648\n" "#define UINT8_MAX 255\n" "#define UINT16_MAX 65535\n" "#define UINT32_MAX 4294967295U\n" " \n" " template struct num_limits {\n" " static int max() { return 0; };\n" " static int min() { return 0; };\n" " };\n" " template<> struct num_limits {\n" " static int max() { return INT8_MAX; };\n" " static int min() { return INT8_MIN; };\n" " };\n" " template<> struct num_limits {\n" " static int max() { return UINT8_MAX; };\n" " static int min() { return 0; };\n" " };\n" " template<> struct num_limits {\n" " static int max() { return INT16_MAX; };\n" " static int min() { return INT16_MIN; };\n" " };\n" " template<> struct num_limits {\n" " static int max() { return UINT16_MAX; };\n" " static int min() { return 0; };\n" " };\n" " template<> struct num_limits {\n" " static int max() { return INT32_MAX; };\n" " static int min() { return INT32_MIN; };\n" " };\n" " template<> struct num_limits {\n" " static int max() { return UINT32_MAX; };\n" " static int min() { return 0; };\n" " };\n" " \n" " // –––––––––––––––––––––––––––––––––––––––––––––––––––\n" " // Function\n" " // –––––––––––––––––––––––––––––––––––––––––––––––––––\n" " inline int dot(int4 i4,int4 w4) {\n" " return i4[0]*w4[0]+i4[1]*w4[1]+i4[2]*w4[2]+i4[3]*w4[3];\n" " }\n" " \n" " template \n" " inline T saturate_round_x2_high_mul(T a,int b) {\n" " return mulhi(a,b)*2;\n" " }\n" " \n" " template \n" " inline T round_divide_by_pot(T x,int exponent) {\n" " int mask=(1 << exponent)-1;\n" " T remainder=x & mask;\n" " T threshold=(mask >> 1)+T(x<0);\n" " return (x >> exponent)+T(remainder>threshold);\n" " }\n" " \n" " // –––––––––––––––––––––––––––––––––––––––––––––––––––\n" " // Typedef\n" " // –––––––––––––––––––––––––––––––––––––––––––––––––––\n" " \n" " typedef struct short4x4 {\n" " private:\n" " short4 v[4];\n" " public:\n" " short4x4(short4 a) {\n" " v[0]=a; v[1]=a; v[2]=a; v[3]=a;\n" " }\n" " short4x4(short4 a,short4 b,short4 c,short4 d) {\n" " v[0]=a; v[1]=b; v[2]=c; v[3]=d;\n" " }\n" " \n" " inline thread short4& operator[] (const int index) {\n" " return v[index];\n" " }\n" " inline device short4& operator[] (const int index) device {\n" " return v[index];\n" " }\n" " inline threadgroup short4& operator[] (const int index) threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline const thread short4& operator[] (const int index) const {\n" " return v[index];\n" " }\n" " inline const device short4& operator[] (const int index) const device {\n" " return v[index];\n" " }\n" " inline const threadgroup short4& operator[] (const int index) const threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline explicit operator half4x4() const {\n" " return half4x4( half4(v[0]),half4(v[1]),half4(v[2]),half4(v[3]) );\n" " }\n" " inline explicit operator half4x4() const device{\n" " return half4x4( half4(v[0]),half4(v[1]),half4(v[2]),half4(v[3]) );\n" " }\n" " inline explicit operator half4x4() const threadgroup {\n" " return half4x4( half4(v[0]),half4(v[1]),half4(v[2]),half4(v[3]) );\n" " }\n" " \n" " inline explicit operator float4x4() const {\n" " return float4x4( float4(v[0]),float4(v[1]),float4(v[2]),float4(v[3]) );\n" " }\n" " inline explicit operator float4x4() const device {\n" " return float4x4( float4(v[0]),float4(v[1]),float4(v[2]),float4(v[3]) );\n" " }\n" " inline explicit operator float4x4() const threadgroup {\n" " return float4x4( float4(v[0]),float4(v[1]),float4(v[2]),float4(v[3]) );\n" " }\n" " } short4x4;\n" " \n" " typedef struct char4x4 {\n" " private:\n" " char4 v[4];\n" " public:\n" " char4x4(char4 a) {\n" " v[0]=a; v[1]=a; v[2]=a; v[3]=a;\n" " }\n" " char4x4(char4 a,char4 b,char4 c,char4 d) {\n" " v[0]=a; v[1]=b; v[2]=c; v[3]=d;\n" " }\n" " \n" " inline thread char4& operator[] (const int index) {\n" " return v[index];\n" " }\n" " inline device char4& operator[] (const int index) device {\n" " return v[index];\n" " }\n" " inline threadgroup char4& operator[] (const int index) threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline const thread char4& operator[] (const int index) const {\n" " return v[index];\n" " }\n" " inline const device char4& operator[] (const int index) const device {\n" " return v[index];\n" " }\n" " inline const threadgroup char4& operator[] (const int index) const threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline explicit operator half4x4() const {\n" " return half4x4( half4(v[0]),half4(v[1]),half4(v[2]),half4(v[3]) );\n" " }\n" " inline explicit operator half4x4() const device {\n" " return half4x4( half4(v[0]),half4(v[1]),half4(v[2]),half4(v[3]) );\n" " }\n" " inline explicit operator half4x4() const threadgroup {\n" " return half4x4( half4(v[0]),half4(v[1]),half4(v[2]),half4(v[3]) );\n" " }\n" " \n" " inline explicit operator float4x4() const {\n" " return float4x4( float4(v[0]),float4(v[1]),float4(v[2]),float4(v[3]) );\n" " }\n" " inline explicit operator float4x4() const device {\n" " return float4x4( float4(v[0]),float4(v[1]),float4(v[2]),float4(v[3]) );\n" " }\n" " inline explicit operator float4x4() const threadgroup {\n" " return float4x4( float4(v[0]),float4(v[1]),float4(v[2]),float4(v[3]) );\n" " }\n" " } char4x4;\n" " typedef struct char4x2 {\n" " private:\n" " char2 v[4];\n" " public:\n" " char4x2(char2 a) {\n" " v[0]=a; v[1]=a; v[2]=a; v[3]=a;\n" " }\n" " char4x2(char2 a,char2 b,char2 c,char2 d) {\n" " v[0]=a; v[1]=b; v[2]=c; v[3]=d;\n" " }\n" " \n" " inline thread char2& operator[] (const int index) {\n" " return v[index];\n" " }\n" " inline device char2& operator[] (const int index) device {\n" " return v[index];\n" " }\n" " inline threadgroup char2& operator[] (const int index) threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline const thread char2& operator[] (const int index) const {\n" " return v[index];\n" " }\n" " inline const device char2& operator[] (const int index) const device {\n" " return v[index];\n" " }\n" " inline const threadgroup char2& operator[] (const int index) const threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline explicit operator half4x2() const {\n" " return half4x2( half2(v[0]),half2(v[1]),half2(v[2]),half2(v[3]) );\n" " }\n" " inline explicit operator half4x2() const device {\n" " return half4x2( half2(v[0]),half2(v[1]),half2(v[2]),half2(v[3]) );\n" " }\n" " inline explicit operator half4x2() const threadgroup {\n" " return half4x2( half2(v[0]),half2(v[1]),half2(v[2]),half2(v[3]) );\n" " }\n" " \n" " inline explicit operator float4x2() const {\n" " return float4x2( float2(v[0]),float2(v[1]),float2(v[2]),float2(v[3]) );\n" " }\n" " inline explicit operator float4x2() const device {\n" " return float4x2( float2(v[0]),float2(v[1]),float2(v[2]),float2(v[3]) );\n" " }\n" " inline explicit operator float4x2() const threadgroup {\n" " return float4x2( float2(v[0]),float2(v[1]),float2(v[2]),float2(v[3]) );\n" " }\n" " } char4x2;\n" " typedef struct uchar4x2 {\n" " private:\n" " uchar2 v[4];\n" " public:\n" " uchar4x2(uchar2 a) {\n" " v[0]=a; v[1]=a; v[2]=a; v[3]=a;\n" " }\n" " uchar4x2(uchar2 a,uchar2 b,uchar2 c,uchar2 d) {\n" " v[0]=a; v[1]=b; v[2]=c; v[3]=d;\n" " }\n" " \n" " inline thread uchar2& operator[] (const int index) {\n" " return v[index];\n" " }\n" " inline device uchar2& operator[] (const int index) device {\n" " return v[index];\n" " }\n" " inline threadgroup uchar2& operator[] (const int index) threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline const thread uchar2& operator[] (const int index) const {\n" " return v[index];\n" " }\n" " inline const device uchar2& operator[] (const int index) const device {\n" " return v[index];\n" " }\n" " inline const threadgroup uchar2& operator[] (const int index) const threadgroup {\n" " return v[index];\n" " }\n" " \n" " inline explicit operator half4x2() const {\n" " return half4x2( half2(v[0]),half2(v[1]),half2(v[2]),half2(v[3]) );\n" " }\n" " inline explicit operator half4x2() const device {\n" " return half4x2( half2(v[0]),half2(v[1]),half2(v[2]),half2(v[3]) );\n" " }\n" " inline explicit operator half4x2() const threadgroup {\n" " return half4x2( half2(v[0]),half2(v[1]),half2(v[2]),half2(v[3]) );\n" " }\n" " \n" " inline explicit operator float4x2() const {\n" " return float4x2( float2(v[0]),float2(v[1]),float2(v[2]),float2(v[3]) );\n" " }\n" " inline explicit operator float4x2() const device {\n" " return float4x2( float2(v[0]),float2(v[1]),float2(v[2]),float2(v[3]) );\n" " }\n" " inline explicit operator float4x2() const threadgroup {\n" " return float4x2( float2(v[0]),float2(v[1]),float2(v[2]),float2(v[3]) );\n" " }\n" " } uchar4x2;\n" "}\n" ; const char* shader_MetalEltwise_metal = "kernel void eltwise_prod(device const M *in0 [[buffer(0)]],\n" " device const M *in1 [[buffer(1)]],\n" " device M *out [[buffer(2)]],\n" " constant int4& shape [[buffer(3)]],\n" " uint gid [[thread_position_in_grid]]) {\n" " if ((int)gid