### 修改TensorFlow代码以保存和加载预训练模型
为避免每次运行代码时都重新训练模型,可以将训练好的模型保存到文件中,并在后续运行时检查是否存在已保存的模型。如果存在,则直接加载模型;否则进行训练并保存模型。以下是修改后的完整代码示例:
```python
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, LSTM, Dense, Dropout, Bidirectional
from tensorflow.keras.models import Model
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
import re
import os
# 数据预处理函数
def preprocess_text(texts):
"""中文文本预处理:保留汉字、数字和常见标点"""
processed = []
for text in texts:
cleaned = re.sub(r'[^\u4e00-\u9fa5\d\s,。?、!:;‘’“”()《》【】]', '', text)
processed.append(cleaned.strip())
return processed
# 检查模型是否已存在
def model_exists():
return os.path.exists('smart_home_binary_model.h5') and os.path.exists('smart_home_multi_task_model.h5')
if not model_exists():
print("开始训练模型...")
# 加载数据
binary_df = pd.read_csv('binary_dataset.csv') # 假设有8000条数据
multi_df = pd.read_csv('multi_dataset.csv') # 假设有4000条数据
# 数据预处理
binary_texts = preprocess_text(binary_df['text'].tolist())
binary_labels = binary_df['label'].values
multi_texts = preprocess_text(multi_df['text'].tolist())
loc_labels = multi_df['location'].values
dev_labels = multi_df['device'].values
switch_labels = multi_df['switch'].values
# 创建Tokenizer并拟合文本
tokenizer = Tokenizer(char_level=True, oov_token='<OOV>')
tokenizer.fit_on_texts(binary_texts + multi_texts) # 使用全部数据拟合tokenizer
vocab_size = len(tokenizer.word_index) + 1
# 文本转序列与填充
max_len = 30
binary_sequences = tokenizer.texts_to_sequences(binary_texts)
binary_padded = pad_sequences(binary_sequences, maxlen=max_len, padding='post', truncating='post')
multi_sequences = tokenizer.texts_to_sequences(multi_texts)
multi_padded = pad_sequences(multi_sequences, maxlen=max_len, padding='post', truncating='post')
# 划分训练测试集
X_binary_train, X_binary_test, y_binary_train, y_binary_test = train_test_split(binary_padded, binary_labels, test_size=0.2, random_state=42)
X_multi_train, X_multi_test, y_loc_train, y_loc_test, y_dev_train, y_dev_test, y_switch_train, y_switch_test = train_test_split(multi_padded, loc_labels, dev_labels, switch_labels, test_size=0.2, random_state=42)
# 编码标签
loc_encoder = LabelEncoder()
dev_encoder = LabelEncoder()
y_loc_train = loc_encoder.fit_transform(y_loc_train)
y_loc_test = loc_encoder.transform(y_loc_test)
y_dev_train = dev_encoder.fit_transform(y_dev_train)
y_dev_test = dev_encoder.transform(y_dev_test)
# 构建二分类模型
def build_binary_model():
inputs = Input(shape=(max_len,))
x = Embedding(vocab_size, 128)(inputs)
x = Bidirectional(LSTM(64, return_sequences=True))(x)
x = Bidirectional(LSTM(32))(x)
x = Dense(32, activation='relu')(x)
x = Dropout(0.5)(x)
outputs = Dense(1, activation='sigmoid')(x)
model = Model(inputs=inputs, outputs=outputs)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# 构建多任务模型
def build_multi_task_model():
inputs = Input(shape=(max_len,))
x = Embedding(vocab_size, 128)(inputs)
x = Bidirectional(LSTM(64, return_sequences=True))(x)
x = Bidirectional(LSTM(32))(x)
x = Dense(64, activation='relu')(x)
x = Dropout(0.5)(x)
loc_out = Dense(len(loc_encoder.classes_), activation='softmax', name='location')(x)
dev_out = Dense(len(dev_encoder.classes_), activation='softmax', name='device')(x)
switch_out = Dense(1, activation='sigmoid', name='switch')(x)
model = Model(inputs=inputs, outputs=[loc_out, dev_out, switch_out])
model.compile(optimizer='adam',
loss={'location': 'sparse_categorical_crossentropy',
'device': 'sparse_categorical_crossentropy',
'switch': 'binary_crossentropy'},
metrics={'location': 'accuracy', 'device': 'accuracy', 'switch': 'accuracy'})
return model
# 加载或训练二分类模型
binary_model_path = 'smart_home_binary_model.h5'
if os.path.exists(binary_model_path):
binary_model = tf.keras.models.load_model(binary_model_path)
else:
binary_model = build_binary_model()
batch_size_binary = 64
epochs_binary = 20
binary_history = binary_model.fit(X_binary_train, y_binary_train, epochs=epochs_binary, batch_size=batch_size_binary, validation_data=(X_binary_test, y_binary_test), verbose=1)
binary_model.save(binary_model_path)
# 加载或训练多任务模型
multi_task_model_path = 'smart_home_multi_task_model.h5'
if os.path.exists(multi_task_model_path):
multi_task_model = tf.keras.models.load_model(multi_task_model_path)
else:
multi_task_model = build_multi_task_model()
batch_size_multi = 32
epochs_multi = 30
multi_history = multi_task_model.fit(X_multi_train, {'location': y_loc_train, 'device': y_dev_train, 'switch': y_switch_train},
epochs=epochs_multi, batch_size=batch_size_multi,
validation_data=(X_multi_test, {'location': y_loc_test, 'device': y_dev_test, 'switch': y_switch_test}),
verbose=1)
multi_task_model.save(multi_task_model_path)
# 定义智能助手类
class SmartHomeAssistant:
def __init__(self):
self.binary_model = tf.keras.models.load_model(binary_model_path)
self.multi_task_model = tf.keras.models.load_model(multi_task_model_path)
self.tokenizer = tokenizer
self.loc_encoder = loc_encoder
self.dev_encoder = dev_encoder
self.device_mapping = {
'ac': '空调',
'light': '灯',
'tv': '电视',
'curtain': '窗帘',
}
self.location_mapping = {
'bedroom': '卧室',
'living_room': '客厅',
'kitchen': '厨房',
'bathroom': '卫生间',
}
def predict(self, text):
cleaned_text = preprocess_text([text])[0]
sequence = self.tokenizer.texts_to_sequences([cleaned_text])
padded = pad_sequences(sequence, maxlen=max_len, padding='post', truncating='post')
is_command_prob = self.binary_model.predict(padded, verbose=0)[0][0]
is_command = is_command_prob > 0.5
if not is_command:
return {
"is_command": False,
"probability": float(is_command_prob),
"message": "这是普通对话,不是控制指令"
}
loc_pred, dev_pred, switch_pred = self.multi_task_model.predict(padded, verbose=0)
location_idx = np.argmax(loc_pred[0])
device_idx = np.argmax(dev_pred[0])
switch_state = switch_pred[0][0] > 0.5
location = self.loc_encoder.inverse_transform([location_idx])[0]
device = self.dev_encoder.inverse_transform([device_idx])[0]
action = "打开" if switch_state else "关闭"
loc_name = self.location_mapping.get(location, location)
dev_name = self.device_mapping.get(device, device)
return {
"is_command": True,
"location": location,
"device": device,
"switch": bool(switch_state),
"probability": float(is_command_prob),
"message": f"检测到控制指令: {loc_name}的{dev_name}{action}吗?",
"command_details": {
"action": action,
"location": loc_name,
"device": dev_name
}
}
# 使用示例
if __name__ == "__main__":
assistant = SmartHomeAssistant()
test_commands = [
"帮我打开卧室的空调",
"客厅的灯关一下",
"今天天气怎么样",
"厨房的暖气调高一点"
]
for cmd in test_commands:
print(f"输入: {cmd}")
result = assistant.predict(cmd)
print(f"结果: {result['message']}")
if result['is_command']:
print(f"详细解析: 位置={result['command_details']['location']}, "
f"设备={result['command_details']['device']}, "
f"操作={result['command_details']['action']}")
print("-" * 50)
```
#### 为什么之前的回复中出现了PyTorch而非TensorFlow?
之前的回复中错误地使用了PyTorch框架,而用户的需求是基于TensorFlow的解决方案[^1]。这可能是由于混淆了用户的实际需求与通用的深度学习框架示例。为了准确满足用户需求,上述代码完全基于TensorFlow实现,并提供了保存和加载模型的功能。