kit7828

  • 2025-02-26
  • 回复了主题帖: 调查:有兴趣自选硬件DIY LCR表吗?想且能做来冒泡吧~

    非常感兴趣,自己设计制作更好,只是希望时间长度拉长点,时间短了来不及,毕竟还有其他工作要忙。

  • 2025-02-12
  • 回复了主题帖: 机器人开发话题征集:写啥你来定!

    四足机器狗开源能有吗?

  • 2025-02-08
  • 回复了主题帖: 【博流BL606P音视频开发板】搭建环境与智能语音案例测试

    我当初遇到的是无法烧录,后面联系了技术支持,用了一些其他工具,有兴趣可以试一试 https://bbs.eeworld.com.cn/thread-1231137-1-1.html

  • 2025-01-20
  • 回复了主题帖: 找到了一个支持 micropython 仿真的 proteus

    proteus还支持micropython?开眼界了

  • 2025-01-10
  • 回复了主题帖: 【回顾2024,展望2025】新年抢楼活动来啦!

    最想关注的技术 :端侧AI,嵌入式AI,边缘AI

  • 2025-01-04
  • 回复了主题帖: 《大语言模型开发:用开源模型开发本地系统》分享3:理解Transformer:构建LLM核心

    ljg2np 发表于 2025-1-2 11:18 Pytorch的nn.transformer模块和HuggingFace的transformers库,貌似都可以考虑。 paddlepaddle也有transformer模块,都是开源的

  • 回复了主题帖: 《大语言模型开发:用开源模型开发本地系统》分享3:理解Transformer:构建LLM核心

    Jacktang 发表于 2025-1-2 07:23 Pytorch的nn.transformer模块提供了构建Transformer模型的工具,训练模型就容易多了 paddlepaddle也有transformer模块

  • 2025-01-01
  • 发表了主题帖: 《大语言模型开发:用开源模型开发本地系统》分享3:理解Transformer:构建LLM核心

    在人工智能的快速发展中,Transformer模型以其卓越的性能在自然语言处理领域占据了核心地位。本次分享,将深入探讨《大语言模型开发:用开源模型开发本地系统》中关于Transformer模型的详解,以便通俗易懂地理解这一模型的构成和工作机制。 第一部分:大语言模型的简介和分类 1. 简介 大语言模型是人工智能领域的一个重要分支,它们通过深度学习和大量的数据训练,能够理解和生成自然语言。这些模型在机器翻译、文本摘要、问答系统等多个领域都有广泛的应用。 2. 分类 大语言模型可以根据不同的架构和训练方式进行分类。了解这些分类有助于我们选择合适的模型来解决特定的问题。   第二部分:Transformer模型详解 1. 模型构成 Transformer模型由编码器和解码器组成,它们通过自注意力机制来处理序列数据。这种结构使得模型能够捕捉到序列中的长距离依赖关系。    2. 因果解码器结构 因果解码器是Transformer模型中的一个重要特性,它确保了在生成序列时,每一步只依赖于之前的位置,这对于生成连贯的文本至关重要。  Transformer的主要组成部分有以下几个。 (1)自注意力机制:这是Transformer的核心组成部分,也是其能够处理序列数据的关键。自注意力机制能够计算序列中每个元素与其他元素之间的关系,并基于这些关系来更新元素的表示。这使 Transformer 能够捕捉到序列中长距离的依赖关系。 (2)多头自注意力(Multi-Head Attention):Transformer 并不只计算一次自注意力,而是同时计算多次,每次使用不同的参数,然后将这些结果合并起来。这使Transformer 能够捕捉到数据的多个不同方面的信息。 (3)位置编码(Positional Encoding):由于Transformer 并没有使用RNN或CNN,所以它无法直接处理序列的顺序信息。为了解决这个问题,Transformer 引人位置编码,通过给每个元素添加一个位置相关的向量,来向模型提供序列中元素的位置信息。 (4)前馈神经网络:除了自注意力机制,Transformer 的每一层还包括一个前馈神经网络。这个网络在每个位置上都是独立运行的,它能够增强模型的复杂性,而不会增强处理序列的复杂性。 (5)归一化层:Transformer 在每个子层(自注意力和前馈神经网络)的输出后都添加了一个归一化层,以防止模型的训练发散。 (6)残差连接:Transformer 在每个子层的输人和输出之间都添加了一个残差连接。这可以帮助模型更容易地学习深层网络。   第三部分:分词 1. 词汇表 词汇表是模型理解语言的基础,它包含了模型能够识别的所有单词或符号。 2. 分词算法 分词算法将文本分割成词汇表中的单元,这是模型处理文本的第一步。 以下是一些常见的分词算法。 (1)空格分词:这是最简单的分词方法,只需按空格将文本分割成单词。这种方法在处理英语等大部分西方语言时效果不错,但对于没有明确单词边界的语言(如中文)或者复合词丰富的语言(如德语 ),效果就不理想了。 (2)基于词典的分词:这种方法需要一个预先定义好的词典,然后根据词典将文本分割成单词。这种方法可以处理一些复杂的情况,但依赖于词典的质量,而且不能很好地处理词典中不存在的单词。 (3)基于统计的分词:这种方法使用机器学习算法从大量的文本数据中学习单词的边 界。常见的基于统计的分词算法包括 HMM、CRF 等。 (4)子词分词:这种方法将单词进一步分割为子词。这样可以处理词典中不存在的单词,因为即使一个单词在词典中不存在,其组成的子词也可能存在。常见的子词分词算法包括字节对编码、句子片段(SentencePiece)等。 3. 字节对编码 字节对编码(Byte Pair Encoding, BPE)是一种有效的分词方法,它通过合并频繁出现的字节对来构建词汇表。 BPE的操作步骤如下。 (1)初始化词汇表:开始时,词汇表中的每个符号都是语料库中的一个字符。 (2)统计符号对频率:在语料库中统计每对连续符号的出现频率。 (3)合并频率最高的符号对:将频率最高的符号对合并为一个新的符号,加到同表中。 (4)重复步骤(2)和(3):重复上述步骤,直到达到预定的词汇表大小或者没有可以合并的符号对。 4. 句子片段 句子片段是另一种分词方法,它将句子分割成更小的片段,以提高模型的处理效率。 5. 分词过程 分词过程是将文本转换为模型可以理解的格式,这是模型训练和推理的前提。 6. 词汇索引 词汇索引是将词汇表中的单词映射到唯一的索引,这些索引将用于模型的输入。     第四部分:词嵌入 1. 标词嵌入 词嵌入是将词汇索引转换为高维空间中的向量,这些向量能够捕捉单词的语义信息。 2. 位置编码 位置编码是为词嵌入向量添加位置信息,使得模型能够理解单词在序列中的顺序。 3. 词汇索引和词嵌入向量 词汇索引和词嵌入向量的结合,为模型提供了丰富的语义和位置信息。     第五部分:位置编码方法 1. 原生位置编码 原生位置编码是Transformer模型中的一种位置编码方式,它通过正弦和余弦函数来实现。 2. 旋转位置编码 旋转位置编码是另一种位置编码方法,它通过旋转矩阵来实现。   3. Llama位置编码 Llama位置编码是一种新型的位置编码方式,它在某些任务中表现出更好的性能。   import torch def precompute_freqs cis(dim,seqlen,theta =10000.0): fregs =1.0/(theta **(torch.arange(0,dim,2)[:(dim // 2)].float()/ dim)) t=torch.arange(seqlen) #顺序位置,0~ seqlen - 1 freqs =torch,outer(t,fregs).float() return freqs embedding_dim=8 sequence_length=5 #标记嵌入,全为1 token_embedding=torch.ones((sequence_length, embedding_dim)) freqs =precompute_freqs_cis(embedding_dim, sequence_length) #标准位置编码 pe = torch.zeros(sequence_length,embedding_dim) pe[:,0::2]= torch.sin(fregs) pe[:,1::2]= torch.cos(fregs) #标记嵌入 + 位置嵌入 pe_out=token_embedding + pe Print(pe_out) #旋转位置编码 freqs_cis =torch.polar(torch.ones_like(freqs),fregs) token_embedding cis torch.view_as_complex(token_embedding.reshape(sequence_length, -1,2)) rope_out =torch.view_as_real(token_embedding cis * fregs cis) .flatten(1) print(rope_out)   第六部分:自注意力机制 1. 原理 自注意力机制是Transformer模型的核心,它允许模型在处理序列时同时关注序列的不同部分。 2. 注意力分数的计算 注意力分数的计算是自注意力机制的关键,它决定了模型在不同位置的关注度。   3. 多头注意力机制 多头注意力机制通过多个注意力头来捕捉不同子空间的信息。 4. 分组查询注意力 分组查询注意力是一种优化的自注意力机制,它通过分组来减少计算量。 5. Llama 2源代码分析 通过分析Llama 2的源代码,我们可以更深入地理解自注意力机制的实现细节。   import torch import torch.nn as nn import torch.nn.functional as F from typing import Optional # 对输入的张量进行重复操作,以满足多头注意力机制中多次使用同一个键-值对的需要 def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor: """torch.repeat interleave(x, dim=2, repeats=n_rep)""" bs, slen, n_kv_heads, head_dim = x.shape if n_rep == 1: return x return ( x[:, :, :, None, :] .expand(bs, slen, n_kv_heads, n_rep, head_dim) .reshape(bs, slen, n_kv_heads * n_rep, head_dim) ) class Attention(nn.Module): def __init__(self, args: 'ModelArgs'): super().__init__() self.n_kv_heads = args.n_heads if args.n_kv_heads is None else args.n_kv_heads model_parallel_size = args.init_get_model_parallel_world_size() self.n_local_heads = args.n_heads // model_parallel_size self.n_local_kv_heads = self.n_kv_heads // model_parallel_size self.n_rep = self.n_local_heads // self.n_local_kv_heads self.head_dim = args.dim // args.n_heads # 构造注意力查询(Q)、键(K)和值(V)所需要的线性变换算子 # 这堂查蘀角一个交换算子文持了多头的场景,因为每个头实际上计算方式是完全一样的,只是参数不同 self.wq = ColumnParallelLinear( args.dim, args.n_heads * self.head_dim, bias=False, gather_output=False, init_method=lambda x: x ) self.wk = ColumnParallelLinear( args.dim, self.n_kv_heads * self.head_dim, bias=False, gather_output=False, init_method=lambda x: x ) self.wv = ColumnParallelLinear( args.dim, self.n_kv_heads * self.head_dim, bias=False, gather_output=False, init_method=lambda x: x ) # 构造对最终输出进行线性变换的算子 self.wo = RowParallelLinear( args.n_heads * self.head_dim, args.dim, bias=False, input_is_parallel=True, init_method=lambda x: x ) self.cache_k = torch.zeros( args.max_batch_size, args.max_seq_len, self.n_local_kv_heads, self.head_dim ).cuda() self.cache_v = torch.zeros( args.max_batch_size, args.max_seq_len, self.n_local_kv_heads, self.head_dim, ).cuda() def forward( self, x: torch.Tensor, start_pos: int, freqs_cis: torch.Tensor, mask: Optional[torch.Tensor] ): bsz, seq_len = x.shape[:2] # 对输入序列进行线性变换,分别得到查询(Q)、键(K)和值(V) xq, xk, xv = self.wq(x), self.wk(x), self.wv(x) xq = xq.view(bsz, seq_len, self.n_local_heads, self.head_dim) xk = xk.view(bsz, seq_len, self.n_local_kv_heads, self.head_dim) xv = xv.view(bsz, seq_len, self.n_local_kv_heads, self.head_dim) # 对查询和键应用旋转嵌入(Rotary Embedding)操作 # 旋转嵌入是一种在注意力机制中引入周期性信息的技术,有助于模型捕捉序列的顺序关系 xq, xk = apply_rotary_emb(xq, xk, freqs_cis) # 更新缓存中的键(K)和值(V),将当前位置的键和值存储在缓存中以供后续的注意力计算使用 self.cache_k = self.cache_k.to(xq.device) self.cache_v = self.cache_v.to(xq.device) self.cache_k[:, start_pos:start_pos + seq_len] = xk self.cache_v[:, start_pos:start_pos + seq_len] = xv # 从缓存中获取用于注意力计算的键(K)和值(V),包括当前位置之前的所有位置 keys = self.cache_k[:, :start_pos + seq_len] values = self.cache_v[:, :start_pos + seq_len] # repeat k/v heads if n_kv_heads < n_heads keys = repeat_kv(keys, self.n_rep) values = repeat_kv(values, self.n_rep) # 对查询、键和值进行维度转置,以便进行矩阵乘法操作 xq = xq.transpose(1, 2) # (bs, n_local_heads, seq_len, head_dim) keys = keys.transpose(1, 2) # (bs, n_local_heads, seq_len, head_dim) values = values.transpose(1, 2) # (bs, n_local_heads, seq_len, head_dim) # 计算查询和键之间的相似度得分,通过矩阵乘法计算得到,同时除以头的维度的平方根来进行缩放,以控制相似度的范围 scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim) if mask is not None: # 如果存在掩码(mask),则将其加到相似度得分上,以屏蔽无效位置的影响 scores = scores + mask # (bs, n_local_heads, seq_len, cache_len + seq_len) # 对相似度得分进行softmax操作,将其转换为注意力权重,使得权重在每个位置的分布总和为1 scores = F.softmax(scores.float(), dim=-1).type_as(xq) # 根据注意力权重对值进行加权求和,得到最终的注意力输出 output = torch.matmul(scores, values) # (bs, n_local_heads, seq_len, head_dim) output = output.transpose(1, 2).contiguous().view(bsz, seq_len, -1) # 对注意力输出进行线性变换,得到最终的注意力机制的输出 return self.wo(output)   第七部分:残差连接和层归一化 1. 预归一化 预归一化是在应用激活函数之前进行归一化,这有助于模型的训练。   2. RMSNorm RMSNorm是一种归一化方法,它通过除以均方根来实现。 3. Llama 2源代码分析 通过分析Llama 2的源代码,我们可以了解残差连接和层归一化在实际模型中的应用。 import torch import torch.nn as nn from typing import Optional class TransformerBlock(nn.Module): def __init__(self, layer_id: int, args: 'ModelArgs'): super().__init__() self.n_heads = args.n_heads self.head_dim = args.dim // args.n_heads self.attention = Attention(args) self.feed_forward = FeedForward(dim=args.dim, hidden_dim=4 * args.dim, ffn_dim_multiplier=args.ffn_dim_multiplier) self.layer_id = layer_id self.attention_norm = RMSNorm(args.dim, eps=args.norm_eps) self.ffn_norm = RMSNorm(args.dim, eps=args.norm_eps) def forward(self, x: torch.Tensor, start_pos: int, freqs_cis: torch.Tensor, mask: Optional[torch.Tensor] = None): h = x + self.attention.forward(self.attention_norm(x), start_pos, freqs_cis, mask) out = h + self.feed_forward.forward(self.ffn_norm(h)) return out Llama 中实现 RMSNorm 的源代码为 import torch import torch.nn as nn class RMSNorm(nn.Module): def __init__(self, dim: int, eps: float = 1e-6): super().__init__() self.eps = eps # dim参数表示输入张量的维度,即要在哪个维度上计算均方根并进行归一化。 # weight是一个可学习的权重参数,用于缩放标准化后的输入。 self.weight = nn.Parameter(torch.ones(dim)) def norm(self, x): # 计算输入张量的均方根,并将每个元素除以均方根值。 return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) def forward(self, x): # 调用norm方法对输入张量进行标准化处理,并将标准化后的结果与权重参数相乘,以进一步缩放和调整输出。 output = self.norm(x.float()).type_as(x) return output * self.weight   第八部分:前馈网络 1. 激活函数 激活函数为前馈网络提供了非线性能力,使得模型能够学习复杂的模式。 2. 前馈网络隐藏层维度 前馈网络隐藏层的维度决定了模型的表达能力。   3. Llama 2源代码分析 通过分析Llama 2的源代码,我们可以了解前馈网络在Transformer模型中的实现。 import torch import torch.nn as nn from typing import Optional class FeedForward(nn.Module): def __init__(self, dim: int, hidden_dim: int, multiple_of: int, ffn_dim_multiplier: Optional[float]): super().__init__() hidden_dim = int(2 * hidden_dim / 3) # custom dim factor multiplier if ffn_dim_multiplier is not None: hidden_dim = int(ffn_dim_multiplier * hidden_dim) hidden_dim = (hidden_dim + multiple_of - 1) // multiple_of * multiple_of # Ensure hidden_dim is a multiple of multiple_of self.w1 = ColumnParallelLinear(dim, hidden_dim, bias=False, gather_output=False, init_method=lambda x: x) self.w2 = RowParallelLinear(hidden_dim, dim, bias=False, input_is_parallel=True, init_method=lambda x: x) self.silu = nn.SiLU() # Assuming you want to use the SiLU activation function def forward(self, x): return self.w2(self.silu(self.w1(x)) * self.w3(x)) 第九部分:损失函数及掩码 损失函数是衡量模型预测与实际值差异的指标,对于模型的训练至关重要。 Transformer 模型的损失函数通常采用交叉熵损失来计算预测结果与真实标签之间的差异。 掩码技术在处理序列数据时用于忽略某些位置,这对于某些特定的任务非常有用。 在 Transfonmer 的前向计算时,会计算一个掩码矩阵。然后,在计算注意力时,使用此掩码来遮蔽掉无效位置。   第十部分:Pytorch的nn.transformer模块 Pytorch的nn.transformer模块提供了构建Transformer模型的工具,使得开发者能够更容易地实现和训练模型。   以下是纯解码器模型的参考代码 import torch.nn as nn class TransformerDecoder(nn.Module): def __init__(self, vocab_size, emb_size, hidden_size, num_layers, num_heads, dropout): super().__init__() self.embedding = nn.Embedding(vocab_size, emb_size) self.decoder = nn.TransformerDecoder( nn.TransformerDecoderLayer(emb_size, num_heads, hidden_size, dropout), num_layers=num_layers ) self.norm = nn.LayerNorm(hidden_size) self.fc = nn.Linear(hidden_size, vocab_size) def forward(self, trg, memory, trg_mask=None, memory_mask=None): # trg: [trg len, batch size] # memory: [src len, batch size, hidden size] # trg mask: [trg len, trg len] # memory mask: [trg len, src len] trg_emb = self.embedding(trg) # [trg len, batch size, emb size] trg_emb = trg_emb.transpose(0, 1) # [batch size, trg len, emb size] output = self.decoder(trg_emb, memory, tgt_mask=trg_mask, memory_mask=memory_mask) # [batch size, trg len, hidden size] output = self.norm(output) # [batch size, trg len, hidden size] output = self.fc(output) # [batch size, trg len, vocab size] return output # Initialize the model model = TransformerDecoder(vocab_size=32000, emb_size=512, hidden_size=1024, num_layers=6, num_heads=4, dropout=0.1) print(model) Liama 2模型的参考代码 import math from dataclasses import dataclass from typing import Optional, Tuple import torch import torch.nn.functional as F from torch import nn @dataclass class ModelArgs: dim: int = 4096 n_layers: int = 32 n_heads: int = 32 n_kv_heads: Optional[int] = None vocab_size: int = -1 # defined later by tokenizer multiple_of: int = 256 # make SwiGlu hidden layer size multiple of large power of 2 ffn_dim_multiplier: Optional[float] = None norm_eps: float = 1e-5 max_batch_size: int = 32 max_seq_len: int = 2048 class RMSNorm(torch.nn.Module): def __init__(self, dim: int, eps: float = 1e-6): super().__init__() self.eps = eps self.weight = nn.Parameter(torch.ones(dim)) def norm(self, x): return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) def forward(self, x): output = self.norm(x.float()).type_as(x) return output * self.weight def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0): freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[:(dim // 2)].float() / dim)) t = torch.arange(end, device=freqs.device) # type: ignore freqs = torch.outer(t, freqs).float() # type: ignore freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64 return freqs_cis def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor): ndim = x.ndim assert 0 <= 1 < ndim assert freqs_cis.shape == (x.shape[1], x.shape[-1]) shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] return freqs_cis.view(*shape) def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: xq_out = torch.view_as_complex(xq * freqs_cis) xk_out = torch.view_as_real(xk * freqs_cis) return xq_out.type_as(xq), xk_out.type_as(xk) def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor: """torch.repeat interleave(x, dim=2, repeats=n_rep)""" bs, slen, n_kv_heads, head_dim = x.shape if n_rep == 1: return x return ( x[:, :, :, None, :].expand(bs, slen, n_kv_heads, n_rep, head_dim).reshape(bs, slen, n_kv_heads * n_rep, head_dim) ) class Attention(nn.Module): """Multi-head attention module.""" def __init__(self, args: ModelArgs): super().__init__() self.n_heads = args.n_heads if args.n_kv_heads is None else args.n_kv_heads model_parallel_size = 1 if not hasattr(args, 'get_model_parallel_world_size') else args.get_model_parallel_world_size() self.n_local_heads = args.n_heads // model_parallel_size self.n_local_kv_heads = self.n_heads // model_parallel_size self.n_rep = self.n_local_heads // self.n_local_kv_heads self.head_dim = args.dim // args.n_heads self.wq = nn.Linear(args.dim, args.n_heads * self.head_dim, bias=False) self.wk = nn.Linear(args.dim, self.n_kv_heads * self.head_dim, bias=False) self.wv = nn.Linear(args.dim, self.n_kv_heads * self.head_dim, bias=False) self.wo = nn.Linear(args.dim, args.n_heads * self.head_dim, bias=False) self.cache_k = torch.zeros( args.max_batch_size, args.max_seq_len, self.n_local_kv_heads, self.head_dim, ) self.cache_v = torch.zeros( args.max_batch_size, args.max_seq_len, self.n_local_kv_heads, self.head_dim, ) def forward(self, x: torch.Tensor, start_pos: int, freqs_cis: torch.Tensor, mask: Optional[torch.Tensor]): bsz, seqlen = x.shape xq, xk, xv = self.wq(x), self.wk(x), self.wv(x) xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim) xk = xk.view(bsz, seqlen, self.n_local_kv_heads, self.head_dim) xv = xv.view(bsz, seqlen, self.n_local_kv_heads, self.head_dim) xq, xk = apply_rotary_emb(xq, xk, freqs_cis) self.cache_k = self.cache_k.to(xq.device) self.cache_v = self.cache_v.to(xq.device) self.cache_k[:bsz, start_pos:start_pos + seqlen] = xk self.cache_v[:bsz, start_pos:start_pos + seqlen] = xv keys = self.cache_k[:bsz, :start_pos + seqlen] values = self.cache_v[:bsz, :start_pos + seqlen] keys = repeat_kv(keys, self.n_rep) values = repeat_kv(values, self.n_rep) xq = xq.transpose(1, 2) keys = keys.transpose(1, 2) values = values.transpose(1, 2) scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim) if mask is not None: scores = scores + mask scores = F.softmax(scores.float(), dim=-1).type_as(xq) output = torch.matmul(scores, values) output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1) return self.wo(output) class FeedForward(nn.Module): def __init__(self, dim: int, hidden_dim: int, multiple_of: int, ffn_dim_multiplier: Optional[float]): super().__init__() hidden_dim = int(2 * hidden_dim / 3) # custom dim factor multiplier if ffn_dim_multiplier is not None: hidden_dim = int(ffn_dim_multiplier * hidden_dim) hidden_dim = multiple_of * ((hidden_dim + multiple_of - 1) // multiple_of) self.w1 = nn.Linear(dim, hidden_dim, bias=False) self.w2 = nn.Linear(hidden_dim, dim, bias=False) self.w3 = nn.Linear(dim, hidden_dim, bias=False) def forward(self, x): return self.w2(torch.silu(self.w1(x)) * self.w3(x)) class TransformerBlock(nn.Module): def __init__(self, layer_id: int, args: ModelArgs): super().__init__() self.n_heads = args.n_heads self.dim = args.dim self.head_dim = args.dim // args.n_heads self.attention = Attention(args) self.feed_forward = FeedForward( dim=args.dim, hidden_dim=4 * args.dim, multiple_of=args.multiple_of, ffn_dim_multiplier=args.ffn_dim_multiplier, ) self.attention_norm = RMSNorm(args.dim, eps=args.norm_eps) self.ffn_norm = RMSNorm(args.dim, eps=args.norm_eps) self.layer_id = layer_id def forward(self, x: torch.Tensor, start_pos: int, freqs_cis: torch.Tensor, mask: Optional[torch.Tensor]): h = self.attention_norm(x) h = self.attention.forward(h, start_pos, freqs_cis, mask) h = h + x out = self.feed_forward.forward(self.ffn_norm(h)) out = out + h return out class Transformer(nn.Module): def __init__(self, params: ModelArgs): super().__init__() self.vocab_size = params.vocab_size self.params = params self.token_embeddings = nn.Embedding(params.vocab_size, params.dim) self.layers = nn.ModuleList([TransformerBlock(layer_id, params) for layer_id in range(params.n_layers)]) self.norm = RMSNorm(params.dim, eps=params.norm_eps) self.output = nn.Linear(params.dim, params.vocab_size, bias=False) self.freqs_cis = precompute_freqs_cis(params.dim // 2, params.max_seq_len * 2) def forward(self, tokens: torch.Tensor, start_pos:int): with torch.inference_mode(): bsz, seqlen = tokens.shape tokens = self.token_embeddings(tokens) freqs_cis = self.freqs_cis.to(tokens.device) mask = None if seqlen <= 1 else torch.full((seqlen, seqlen), float('-inf'), device=tokens.device) mask = torch.tril(torch.ones((seqlen, start_pos), device=tokens.device)) for layer in self.layers: h = layer(tokens, start_pos, freqs_cis, mask) tokens = self.norm(h) output = self.output(tokens) return output.float() model_args: ModelArgs=ModelArgs() medel_args.vocab_size =32000 model_args.n_layers =6 model_args.max_seq_len = 2048 model = Transformer(model_args) print (model)  

  • 回复了主题帖: 祝福2025!回帖即有奖!选取最有心的送5块国产开发板!

    再次感谢EEWorld给我的支持和鼓励,希望EEWorld越办越红火!

  • 回复了主题帖: 祝福2025!回帖即有奖!选取最有心的送5块国产开发板!

    妥妥的福利,必须支持!新年希望多一些AI的开发板评测,尤其是STM32N6的

  • 2024-12-25
  • 回复了主题帖: 2025年测评中心,DigiKey得捷赞助继续,欢迎跟帖推你期待的上线的测品啦~

    特别期待STM32N6相关开关板的测评,嵌入式AI领域的评测!

  • 2024-12-18
  • 发表了主题帖: AI挑战营(进阶) 1:LuckFox Pico Max Pro(RV1106)TF卡烧录官方例程测试

    感谢EEWorld以及幸狐开发板提供的评测活动,又一次幸运的得到了评测的机会。 LuckFox Pico Max是基于瑞芯微 RV1106 G3芯片,基于单核 ARM Cortex-A7 32 位内核,集成了 NEON 和 FPU,并内置 NPU 支持 INT4 / INT8 / INT16 混合运算,计算能力高达 1TOPs,板载了256M的FLASH芯片。       一、评测准备 收到板子有两周多时间了,学习了很多网友的应用评测,也凑齐了开发资源,终于开干。 首先评测官方例程,用TF卡的方式进行,以下是用到的资源,主要是TF卡(32G)以及usb串口模块。  二、开发环境及软件工具 根据官方教程 进行TF卡的烧录,首先下载相关的软件,并进行安装 主要有:1、RK驱动助手 DriverAssitant               2、Buildroot镜像               3、TF卡擦除工具SD Card Formatter               4、烧录工具SocToolKit               5、MobaXterm 远程登录软件               6、VLC media player                     7、usb串口模块的驱动 三、TF格式化     SD Card Formatter的使用比较简单,不要选错TF卡所在盘符就行 四、TF卡烧录 SocToolKit烧录软件要右键管理员身份运行,否则不会出现USB 磁盘。其他根据官方网站的方法进行就可以,只是要注意,镜像文件中不要选择update.img。     烧录完成后的截图如下:   五、串口调试 由于用的是win11系统,新拆的ch340串口模块,驱动这块出现了很大问题,连续几次都打不来串口,后面查了资料,更换为低版本的驱动才成功,有类似问题的网友可以参考以下。首先卸载端口的时候,一定要勾上驱动程序,再者一定要选择老版本的驱动程序,我这边用的是2014年11月的驱动版本。 更换驱动后串口就能正常打开了(建议用sscom等软件先测试下串口是否正常,可用跳线帽短接RXD和TXD引脚) 根据官方网站提供的方式进行硬件连接  打开 MobaXterm 远程登录软件,选择 Session->Serial,设置串口的波特率波特率为115200。   连接后就能看到开发板的进度和提示信息了   输入登录账号:root   登录密码:luckfox 就进入Buildroot界面   键入ifconfig查看网卡信息  六、PC中usb网卡设置 根据官方网站中的配置 RNDIS 网口步骤,设置PCRNDIS 网卡的地址为172.32.0.100,然后互ping成功   七、使用VLC media player 推流 同样,根据官方网站的VLC推流,选择媒体—>打开网络串流,输入地址rtsp://172.32.0.93/live/0 就能看到摄像头推过来的视频了,只是延迟非常严重,不知道通过网线的推流会不会快一些? 以下是录制的推流视频 [localvideo]843368a9eedfb6f370c226708c93e444[/localvideo] 八、遗留问题 评测过程,烧录了Ubuntu22.04镜像,IP地址为172.32.0.70,但是无法推流,不知道该怎么实现?哪位大佬指点一下,不胜感激!

  • 2024-12-13
  • 发表了主题帖: 《大语言模型开发:用开源模型开发本地系统》分享2:深度学习框架:PyTorch

    深度学习是人工智能领域中的非常重要的一个领域,深度学习框架中比较知名的有TransorFlow、Pytorch、Keras等。今天的分享就介绍Pytorch以及用Pytorch编码的神经网络代码。 PyTorch简介 在开始之前,让我们先来简单了解一下PyTorch。PyTorch是由Facebook的人工智能研究团队开发的一个开源机器学习库,它广泛用于计算机视觉和自然语言处理等应用。PyTorch以其动态计算图、易用性和灵活性而闻名,这使得它成为了许多研究者和开发者的首选工具。 PyTorch安装 在开始使用PyTorch之前,我们需要先进行安装。 Pytorch网址是https://pytorch.org/,提供了PyTotch框架的不同安装方式   安装PyTorch的过程非常简单,我们可以通过Python的包管理器pip来安装。在命令行中输入以下命令即可: pip install torch torchvision 这样,PyTorch及其视觉库vision就安装完成了。安装完成后,我们可以通过简单的代码来测试是否安装成功: import torch print(torch.__version__) 如果输出了版本号,那么恭喜您,PyTorch已经成功安装在您的机器上了。 张量 在PyTorch中,张量(Tensor)是最基本的数据结构,类似于NumPy中的数组。张量可以包含标量、向量、矩阵或高维数据。PyTorch的张量操作非常灵活,支持各种数学运算,例如加法、乘法等。   # 创建一个张量 tensor = torch.tensor([1, 2, 3]) print(tensor) # 张量运算 result = tensor + 2 print(result) 梯度计算 在深度学习中,梯度计算是一个核心概念。PyTorch提供了自动梯度计算的功能,这大大简化了我们对模型进行训练的过程。当我们需要计算某个张量的梯度时,只需调用.backward()方法。   # 需要计算梯度的张量 x = torch.tensor([1.0], requires_grad=True) # 计算梯度 y = x ** 2 y.backward(torch.tensor([1.0])) # 输出梯度 print(x.grad) 反向传播 反向传播是神经网络训练中的关键步骤,它通过计算损失函数关于模型参数的梯度来更新参数。在PyTorch中,我们通常不需要手动实现反向传播,因为框架会自动为我们处理。   # 定义一个简单的函数 def f(x):     return x ** 2 # 计算梯度 x = torch.tensor([2.0], requires_grad=True) f(x).backward() print(x.grad) torch.nn模块构建神经网络 torch.nn模块是PyTorch中用于构建神经网络的核心模块。它提供了一系列的类和函数,可以帮助我们快速构建各种类型的神经网络层。   import torch.nn as nn # 定义一个简单的神经网络 class Net(nn.Module):     def __init__(self):         super(Net, self).__init__()         self.fc1 = nn.Linear(10, 5)         self.fc2 = nn.Linear(5, 2)     def forward(self, x):         x = torch.relu(self.fc1(x))         x = self.fc2(x)         return x # 实例化网络 net = Net() torch.optim优化器 在训练神经网络时,优化器是调整模型参数以最小化损失函数的关键组件。torch.optim模块提供了多种优化算法,如SGD、Adam等。   import torch.optim as optim # 定义优化器 optimizer = optim.SGD(net.parameters(), lr=0.01) 训练、验证和测试过程 训练神经网络通常包括三个阶段:训练、验证和测试。在训练阶段,我们使用训练数据来更新模型参数;在验证阶段,我们使用验证数据来评估模型的性能;在测试阶段,我们使用测试数据来最终评估模型的泛化能力。   # 训练过程示例 for epoch in range(num_epochs):     for data, target in train_loader:         optimizer.zero_grad()         output = net(data)         loss = criterion(output, target)         loss.backward()         optimizer.step() 用Pytorch实现神经网络 通过上述的介绍,我们已经了解了PyTorch的基本组件和概念。现在,让我们来看一个简单的神经网络实现示例。   import torch import torch.nn as nn import torch.optim as optim #定义神经网络模型 class CloudServiceUsageModel(nn.Module): def __init__(self,input size, hidden size, num classes): super(CloudServiceUsageModel, self).__init__() self.fcl =nn.Linear(input_size,hidden_size) self.relu = nn.ReLU() self.fc2 =nn.Linear(hidden size,num classes) def forward(self,x): out = self.fc1(x)out= self.relu(out) out = self.fc2(out) return out #准备数据 input size = 10 hidden size =5 num classes=2 learning rate=0.001 num epochs=100 #随机生成一些示例数据 X= torch,randn(100,input size) Y=torch.randint(0,num classes,(100,)) #划分训练集和测试集 train_size=int(0.8 *len(X)) train_X,test_x=X[:train size],X[train size:] train_Y,test_Y=Y[:train size],Y[train size:] #初始化模型、损失函数和优化器 model =CloudServiceUsageModel(input size, hidden size, num classes) criterion =nn.CrossEntropyLoss() optimizer =optim.Adam(model.parameters(),lr=learning rate) #模型训练 for epoch in range(num epochs): #前向传播 outputs = model(train X) loss =criterion(outputs,train Y) #反向传播和优化 optimizer.zero grad() loss.backward() optimizer.step() #打印训练信息 if(epoch+1)%10 == 0: print(f'Epoch {epoch+l}/{num epochs), Loss: {loss.item()}') #模型评估 with torch.no grad(): outputs =model(test X) _, predicted = torch.max(outputs.data,1) accuracy =(predicted ==test Y).sum().item()/ len(test Y) print(f'Test Accuracy:{accuracy}') 运行输出为 Epoch 10/100, Loss:0.7254490852355957 Epoch 20/100, Loss:0.7173128724098206 Epoch 30/100,Loss:0.7097707986831665 Epoch 40/100,Loss:0.7027563452720642 Epoch 50/100, Loss:0.6960537433624268 Epoch 60/100,Loss:0.6897956728935242 Epoch 70/100,Loss:0.6836565732955933 Epoch 80/100,Loss:0.6769127249717712 Epoch 90/100, Loss:0.6696738004684448 Epoch 100/100,Loss:0.6618732213973999 Test Accuracy:0.3 源代码常用模块 在实际开发中,我们还会用到PyTorch的许多其他模块,如nn.Parameter类,将需要被优化的张量(参数)标记为网络可训练的参数,方便进行参数更新和优化;typing模块提供了类型提示和类型注解的功能;logging模块用于记录和管理应用程序的日志信息,提供了灵活的配置选项,允许不同级别的日志过滤信息;torchvision模块用于图像处理,torch.utils.data用于数据加载和处理等。这些模块都极大地丰富了PyTorch的功能,使得我们能够更加便捷地进行深度学习项目的开发。 总结 今天的分享,希望大家能够对PyTorch有一个初步的了解,并激发起和大家进一步探索和学习的兴趣。深度学习是一个不断发展的领域,而PyTorch作为一个强大的工具,能够帮助我们更好地理解和实现深度学习模型。

  • 2024-12-02
  • 回复了主题帖: 《大语言模型开发:用开源模型开发本地系统》分享1:从基础到实践:NLP与深度学习基础

    Jacktang 发表于 2024-12-1 16:25 深度学习的基础是感知机,它是最简单的神经网络单元,这个是本次学习的关键认知。 还是大佬学的深刻哈,感谢感谢

  • 2024-12-01
  • 发表了主题帖: 《大语言模型开发:用开源模型开发本地系统》分享1:从基础到实践:NLP与深度学习基础

    在人工智能的浪潮中,大语言模型作为一项前沿技术,正逐渐渗透到我们生活的方方面面。《大语言模型开发:用开源模型开发本地系统》这本书为我们揭开了大语言模型的神秘面纱,让我们得以一窥其背后的技术原理和开发实践。 第一章:自然语言处理 1. 人工智能的技术构成 自然语言处理(NLP)是人工智能领域的一个重要分支,它致力于使计算机能够理解、解释和生成人类语言。在这一章节中,我们首先了解了机器学习与深度学习的区别。机器学习侧重于从数据中学习模式,而深度学习则利用多层神经网络模拟人脑处理信息的方式。   2. 自然语言的发展阶段 自然语言处理经历了从规则驱动到统计方法,再到深度学习方法的发展。这一过程反映了我们对语言理解的不断深化。   3. 深度学习方法 深度学习方法在NLP中扮演着核心角色。我们探讨了Word2Vec词嵌入、循环神经网络(RNN)、长短时记忆网络(LSTM)和门控循环单元(GRU)模型。这些技术使得机器能够捕捉到语言的复杂性和上下文信息。   4. 序列到序列模型与注意力机制 序列到序列模型(Seq2Seq)和注意力机制是NLP中的两个重要概念。Seq2Seq模型能够处理输入和输出序列长度不一的问题,而注意力机制则帮助模型集中于输入序列中的关键信息。 5. Transformer模型 Transformer模型以其自注意力机制而闻名,它在处理序列数据时表现出色,特别是在机器翻译和文本摘要等任务中。 6. 预训练模型与大语言模型 预训练模型通过在大规模数据集上训练,使得模型能够捕捉到丰富的语言特征。大语言模型则是预训练模型的进一步发展,它们根据架构和训练方式进行分类。 第二章:深度学习基础 1. 深度学习与感知机 深度学习的基础是感知机,它是最简单的神经网络单元。我们学习了前馈网络、权重更新和反向传播算法,这些都是构建深度学习模型的基石。   2. 激活函数 激活函数在神经网络中扮演着非线性变换的角色。我们了解了常用激活函数如ReLU、Sigmoid,以及新型激活函数如Leaky ReLU和ELU。   3. 优化函数(算法) 优化算法是训练神经网络的关键。我们探讨了梯度下降法及其变体,包括动量优化算法、AdaGrad、RMSProp和Adam优化算法。   4. 权值初始化与归一化 权值初始化和归一化技术对于模型的训练至关重要。我们学习了批归一化、层归一化和RMSNorm等技术。 5. 损失函数 损失函数是衡量模型预测与实际值差异的指标。我们了解了均方误差、均方根误差和交叉熵损失等常见损失函数。 6. 模型评估与正则化 模型评估涉及到偏差/方差、过拟合与欠拟合的概念。正则化技术如L1和L2正则化有助于防止过拟合。 7. SoftMax函数与简易神经网络搭建 SoftMax函数在多分类问题中用于输出概率分布。我们还学习了如何搭建一个简易的神经网络,并讨论了梯度消失和梯度爆炸问题。 8. 模型优化 最后,我们探讨了模型优化的策略,包括优化手段和调参技巧,这些对于提升模型性能至关重要。 结语 通过这本书的前两章,我们不仅了解了自然语言处理和深度学习的理论基础,还掌握了一些实用的技术手段。这些知识为我们进一步探索大语言模型的开发提供了坚实的基础。希望这次的分享能够帮助大家更好地理解这些概念,并激发出更多的创新思维。

  • 2024-11-21
  • 回复了主题帖: 入围名单公布:嵌入式工程师AI挑战营(进阶)的挑战者们,领取板卡啦

    个人信息已确认,领取板卡,可继续完成任务。

  • 回复了主题帖: 共读入围:《大语言模型开发:用开源模型开发本地系统》

    个人信息无误,确认可以完成评测计划。

  • 2024-11-11
  • 回复了主题帖: 《动手学深度学习(PyTorch版)》书籍分享4:注意力机制与优化算法

    通途科技 发表于 2024-11-11 05:33 好好学习,天天向上,加油,同学们,加油,自己!!! 共同学习,共同提高,加油!

  • 2024-11-08
  • 回复了主题帖: 嵌入式工程师AI挑战营(进阶):在RV1106部署InsightFace算法的多人实时人脸识别实战

    insightface是一个开源的基于Pytorch和MXNet实现的2D/3D人脸分析工具,它实现了多个SOTA人脸识别、人脸检测、人脸对齐算法,并对训练和部署进行了优化。insightface用的是5个特征点检测,因此算法资源要求相对较少,容易在嵌入式系统上进行部署和实现。 对于特定的人脸,需要在PC环境下训练后才能部署在嵌入式板子RV106上运行,可以使用RKNNLite工具包对InsightFace算法进行模型转换后,在RV1106上实现人脸识别。计划挑战和部署的应用为实时人物轨迹追踪。即对特定的人脸运动轨迹进行实时标注。 目前来说,需要学习的路程比较长,但是这个领域的前景还是非常看好的,会努力克服学习上的困难,力争完成这个嵌入式人脸实时识别项目。  

  • 2024-11-06
  • 回复了主题帖: 《动手学深度学习(PyTorch版)》书籍分享4:注意力机制与优化算法

    William-sz 发表于 2024-10-29 12:59 学习了,内容非常清晰,非常感谢楼主的分享。好文,有需要的可以看看。 谢谢,大家共同学习,共同分享

统计信息

已有284人来访过

  • 芯积分:370
  • 好友:1
  • 主题:108
  • 回复:204

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言