Deeplearning/Qtorch/Models/Qcnn.py

97 lines
3.0 KiB
Python

import torch
import torch.nn as nn
import numpy as np
from Qtorch.Models.Qnn import Qnn
class QCNN(Qnn):
def __init__(
self,
data,
labels=None,
conv_channels=(16, 32),
kernel_size=3,
hidden_size=128,
dropout_rate=0.3,
test_size=0.2,
random_state=None,
batch_size=64,
learning_rate=0.00001,
weight_decay=1e-5,
lr_scheduler_patience=10,
early_stop_patience=100,
early_stop_threshold=0.99,
):
super(QCNN, self).__init__(
data=data,
labels=labels,
test_size=test_size,
random_state=random_state,
batch_size=batch_size,
learning_rate=learning_rate,
weight_decay=weight_decay,
lr_scheduler_patience=lr_scheduler_patience,
early_stop_patience=early_stop_patience,
early_stop_threshold=early_stop_threshold,
)
self.conv_channels = tuple(conv_channels)
self.kernel_size = kernel_size
self.hidden_size = hidden_size
self.dropout_rate = dropout_rate
self.feature_extractor = nn.Sequential()
self.classifier = nn.Sequential()
# 构造 1D CNN 网络结构
self.build_model(input_shape=self.X_train.shape[1:], num_classes=self.num_classes)
self._model_built = True
def _transform_features(self, features):
# 1D CNN 输入格式: [batch, channel=1, length]
return torch.tensor(features, dtype=torch.float32).unsqueeze(1)
def build_model(self, input_shape, num_classes):
if len(self.conv_channels) == 0:
raise ValueError("'conv_channels' must contain at least one channel size.")
input_length = int(np.prod(input_shape))
conv_layers = []
in_channels = 1
for out_channels in self.conv_channels:
conv_layers.append(nn.Conv1d(in_channels=in_channels, out_channels=out_channels, kernel_size=self.kernel_size))
conv_layers.append(nn.ReLU())
conv_layers.append(nn.MaxPool1d(kernel_size=2))
in_channels = out_channels
self.feature_extractor = nn.Sequential(*conv_layers)
conv_output_size = self._get_conv_output_size(input_length)
self.classifier = nn.Sequential(
nn.Linear(conv_output_size, self.hidden_size),
nn.ReLU(),
nn.Dropout(self.dropout_rate),
nn.Linear(self.hidden_size, num_classes),
)
self.__init_weights()
def _get_conv_output_size(self, input_length):
x = torch.randn(1, 1, input_length)
x = self.feature_extractor(x)
return int(x.numel())
def forward(self, x):
x = self.feature_extractor(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
def __init_weights(self):
for m in self.modules():
if isinstance(m, (nn.Conv1d, nn.Linear)):
nn.init.xavier_uniform_(m.weight)
if m.bias is not None:
nn.init.zeros_(m.bias)