# Fashion-MNIST & CIFAR-10 Classification
## 先閱讀
[CNN 筆記](https://hackmd.io/@wilson920430/SJK5mHwtp)
## Fashion-MNIST ([Keras Example](https://www.tensorflow.org/tutorials/keras/classification))
### 資料集說明

70000 張 28x28 黑白圖片(1 channel),可分類成 10 個類別
### Load Datasets
```python=
fashion_mnist = tf.keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
```
### Map values to [0,1]
```python=
train_images = train_images / 255.0
test_images = test_images / 255.0
```
### Define the Network Structure
```python=
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)), # flatten to (28 * 28 = 784 pixels)
tf.keras.layers.Dense(256, activation='relu'), # Fully connected with 256 neurons
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dropout(0.6),
tf.keras.layers.Dense(10)
])
```
### Compile Model, Specify Optimizer and Loss Function
```python=
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
```
### Fit the model to the Training Data & Test Accuracy
```python=
model.fit(train_images, train_labels, epochs=10, batch_size=600)
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2, batch_size=10)
print('\nTest accuracy:', test_acc)
```
### Making Predictions
```python=
probability_model = tf.keras.Sequential([model,
tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)
```
## Fashion-MNIST (Pytorch)
### Define Some Hyper Parameters
```python=
# hyper-params
batch_size = 100
lr = 0.001
epoch = 10
seed = 12345
```
### Load Data
```python=
# load data
train_data = datasets.FashionMNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())
test_data = datasets.FashionMNIST(root='./data', train=False, download=True, transform=transforms.ToTensor())
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False)
```
與 Keras 稍微不同
在 PyTorch 中,```transform=transforms.ToTensor()```就會將數值範圍 Map 到 0~1 之間
### Fix Seed
```python=
def same_seeds(seed):
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True
same_seeds(seed)
```
### Define Network
```python=
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.net = nn.Sequential(
nn.Flatten(),
nn.BatchNorm1d(784),
nn.Linear(784, 64),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.Linear(64, 32),
nn.BatchNorm1d(32),
nn.ReLU(),
nn.Linear(32, 10)
)
def forward(self, x):
x = self.net(x)
return x
```
### Start Training and Evaluating Accuracy
```python=
model = Net().to(device)
# loss function and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
best_acc = 0
for e in range(epoch):
print(f"\nepoch: {e + 1}")
# training
model.train()
for batch, (X, y) in enumerate(train_loader):
pred = model(X)
batch_loss = criterion(pred, y)
optimizer.zero_grad()
batch_loss.backward()
optimizer.step()
if (batch+1) % 10 == 0:
print(f"\rloss: {batch_loss.item()} [{batch_size * (batch+1)}/{len(train_loader.dataset)}]", end='')
# evaluating
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in test_loader:
pred = model(X)
pred_label = pred.argmax(dim=1) # _, pred_label = torch.max(pred, dim=1)
test_loss += criterion(pred, y).item()
correct += (pred_label == y).sum().item()
test_loss /= (len(test_loader.dataset) / batch_size)
correct /= len(test_loader.dataset)
print(f"\nTest Error: Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f}")
if correct > best_acc:
best_acc = correct
torch.save(model.state_dict(), "model.pth")
print("Best Model Saved")
print(f"\nBest Model: Accuracy: {(100 * best_acc):>0.1f}% \n")
```
選擇將 Test Accuracy 最高的 Model 儲存
最後最高的 Accuracy 可以達到 89%
因為圖片不複雜,用這樣多層 Linear 即可達到不錯效果,且運算效率高
也有嘗試用 CNN 做,效果差不多,但 CNN 要耗費較高的運算資源
## CIFAR-10 (Pytorch)
### 資料集說明

60000 張 32x32 彩色圖片(3 channels),可分類成 10 個類別
50000 張 For training,10000 張 For testing
> Briefly, they are 18% test error without data augmentation and 11% with.
文件表示:沒有 Data Augmentation 時,可達 82% 正確率;而有 Data Augmentation 時,可達 89%
程式與 [Fashion-MNIST (Pytorch)](#Fashion-MNIST-Pytorch) 相似,以下僅說明新增或不同的部份
### Transform Methods
```python=
train_trans_method = transforms.Compose([
transforms.RandomCrop(32, padding=4),
transforms.RandomHorizontalFlip(p=0.5),
transforms.ToTensor(), # This will map the pixels to 0~1
transforms.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2023, 0.1994, 0.2010]), # map the pixels to -1~1
])
test_trans_method = transforms.Compose([
transforms.ToTensor(), # This will map the pixels to 0~1
transforms.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2023, 0.1994, 0.2010]), # map the pixels to -1~1
])
```
### Load Data and Inspect
```python=
# load data
train_data = datasets.CIFAR10(root='./data', train=True, download=True, transform=train_trans_method)
test_data = datasets.CIFAR10(root='./data', train=False, download=True, transform=test_trans_method)
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False)
print(f"Train Data Shape: {np.shape(train_data.data)}")
print(f"Test Data Shape: {np.shape(test_data.data)}")
class_names = train_data.classes # 10 item array
```
### Network
```python=
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.net = nn.Sequential(
# 32*32, 3
nn.Conv2d(3, 100, kernel_size=3),
nn.BatchNorm2d(100),
nn.ReLU(),
nn.MaxPool2d(2),
# 15*15, 100
nn.Conv2d(100, 50, kernel_size=4),
nn.BatchNorm2d(50),
nn.ReLU(),
nn.MaxPool2d(2),
# 6*6, 50
nn.Conv2d(50, 30, kernel_size=3),
nn.BatchNorm2d(30),
nn.ReLU(),
nn.MaxPool2d(2),
# 2*2, 30
nn.Flatten(),
nn.Linear(120, 10)
)
def forward(self, x):
x = self.net(x)
return x
```
### 結果
Test Accuacy: 77.0% Correct
測試時可加上以下 Code 查看辨識錯誤的圖片
```python=
saved_model.eval()
with torch.no_grad():
for X, y in test_loader:
pred = saved_model(X)
pred_label = pred.argmax(dim=1)
for i, identical in enumerate(pred_label == y):
if not identical:
plt.figure()
plt.imshow(X[i].squeeze().T * .5 + .5, cmap=plt.cm.binary)
plt.grid(False)
plt.xlabel(f"pred: {class_names[pred_label[i]]} / ans: {class_names[y[i]]}")
plt.show()
os.system("pause")
```