Self-study Python Fish-C Note13 P48to49

函数 (part 3)

本节主要讲函数的 lambda 表达式, 生成器

lambda 表达式 (匿名函数)(P48)

匿名函数(lambda 表达式)语法规则:lambda arg1, arg2, arg3, ... argN : expression
其中 arg 为参数,expression 为函数实现的表达式以及返回值
我们把lambda表达式作为极致精简的函数,相当于传统函数定义的:
def <lambda> (arg1,arg2,arg3,... argN): return expression
示例 1:

# 传统定义的函数
def squareX(x):
    return x*x
squareX(3)
9
# lambda 表达式
squareY = lambda y : y*y
squareY(3)
9
# 传统定义的函数函数名就是一个函数的引用
squareX
<function __main__.squareX(x)>
# 而 lambda 表达式,整个表达式就是一个函数的引用
squareY
<function __main__.<lambda>(y)>

两者重大的区别就是,lambda 是一个表达式,可以用在常规函数不可能存在的地方。
示例2:lambda 表达放入列表(这里只是做示例示范可以,但不推荐大家开发的时候这么写哈)

y = [lambda x:x*x,2,3]
y[0](y[1]) # 把 y 列表的第二个值(2),传入列表第一个值 lambda 表达式中
4

lambda 表达式与 mapfilter 等函数合用。这两者的参数都是要求传入一个用于计算的函数,此时就可以使用 lambda 表达式。
比如 map 函数,第一个参数就是传入一个函数的引用,第二个参数要求是序列类型,其会把每个元素挨个传递给第一个参数指定的函数,在运算之后把结果构成一个迭代器返回。
示例3:

mapped = map(lambda x:ord(x)+10, 'abcdef')
list(mapped)
[107, 108, 109, 110, 111, 112]
# 如果我们用传统的函数
def tradation(x):
    return ord(x)+10
list(map(tradation,'abcdef'))
[107, 108, 109, 110, 111, 112]
# 再比如我们用在 filter 上
list(filter(lambda x : x%2,range(10))) # 求 10 以内的所有奇数
[1, 3, 5, 7, 9]

总结,lambda 是一个表达式而非语句,所以它能够出现在 Python 语法不允许 def 语句出现的地方(优势)。但由于所有的功能代码都局限在一个表达式中实现,因此 lambda 通常也只能实现那些较为简单的需求。一般来讲,匿名函数用于实现简单的需求,def 语句负责用于定义功能复杂的函数,去处理复杂的工作。

生成器 (generator) (P49)

对于调用一个普通的 Python 函数来说,一般我们都是从函数的第一行代码开始执行的,当所有语句执行完毕,或者遇到 return 语句的时候,这个函数就算是结束了。一旦函数将控制权交还给调用者的时候,这就意味这这个函数的结束。函数中做的所有工作,以及保存在局部变量中的数据也都会丢失。当再次调用的时候,一切从头开始。
有没有办法让函数在退出之后还能保留状态呢?使用闭包或者全局变量。不过过多使用全局变量会污染命名空间,闭包的定义又相对复杂。
此时,生成器 (generator) 就是一个更简单和安全的方法。
定义一个生成器:

在函数中使用 yield 表达式来代替 return语句

示例1:

def counter():
    i=0
    while i <= 3:
        yield i
        i+=1
# 这样我们就定义了一个 叫 counter 的生成器
# 现在我们调用 counter() 函数
counter() # 可以看到得到的不再是一个返回值,而是一个生成器对象 `generator object`
<generator object counter at 0x0000017F4A3B8430>
# counter 现在是一个生成器了,我们可以在 for 中使用
for i in counter():
    print(i)
0
1
2
3

我们知道 for 语句,是从一个可迭代对象里面每次获取一个数据。这个 counter 生成器的作用就是每次调用的时候提供一个数据,注意是提供一个数据。
更深入讲,每次在执行到 yield i的时候,就生成一个数据,暂停并保留状态。下一次调用则从下一个语句 i+=1开始继续执行。
注意:生成器它不像是列表,元组之类的可迭代对象,生成器可以看作是一个制作机器,他的作用就是每调用一次提供一个数据,并且会记住当时的状态。而列表元组这些可迭代对象则是容器,他们里面存放的是早已经准备好的所有数据。生成器是一种特殊的迭代器,他首先不走回头路,其次支持 next()函数

c = counter()
next(c)
0
next(c)
1
next(c)
2
next(c)
# 如果再 使用 next(c) 就会抛出 StopIteration 的异常
3

由于生成器每调用一次获取一个结果的特性,所以生成器对象是无法使用下标索引这种随机访问的方式的

c = counter()
print(next(c))
print(next(c)) # 此时 c 的状态 i =1
print('_'*30)
for i in c: # 再调用是从 i=1开始 i=i+1
    print(i)
0
1
______________________________
2
3

示例2:
使用生成器来实现 斐波那契数列
斐波那契数列:由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出:0,1,1,2,3,5,8 …

def fib():
    back1,back2 = 0,1
    while True:
        yield back1
        back1,back2 = back2,back1+back2
        
f = fib()
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
0
1
1
2
3
5
8
13

这里我们写了一个无限的斐波那契数列,如果我们不小心用到了 for 上,他就会一直生成下去。此时要用 control+C 强制退出,否则会一直进行下去

生成器表达式 (generator expression)

在之前的课程中我们提到过,列表有列表推导是而元组则没有。这里就可以做一个解答,列表推导式的 [] 换成 (),其实就变成了生成器表达式。
示例:

(i**2 for i in range(3))
<generator object <genexpr> at 0x0000017F4A3C49E0>
t = (i**2 for i in range(3)) # range(3) 包括 0,1,2 不包括 3
print(next(t))
print(next(t))
print(next(t))
0
1
4

这种利用推导的形式获得生成器的方法,我们称之为生成器表达式。生成器表达式和列表推导式最大的不同就是,列表推导式会一下子将所有数据生产出来并放到一个列表中,但是生成器表达式一次只生成一个数据。
总结来说,生成生成器的两种方法一个就是使用 yield 表达式,另一个就是直接使用生成器表达式。




附言: 题目:Self-study Python Fish-C Note-13 P48-P49 本文为自学B站上鱼C的python课程随手做的笔记。一些概念和例子我个人为更好的理解做了些查询和补充 因本人水平有限,如有任何问题,欢迎大家批评指正! 原视频链接:https://www.bilibili.com/video/BV1c4411e77t?p=8

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个 Python 代码示例,用于实现 multi-head self-attention: ```python import torch import torch.nn as nn class MultiHeadAttention(nn.Module): def __init__(self, d_model, num_heads): super(MultiHeadAttention, self).__init__() self.num_heads = num_heads self.d_model = d_model self.depth = d_model // num_heads self.query_linear = nn.Linear(d_model, d_model) self.key_linear = nn.Linear(d_model, d_model) self.value_linear = nn.Linear(d_model, d_model) self.output_linear = nn.Linear(d_model, d_model) def forward(self, query, key, value, mask=None): batch_size = query.size() # Linear transformations query = self.query_linear(query) key = self.key_linear(key) value = self.value_linear(value) # Split into heads query = query.view(batch_size * self.num_heads, -1, self.depth) key = key.view(batch_size * self.num_heads, -1, self.depth) value = value.view(batch_size * self.num_heads, -1, self.depth) # Transpose for matrix multiplication query = query.transpose(1, 2) key = key.transpose(1, 2) value = value.transpose(1, 2) # Calculate scores scores = torch.matmul(query, key.transpose(-2, -1)) scores = scores / torch.sqrt(torch.tensor(self.depth).float()) # Apply mask (if provided) if mask is not None: mask = mask.unsqueeze(1) scores = scores.masked_fill(mask == , -1e9) # Softmax attention_weights = nn.Softmax(dim=-1)(scores) # Dropout attention_weights = nn.Dropout(p=.1)(attention_weights) # Multiply by values context = torch.matmul(attention_weights, value) # Reshape and concatenate context = context.transpose(1, 2).contiguous().view(batch_size, -1, self.num_heads * self.depth) # Linear transformation output = self.output_linear(context) return output ``` 希望对你有所帮助! ### 回答2: 下面是使用Python语言实现multi-head self-attention的一个示例代码: ``` import torch import torch.nn as nn import torch.nn.functional as F class MultiHeadSelfAttention(nn.Module): def __init__(self, d_model, num_heads): super(MultiHeadSelfAttention, self).__init__() self.num_heads = num_heads self.d_head = d_model // num_heads self.fc_query = nn.Linear(d_model, d_model) self.fc_key = nn.Linear(d_model, d_model) self.fc_value = nn.Linear(d_model, d_model) self.fc_concat = nn.Linear(d_model, d_model) def forward(self, x): batch_size, seq_len, d_model = x.size() h = self.num_heads # Split input into multiple heads query = self.fc_query(x).view(batch_size, seq_len, h, self.d_head) key = self.fc_key(x).view(batch_size, seq_len, h, self.d_head) value = self.fc_value(x).view(batch_size, seq_len, h, self.d_head) # Compute attention scores scores = torch.matmul(query, key.transpose(-2, -1)) / (self.d_head ** 0.5) attn_weights = F.softmax(scores, dim=-1) # Apply attention weights to value vectors attended_values = torch.matmul(attn_weights, value) attended_values = attended_values.transpose(1, 2).contiguous().view(batch_size, seq_len, -1) # Concatenate and linearly transform attended values output = self.fc_concat(attended_values) return output # 使用示例 d_model = 128 num_heads = 8 seq_len = 10 batch_size = 4 input_tensor = torch.randn(batch_size, seq_len, d_model) attention = MultiHeadSelfAttention(d_model, num_heads) output = attention(input_tensor) print("Input Shape: ", input_tensor.shape) print("Output Shape: ", output.shape) ``` 上述代码定义了一个`MultiHeadSelfAttention`的类,其中`forward`函数实现了multi-head self-attention的计算过程。在使用示例中,我们输入一个大小为`(batch_size, seq_len, d_model)`的张量,经过multi-head self-attention计算后输出一个大小为`(batch_size, seq_len, d_model)`的张量。其中`d_model`表示输入的特征维度,`num_heads`表示attention头的数量。 ### 回答3: 下面是使用Python实现multi-head self-attention示例的代码: ```python import torch import torch.nn as nn class MultiHeadSelfAttention(nn.Module): def __init__(self, embed_size, num_heads): super(MultiHeadSelfAttention, self).__init__() self.embed_size = embed_size self.num_heads = num_heads self.head_size = embed_size // num_heads self.query = nn.Linear(embed_size, embed_size) self.key = nn.Linear(embed_size, embed_size) self.value = nn.Linear(embed_size, embed_size) self.out = nn.Linear(embed_size, embed_size) def forward(self, x): batch_size, seq_len, embed_size = x.size() # Split the embedding into num_heads and reshape x = x.view(batch_size, seq_len, self.num_heads, self.head_size) x = x.permute(0, 2, 1, 3) # Apply linear transformations to obtain query, key, and value query = self.query(x) key = self.key(x) value = self.value(x) # Compute scaled dot product attention scores scores = torch.matmul(query, key.permute(0, 1, 3, 2)) scores = scores / self.head_size**0.5 # Apply softmax to obtain attention probabilities attn_probs = nn.Softmax(dim=-1)(scores) # Apply attention weights to value and sum across heads attended = torch.matmul(attn_probs, value) attended = attended.permute(0, 2, 1, 3) attended = attended.contiguous().view(batch_size, seq_len, self.embed_size) # Apply output linear transformation output = self.out(attended) return output ``` 上述代码中定义了一个名为MultiHeadSelfAttention的类,继承自nn.Module,可以通过指定嵌入大小(embed_size)和头部数量(num_heads)来创建多头自注意力层。在前向传播方法forward中,先通过线性变换将输入张量分别变换为查询(query)、键(key)和值(value)张量。然后计算缩放点积注意力得分,将其作为注意力概率经过softmax函数进行归一化。通过注意力概率权重对值进行加权求和,并应用线性变换得到最终的输出张量。最后返回输出张量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值