为什么from tensorflow.keras.layers import Layer在keras和layer报错

时间: 2023-11-06 18:04:49 浏览: 23
在 `from tensorflow.keras.layers import Layer` 时,需要确保已经安装了 TensorFlow 2.x 版本。如果您使用的是 TensorFlow 1.x 版本,则需要使用 `from keras.layers import Layer`。 另外,如果您在使用 `keras.layers` 时遇到报错,可能是因为您的 Keras 版本不兼容。如果您正在使用 TensorFlow 2.x 版本,则应该使用 `from tensorflow.keras.layers import Layer`。如果您正在使用 TensorFlow 1.x 版本,则应该使用 `from keras.layers import Layer`。如果您的 Keras 版本过低,则需要升级 Keras。
相关问题

from tensorflow.keras.layers import Lambda

`Lambda` 是 TensorFlow Keras 中的一个层,用于将任意表达式封装为一个 Keras 层,以便在 Keras 模型中使用。 使用 `Lambda` 层时,需要将一个函数作为参数传递给它。这个函数可以是任意可调用对象,例如 Python 函数、Lambda 表达式或类实例方法。 以下是一个简单的例子,演示如何使用 `Lambda` 层将一个函数封装为 Keras 层: ```python from tensorflow.keras.layers import Input, Lambda from tensorflow.keras.models import Model # 定义一个函数 def double(x): return x*2 # 创建输入层 input_layer = Input(shape=(1,)) # 创建 Lambda 层,并将 double 函数作为参数传递给它 double_layer = Lambda(double)(input_layer) # 创建模型,并将输入层和 Lambda 层作为输入 model = Model(inputs=input_layer, outputs=double_layer) # 打印模型的结构 model.summary() ``` 在这个例子中,我们定义了一个 `double` 函数,它将输入值乘以 2,并将它作为参数传递给 `Lambda` 层。然后,我们创建一个输入层和一个 `Lambda` 层,并将它们作为输入创建一个 Keras 模型。最后,我们打印模型的结构,以确认模型正确地使用了 `Lambda` 层。 注意,`Lambda` 层可以用于任何表达式,而不仅仅是简单的函数。例如,你可以使用 Lambda 表达式、类实例方法等。

from tensorflow.keras.layers import Dense, Lambda, Dot, Activation, Concatenate, Layer 需要什么包?

这些层是Keras中的内置层,它们位于`tensorflow.keras.layers`模块中。如果你已经安装了TensorFlow,那么你可以直接使用以下代码导入这些层: ``` from tensorflow.keras.layers import Dense, Lambda, Dot, Activation, Concatenate, Layer ``` 如果你还没有安装TensorFlow,可以使用以下命令安装: ``` pip install tensorflow ``` 这将安装最新版本的TensorFlow。如果你只想安装特定版本的TensorFlow,可以使用以下命令: ``` pip install tensorflow==<version> ``` 其中`<version>`是你想要安装的TensorFlow版本号。例如,如果你想安装TensorFlow 2.4版本,可以使用以下命令: ``` pip install tensorflow==2.4 ``` 需要注意的是,TensorFlow 2.x版本中已经将Keras API整合到TensorFlow中,因此你可以直接使用`tensorflow.keras.layers`模块来加载层和相关函数。

相关推荐

是的,TensorFlow Keras中提供了Transformer的封装。您可以在tensorflow.keras.layers中找到MultiHeadAttention和Transformer等层。Transformer层将多头自注意力和前馈神经网络组合在一起,实现了Transformer的核心架构。您可以使用这些层来构建自己的Transformer模型。以下是一个简单的示例: python import tensorflow as tf # 定义Transformer层 class TransformerBlock(tf.keras.layers.Layer): def __init__(self, embedding_dim, num_heads, dense_dim, rate=0.1): super().__init__() self.attention = tf.keras.layers.MultiHeadAttention(num_heads=num_heads, key_dim=embedding_dim) self.dense1 = tf.keras.layers.Dense(dense_dim, activation='relu') self.dense2 = tf.keras.layers.Dense(embedding_dim) self.dropout1 = tf.keras.layers.Dropout(rate) self.dropout2 = tf.keras.layers.Dropout(rate) self.layer_norm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6) self.layer_norm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6) def call(self, inputs, training): attn_output = self.attention(inputs, inputs) attn_output = self.dropout1(attn_output, training=training) out1 = self.layer_norm1(inputs + attn_output) dense_output = self.dense1(out1) dense_output = self.dense2(dense_output) dense_output = self.dropout2(dense_output, training=training) out2 = self.layer_norm2(out1 + dense_output) return out2 # 定义Transformer模型 class TransformerModel(tf.keras.Model): def __init__(self, num_layers, embedding_dim, num_heads, dense_dim, input_vocab_size, target_vocab_size, rate=0.1): super().__init__() self.embedding = tf.keras.layers.Embedding(input_vocab_size, embedding_dim) self.transformer_blocks = [TransformerBlock(embedding_dim, num_heads, dense_dim, rate) for _ in range(num_layers)] self.dense = tf.keras.layers.Dense(target_vocab_size) def call(self, inputs, training): embed_output = self.embedding(inputs) for transformer_block in self.transformer_blocks: embed_output = transformer_block(embed_output, training) output = self.dense(embed_output) return output 在此示例中,我们定义了一个TransformerBlock层和一个TransformerModel模型。TransformerBlock层包含多头自注意力、前馈神经网络和残差连接,并使用层归一化进行归一化。TransformerModel模型包含多个TransformerBlock层以及嵌入层和最终的全连接层。通过这些层的组合,我们可以构建一个完整的Transformer模型。
tf.keras.layers.LayerNormalization 是 TensorFlow 中的一个层,用于实现层归一化(Layer Normalization)操作。 层归一化是一种归一化技术,旨在在深度神经网络中减少内部协变量偏移(Internal Covariate Shift)。它可以将每个样本的特征进行归一化,而不是整个批次。 层归一化的计算方式如下: 1. 对于一个输入张量 x,计算其均值 μ 和方差 σ。 2. 使用以下公式对输入进行归一化:(x - μ) / sqrt(σ^2 + ε),其中 ε 是一个小的常数,用于防止除以零。 3. 使用两个可训练参数(缩放因子和偏移量)对归一化后的值进行缩放和平移:gamma * 归一化值 + beta。 tf.keras.layers.LayerNormalization 可以作为神经网络模型的一层,在模型中应用层归一化操作。它可以应用于任何维度的输入张量,并且可以在训练过程中自动更新可训练参数。 以下是一个使用 tf.keras.layers.LayerNormalization 的简单示例: python import tensorflow as tf # 创建一个 LayerNormalization 层 layer_norm = tf.keras.layers.LayerNormalization() # 创建一个输入张量 input_tensor = tf.keras.Input(shape=(64,)) # 应用层归一化操作 normalized_tensor = layer_norm(input_tensor) # 创建一个模型 model = tf.keras.Model(inputs=input_tensor, outputs=normalized_tensor) 在上述示例中,input_tensor 是一个形状为 (batch_size, 64) 的输入张量。normalized_tensor 是应用层归一化操作后的输出张量。
Stacked Denoising Autoencoder (Sdae) 是一种无监督学习方法,用于学习数据的低维表示。它是一种深度学习方法,由多个堆叠的自编码器组成,每个自编码器都学习数据的不同层次的特征表示。在训练过程中,每个自编码器都会对输入数据进行降噪处理,以增强其鲁棒性。 在 TensorFlow.Keras 框架下,可以使用 tf.keras 库来实现 Sdae 模型。以下是一个简单的 Sdae 模型示例代码: python from tensorflow.keras.layers import Input, Dense from tensorflow.keras.models import Model # 定义输入层 input_layer = Input(shape=(784,)) # 定义编码器层 encoded = Dense(128, activation='relu')(input_layer) encoded = Dense(64, activation='relu')(encoded) encoded = Dense(32, activation='relu')(encoded) # 定义解码器层 decoded = Dense(64, activation='relu')(encoded) decoded = Dense(128, activation='relu')(decoded) decoded = Dense(784, activation='sigmoid')(decoded) # 定义 Sdae 模型 sdae = Model(inputs=input_layer, outputs=decoded) # 编译 Sdae 模型 sdae.compile(optimizer='adam', loss='binary_crossentropy') 在上面的代码中,我们定义了一个三层编码器和三层解码器的 Sdae 模型。编码器层由三个具有 ReLU 激活函数的 Dense 层组成,解码器层由三个 Dense 层组成,其中最后一层使用 Sigmoid 激活函数。我们使用二元交叉熵作为损失函数,并使用 Adam 优化器进行训练。 接下来,我们可以使用 fit() 方法训练模型: python # 训练 Sdae 模型 sdae.fit(x_train, x_train, epochs=10, batch_size=256, shuffle=True) 在上面的代码中,我们使用 x_train 作为输入和输出数据,训练模型 10 个 epochs,使用批量大小为 256 进行训练,并在每个 epoch 之前打乱数据的顺序。
如果你想手动添加transformer层,可以参考以下代码实现: python import tensorflow as tf class MultiHeadSelfAttention(tf.keras.layers.Layer): def __init__(self, embed_dim, num_heads, **kwargs): super().__init__(**kwargs) self.embed_dim = embed_dim self.num_heads = num_heads if embed_dim % num_heads != 0: raise ValueError( f"embedding dimension = {embed_dim} should be divisible by number of heads = {num_heads}" ) self.projection_dim = embed_dim // num_heads self.query_dense = tf.keras.layers.Dense(embed_dim) self.key_dense = tf.keras.layers.Dense(embed_dim) self.value_dense = tf.keras.layers.Dense(embed_dim) self.combine_heads = tf.keras.layers.Dense(embed_dim) def attention(self, query, key, value): score = tf.matmul(query, key, transpose_b=True) dim_key = tf.cast(tf.shape(key)[-1], tf.float32) scaled_score = score / tf.math.sqrt(dim_key) weights = tf.nn.softmax(scaled_score, axis=-1) output = tf.matmul(weights, value) return output, weights def separate_heads(self, x, batch_size): x = tf.reshape(x, (batch_size, -1, self.num_heads, self.projection_dim)) return tf.transpose(x, perm=[0, 2, 1, 3]) def call(self, inputs): batch_size = tf.shape(inputs)[0] query = self.query_dense(inputs) key = self.key_dense(inputs) value = self.value_dense(inputs) query = self.separate_heads(query, batch_size) key = self.separate_heads(key, batch_size) value = self.separate_heads(value, batch_size) attention, weights = self.attention(query, key, value) attention = tf.transpose(attention, perm=[0, 2, 1, 3]) concat_attention = tf.reshape(attention, (batch_size, -1, self.embed_dim)) output = self.combine_heads(concat_attention) return output class TransformerBlock(tf.keras.layers.Layer): def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1, **kwargs): super().__init__(**kwargs) self.att = MultiHeadSelfAttention(embed_dim, num_heads) self.ffn = tf.keras.Sequential( [tf.keras.layers.Dense(ff_dim, activation="relu"), tf.keras.layers.Dense(embed_dim),] ) self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6) self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6) self.dropout1 = tf.keras.layers.Dropout(rate) self.dropout2 = tf.keras.layers.Dropout(rate) def call(self, inputs, training): attn_output = self.att(inputs) attn_output = self.dropout1(attn_output, training=training) out1 = self.layernorm1(inputs + attn_output) ffn_output = self.ffn(out1) ffn_output = self.dropout2(ffn_output, training=training) return self.layernorm2(out1 + ffn_output) class TokenAndPositionEmbedding(tf.keras.layers.Layer): def __init__(self, maxlen, vocab_size, embed_dim, **kwargs): super().__init__(**kwargs) self.token_emb = tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=embed_dim) self.pos_emb = tf.keras.layers.Embedding(input_dim=maxlen, output_dim=embed_dim) def call(self, x): maxlen = tf.shape(x)[-1] positions = tf.range(start=0, limit=maxlen, delta=1) positions = self.pos_emb(positions) x = self.token_emb(x) return x + positions class Transformer(tf.keras.Model): def __init__(self, vocab_size, maxlen, embed_dim, num_heads, ff_dim, num_layers=4, **kwargs): super().__init__(**kwargs) self.embedding = TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim) self.transformer_blocks = [TransformerBlock(embed_dim, num_heads, ff_dim) for _ in range(num_layers)] self.out = tf.keras.layers.Dense(vocab_size, activation="softmax") def call(self, inputs, training): x = self.embedding(inputs) for block in self.transformer_blocks: x = block(x, training) x = self.out(x) return x 这里实现了一个基本的Transformer模型,包括多头自注意力机制(MultiHeadSelfAttention)、Transformer块(TransformerBlock)、位置编码嵌入层(TokenAndPositionEmbedding)和Transformer模型(Transformer)。你可以根据需要调整其中的参数来满足你的需求。
### 回答1: tf.keras.layers.LayerNormalization() 是一种对输入进行标准化的方法,可以用于加速训练和提高模型的性能。它的参数如下: - axis: 整数或整数元组,指定要标准化的轴。默认为 -1,表示最后一个轴。 - epsilon: 使用的小常数,以避免除以零。 - center: 布尔值,指定是否应该在标准化后添加偏置。默认为 True。 - scale: 布尔值,指定是否应该在标准化后应用缩放。默认为 True。 - beta_initializer: 用于初始化偏置向量的初始化器。默认为 "zeros"。 - gamma_initializer: 用于初始化缩放向量的初始化器。默认为 "ones"。 - beta_regularizer: 可选的正则化函数,应用于偏置向量。 - gamma_regularizer: 可选的正则化函数,应用于缩放向量。 - beta_constraint: 可选的约束函数,应用于偏置向量。 - gamma_constraint: 可选的约束函数,应用于缩放向量。 - trainable: 布尔值,指定是否应该在训练过程中更新变量。默认为 True。 - name: 层的名称。 - dtype: 输出张量的数据类型。 例如,以下代码将创建一个将输入张量在最后一个轴上进行标准化的层: import tensorflow as tf inputs = tf.keras.layers.Input(shape=(10,)) normalized_layer = tf.keras.layers.LayerNormalization()(inputs) 这个层将会对输入张量进行标准化,并产生具有相同形状的输出张量。 ### 回答2: tf.keras.layers.LayerNormalization中的参数有以下几个: - axis:指定归一化的轴。默认为-1,表示对最后一个轴进行归一化。可以是单个整数或整数列表。如果指定了整数列表,则会对指定的轴进行归一化。 - epsilon:避免分母为零的小量,用于计算标准差和方差时添加到分母上的常数。默认为1e-3。 - center:指示是否在归一化过程中应用平均值偏移。默认为True,表示应用平均值偏移。 - scale:指示是否在归一化过程中应用标准差比例。默认为True,表示应用标准差比例。 - beta_initializer:平均值偏移参数的权重初始化器。默认为'zeros',表示使用0初始化。 - gamma_initializer:标准差比例参数的权重初始化器。默认为'ones',表示使用1初始化。 - beta_regularizer:平均值偏移参数的正则化,用于限制参数的大小。默认为None,表示不使用正则化。 - gamma_regularizer:标准差比例参数的正则化,用于限制参数的大小。默认为None,表示不使用正则化。 - beta_constraint:平均值偏移参数的约束,用于限制参数的范围。默认为None,表示不使用约束。 - gamma_constraint:标准差比例参数的约束,用于限制参数的范围。默认为None,表示不使用约束。 上述参数可以根据具体的需求进行设置,来调整归一化层的行为和效果。通过对数据进行均值偏移和标准差比例缩放,LayerNormalization可以使得不同样本的不同特征具有相似的分布,从而有助于提高模型的训练效果和泛化能力。 ### 回答3: tf.keras.layers.LayerNormalization是一种在神经网络中用于正则化的方法。它的参数如下: - axis: 一个整数或者一个整数列表,表示需要被归一化的轴。默认为-1,表示在最后一个轴进行归一化。 - epsilon: 一个小的精度值,用于避免除零错误。默认为1e-3。 - center: 一个布尔值,表示是否需要进行均值偏置。默认为True,表示进行均值偏置。 - scale: 一个布尔值,表示是否需要进行均方差缩放。默认为True,表示进行均方差缩放。 - trainable: 一个布尔值,表示均值和方差是否可以训练。默认为True,表示可以训练均值和方差。 LayerNormalization通过计算输入数据的均值和方差,然后对输入数据进行标准化处理,使得网络中的每个样本都具有零均值和单位方差的特征。这样可以增强网络的稳定性,改善模型的性能。 通过调整不同的参数可以对LayerNormalization的行为进行调整,例如可以指定需要进行归一化的轴、是否进行均值偏置和均方差缩放等。这些参数可以根据具体的任务和数据集进行调整,以得到最佳的模型性能。
你可以按照以下步骤调用 class MultiHeadAttention(tf.keras.layers.Layer): 1. 首先,导入 tensorflow 库: python import tensorflow as tf 2. 创建一个 MultiHeadAttention 类的实例,并传入所需的参数: python mha = MultiHeadAttention(heads=8, d_model=512, dropout=0.2) 这里的 heads 表示头的数量,d_model 表示模型的维度,dropout 表示 dropout 的概率。 3. 将输入数据传递给 MultiHeadAttention 实例: python output = mha(inputs) 这里的 inputs 是一个形状为 (batch_size, seq_len, d_model) 的张量,表示输入数据的形状。 完整的调用代码示例: python import tensorflow as tf class MultiHeadAttention(tf.keras.layers.Layer): def __init__(self, heads, d_model, dropout): super(MultiHeadAttention, self).__init__() self.heads = heads self.d_model = d_model self.dropout = dropout self.depth = d_model // heads self.Wq = tf.keras.layers.Dense(d_model) self.Wk = tf.keras.layers.Dense(d_model) self.Wv = tf.keras.layers.Dense(d_model) self.dense = tf.keras.layers.Dense(d_model) def split_heads(self, x, batch_size): x = tf.reshape(x, (batch_size, -1, self.heads, self.depth)) return tf.transpose(x, perm=[0, 2, 1, 3]) def call(self, inputs): q = self.Wq(inputs) k = self.Wk(inputs) v = self.Wv(inputs) batch_size = tf.shape(q)[0] q = self.split_heads(q, batch_size) k = self.split_heads(k, batch_size) v = self.split_heads(v, batch_size) scaled_attention, attention_weights = scaled_dot_product_attention(q, k, v) scaled_attention = tf.transpose(scaled_attention, perm=[0, 2, 1, 3]) concat_attention = tf.reshape(scaled_attention, (batch_size, -1, self.d_model)) output = self.dense(concat_attention) return output mha = MultiHeadAttention(heads=8, d_model=512, dropout=0.2) inputs = tf.random.uniform((64, 10, 512)) output = mha(inputs) print(output.shape) 这里的输入数据 inputs 的形状是 (64, 10, 512),表示有 64 个序列,每个序列的长度为 10,每个词的向量维度为 512。输出的形状也是 (64, 10, 512)。

最新推荐

网络技术-综合布线-河南农村宽带客户细分的研究.pdf

网络技术-综合布线-河南农村宽带客户细分的研究.pdf

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire

理解Socket编程的基础概念

# 1. 介绍Socket编程的基本概念 ## 1.1 什么是Socket编程 Socket编程是一种在网络编程中使用的抽象概念,它允许应用程序通过网络进行通信。通过Socket编程,可以实现客户端与服务器端之间的数据交换和通信。 ## 1.2 Socket编程的应用范围 Socket编程广泛应用于网络通信领域,包括但不限于Web服务、即时通讯、网络游戏、远程控制等。 ## 1.3 Socket编程的基本原理 Socket编程基于网络套接字(socket)的概念,通过套接字建立连接、传输数据和关闭连接来实现通信。在Socket编程中,使用不同的协议(如TCP、UDP)来实现数据传输和通信

c语言桌子上有几堆糖果,每堆糖果的数量记录在一个整型数组 nums 中。我们可以每次选择任意一堆,拿走其中的一颗或者两颗糖果,求拿完所有糖果的最少次数。

好的,以下是 C 语言的实现代码: ```c #include <stdio.h> #include <stdlib.h> int min(int a, int b) { return a < b ? a : b; } int minSteps(int* nums, int numsSize) { int dp[numsSize + 1]; dp[0] = 0; dp[1] = 1; for (int i = 2; i <= numsSize; i++) { dp[i] = min(dp[i-1] + 1, dp[i-2] + 1)

供应链管理制度(全).ppt

供应链管理制度

"互动学习:行动中的多样性与论文攻读经历"

多样性她- 事实上SCI NCES你的时间表ECOLEDO C Tora SC和NCESPOUR l’Ingén学习互动,互动学习以行动为中心的强化学习学会互动,互动学习,以行动为中心的强化学习计算机科学博士论文于2021年9月28日在Villeneuve d'Asq公开支持马修·瑟林评审团主席法布里斯·勒菲弗尔阿维尼翁大学教授论文指导奥利维尔·皮耶昆谷歌研究教授:智囊团论文联合主任菲利普·普雷教授,大学。里尔/CRISTAL/因里亚报告员奥利维耶·西格德索邦大学报告员卢多维奇·德诺耶教授,Facebook /索邦大学审查员越南圣迈IMT Atlantic高级讲师邀请弗洛里安·斯特鲁布博士,Deepmind对于那些及时看到自己错误的人...3谢谢你首先,我要感谢我的两位博士生导师Olivier和Philippe。奥利维尔,"站在巨人的肩膀上"这句话对你来说完全有意义了。从科学上讲,你知道在这篇论文的(许多)错误中,你是我可以依

Gunicorn监控和自动化运维

# 1. Gunicorn简介 ### 1.1 什么是Gunicorn Gunicorn是一个轻量级的Python WSGI HTTP服务器,可用于运行Django、Flask等Web应用。它通过将请求传递给应用程序的多个进程来实现并发处理,从而提高Web应用的性能和稳定性。 ### 1.2 Gunicorn的特点和优势 - **简单易用**:Gunicorn易于安装和配置,使用简单。 - **性能稳定**:Gunicorn能够有效管理并发连接,提供稳定的性能。 - **资源占用低**:相较于其他服务器,Gunicorn对资源的消耗相对较低。 - **支持异步处理**:Gunicorn

inno setup 怎么在脚本中设置程序的安装目录

在 Inno Setup 脚本中,你可以使用 `[Setup]` 节点中的 `DefaultDirName` 属性来设置应用程序的安装目录。默认情况下,`DefaultDirName` 属性设置为 `{pf}\{#MyAppPublisher}\{#MyAppName}`,其中 `{pf}` 表示“Program Files”目录,`{#MyAppPublisher}` 和 `{#MyAppName}` 分别表示你在脚本中定义的应用程序发布者和名称。 以下是一个示例脚本,演示如何设置应用程序的安装目录: ``` [Setup] AppName=MyApp AppVersion=1.0 De

中铁隧道集团机械设备管理规则.docx

中铁隧道集团机械设备管理规则.docx

关系数据表示学习

关系数据卢多维奇·多斯桑托斯引用此版本:卢多维奇·多斯桑托斯。关系数据的表示学习机器学习[cs.LG]。皮埃尔和玛丽·居里大学-巴黎第六大学,2017年。英语。NNT:2017PA066480。电话:01803188HAL ID:电话:01803188https://theses.hal.science/tel-01803188提交日期:2018年HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaireUNIVERSITY PIERRE和 MARIE CURIE计算机科学、电信和电子学博士学院(巴黎)巴黎6号计算机科学实验室D八角形T HESIS关系数据表示学习作者:Ludovic DOS SAntos主管:Patrick GALLINARI联合主管:本杰明·P·伊沃瓦斯基为满足计算机科学博士学位的要求而提交的论文评审团成员:先生蒂埃里·A·退休记者先生尤尼斯·B·恩