Skip to content

Commit ac2d2f0

Browse files
committed
updated regression model inline with other models
1 parent 1bef748 commit ac2d2f0

File tree

3 files changed

+113
-27
lines changed

3 files changed

+113
-27
lines changed

regression/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
# Linear regression example
22

33
Trains a single fully-connected layer to fit a 4th degree polynomial.
4+
5+
```bash
6+
pip install -r requirements.txt
7+
python main.py
8+
```

regression/main.py

+106-27
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,47 @@
1-
#!/usr/bin/env python
2-
from __future__ import print_function
3-
from itertools import count
4-
1+
import argparse
52
import torch
63
import torch.nn.functional as F
4+
import torch.optim as optim
5+
from torch.optim.lr_scheduler import StepLR
76

7+
# Polynomial degree and target weights/bias
88
POLY_DEGREE = 4
99
W_target = torch.randn(POLY_DEGREE, 1) * 5
1010
b_target = torch.randn(1) * 5
1111

1212

13+
def parse_args():
14+
"""Command line arguments"""
15+
parser = argparse.ArgumentParser(description='Polynomial Regression Example')
16+
parser.add_argument('--batch-size', type=int, default=32, metavar='N',
17+
help='input batch size for training (default: 32)')
18+
parser.add_argument('--epochs', type=int, default=100, metavar='N',
19+
help='number of epochs to train (default: 100)')
20+
parser.add_argument('--lr', type=float, default=0.1, metavar='LR',
21+
help='learning rate (default: 0.1)')
22+
parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
23+
help='Learning rate step gamma (default: 0.7)')
24+
parser.add_argument('--no-cuda', action='store_true', default=False,
25+
help='disables CUDA training')
26+
parser.add_argument('--log-interval', type=int, default=10, metavar='N',
27+
help='how many batches to wait before logging training status')
28+
parser.add_argument('--save-model', action='store_true', default=False,
29+
help='For saving the current model')
30+
parser.add_argument('--dry-run', action='store_true', default=False,
31+
help='quickly check a single pass')
32+
parser.add_argument('--seed', type=int, default=1, metavar='S',
33+
help='random seed (default: 1)')
34+
return parser.parse_args()
35+
36+
1337
def make_features(x):
1438
"""Builds features i.e. a matrix with columns [x, x^2, x^3, x^4]."""
1539
x = x.unsqueeze(1)
16-
return torch.cat([x ** i for i in range(1, POLY_DEGREE+1)], 1)
40+
return torch.cat([x ** i for i in range(1, POLY_DEGREE + 1)], 1)
1741

1842

1943
def f(x):
20-
"""Approximated function."""
44+
"""Approximated function. function f(x) = W_target * x + b_target"""
2145
return x.mm(W_target) + b_target.item()
2246

2347

@@ -38,31 +62,86 @@ def get_batch(batch_size=32):
3862
return x, y
3963

4064

41-
# Define model
42-
fc = torch.nn.Linear(W_target.size(0), 1)
65+
class PolyRegressor(torch.nn.Module):
66+
"""Define the model (simple linear regression)"""
67+
def __init__(self):
68+
super(PolyRegressor, self).__init__()
69+
self.fc = torch.nn.Linear(POLY_DEGREE, 1)
70+
71+
def forward(self, x):
72+
return self.fc(x)
73+
74+
75+
def train(args, model, device, optimizer, epoch, log_interval=10):
76+
"""Training loop"""
77+
model.train()
78+
for batch_idx in range(1, args.epochs + 1):
79+
# Get a batch of data
80+
batch_x, batch_y = get_batch(args.batch_size)
81+
batch_x, batch_y = batch_x.to(device), batch_y.to(device)
82+
83+
# Reset gradients
84+
optimizer.zero_grad()
85+
86+
# Forward pass
87+
output = model(batch_x)
88+
loss = F.smooth_l1_loss(output, batch_y)
89+
90+
# Backward pass
91+
loss.backward()
92+
93+
# Apply gradients
94+
optimizer.step()
95+
96+
if batch_idx % log_interval == 0:
97+
print(f'Epoch {epoch} Batch {batch_idx}/{args.epochs} Loss: {loss.item():.6f}')
98+
99+
# Dry run for a quick check
100+
if args.dry_run:
101+
break
102+
103+
104+
def test(model, device):
105+
"""Test function (in this case, we'll use it to print the learned function)"""
106+
model.eval()
107+
model.to(device)
108+
with torch.no_grad():
109+
print('==> Learned function:')
110+
print(poly_desc(model.fc.weight.view(-1), model.fc.bias))
111+
print('==> Actual function:')
112+
print(poly_desc(W_target.view(-1), b_target))
113+
114+
115+
def main():
116+
args = parse_args()
117+
118+
# Set the random seed
119+
torch.manual_seed(args.seed)
120+
121+
# Select the device (GPU/CPU)
122+
use_cuda = not args.no_cuda and torch.cuda.is_available()
123+
device = torch.device("cuda" if use_cuda else "cpu")
43124

44-
for batch_idx in count(1):
45-
# Get data
46-
batch_x, batch_y = get_batch()
125+
# Initialize the model, optimizer and scheduler
126+
model = PolyRegressor().to(device)
127+
optimizer = optim.SGD(model.parameters(), lr=args.lr)
128+
scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)
47129

48-
# Reset gradients
49-
fc.zero_grad()
130+
# Training loop
131+
for epoch in range(1, args.epochs + 1):
132+
train(args, model, device, optimizer, epoch, args.log_interval)
133+
scheduler.step()
50134

51-
# Forward pass
52-
output = F.smooth_l1_loss(fc(batch_x), batch_y)
53-
loss = output.item()
135+
# Print the learned function after each epoch
136+
test(model, device)
54137

55-
# Backward pass
56-
output.backward()
138+
if args.save_model:
139+
torch.save(model.state_dict(), "polynomial_regressor.pt")
57140

58-
# Apply gradients
59-
for param in fc.parameters():
60-
param.data.add_(-0.1 * param.grad)
141+
print("Training complete.")
142+
if args.save_model:
143+
print("Model saved to polynomial_regressor.pt")
61144

62-
# Stop criterion
63-
if loss < 1e-3:
64-
break
65145

66-
print('Loss: {:.6f} after {} batches'.format(loss, batch_idx))
67-
print('==> Learned function:\t' + poly_desc(fc.weight.view(-1), fc.bias))
68-
print('==> Actual function:\t' + poly_desc(W_target.view(-1), b_target))
146+
if __name__ == '__main__':
147+
main()

regression/requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
torch
2+
torchvision==0.20.0

0 commit comments

Comments
 (0)