我用numpy实现了GPT-2,GPT-2源码,GPT-2模型加速推理,并且可以在树莓派上运行,读了不少hungging face源码,手动实现了numpy的GPT2模型
之前分别用numpy实现了mlp,cnn,lstm和bert模型,这周顺带搞一下GPT-2,纯numpy实现,最重要的是可在树莓派上或其他不能安装pytorch的板子上运行,生成数据
gpt-2的mask-multi-headed-self-attention我现在才彻底的明白它是真的牛逼,比bert的multi-headed-self-attention牛的不是一点半点,提出mask的人智商也是相当高了
这次模型依然是从hungging face上找的一个,gpt-2 small版本,参数比bert还小,主要是gpt-2没有token-type那个2*768的矩阵和一个pooler矩阵,别的都有
gpt-2的模型结构和bert类似,只不过multi-headed-self-attention换成了mask-multi-headed-self-attention,另外
- import numpy as np
- import time
- def top_k_sampling(probs, k):
- # 使用argsort对概率分布数组进行排序,得到索引数组
- sorted_indices = np.argsort(probs)[::-1]
- # 选择前K个概率最高的词的索引
- topk_indices = sorted_indices[:k]
- # 根据选择的Top-K索引进行进一步处理,例如按概率重新归一化或随机采样
- return topk_indices
- def random_sampling(array, k):
- sample = np.random.choice(array, size=k, replace=False)
- return sample
- def word_embedding(input_ids, word_embeddings):
- return word_embeddings[input_ids]
- def position_embedding(position_ids, position_embeddings):
- return position_embeddings[position_ids]
- def token_type_embedding(token_type_ids, token_type_embeddings):
- return token_type_embeddings[token_type_ids]
- def softmax(x, axis=None):
- # e_x = np.exp(x).astype(np.float32) #
- e_x = np.exp(x - np.max(x, axis=axis, keepdims=True))
- sum_ex = np.sum(e_x, axis=axis,keepdims=True).astype(np.float32)
- return e_x / sum_ex
- def scaled_dot_product_attention(Q, K, V, mask=None):
- d_k = Q.shape[-1]
- attention_scores = np.matmul(Q, K.transpose(0, 2, 1)) / np.sqrt(d_k) #一致
- if mask is not None:
- # min_value = scores.min()
- min_value = np.finfo(attention_scores.dtype).min #找的scores.dtype 这个类型数据的最小值
- # scores = np.where(mask, scores, np.full_like(scores, -np.inf))
- scores = np.where(mask, attention_scores, np.full_like(attention_scores, min_value)) # 用最小值替换0的部分
- attention_weights = softmax(scores, axis=-1) # 这样softmax的权重在本来是0的地方得到的数值是0
- output = np.matmul(attention_weights, V) #一致了
- return output, attention_weights
- def scaled_dot_product_attention2(Q, K, V): # 单部推理 降低计算量
- global att_scores
- d_k = Q.shape[-1]
- attention_scores = np.matmul(Q, K.transpose(0, 2, 1)) / np.sqrt(d_k) #一致
- attention_weights = softmax(attention_scores, axis=-1) # 这样softmax的权重在本来是0的地方得到的数值是0
- output = np.matmul(attention_weights, V) #一致了
- return output, attention_weights
- global_q = {}
- global_k = {}
- global_v = {}
- def mask_multihead_attention(i,input, num_heads,W_Q,B_Q,W_K,B_K,W_V,B_V,W_O,B_O):
- global global_q,global_k,global_v
- q = np.matmul(input, W_Q)+B_Q
- k = np.matmul(input, W_K)+B_K
- v = np.matmul(input, W_V)+B_V
- if q.shape[-2] == 1:
- k = global_k[i] = np.concatenate([global_k[i],k],axis=-2)
- v = global_v[i] = np.concatenate([global_v[i],v],axis=-2)
- else:
- global_q[i] = q
- global_k[i] = k
- global_v[i] = v
- _,n,_ = k.shape
- # 分割输入为多个头
- q = np.split(q, num_heads, axis=-1)
- k = np.split(k, num_heads, axis=-1)
- v = np.split(v, num_heads, axis=-1) #到这里都是一致的
- outputs = []
- if q[0].shape[-2] != 1:
- mask = np.tril(np.ones((n, n))) #下三角矩阵
- for q_,k_,v_ in zip(q,k,v):
- output, attention_weights = scaled_dot_product_attention(q_, k_, v_,mask) #一致
- outputs.append(output)
- else:
- for q_,k_,v_ in zip(q,k,v):
- output, attention_weights = scaled_dot_product_attention2(q_, k_, v_) #一致
- outputs.append(output)
- outputs = np.concatenate(outputs, axis=-1)
- outputs = np.matmul(outputs, W_O)+B_O
- return outputs #一致
- def layer_normalization(x, weight, bias, eps=1e-12):
- mean = np.mean(x, axis=-1, keepdims=True)
- variance = np.var(x, axis=-1, keepdims=True)
- std = np.sqrt(variance + eps)
- normalized_x = (x - mean) / std
- output = weight * normalized_x + bias
- return output
- def feed_forward_layer(inputs, weight, bias=None, activation='relu'):
- if bias is not None:
- linear_output = np.matmul(inputs,weight) + bias
- else:
- linear_output = np.matmul(inputs,weight)
- if activation == 'relu':
- activated_output = np.maximum(0, linear_output) # ReLU激活函数
- elif activation == 'gelu':
- activated_output = 0.5 * linear_output * (1 + np.tanh(np.sqrt(2 / np.pi) * (linear_output + 0.044715 * np.power(linear_output, 3)))) # GELU激活函数
- elif activation == "tanh" :
- activated_output = np.tanh(linear_output)
- else:
- activated_output = linear_output # 无激活函数
- return activated_output
- def residual_connection(inputs, residual):
- # 残差连接
- residual_output = inputs + residual
- return residual_output
- with open('vocab.txt', 'r', encoding='utf-8') as f:
- vocab = f.readlines()
- vocab = [i.strip() for i in vocab]
- # print(len(vocab))
- def tokenize_sentence(sentence):
- tokenized_sentence = list(sentence) # 在句子开头添加[cls]
- token_ids = [vocab.index(token) for token in tokenized_sentence]
- return token_ids
- # 加载保存的模型数据
- model_data = np.load('gpt2_model_params.npz')
- # for i in model_data:
- # # print(i)
- # print(i,model_data[i].shape)
- def get_sentence_ids(sentence):
- token_ids = tokenize_sentence(sentence)
- input_ids = np.array(token_ids) # 输入的词汇id
- return input_ids
- word_embeddings = model_data["transformer.wte.weight"]
- position_embeddings = model_data["transformer.wpe.weight"]
- def model_input(input_ids,position_ids):
- word_embedded = word_embedding(input_ids, word_embeddings)
- position_ids = np.array(position_ids) # 位置id
- # 位置嵌入矩阵,形状为 (max_position, embedding_size)
- position_embedded = position_embedding(position_ids, position_embeddings)
- embedding_output = np.expand_dims(word_embedded + position_embedded, axis=0)
- return embedding_output
- def gpt2(input,num_heads):
- for i in range(12):
- LayerNorm1_weight = model_data['transformer.h.{}.ln_1.weight'.format(i)]
- LayerNorm1_bias = model_data['transformer.h.{}.ln_1.bias'.format(i)]
- # 调用多头自注意力函数
- W_QKV = model_data['transformer.h.{}.attn.c_attn.weight'.format(i)]
- B_QKV = model_data['transformer.h.{}.attn.c_attn.bias'.format(i)]
- W_O = model_data['transformer.h.{}.attn.c_proj.weight'.format(i)]
- B_O = model_data['transformer.h.{}.attn.c_proj.bias'.format(i)]
- LayerNorm2_weight = model_data['transformer.h.{}.ln_2.weight'.format(i)]
- LayerNorm2_bias = model_data['transformer.h.{}.ln_2.bias'.format(i)]
- intermediate_weight = model_data['transformer.h.{}.mlp.c_fc.weight'.format(i)]
- intermediate_bias = model_data['transformer.h.{}.mlp.c_fc.bias'.format(i)]
- dense_weight = model_data['transformer.h.{}.mlp.c_proj.weight'.format(i)]
- dense_bias = model_data['transformer.h.{}.mlp.c_proj.bias'.format(i)]
- input1 = layer_normalization(input,LayerNorm1_weight,LayerNorm1_bias) #这里和模型输出一致
- W_Q,W_K,W_V = np.split(W_QKV, 3, axis=-1)
- B_Q,B_K,B_V = np.split(B_QKV, 3, axis=-1)
- output = mask_multihead_attention(i,input1, num_heads,W_Q,B_Q,W_K,B_K,W_V,B_V,W_O,B_O) #一致
- output1 = residual_connection(input,output) #一致
- output = layer_normalization(output1,LayerNorm2_weight,LayerNorm2_bias) #一致
- output = feed_forward_layer(output, intermediate_weight, intermediate_bias, activation='gelu')
- output = feed_forward_layer(output, dense_weight, dense_bias, activation='') #一致
- output2 = residual_connection(output1,output)
- input = output2
- ln_f_weight = model_data['transformer.ln_f.weight']
- ln_f_bias = model_data['transformer.ln_f.bias']
- output = layer_normalization(output2,ln_f_weight,ln_f_bias)
- return output
- classifier_weight = model_data['lm_head.weight']
- def predict(sentence="今天是个好日子",accelerater=True,gen_len=100):
- start = time.time()
- sentence_ids = get_sentence_ids(sentence)
- position_ids = range(len(sentence_ids))
- print("prompt输入:",sentence)
- for i in range(gen_len):
- embeddings = model_input(sentence_ids,position_ids)
- output = gpt2(embeddings,num_heads=12)
- # print(output)
- output = feed_forward_layer(output[:,-1], classifier_weight.T, activation='')
- samples = top_k_sampling(output[0],k=1)
- label_id = random_sampling(samples,k=1)
- print(vocab[label_id[0]],end="")
- if accelerater: #是否使用加速推理减少计算量
- sentence_ids = label_id #每次使用上一步的q,和全量的key和v做计算,比使用所有历史时间部的q计算量小很多,所以可以加速
- position_ids = [position_ids[-1]+1]
- else:
- sentence_ids = np.concatenate([sentence_ids,label_id],axis=-1) #慢推理,每次都需要从头计算,计算量会越来越大
- position_ids = range(len(sentence_ids))
- end = time.time()
- print("\nspend time:",end-start)
- if __name__ == "__main__":
- accelerater = False
- sentence = "今天是个好日子" #我们要做的就是把握住这个机会
- predict(sentence,accelerater)
- # embeddings = model_input(sentence_ids)
- # output = gpt2(embeddings,num_heads=12)
- # # print(output)
- # output = feed_forward_layer(output[:,:], classifier_weight.T, activation='')
- # samples = np.argmax(output,axis=-1)
- # for i in samples[0]:
- # print(vocab[i],end="")
结果:同样的结果,序列长度越长,时间上的差异越明显,这才生成100tokens,就已经明显看出速度的差异了
- 使用加速:
- prompt输入: 今天是个好日子
- ,我们要做的就是把握住这个机会,把握住这个机会,把握住了,我相信我们的投资将会创造奇迹,而且我相信我们的投资团队一定能够创造奇迹,我相信我们的投资团队一定能够创造奇迹,我相信我们的投资团队一定能够创造
- spend time: 22.19951105117798
- 不使用加速:
- prompt输入: 今天是个好日子
- ,我们要做的就是把握住这个机会,把握住这个机会,把握住了,我相信我们的投资将会创造奇迹,而且我相信我们的投资团队一定能够创造奇迹,我相信我们的投资团队一定能够创造奇迹,我相信我们的投资团队一定能够创造
- spend time: 42.4955039024353
模型参数:
- transformer.wte.weight (21128, 768)
- transformer.wpe.weight (1024, 768)
- transformer.h.0.ln_1.weight (768,)
- transformer.h.0.ln_1.bias (768,)
- transformer.h.0.attn.c_attn.weight (768, 2304)
- transformer.h.0.attn.c_attn.bias (2304,)
- transformer.h.0.attn.c_proj.weight (768, 768)
- transformer.h.0.attn.c_proj.bias (768,)
- transformer.h.0.ln_2.weight (768,)
- transformer.h.0.ln_2.bias (768,)
- transformer.h.0.mlp.c_fc.weight (768, 3072)
- transformer.h.0.mlp.c_fc.bias (3072,)
- transformer.h.0.mlp.c_proj.weight (3072, 768)
- transformer.h.0.mlp.c_proj.bias (768,)
- transformer.h.1.ln_1.weight (768,)
- transformer.h.1.ln_1.bias (768,)
- transformer.h.1.attn.c_attn.weight (768, 2304)
- transformer.h.1.attn.c_attn.bias (2304,)
- transformer.h.1.attn.c_proj.weight (768, 768)
- transformer.h.1.attn.c_proj.bias (768,)
- transformer.h.1.ln_2.weight (768,)
- transformer.h.1.ln_2.bias (768,)
- transformer.h.1.mlp.c_fc.weight (768, 3072)
- transformer.h.1.mlp.c_fc.bias (3072,)
- transformer.h.1.mlp.c_proj.weight (3072, 768)
- transformer.h.1.mlp.c_proj.bias (768,)
- transformer.h.2.ln_1.weight (768,)
- transformer.h.2.ln_1.bias (768,)
- transformer.h.2.attn.c_attn.weight (768, 2304)
- transformer.h.2.attn.c_attn.bias (2304,)
- transformer.h.2.attn.c_proj.weight (768, 768)
- transformer.h.2.attn.c_proj.bias (768,)
- transformer.h.2.ln_2.weight (768,)
- transformer.h.2.ln_2.bias (768,)
- transformer.h.2.mlp.c_fc.weight (768, 3072)
- transformer.h.2.mlp.c_fc.bias (3072,)
- transformer.h.2.mlp.c_proj.weight (3072, 768)
- transformer.h.2.mlp.c_proj.bias (768,)
- transformer.h.3.ln_1.weight (768,)
- transformer.h.3.ln_1.bias (768,)
- transformer.h.3.attn.c_attn.weight (768, 2304)
- transformer.h.3.attn.c_attn.bias (2304,)
- transformer.h.3.attn.c_proj.weight (768, 768)
- transformer.h.3.attn.c_proj.bias (768,)
- transformer.h.3.ln_2.weight (768,)
- transformer.h.3.ln_2.bias (768,)
- transformer.h.3.mlp.c_fc.weight (768, 3072)
- transformer.h.3.mlp.c_fc.bias (3072,)
- transformer.h.3.mlp.c_proj.weight (3072, 768)
- transformer.h.3.mlp.c_proj.bias (768,)
- transformer.h.4.ln_1.weight (768,)
- transformer.h.4.ln_1.bias (768,)
- transformer.h.4.attn.c_attn.weight (768, 2304)
- transformer.h.4.attn.c_attn.bias (2304,)
- transformer.h.4.attn.c_proj.weight (768, 768)
- transformer.h.4.attn.c_proj.bias (768,)
- transformer.h.4.ln_2.weight (768,)
- transformer.h.4.ln_2.bias (768,)
- transformer.h.4.mlp.c_fc.weight (768, 3072)
- transformer.h.4.mlp.c_fc.bias (3072,)
- transformer.h.4.mlp.c_proj.weight (3072, 768)
- transformer.h.4.mlp.c_proj.bias (768,)
- transformer.h.5.ln_1.weight (768,)
- transformer.h.5.ln_1.bias (768,)
- transformer.h.5.attn.c_attn.weight (768, 2304)
- transformer.h.5.attn.c_attn.bias (2304,)
- transformer.h.5.attn.c_proj.weight (768, 768)
- transformer.h.5.attn.c_proj.bias (768,)
- transformer.h.5.ln_2.weight (768,)
- transformer.h.5.ln_2.bias (768,)
- transformer.h.5.mlp.c_fc.weight (768, 3072)
- transformer.h.5.mlp.c_fc.bias (3072,)
- transformer.h.5.mlp.c_proj.weight (3072, 768)
- transformer.h.5.mlp.c_proj.bias (768,)
- transformer.h.6.ln_1.weight (768,)
- transformer.h.6.ln_1.bias (768,)
- transformer.h.6.attn.c_attn.weight (768, 2304)
- transformer.h.6.attn.c_attn.bias (2304,)
- transformer.h.6.attn.c_proj.weight (768, 768)
- transformer.h.6.attn.c_proj.bias (768,)
- transformer.h.6.ln_2.weight (768,)
- transformer.h.6.ln_2.bias (768,)
- transformer.h.6.mlp.c_fc.weight (768, 3072)
- transformer.h.6.mlp.c_fc.bias (3072,)
- transformer.h.6.mlp.c_proj.weight (3072, 768)
- transformer.h.6.mlp.c_proj.bias (768,)
- transformer.h.7.ln_1.weight (768,)
- transformer.h.7.ln_1.bias (768,)
- transformer.h.7.attn.c_attn.weight (768, 2304)
- transformer.h.7.attn.c_attn.bias (2304,)
- transformer.h.7.attn.c_proj.weight (768, 768)
- transformer.h.7.attn.c_proj.bias (768,)
- transformer.h.7.ln_2.weight (768,)
- transformer.h.7.ln_2.bias (768,)
- transformer.h.7.mlp.c_fc.weight (768, 3072)
- transformer.h.7.mlp.c_fc.bias (3072,)
- transformer.h.7.mlp.c_proj.weight (3072, 768)
- transformer.h.7.mlp.c_proj.bias (768,)
- transformer.h.8.ln_1.weight (768,)
- transformer.h.8.ln_1.bias (768,)
- transformer.h.8.attn.c_attn.weight (768, 2304)
- transformer.h.8.attn.c_attn.bias (2304,)
- transformer.h.8.attn.c_proj.weight (768, 768)
- transformer.h.8.attn.c_proj.bias (768,)
- transformer.h.8.ln_2.weight (768,)
- transformer.h.8.ln_2.bias (768,)
- transformer.h.8.mlp.c_fc.weight (768, 3072)
- transformer.h.8.mlp.c_fc.bias (3072,)
- transformer.h.8.mlp.c_proj.weight (3072, 768)
- transformer.h.8.mlp.c_proj.bias (768,)
- transformer.h.9.ln_1.weight (768,)
- transformer.h.9.ln_1.bias (768,)
- transformer.h.9.attn.c_attn.weight (768, 2304)
- transformer.h.9.attn.c_attn.bias (2304,)
- transformer.h.9.attn.c_proj.weight (768, 768)
- transformer.h.9.attn.c_proj.bias (768,)
- transformer.h.9.ln_2.weight (768,)
- transformer.h.9.ln_2.bias (768,)
- transformer.h.9.mlp.c_fc.weight (768, 3072)
- transformer.h.9.mlp.c_fc.bias (3072,)
- transformer.h.9.mlp.c_proj.weight (3072, 768)
- transformer.h.9.mlp.c_proj.bias (768,)
- transformer.h.10.ln_1.weight (768,)
- transformer.h.10.ln_1.bias (768,)
- transformer.h.10.attn.c_attn.weight (768, 2304)
- transformer.h.10.attn.c_attn.bias (2304,)
- transformer.h.10.attn.c_proj.weight (768, 768)
- transformer.h.10.attn.c_proj.bias (768,)
- transformer.h.10.ln_2.weight (768,)
- transformer.h.10.ln_2.bias (768,)
- transformer.h.10.mlp.c_fc.weight (768, 3072)
- transformer.h.10.mlp.c_fc.bias (3072,)
- transformer.h.10.mlp.c_proj.weight (3072, 768)
- transformer.h.10.mlp.c_proj.bias (768,)
- transformer.h.11.ln_1.weight (768,)
- transformer.h.11.ln_1.bias (768,)
- transformer.h.11.attn.c_attn.weight (768, 2304)
- transformer.h.11.attn.c_attn.bias (2304,)
- transformer.h.11.attn.c_proj.weight (768, 768)
- transformer.h.11.attn.c_proj.bias (768,)
- transformer.h.11.ln_2.weight (768,)
- transformer.h.11.ln_2.bias (768,)
- transformer.h.11.mlp.c_fc.weight (768, 3072)
- transformer.h.11.mlp.c_fc.bias (3072,)
- transformer.h.11.mlp.c_proj.weight (3072, 768)
- transformer.h.11.mlp.c_proj.bias (768,)
- transformer.ln_f.weight (768,)
- transformer.ln_f.bias (768,)
- lm_head.weight (21128, 768)
原始的hunggingface模型,保存模型参数为numpy,然后上面的numpy版的gpt-2就可以加载了
- import numpy as np
- from transformers import BertTokenizer, GPT2LMHeadModel, TextGenerationPipeline
- tokenizer = BertTokenizer.from_pretrained("uer/gpt2-chinese-cluecorpussmall")
- model = GPT2LMHeadModel.from_pretrained("uer/gpt2-chinese-cluecorpussmall")
- text_generator = TextGenerationPipeline(model, tokenizer)
- print(text_generator("今天是个好日子", max_length=20, do_sample=True))
- print(model)
- # 打印BERT模型的权重维度
- # for name, param in model.named_parameters():
- # print(name, param.data.shape)
- # print(model.lm_head.weight)
- # print(model.lm_head.bias)
- # # # 保存模型参数为NumPy格式
- model_params = {name: param.data.cpu().numpy() for name, param in model.named_parameters()}
- model_params["lm_head.weight"] = model.lm_head.weight.data.cpu().numpy()
- np.savez('gpt2_model_params.npz', **model_params)
- # model_params
我用numpy实现了GPT-2,GPT-2源码,GPT-2模型加速推理,并且可以在树莓派上运行,读了不少hungging face源码,手动实现了numpy的GPT2模型的更多相关文章
- 手把手教你玩转SOCKET模型之重叠I/O篇(上)
“身为一个初学者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人.我也希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,因为最应该被鄙视的是不肯付 ...
- 有关python numpy pandas scipy 等 能在YARN集群上 运行PySpark
有关这个问题,似乎这个在某些时候,用python写好,且spark没有响应的算法支持, 能否能在YARN集群上 运行PySpark方式, 将python分析程序提交上去? Spark Applicat ...
- ZBrush中如何把模型的细节映射到低模上
我们在ZBrush®雕刻模型的时候,发现模型布线不利于雕刻,这使我们不得不对模型进行重建细分,而重建细分之后的模型细节已经没有了,这个时候我们就需要把原来高模的细节映射到新的模型上面. 接下来我们介绍 ...
- StartDT AI Lab | 视觉智能引擎之算法模型加速
通过StartDT AI Lab专栏之前多篇文章叙述,相信大家已经对计算机视觉技术及人工智能算法在奇点云AIOT战略中的支撑作用有了很好的理解.同样,这种业务牵引,技术覆盖的模式也收获了市场的良好反响 ...
- 【实战】yolov8 tensorrt模型加速部署
[实战]yolov8 tensorrt模型加速部署 TensorRT-Alpha基于tensorrt+cuda c++实现模型end2end的gpu加速,支持win10.linux,在2023年已经更 ...
- Windows10下yolov8 tensorrt模型加速部署【实战】
Windows10下yolov8 tensorrt模型加速部署[实战] TensorRT-Alpha基于tensorrt+cuda c++实现模型end2end的gpu加速,支持win10.linux ...
- Win10下yolov8 tensorrt模型加速部署【实战】
Win10下yolov8 tensorrt模型加速部署[实战] TensorRT-Alpha基于tensorrt+cuda c++实现模型end2end的gpu加速,支持win10.linux,在20 ...
- 模型加速[tensorflow&tensorrt]
在tensorflow1.8之后的版本中,tensorflow.contrib部分都有tensorrt的组件,该组件存在的意义在于,你可以读取pb文件,并调用tensorrt的方法进行subgraph ...
- {python之IO多路复用} IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) IO模型比较分析 selectors模块
python之IO多路复用 阅读目录 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 ...
- 理解盒模型——外边距、内边距和边框之间的关系,IE 8以下版本的浏览器中的盒模型有什么不同。
一个元素盒模型的层次从内到外分别为:内边距.边框和外边距IE8以下浏览器的盒模型中定义的元素的宽高不包括内边距和边框
随机推荐
- 【D01】Django中实现带进度条的倒计时功能(简易版)
首先说明简易版是只有一个 倒计时 和一个 进度条,页面加载后自动开始计时,下次计时需要手动刷新页面. 后续会更新实现完整的倒计时功能的文章 前期准备 前端框架 你需要准备一些前端框架:Bootstra ...
- PHP开发者交流群
PHP开发者交流群 欢迎大家加入学习讨论 QQ群(493834732)
- Proxy 与 Object.defineProperty 优劣对比?
Proxy的优势如下 1.Proxy 可以直接监听对象而不是属性(Object.defineProperty一次只能监视一个属性,如果要监视一个对象,那么需要遍历这个对象),可以直接监听数组的变化(O ...
- 深度学习入门系列之doc
这周老师让把深度学习的名词过一遍,小玛同学准备在过一遍Deep Learning名词的同时把基本的模型也过一遍. 感谢杰哥发我深度学习入门系列能让我有机会快速入门. 下面就来doc一些学到的东西 线性 ...
- C语言跳转浏览器打开指定URL
#include <stdlib.h> int main() { // 定义要打开的URL char* url = "https://rjku.gitee.io/"; ...
- 深度相机(TOF)的工作原理
文章目录 深度相机(TOF)的工作原理 TOF由什么组成? 一.TOF相机采用主动光探测,通常包括以下几个部分: 二.TOF是如何测距的呢? 三.TOF会受什么影响? 四.那TOF相机最后输出的是什么 ...
- 刺激!ChatGPT给我虚构了一本书?
ChatGPT很强大,可以帮我们处理很多问题,但这些问题的答案的正确性您是否有考证过呢? 昨晚,DD就收到了一个有趣的反馈: 提问:有什么关于数据权限设计的资料推荐吗? ChatGPT居然介绍了一本根 ...
- 如何实现一个sync.Once
sync.Once 是 golang里用来实现单例的同步原语.Once 常常用来初始化单例资源, 或者并发访问只需初始化一次的共享资源,或者在测试的时候初始化一次测试资源. 单例,就是某个资源或者对象 ...
- Java8 Stream流的合并
最近的需求里有这样一个场景,要校验一个集合中每个对象的多个Id的有效性.比如一个Customer对象,有3个Id:id1,id2,id3,要把这些Id全部取出来,然后去数据库里查询它是否存在. @Da ...
- PCI-5565系列反射内存卡 反射内存交换机
主要性能:1路发射,一路接收光纤高速网络2.125GHz.最大256个节点.在板128MByte SDRAM.光纤通讯协议不占用CPU资源.动态包长,每个包4 到 64 个字节.33MHz PCI 3 ...