{"id":1190,"date":"2025-10-24T07:51:00","date_gmt":"2025-10-23T23:51:00","guid":{"rendered":"https:\/\/www.laoyulaoyu.com\/?p=1190"},"modified":"2025-10-23T19:45:40","modified_gmt":"2025-10-23T11:45:40","slug":"%e5%80%9f%e5%8a%a9-transformer-%e5%ae%9e%e7%8e%b0%e7%be%8e%e8%82%a1%e4%bb%b7%e6%a0%bc%e7%9a%84%e9%a2%84%e6%b5%8b%ef%bc%88python%e5%b9%b2%e8%b4%a7%ef%bc%89","status":"publish","type":"post","link":"https:\/\/laoyulaoyu.com\/index.php\/2025\/10\/24\/%e5%80%9f%e5%8a%a9-transformer-%e5%ae%9e%e7%8e%b0%e7%be%8e%e8%82%a1%e4%bb%b7%e6%a0%bc%e7%9a%84%e9%a2%84%e6%b5%8b%ef%bc%88python%e5%b9%b2%e8%b4%a7%ef%bc%89\/","title":{"rendered":"\u501f\u52a9 Transformer \u5b9e\u73b0\u7f8e\u80a1\u4ef7\u683c\u7684\u9884\u6d4b\uff08Python\u5e72\u8d27\uff09"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<p>\u4f5c\u8005\uff1a<a href=\"https:\/\/www.laoyulaoyu.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">\u8001\u4f59\u635e\u9c7c<\/a><\/p>\n\n\n\n<p><strong><mark style=\"background-color:#ffffff\" class=\"has-inline-color has-cyan-bluish-gray-color\">\u539f\u521b\u4e0d\u6613\uff0c\u8f6c\u8f7d\u8bf7\u6807\u660e\u51fa\u5904\u53ca\u539f\u4f5c\u8005\u3002<\/mark><\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/06\/4-1024x567.jpg\" alt=\"\" class=\"wp-image-68\"\/><\/figure>\n\n\n\n<p><strong>\u5199\u5728\u524d\u9762\u7684\u8bdd\uff1a<\/strong>Transformer \u662f\u4e00\u79cd\u5728\u81ea\u7136\u8bed\u8a00\u5904\u7406\u7b49\u9886\u57df\u5e7f\u6cdb\u5e94\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u67b6\u6784\uff0c\u4e0e\u4f20\u7edf\u7684\u5faa\u73af\u795e\u7ecf\u7f51\u7edc\uff08RNN\uff09\u76f8\u6bd4\uff0cTransformer \u53ef\u4ee5\u5e76\u884c\u5904\u7406\u8f93\u5165\u5e8f\u5217\u7684\u5404\u4e2a\u4f4d\u7f6e\uff0c\u5927\u5927\u63d0\u9ad8\u4e86\u8ba1\u7b97\u6548\u7387\u3002\u800c\u4e14\u901a\u8fc7\u591a\u5c42\u7684\u6df1\u5ea6\u5806\u53e0\uff0c\u80fd\u591f\u5b66\u4e60\u5230\u66f4\u590d\u6742\u548c\u62bd\u8c61\u7684\u7279\u5f81\u8868\u793a\u3002\u672c\u6587\u5c06\u5229\u7528Python\u4ee3\u7801\u6765\u5b9e\u73b0\u7f8e\u80a1\u4ef7\u683c\u7684\u9884\u6d4b\u6a21\u62df\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>\u8bdd\u4e0d\u591a\u8bf4\uff0c\u4ee3\u7801\u5982\u4e0b\uff1a<\/strong>\n<li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li><li style=\"margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; list-style-type: none; text-align: right;\"><\/li>\nimport numpy as np\nimport pandas as pd\nimport os, datetime\nimport tensorflow as tf\nfrom tensorflow.keras.models import *\nfrom tensorflow.keras.layers import *\nprint('Tensorflow version: {}'.format(tf.__version__))\n\nimport matplotlib.pyplot as plt\nplt.style.use('seaborn')\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\nphysical_devices = tf.config.list_physical_devices()\nprint('Physical devices: {}'.format(physical_devices))\n\n# Filter out the CPUs and keep only the GPUs\ngpus = &#91;device for device in physical_devices if 'GPU' in device.device_type]\n\n# If GPUs are available, set memory growth to True\nif len(gpus) > 0:\n    tf.config.experimental.set_visible_devices(gpus&#91;0], 'GPU')\n    tf.config.experimental.set_memory_growth(gpus&#91;0], True)\n    print('GPU memory growth: True')<\/code><\/pre>\n\n\n\n<p>Tensorflow version: 2.9.1<br>Physical devices: [PhysicalDevice(name=&#8217;\/physical_device:CPU:0&#8242;, device_type=&#8217;CPU&#8217;)]<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Hyperparameters<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>batch_size = 32\nseq_len = 128\n\nd_k = 256\nd_v = 256\nn_heads = 12\nff_dim = 256<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Load IBM data<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>IBM_path = 'IBM.csv'<\/code><code>\n<\/code><code>df = pd.read_csv(IBM_path, delimiter=',', usecols=&#91;'Date', 'Open', 'High', 'Low', 'Close', 'Volume'])<\/code><code>\n<\/code><code><em># Replace 0 to avoid dividing by 0 later on<\/em><\/code><code>df&#91;'Volume'].replace(to_replace=0, method='ffill', inplace=True) <\/code><code>df.sort_values('Date', inplace=True)<\/code><code>df.tail()<\/code> df.head()<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640.png\" alt=\"\" class=\"wp-image-1191\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-1.png\" alt=\"\" class=\"wp-image-1192\"\/><\/figure>\n\n\n\n<ul class=\"wp-block-list\"><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><code><em># print the shape of the dataset<\/em><\/code><code>print('Shape of the dataframe: {}'.format(df.shape))<\/code>Shape of the dataframe: (14588, 6)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Plot daily IBM closing prices and volume<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>fig = plt.figure(figsize=(15,10))<\/code><code>st = fig.suptitle(\"IBM Close Price and Volume\", fontsize=20)<\/code><code>st.set_y(0.92)<\/code><code><br><\/code><code>ax1 = fig.add_subplot(211)<\/code><code>ax1.plot(df&#91;'Close'], label='IBM Close Price')<\/code><code>ax1.set_xticks(range(0, df.shape&#91;0], 1464))<\/code><code>ax1.set_xticklabels(df&#91;'Date'].loc&#91;::1464])<\/code><code>ax1.set_ylabel('Close Price', fontsize=18)<\/code><code>ax1.legend(loc=\"upper left\", fontsize=12)<\/code><code><br><\/code><code>ax2 = fig.add_subplot(212)<\/code><code>ax2.plot(df&#91;'Volume'], label='IBM Volume')<\/code><code>ax2.set_xticks(range(0, df.shape&#91;0], 1464))<\/code><code>ax2.set_xticklabels(df&#91;'Date'].loc&#91;::1464])<\/code><code>ax2.set_ylabel('Volume', fontsize=18)<\/code><code>ax2.legend(loc=\"upper left\", fontsize=12)<\/code><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-2-1024x703.jpg\" alt=\"\" class=\"wp-image-1193\" style=\"width:645px;height:auto\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Calculate normalized percentage change of all columns<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>'''Calculate percentage change'''<\/code><code><br><\/code><code>df&#91;'Open'] = df&#91;'Open'].pct_change() <em># Create arithmetic returns column<\/em><\/code><code>df&#91;'High'] = df&#91;'High'].pct_change() <em># Create arithmetic returns column<\/em><\/code><code>df&#91;'Low'] = df&#91;'Low'].pct_change() <em># Create arithmetic returns column<\/em><\/code><code>df&#91;'Close'] = df&#91;'Close'].pct_change() <em># Create arithmetic returns column<\/em><\/code><code>df&#91;'Volume'] = df&#91;'Volume'].pct_change()<\/code><code><br><\/code><code>df.dropna(how='any', axis=0, inplace=True) <em># Drop all rows with NaN values<\/em><\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code>'''Create indexes to split dataset'''<\/code><code><br><\/code><code>times = sorted(df.index.values)<\/code><code>last_10pct = sorted(df.index.values)&#91;-int(0.1*len(times))] <em># Last 10% of series<\/em><\/code><code>last_20pct = sorted(df.index.values)&#91;-int(0.2*len(times))] <em># Last 20% of series<\/em><\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code>'''Normalize price columns'''<\/code><code><em>#<\/em><\/code><code>min_return = min(df&#91;(df.index &lt; last_20pct)]&#91;&#91;'Open', 'High', 'Low', 'Close']].min(axis=0))<\/code><code>max_return = max(df&#91;(df.index &lt; last_20pct)]&#91;&#91;'Open', 'High', 'Low', 'Close']].max(axis=0))<\/code><code><br><\/code><code><em># Min-max normalize price columns (0-1 range)<\/em><\/code><code>df&#91;'Open'] = (df&#91;'Open'] - min_return) \/ (max_return - min_return)<\/code><code>df&#91;'High'] = (df&#91;'High'] - min_return) \/ (max_return - min_return)<\/code><code>df&#91;'Low'] = (df&#91;'Low'] - min_return) \/ (max_return - min_return)<\/code><code>df&#91;'Close'] = (df&#91;'Close'] - min_return) \/ (max_return - min_return)<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code>'''Normalize volume column'''<\/code><code><br><\/code><code>min_volume = df&#91;(df.index &lt; last_20pct)]&#91;'Volume'].min(axis=0)<\/code><code>max_volume = df&#91;(df.index &lt; last_20pct)]&#91;'Volume'].max(axis=0)<\/code><code><br><\/code><code><em># Min-max normalize volume columns (0-1 range)<\/em><\/code><code>df&#91;'Volume'] = (df&#91;'Volume'] - min_volume) \/ (max_volume - min_volume)<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code>'''Create training, validation and test split'''<\/code><code><br><\/code><code>df_train = df&#91;(df.index &lt; last_20pct)]  <em># Training data are 80% of total data<\/em><\/code><code>df_val = df&#91;(df.index &gt;= last_20pct) &amp; (df.index &lt; last_10pct)]<\/code><code>df_test = df&#91;(df.index &gt;= last_10pct)]<\/code><code><br><\/code><code><em># Remove date column<\/em><\/code><code>df_train.drop(columns=&#91;'Date'], inplace=True)<\/code><code>df_val.drop(columns=&#91;'Date'], inplace=True)<\/code><code>df_test.drop(columns=&#91;'Date'], inplace=True)<\/code><code><br><\/code><code><em># Convert pandas columns into arrays<\/em><\/code><code>train_data = df_train.values<\/code><code>val_data = df_val.values<\/code><code>test_data = df_test.values<\/code><code>print('Training data shape: {}'.format(train_data.shape))<\/code><code>print('Validation data shape: {}'.format(val_data.shape))<\/code><code>print('Test data shape: {}'.format(test_data.shape))<\/code><code><br><\/code><code>df_train.head()<\/code><\/code><\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">Training data shape: (11678, 5)<br>Validation data shape: (1460, 5)<br>Test data shape: (1459, 5)<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-3.png\" alt=\"\" class=\"wp-image-1196\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Plot daily changes of close prices and volume<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\"><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><code>fig = plt.figure(figsize=(15,12))<\/code><code>st = fig.suptitle(\"Data Separation\", fontsize=20)<\/code><code>st.set_y(0.95)<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code><br><\/code><code>ax1 = fig.add_subplot(211)<\/code><code>ax1.plot(np.arange(train_data.shape&#91;0]), df_train&#91;'Close'], label='Training data')<\/code><code><br><\/code><code>ax1.plot(np.arange(train_data.shape&#91;0], <\/code><code>                   train_data.shape&#91;0]+val_data.shape&#91;0]), df_val&#91;'Close'], label='Validation data')<\/code><code><br><\/code><code>ax1.plot(np.arange(train_data.shape&#91;0]+val_data.shape&#91;0], <\/code><code>                   train_data.shape&#91;0]+val_data.shape&#91;0]+test_data.shape&#91;0]), df_test&#91;'Close'], label='Test data')<\/code><code>ax1.set_xlabel('Date')<\/code><code>ax1.set_ylabel('Normalized Closing Returns')<\/code><code>ax1.set_title(\"Close Price\", fontsize=18)<\/code><code>ax1.legend(loc=\"best\", fontsize=12)<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code><br><\/code><code>ax2 = fig.add_subplot(212)<\/code><code>ax2.plot(np.arange(train_data.shape&#91;0]), df_train&#91;'Volume'], label='Training data')<\/code><code><br><\/code><code>ax2.plot(np.arange(train_data.shape&#91;0], <\/code><code>                   train_data.shape&#91;0]+val_data.shape&#91;0]), df_val&#91;'Volume'], label='Validation data')<\/code><code><br><\/code><code>ax2.plot(np.arange(train_data.shape&#91;0]+val_data.shape&#91;0], <\/code><code>                   train_data.shape&#91;0]+val_data.shape&#91;0]+test_data.shape&#91;0]), df_test&#91;'Volume'], label='Test data')<\/code><code>ax2.set_xlabel('Date')<\/code><code>ax2.set_ylabel('Normalized Volume Changes')<\/code><code>ax2.set_title(\"Volume\", fontsize=18)<\/code><code>ax2.legend(loc=\"best\", fontsize=12)<\/code><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-4-1024x891.jpg\" alt=\"\" class=\"wp-image-1197\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Create chunks of training, validation and test data<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code><em># Training data<\/em><\/code><code>X_train, y_train = &#91;], &#91;]<\/code><code>for i in range(seq_len, len(train_data)):<\/code><code>  X_train.append(train_data&#91;i-seq_len:i]) <em># Chunks of training data with a length of 128 df-rows<\/em><\/code><code>  y_train.append(train_data&#91;:, 3]&#91;i]) <em>#Value of 4th column (Close Price) of df-row 128+1<\/em><\/code><code>X_train, y_train = np.array(X_train), np.array(y_train)<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code><br><\/code><code><em># Validation data<\/em><\/code><code>X_val, y_val = &#91;], &#91;]<\/code><code>for i in range(seq_len, len(val_data)):<\/code><code>    X_val.append(val_data&#91;i-seq_len:i])<\/code><code>    y_val.append(val_data&#91;:, 3]&#91;i])<\/code><code>X_val, y_val = np.array(X_val), np.array(y_val)<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code><br><\/code><code><em># Test data<\/em><\/code><code>X_test, y_test = &#91;], &#91;]<\/code><code>for i in range(seq_len, len(test_data)):<\/code><code>    X_test.append(test_data&#91;i-seq_len:i])<\/code><code>    y_test.append(test_data&#91;:, 3]&#91;i])    <\/code><code>X_test, y_test = np.array(X_test), np.array(y_test)<\/code><code><br><\/code><code>print('Training set shape', X_train.shape, y_train.shape)<\/code><code>print('Validation set shape', X_val.shape, y_val.shape)<\/code><code>print('Testing set shape' ,X_test.shape, y_test.shape)<\/code><\/code><\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">Training set shape (11550, 128, 5) (11550,)<br>Validation set shape (1332, 128, 5) (1332,)<br>Testing set shape (1331, 128, 5) (1331,)<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>TimeVector<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\"><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><code>class Time2Vector(Layer):<\/code><code>  def __init__(self, seq_len, **kwargs):<\/code><code>    super(Time2Vector, self).__init__()<\/code><code>    self.seq_len = seq_len<\/code><code><br><\/code><code>  def build(self, input_shape):<\/code><code>    '''Initialize weights and biases with shape (batch, seq_len)'''<\/code><code>    self.weights_linear = self.add_weight(name='weight_linear',<\/code><code>                                shape=(int(self.seq_len),),<\/code><code>                                initializer='uniform',<\/code><code>                                trainable=True)<\/code><code>    <\/code><code>    self.bias_linear = self.add_weight(name='bias_linear',<\/code><code>                                shape=(int(self.seq_len),),<\/code><code>                                initializer='uniform',<\/code><code>                                trainable=True)<\/code><code>    <\/code><code>    self.weights_periodic = self.add_weight(name='weight_periodic',<\/code><code>                                shape=(int(self.seq_len),),<\/code><code>                                initializer='uniform',<\/code><code>                                trainable=True)<\/code><code><br><\/code><code>    self.bias_periodic = self.add_weight(name='bias_periodic',<\/code><code>                                shape=(int(self.seq_len),),<\/code><code>                                initializer='uniform',<\/code><code>                                trainable=True)<\/code><code><br><\/code><code>  def call(self, x):<\/code><code>    '''Calculate linear and periodic time features'''<\/code><code>    x = tf.math.reduce_mean(x&#91;:,:,:4], axis=-1) <\/code><code>    time_linear = self.weights_linear * x + self.bias_linear <em># Linear time feature<\/em><\/code><code>    time_linear = tf.expand_dims(time_linear, axis=-1) <em># Add dimension (batch, seq_len, 1)<\/em><\/code><code>    <\/code><code>    time_periodic = tf.math.sin(tf.multiply(x, self.weights_periodic) + self.bias_periodic)<\/code><code>    time_periodic = tf.expand_dims(time_periodic, axis=-1) <em># Add dimension (batch, seq_len, 1)<\/em><\/code><code>    return tf.concat(&#91;time_linear, time_periodic], axis=-1) <em># shape = (batch, seq_len, 2)<\/em><\/code><code>   <\/code><code>  def get_config(self): <em># Needed for saving and loading model with custom layer<\/em><\/code><code>    config = super().get_config().copy()<\/code><code>    config.update({'seq_len': self.seq_len})<\/code><code>    return config<\/code><\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Transformer<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>class SingleAttention(Layer):<\/code><code>  def __init__(self, d_k, d_v):<\/code><code>    super(SingleAttention, self).__init__()<\/code><code>    self.d_k = d_k<\/code><code>    self.d_v = d_v<\/code><code><br><\/code><code>  def build(self, input_shape):<\/code><code>    self.query = Dense(self.d_k, <\/code><code>                       input_shape=input_shape, <\/code><code>                       kernel_initializer='glorot_uniform', <\/code><code>                       bias_initializer='glorot_uniform')<\/code><code>    <\/code><code>    self.key = Dense(self.d_k, <\/code><code>                     input_shape=input_shape, <\/code><code>                     kernel_initializer='glorot_uniform', <\/code><code>                     bias_initializer='glorot_uniform')<\/code><code>    <\/code><code>    self.value = Dense(self.d_v, <\/code><code>                       input_shape=input_shape, <\/code><code>                       kernel_initializer='glorot_uniform', <\/code><code>                       bias_initializer='glorot_uniform')<\/code><code><br><\/code><code>  def call(self, inputs): <em># inputs = (in_seq, in_seq, in_seq)<\/em><\/code><code>    q = self.query(inputs&#91;0])<\/code><code>    k = self.key(inputs&#91;1])<\/code><code><br><\/code><code>    attn_weights = tf.matmul(q, k, transpose_b=True)<\/code><code>    attn_weights = tf.map_fn(lambda x: x\/np.sqrt(self.d_k), attn_weights)<\/code><code>    attn_weights = tf.nn.softmax(attn_weights, axis=-1)<\/code><code>    <\/code><code>    v = self.value(inputs&#91;2])<\/code><code>    attn_out = tf.matmul(attn_weights, v)<\/code><code>    return attn_out    <\/code><code><br><\/code><code><em>#############################################################################<\/em><\/code><code><br><\/code><code>class MultiAttention(Layer):<\/code><code>  def __init__(self, d_k, d_v, n_heads):<\/code><code>    super(MultiAttention, self).__init__()<\/code><code>    self.d_k = d_k<\/code><code>    self.d_v = d_v<\/code><code>    self.n_heads = n_heads<\/code><code>    self.attn_heads = list()<\/code><code><br><\/code><code>  def build(self, input_shape):<\/code><code>    for n in range(self.n_heads):<\/code><code>      self.attn_heads.append(SingleAttention(self.d_k, self.d_v))  <\/code><code>    <\/code><code>    <em># input_shape&#91;0]=(batch, seq_len, 7), input_shape&#91;0]&#91;-1]=7 <\/em><\/code><code>    self.linear = Dense(input_shape&#91;0]&#91;-1], <\/code><code>                        input_shape=input_shape, <\/code><code>                        kernel_initializer='glorot_uniform', <\/code><code>                        bias_initializer='glorot_uniform')<\/code><code><br><\/code><code>  def call(self, inputs):<\/code><code>    attn = &#91;self.attn_heads&#91;i](inputs) for i in range(self.n_heads)]<\/code><code>    concat_attn = tf.concat(attn, axis=-1)<\/code><code>    multi_linear = self.linear(concat_attn)<\/code><code>    return multi_linear   <\/code><code><br><\/code><code><em>#############################################################################<\/em><\/code><code><br><\/code><code>class TransformerEncoder(Layer):<\/code><code>  def __init__(self, d_k, d_v, n_heads, ff_dim, dropout=0.1, **kwargs):<\/code><code>    super(TransformerEncoder, self).__init__()<\/code><code>    self.d_k = d_k<\/code><code>    self.d_v = d_v<\/code><code>    self.n_heads = n_heads<\/code><code>    self.ff_dim = ff_dim<\/code><code>    self.attn_heads = list()<\/code><code>    self.dropout_rate = dropout<\/code><code><br><\/code><code>  def build(self, input_shape):<\/code><code>    self.attn_multi = MultiAttention(self.d_k, self.d_v, self.n_heads)<\/code><code>    self.attn_dropout = Dropout(self.dropout_rate)<\/code><code>    self.attn_normalize = LayerNormalization(input_shape=input_shape, epsilon=1e-6)<\/code><code><br><\/code><code>    self.ff_conv1D_1 = Conv1D(filters=self.ff_dim, kernel_size=1, activation='relu')<\/code><code>    <em># input_shape&#91;0]=(batch, seq_len, 7), input_shape&#91;0]&#91;-1] = 7 <\/em><\/code><code>    self.ff_conv1D_2 = Conv1D(filters=input_shape&#91;0]&#91;-1], kernel_size=1) <\/code><code>    self.ff_dropout = Dropout(self.dropout_rate)<\/code><code>    self.ff_normalize = LayerNormalization(input_shape=input_shape, epsilon=1e-6)    <\/code><code>  <\/code><code>  def call(self, inputs): <em># inputs = (in_seq, in_seq, in_seq)<\/em><\/code><code>    attn_layer = self.attn_multi(inputs)<\/code><code>    attn_layer = self.attn_dropout(attn_layer)<\/code><code>    attn_layer = self.attn_normalize(inputs&#91;0] + attn_layer)<\/code><code><br><\/code><code>    ff_layer = self.ff_conv1D_1(attn_layer)<\/code><code>    ff_layer = self.ff_conv1D_2(ff_layer)<\/code><code>    ff_layer = self.ff_dropout(ff_layer)<\/code><code>    ff_layer = self.ff_normalize(inputs&#91;0] + ff_layer)<\/code><code>    return ff_layer <\/code><code><br><\/code><code>  def get_config(self): <em># Needed for saving and loading model with custom layer<\/em><\/code><code>    config = super().get_config().copy()<\/code><code>    config.update({'d_k': self.d_k,<\/code><code>                   'd_v': self.d_v,<\/code><code>                   'n_heads': self.n_heads,<\/code><code>                   'ff_dim': self.ff_dim,<\/code><code>                   'attn_heads': self.attn_heads,<\/code><code>                   'dropout_rate': self.dropout_rate})<\/code><code>    return config<\/code><\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Model<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>def create_model():<\/code><code>  '''Initialize time and transformer layers'''<\/code><code>  time_embedding = Time2Vector(seq_len)<\/code><code>  attn_layer1 = TransformerEncoder(d_k, d_v, n_heads, ff_dim)<\/code><code>  attn_layer2 = TransformerEncoder(d_k, d_v, n_heads, ff_dim)<\/code><code>  attn_layer3 = TransformerEncoder(d_k, d_v, n_heads, ff_dim)<\/code><code>\n<\/code><code>  '''Construct model'''<\/code><code>  in_seq = Input(shape=(seq_len, 5))<\/code><code>  x = time_embedding(in_seq)<\/code><code>  x = Concatenate(axis=-1)(&#91;in_seq, x])<\/code><code>  x = attn_layer1((x, x, x))<\/code><code>  x = attn_layer2((x, x, x))<\/code><code>  x = attn_layer3((x, x, x))<\/code><code>  x = GlobalAveragePooling1D(data_format='channels_first')(x)<\/code><code>  x = Dropout(0.1)(x)<\/code><code>  x = Dense(64, activation='relu')(x)<\/code><code>  x = Dropout(0.1)(x)<\/code><code>  out = Dense(1, activation='linear')(x)<\/code><code>\n<\/code><code>  model = Model(inputs=in_seq, outputs=out)<\/code><code>  model.compile(loss='mse', optimizer='adam', metrics=&#91;'mae', 'mape'])<\/code><code>  return model<\/code><code>\n<\/code><code>\n<\/code><code>model = create_model()<\/code><code>model.summary()<\/code><code>\n<\/code><code>callback = tf.keras.callbacks.ModelCheckpoint('Transformer+TimeEmbedding.hdf5', <\/code><code>                                              monitor='val_loss', <\/code><code>                                              save_best_only=True, verbose=1)<\/code><code>\n<\/code><code>history = model.fit(X_train, y_train, <\/code><code>                    batch_size=batch_size, <\/code><code>                    epochs=35, <\/code><code>                    callbacks=&#91;callback],<\/code><code>                    validation_data=(X_val, y_val))  <\/code><code>\n<\/code><code>model = tf.keras.models.load_model('Transformer+TimeEmbedding.hdf5',<\/code><code>                                   custom_objects={'Time2Vector': Time2Vector, <\/code><code>                                                   'SingleAttention': SingleAttention,<\/code><code>                                                   'MultiAttention': MultiAttention,<\/code><code>                                                   'TransformerEncoder': TransformerEncoder})<\/code><code>\n<\/code><code>\n<\/code><code><em>###############################################################################<\/em><\/code><code>'''Calculate predictions and metrics'''<\/code><code>\n<\/code><code><em>#Calculate predication for training, validation and test data<\/em><\/code><code>train_pred = model.predict(X_train)<\/code><code>val_pred = model.predict(X_val)<\/code><code>test_pred = model.predict(X_test)<\/code><code>\n<\/code><code><em>#Print evaluation metrics for all datasets<\/em><\/code><code>train_eval = model.evaluate(X_train, y_train, verbose=0)<\/code><code>val_eval = model.evaluate(X_val, y_val, verbose=0)<\/code><code>test_eval = model.evaluate(X_test, y_test, verbose=0)<\/code><code>print(' ')<\/code><code>print('Evaluation metrics')<\/code><code>print('Training Data - Loss: {:.4f}, MAE: {:.4f}, MAPE: {:.4f}'.format(train_eval&#91;0], train_eval&#91;1], train_eval&#91;2]))<\/code><code>print('Validation Data - Loss: {:.4f}, MAE: {:.4f}, MAPE: {:.4f}'.format(val_eval&#91;0], val_eval&#91;1], val_eval&#91;2]))<\/code><code>print('Test Data - Loss: {:.4f}, MAE: {:.4f}, MAPE: {:.4f}'.format(test_eval&#91;0], test_eval&#91;1], test_eval&#91;2]))<\/code><code>\n<\/code><code><em>###############################################################################<\/em><\/code><code>'''Display results'''<\/code><code>\n<\/code><code>fig = plt.figure(figsize=(15,20))<\/code><code>st = fig.suptitle(\"Transformer + TimeEmbedding Model\", fontsize=22)<\/code><code>st.set_y(0.92)<\/code><code>\n<\/code><code><em>#Plot training data results<\/em><\/code><code>ax11 = fig.add_subplot(311)<\/code><code>ax11.plot(train_data&#91;:, 3], label='IBM Closing Returns')<\/code><code>ax11.plot(np.arange(seq_len, train_pred.shape&#91;0]+seq_len), train_pred, linewidth=3, label='Predicted IBM Closing Returns')<\/code><code>ax11.set_title(\"Training Data\", fontsize=18)<\/code><code>ax11.set_xlabel('Date')<\/code><code>ax11.set_ylabel('IBM Closing Returns')<\/code><code>ax11.legend(loc=\"best\", fontsize=12)<\/code><code>\n<\/code><code><em>#Plot validation data results<\/em><\/code><code>ax21 = fig.add_subplot(312)<\/code><code>ax21.plot(val_data&#91;:, 3], label='IBM Closing Returns')<\/code><code>ax21.plot(np.arange(seq_len, val_pred.shape&#91;0]+seq_len), val_pred, linewidth=3, label='Predicted IBM Closing Returns')<\/code><code>ax21.set_title(\"Validation Data\", fontsize=18)<\/code><code>ax21.set_xlabel('Date')<\/code><code>ax21.set_ylabel('IBM Closing Returns')<\/code><code>ax21.legend(loc=\"best\", fontsize=12)<\/code><code>\n<\/code><code><em>#Plot test data results<\/em><\/code><code>ax31 = fig.add_subplot(313)<\/code><code>ax31.plot(test_data&#91;:, 3], label='IBM Closing Returns')<\/code><code>ax31.plot(np.arange(seq_len, test_pred.shape&#91;0]+seq_len), test_pred, linewidth=3, label='Predicted IBM Closing Returns')<\/code><code>ax31.set_title(\"Test Data\", fontsize=18)<\/code><code>ax31.set_xlabel('Date')<\/code><code>ax31.set_ylabel('IBM Closing Returns')<\/code><code>ax31.legend(loc=\"best\", fontsize=12)<\/code><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-5-753x1024.jpg\" alt=\"\" class=\"wp-image-1198\" style=\"width:645px;height:auto\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code><em>###############################################################################<\/em><\/code><code>'''Calculate predictions and metrics'''<\/code><code><br><\/code><code><em>#Calculate predication for training, validation and test data<\/em><\/code><code>train_pred = model.predict(X_train)<\/code><code>val_pred = model.predict(X_val)<\/code><code>test_pred = model.predict(X_test)<\/code><code><br><\/code><code><em>#Print evaluation metrics for all datasets<\/em><\/code><code>train_eval = model.evaluate(X_train, y_train, verbose=0)<\/code><code>val_eval = model.evaluate(X_val, y_val, verbose=0)<\/code><code>test_eval = model.evaluate(X_test, y_test, verbose=0)<\/code><code>print(' ')<\/code><code>print('Evaluation metrics')<\/code><code>print('Training Data - Loss: {:.4f}, MAE: {:.4f}, MAPE: {:.4f}'.format(train_eval&#91;0], train_eval&#91;1], train_eval&#91;2]))<\/code><code>print('Validation Data - Loss: {:.4f}, MAE: {:.4f}, MAPE: {:.4f}'.format(val_eval&#91;0], val_eval&#91;1], val_eval&#91;2]))<\/code><code>print('Test Data - Loss: {:.4f}, MAE: {:.4f}, MAPE: {:.4f}'.format(test_eval&#91;0], test_eval&#91;1], test_eval&#91;2]))<\/code><code><br><\/code><code><em>###############################################################################<\/em><\/code><code>'''Display results'''<\/code><code><br><\/code><code>fig = plt.figure(figsize=(15,20))<\/code><code>st = fig.suptitle(\"Transformer + TimeEmbedding Model\", fontsize=22)<\/code><code>st.set_y(0.92)<\/code><code><br><\/code><code><em>#Plot training data results<\/em><\/code><code>ax11 = fig.add_subplot(311)<\/code><code>ax11.plot(train_data&#91;:, 3], label='IBM Closing Returns')<\/code><code>ax11.plot(np.arange(seq_len, train_pred.shape&#91;0]+seq_len), train_pred, linewidth=3, label='Predicted IBM Closing Returns')<\/code><code>ax11.set_title(\"Training Data\", fontsize=18)<\/code><code>ax11.set_xlabel('Date')<\/code><code>ax11.set_ylabel('IBM Closing Returns')<\/code><code>ax11.legend(loc=\"best\", fontsize=12)<\/code><code><br><\/code><code><em>#Plot validation data results<\/em><\/code><code>ax21 = fig.add_subplot(312)<\/code><code>ax21.plot(val_data&#91;:, 3], label='IBM Closing Returns')<\/code><code>ax21.plot(np.arange(seq_len, val_pred.shape&#91;0]+seq_len), val_pred, linewidth=3, label='Predicted IBM Closing Returns')<\/code><code>ax21.set_title(\"Validation Data\", fontsize=18)<\/code><code>ax21.set_xlabel('Date')<\/code><code>ax21.set_ylabel('IBM Closing Returns')<\/code><code>ax21.legend(loc=\"best\", fontsize=12)<\/code><code><br><\/code><code><em>#Plot test data results<\/em><\/code><code>ax31 = fig.add_subplot(313)<\/code><code>ax31.plot(test_data&#91;:, 3], label='IBM Closing Returns')<\/code><code>ax31.plot(np.arange(seq_len, test_pred.shape&#91;0]+seq_len), test_pred, linewidth=3, label='Predicted IBM Closing Returns')<\/code><code>ax31.set_title(\"Test Data\", fontsize=18)<\/code><code>ax31.set_xlabel('Date')<\/code><code>ax31.set_ylabel('IBM Closing Returns')<\/code><code>ax31.legend(loc=\"best\", fontsize=12)<\/code><\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Model metrics<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>'''Display model metrics'''<\/code><code><br><\/code><code>fig = plt.figure(figsize=(15,20))<\/code><code>st = fig.suptitle(\"Transformer + TimeEmbedding Model Metrics\", fontsize=22)<\/code><code>st.set_y(0.92)<\/code><code><br><\/code><code><em>#Plot model loss<\/em><\/code><code>ax1 = fig.add_subplot(311)<\/code><code>ax1.plot(history.history&#91;'loss'], label='Training loss (MSE)')<\/code><code>ax1.plot(history.history&#91;'val_loss'], label='Validation loss (MSE)')<\/code><code>ax1.set_title(\"Model loss\", fontsize=18)<\/code><code>ax1.set_xlabel('Epoch')<\/code><code>ax1.set_ylabel('Loss (MSE)')<\/code><code>ax1.legend(loc=\"best\", fontsize=12)<\/code><code><br><\/code><code><em>#Plot MAE<\/em><\/code><code>ax2 = fig.add_subplot(312)<\/code><code>ax2.plot(history.history&#91;'mae'], label='Training MAE')<\/code><code>ax2.plot(history.history&#91;'val_mae'], label='Validation MAE')<\/code><code>ax2.set_title(\"Model metric - Mean average error (MAE)\", fontsize=18)<\/code><code>ax2.set_xlabel('Epoch')<\/code><code>ax2.set_ylabel('Mean average error (MAE)')<\/code><code>ax2.legend(loc=\"best\", fontsize=12)<\/code><code><br><\/code><code><em>#Plot MAPE<\/em><\/code><code>ax3 = fig.add_subplot(313)<\/code><code>ax3.plot(history.history&#91;'mape'], label='Training MAPE')<\/code><code>ax3.plot(history.history&#91;'val_mape'], label='Validation MAPE')<\/code><code>ax3.set_title(\"Model metric - Mean average percentage error (MAPE)\", fontsize=18)<\/code><code>ax3.set_xlabel('Epoch')<\/code><code>ax3.set_ylabel('Mean average percentage error (MAPE)')<\/code><code>ax3.legend(loc=\"best\", fontsize=12)<\/code><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-6-758x1024.jpeg\" alt=\"\" class=\"wp-image-1199\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Model architecture overview<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>tf.keras.utils.plot_model(<br>model,<br>to_file=\"IBM_Transformer+TimeEmbedding.png\",<br>show_shapes=True,<br>show_layer_names=True,<br>expand_nested=True,<br>dpi=96,)<br>tf.keras.utils.plot_model(<br>model,<br>to_file=\"IBM_Transformer+TimeEmbedding.png\",<br>show_shapes=True,<br>show_layer_names=True,<br>expand_nested=True,<br>dpi=96,)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Moving Average<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Moving Average &#8211; Load IBM data again, to apply rolling window<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code><code>IBM_path = 'IBM.csv'<\/code><code><br><\/code><code>df = pd.read_csv(IBM_path, delimiter=',', usecols=&#91;'Date', 'Open', 'High', 'Low', 'Close', 'Volume'])<\/code><code><br><\/code><code><em># Replace 0 to avoid dividing by 0 later on<\/em><\/code><code>df&#91;'Volume'].replace(to_replace=0, method='ffill', inplace=True) <\/code><code>df.sort_values('Date', inplace=True)<\/code><code><br><\/code><code><em># Apply moving average with a window of 10 days to all columns<\/em><\/code><code>df&#91;&#91;'Open', 'High', 'Low', 'Close', 'Volume']] = df&#91;&#91;'Open', 'High', 'Low', 'Close', 'Volume']].rolling(10).mean() <\/code><code><br><\/code><code><em># Drop all rows with NaN values<\/em><\/code><code>df.dropna(how='any', axis=0, inplace=True) <\/code><code>df.head()<\/code><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-7.png\" alt=\"\" class=\"wp-image-1200\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Moving Average &#8211; Plot daily IBM closing prices and volume<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\"><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><code>fig = plt.figure(figsize=(15,10))<\/code><code>st = fig.suptitle(\"IBM Close Price and Volume\", fontsize=20)<\/code><code>st.set_y(0.92)<\/code><code><br><\/code><code>ax1 = fig.add_subplot(211)<\/code><code>ax1.plot(df&#91;'Close'], label='IBM Close Price')<\/code><code>ax1.set_xticks(range(0, df.shape&#91;0], 1464))<\/code><code>ax1.set_xticklabels(df&#91;'Date'].loc&#91;::1464])<\/code><code>ax1.set_ylabel('Close Price', fontsize=18)<\/code><code>ax1.legend(loc=\"upper left\", fontsize=12)<\/code><code><br><\/code><code>ax2 = fig.add_subplot(212)<\/code><code>ax2.plot(df&#91;'Volume'], label='IBM Volume')<\/code><code>ax2.set_xticks(range(0, df.shape&#91;0], 1464))<\/code><code>ax2.set_xticklabels(df&#91;'Date'].loc&#91;::1464])<\/code><code>ax2.set_ylabel('Volume', fontsize=18)<\/code><code>ax2.legend(loc=\"upper left\", fontsize=12)<\/code><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.laoyulaoyu.com\/wp-content\/uploads\/2024\/08\/640-8-1024x703.jpeg\" alt=\"\" class=\"wp-image-1201\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-text-align-center\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-cyan-bluish-gray-color\">\u672c\u6587\u5185\u5bb9\u4ec5\u4ec5\u662f\u6280\u672f\u63a2\u8ba8\u548c\u5b66\u4e60\uff0c\u5e76\u4e0d\u6784\u6210\u4efb\u4f55\u6295\u8d44\u5efa\u8bae\u3002<\/mark><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4f5c\u8005\uff1a\u8001\u4f59\u635e\u9c7c \u539f\u521b\u4e0d\u6613\uff0c\u8f6c\u8f7d\u8bf7\u6807\u660e\u51fa\u5904\u53ca\u539f\u4f5c\u8005\u3002&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/laoyulaoyu.com\/index.php\/2025\/10\/24\/%e5%80%9f%e5%8a%a9-transformer-%e5%ae%9e%e7%8e%b0%e7%be%8e%e8%82%a1%e4%bb%b7%e6%a0%bc%e7%9a%84%e9%a2%84%e6%b5%8b%ef%bc%88python%e5%b9%b2%e8%b4%a7%ef%bc%89\/\">Continue reading<span class=\"screen-reader-text\">\u501f\u52a9 Transformer \u5b9e\u73b0\u7f8e\u80a1\u4ef7\u683c\u7684\u9884\u6d4b\uff08Python\u5e72\u8d27\uff09<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[5,6],"class_list":["post-1190","post","type-post","status-publish","format-standard","hentry","category-aiinvest","tag-ai","tag-6","entry"],"_links":{"self":[{"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/posts\/1190","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/comments?post=1190"}],"version-history":[{"count":2,"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/posts\/1190\/revisions"}],"predecessor-version":[{"id":2867,"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/posts\/1190\/revisions\/2867"}],"wp:attachment":[{"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/media?parent=1190"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/categories?post=1190"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/laoyulaoyu.com\/index.php\/wp-json\/wp\/v2\/tags?post=1190"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}