# 1、生成训练集...h_k(x)=1/(1+e^(-k^*x)),k为参数,这里设置为[1.3,-1.0]
num_inputs = 2 # 特征数
num_examples = 1000 # 训练数据集样本数
true_k = [1.3, -1.0]
features = tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
labels = 1 / (1 + torch.exp(-1 * (true_k[0] * features[:, 0] + true_k[1] * features[:, 1])))
# 加入噪声
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)
num0 = 0
num1 = 0
for i in range(num_examples):
if labels[i] < 0.5:
labels[i] = 0
num0 += 1
else:
labels[i] = 1
num1 += 1
# print(labels)
labels = labels.view(num_examples, 1)
print(num0, num1)
# 2、读取数据
def train_data_loader(batch_size, features, labels):
num_exp = len(features)
indices = list(range(num_exp))
random.shuffle(indices) # 打乱样本顺序
for i in range(0, num_exp, batch_size):
j = torch.LongTensor(indices[i:min(i + batch_size, num_exp)]) # 最后一次可能不足batch
yield features.index_select(0, j), labels.index_select(0, j) # 维度,索引
# yield关键字:带yield的函数是一个生成器,只有调用函数时函数才会执行
# next(函数):每次执行到yield处会return,下一次调用next时从上一次停止的地方继续执行至yield处
# 函数.send(num)会将num值送入上一次停止的地方,再执行next
k = torch.normal(0, 1.0, (num_inputs, 1), dtype=torch.float32) # 训练参数随机初始化
# k = tensor([[0.5], [-0.5]], dtype=torch.float32)
k.requires_grad_(True)
def logistic_regression(x, k):
return 1 / (1 + torch.exp(-1 * torch.mm(x, k)))
这里没有从零开始实现二元交叉熵损失函数,使用了torch.nn.BCELoss函数
# 3.2 损失函数和优化算法
# def bce_loss(y_hat, y):
# return -1 * (y * torch.log10(y_hat) + (1 - y) * torch.log10(1 - y_hat)) 单个样本的损失
def sgd(params, lr, batch_size):
for param in params:
param.data -= lr * param.grad / batch_size # 这里更改param时用的param.data
# 3.3 模型训练
lr = 0.03
num_epochs = 20
batch_size = 10
net = logistic_regression
loss = torch.nn.BCELoss()
for epoch in range(num_epochs): # 一共进行num_epoch个迭代周期
# 每个epoch会遍历使用一遍所有的训练集样本
for x, y in train_data_loader(batch_size, features, labels):
# x,y是一个batch的样本特征和标签
y_hat = net(x, k)
l = loss(y_hat, y)
l.backward() # 求梯度
sgd([k], lr, batch_size)
k.grad.data.zero_() # 梯度清零
train_l = loss(net(features, k), labels) # 计算训练样本的损失
print('epoch %d, loss %f' % (epoch + 1, train_l.item()))
print('k', k)