Hiển thị các bài đăng có nhãn Neural Network. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Neural Network. Hiển thị tất cả bài đăng

Chủ Nhật, 6 tháng 1, 2019

[Python Programming] Pytorch experiences

github.com/yeulam1thienthan/-Udacity-Deep-Learning-with-Pytorch
  • Miscelaneous

Trong các bài toán NN, khi ta đưa đầu vào, thường là các vector, ta cần làm phẳng (flattening out) input. Ví dụ đầu vào là 1 tập 64 ảnh gray size 28x28, khi này input tensor sẽ là (64,1,28,28) với 64 là thể hiện số ảnh. 1 thể hiện độ sáng của ảnh gray từ 0 - 255, ảnh có 28 hàng và 28 cột tương ứng với 784 pixels. Thông thường, với hidden layer ngay cạnh input layer số gồm 784 units ứng với 784 features của input, do đó ta sẽ cần làm phẳng input tensor từ (64,1,28,28) thành (64,784).
Pytorch cung cấp cho ta hàm tối ưu nhất so với torch.reshape và torch.resize đó là torch.view.
Khi dùng torch.view, thay vì ta truyền thẳng các chiều của tensor như. torch.view(64,784), ta chỉ cần dùng torch.view(input.shape[0], -1). Khi này input.shape[0] là 64, và khi tham số thứ 2 là -1, pytorch sẽ tự hiểu là ta muốn reshape với số chiều thứ 2 là tích của các chiều còn lại.


  • Train 1 mạng NN

Pytorch cung cấp hàm loss cross-entropy(nn.CrossEntropyLoss). Đầu vào của hàm này phải là score cho từng class thay vì xác xuất cho từng class khi ta cho đầu ra đi qua hàm soft-max. Ví dụ như sau:


Ở đây ta sử dụng cross-entropy là hàm loss, và input của hàm này là đầu ra của model(images) cùng với lavel cho trước.

Pytorch cũng hỗ trợ các module cho việc tính toán back-propagation và gradient-descent. Ví dụ ta muốn train một mạng fully-connected NN với 5 epochs cho tập dữ liệu MNIST, hàm loss.backward() sẽ thực hiện đạo hàm, và việc update các ma trận W sẽ được thực hiện bởi optimizer.step().

Khi đó, với 1 sample ngẫu nhiên từ tập dataset, ta có thể dự đoán chính xác.


  • Lưu và load 1 mạng NN được train sẵn
Khi mô hình ta đã được train, ta có thể lưu các thông số của mô hình cho các dự đoán tiếp theo mà không cần train lại từ đầu, ta sẽ tìm hiểu cách để lưu và load một pre-trained model trong Pytorch.
Giả sử ta có một class Network trong fc_model, khi đó ta khởi tạo mạng NN như sau:

Cũng trong fc_model, ta gọi method train để tìm ra thông số cho mạng NN này.

Lúc này, tất cả các thông tin của mạng NN được lưu trong model.state_dict() là 1 dictionary. Ta sẽ lưu các thông số này vào 1 file checkpoint.pth sau đó load lại vào state_dict và hiển thị.

Ta cũng có thể xây dựng 1 mạng NN mới và thay thế các thông số của mạng đó bằng thông số của mạng NN đã được lưu, khi đó ta tạo 1 mạng mới và load các thông sô.
Tuy nhiên ta sẽ có lỗi do size của mạng NN được lưu và mạng NN mới khởi tạo không giống nhau, do đó ở bước thay thế các thông số của mạng mới tạo bằng các thông số của mạng lưu sẵn sẽ xảy ra lỗi.

Để tránh vấn đề này, khi lưu model, ta không chỉ lưu các parameters của model đó (W, b) mà còn nên lưu các hyperparameters bằng cách thêm các hyperparameters này khi ta lưu vào checkpoint.pth.
Khi đó, ta cũng có thể tạo 1 hàm dành cho việc load model này.


  • Các bước xây dựng 1 mô hình NN trong Pytorch
Đầu tiên ta phải import các thư viện cần thiết của torch, ví dụ:

Tiếp theo ta load input data và preprocess các dữ liệu này.

Tiếp đó ta định nghĩa kiến trúc của mạng NN, ví dụ ta đang muốn sử dụng Transfer Learning dùng DenseNet121, lúc này ta sẽ lấy feature detection part của DenseNet121 là tự xây dựng classification part. Load mô hình DenseNet121 như sau:
Do đang thực hiện Transfer Learning, ta sẽ phải freeze các thông số của feature detection và định nghĩa là classification để thay thế, ví dụ dữ liệu ta đang có chỉ yêu cầu 2 đầu ra, mà dữ liệu của DenseNet là 1000. Sau đó ta cần định nghĩa làm loss và bộ optimizer:

Bây giờ ta đã có kiến trúc mạng như mong muốn, ta có thể train mô hình và sử dụng cho việc dự đoán. Tập dữ liệu là rất lớn do đó việc train mô hình trên GPU sẽ giúp tiết kiếm thời gian rất nhiều.
NOTE: net.eval() will set all the layers in your model to evaluation mode. This affects layers like dropout layers that turn "off" nodes during training with some probability, but should allow every node to be "on" for evaluation. So, you should set your model to evaluation mode before testing or validating your model, and before, for example, sampling and making predictions about the likely next character in a given sequence. I'll set net.train()` (training mode) only during the training loop.

  • Operations
Để cộng hoặc trừ hai tensor a và b trong pytorch, ta có thể dùng a + b, torch.add(a,b), toán tử y.add_(x)  sẽ trả về y = y + x.

Mọi toán tử giữa hai tensor mà có hậu tố _ như x.copy_(y hoặc x.t_() đều sẽ thay đổi giá trị x.
Khi tensor của ta chỉ có 1 phần tử, ta cần sử dụng .item() để có thể lấy giá trị trị của tensor đó.

>>> x = torch.rand(1)
>>> print(x)
tensor([0.1541])
>>> x.item()
0.15414464473724365

Pytorch cung cấp cho ta các toán tử hầu như giống hệt numpy, và ta còn có thể chuyển đổi kiểu dữ liệu từ numpy sang tensor và ngược lại.

>>> a = torch.ones(5)
>>> a
tensor([1., 1., 1., 1., 1.])
>>> b = a.numpy()
>>> b
array([1., 1., 1., 1., 1.], dtype=float32)
>>> a = torch.from_numpy(b)
>>> a
tensor([2., 2., 2., 2., 2.])

Mọi loại tensors trên CPU ngoại trừ CharTensor đều hỗ trợ việc chuyển đổi sang numpy và ngược lại.


  • CNN trong Pytorch
Trong phân loại ảnh, CIFAR-10 là một tập dữ liệu nổi tiếng và thường thấy để kiểm chứng 1 mô hình. Một số hình ảnh của CIFAR-10 như sau:

Khác với MLP (Multi Layer Perceptron) khi ta sử dụng các linear và fully-connected layers, trong một CNN sẽ bao gồm.
- Convolutional layers: Là tập hợp của các bộ lọc ảnh (image filters) liên tiếp nhau ví dụ.
trong hình trên, 4 bộ lọc khác nhau tạ ra 4 ảnh đầu ra khác nhau, khi ta stack các ảnh này lại, ta tạo ra được một convolutional layer với chiều sâu (depth) là 4.

- Maxpooling layers để giảm kích thước của đầu vào, lúc này ta chỉ giữ lại các giá trị quan trọng nhất trong một cửa sổ. Ví dụ của số là 2x2 với 4 pixel, ta sẽ chỉ lấy 1 giá trị pixel quan trọng nhất, do đó chiều x và y của ảnh sẽ được giảm đi 2 lần với mỗi chiều.
- Linear và Dropout layers để tránh overfitting và sinh ra output.

  • Convolutional Layer trong Pytorch
Ta định nghĩa 1 convolutional layer như sau:
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0)
trong forward, ta sử dụng layer này để xử lý input:
x = F.relu(self.conv1(x))
Giải thích các đầu vào như sau:
  • in_channels - Chiều sâu của dữ liệu đầu vào, ví dụ với ảnh RGB, depth = 3 và ảnh gray thì depth = 1
  • out_channels - Số filters mà ta muốn áp dụng vào ảnh đầu vào, với số filter là K này, đầu ra của ta sẽ là K ảnh.
  • kernel_size - Chiều dài = chiều rộng của convolutional kernel (hay filter)
Ngoài ra còn 1 số tham số khác
  • stride - Chiều dài trượt của kernel, stride được set mặc định là 1
  • padding - Chiều dài ta muốn thêm vào ảnh ở đường biên, mặc định padding được set là 0.
Ngoài ra còn Pooling layer để ta có thể giảm kích thước của ảnh đầu ra sau 1 convolutional layer (tránh overfitting).
self.pool = nn.MaxPool2d(2,2)
Ở đây kernel_size = 2 và stride = 2. Ở trong hàm forward(), hàm pooling được sử dụng sau conv layer.
x = F.relu(self.conv1(x))
x = self.pool(x)
Ví dụ: Ta xây dựng 1 CNN, đầu vào là ảnh gray có kích thước 200x200 do đó nó là 1 mảng 3 chiều có chiều dài 200, rộng 200 và sâu 1.
self.conv1 = nn.Conv2d(1, 16, 2, stride=2)
Đầu vào này được xử lý bởi 16 filters, mỗi filter có chiều dài là 2 và rộng là 2, độ trượt stride = 2 và ta không muốn thêm padding vào đầu input.

Tiếp theo, đầu ra của conv1 sẽ là 16 ảnh khác nhau sau khi đi qua 16 filters. Ta định nghĩa 1 conv kế tiếp có 32 filters có chiều dài và rộng là 3, độ trượt stride = 1 và padding 1 vào đường biên.

self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
Ta có thể thấy đầu vào của conv2 chính là depth của đầu ra sau conv1, vì conv1 có 16 filters nên depth sẽ cũng chính là 16.

Tiếp theo ta sẽ tìm hiểu cách tính toán size của 1 ảnh sau khi qua 1 conv layer.
Ta định nghĩa.

  • K - Số filter của 1 conv layer
  • F - Chiều dài và rộng của 1filter
  • D_in - Depth của layer trước đó, ví dụ layer trước đó là input thì depth là 3 hoặc 1 tương đương với ảnh RGB hay gray. Hoặc là 16 với ví dụ trên khi ta đang xét conv2.
Do vậy, số lượng tham số của 1 filter là F*F*D_in và ta có K filters, do đó số lượng weight sẽ là   K*F*F*D_in.

Ta nhắc lại một số định nghĩa và thêm một số khác.

  • K - Số filter của 1 conv layer
  • F - Chiều dài và rộng của 1filter
  • S - Độ trượt của kernel
  • P - Padding
  • W_in - Là D_in, depth của layer trước đó, ví dụ layer trước đó là input thì depth là 3 hoặc 1 tương đương với ảnh RGB hay gray. Hoặc là 16 với ví dụ trên khi ta đang xét conv2.
Ta lưu ý rằng depth của 1 conv layer sẽ luôn là số lượng filter K.
Khi đó, size của 1 ảnh khi đi qua 1 conv layer được tính là:
((W_in−F+2P)/S)+1 (*)

Ta thử làm một bài toán, dưới với ảnh đầu vào có size là 130x130 và có depth là 3 ứng với ảnh RGB.
nn.Conv2d(3, 10, 3) <--- conv1
nn.MaxPool2d(4, 4) <- maxpool1
nn.Conv2d(10, 20, 5, padding=2) <---- conv2
nn.MaxPool2d(2, 2) <- maxpool2
Khi này depth của output sẽ là depth của conv2 là 20.
Đầu tiên dựa vào công thức (*) ta có size của ảnh sau khi qua conv1.
Với conv1:
W_in = 130
F = 3
P = 0
S = 1 (by default if not specified)

W_out_conv1 = ((130-3+2x0)/1) +1 = 128 (size 128x128)
Khi qua maxpool1, size ảnh sẽ là 128/4 = 32 (size 32x32)
Với conv2:
W_in = 32
F = 5
P = 2
S = 1
W_out_con2 = ((32-5+2x2)/1) +1 = 32 (size 32x32)
Khi qua maxpool2, size ảnh là 32/2 = 16 (size 16x16)

Khi này, output cuối cùng sẽ là 20*16*16

  • Data Augmentation
Khi ta train một mô hình phức tạp, gồm nhiều thông số trong mạng cần tìm, số lượng dữ liệu cần thiết là rất lớn. Do vậy, nếu số lượng dữ liệu của ta không đủ lớn, ta có thể làm gì? Trong thực tế việc tìm kiếm thêm dữ liệu đôi khi không cần thiết, ví dụ như trong ảnh dưới đây, 1 mạng neuron chưa được train tốt sẽ không phân biệt được 3 ảnh này là giống nhau.
Do đó, nếu ta muốn có thêm dữ liệu, ta chỉ cần sửa đổi một chút dữ liệu sẵn có ví dụ như ta đảo chiều ảnh, xoay ảnh hay dịch ảnh, khi đó mạng NN sẽ có thể được train tốt hơn. Kỹ thuật này được gọi là Data Augmentation như minh họa dưới đây.


Các kỹ thuật ta có thể làm bao gồm:
- Flip
Lật ảnh theo chiều dọc hoặc ngang
- Rotation
Xoay 90 độ theo chiều kim đồng hồ
- Scale/Crop
Ảnh đã được scale in 10 và 20%
- Translation
Ảnh dược dịch qua phải là dịch lên trên
- Gaussian Noise
Thêm nhiễu Gaussian
Ngoài ra còn một số kỹ thuật nâng cao khác như GAN, Style transfer, ta có thể đọc thêm từ đây.
https://medium.com/nanonets/how-to-use-deep-learning-when-you-have-limited-data-part-2-data-augmentation-c26971dc8ced

Trong Pytorch, toán tử transforms được dùng để ta có thể thực hiện data augmentation một cách cơ bản như xoay ảnh và lật ảnh, scale/crop. 


Thứ Năm, 27 tháng 12, 2018

[Machine Learning] Deep neural network vs shallow neural network

Trong bài trước, khi ta nhắc đến shallow neural network, ta hiểu rằng đây là mạng nơ ron mà chỉ có một hoặc hai hidden layer, thực ra con số này là không định lượng, việc ta nói shallow và deep chỉ để phân biệt rằng hai kiến trúc mạng một kiến trúc sử dụng số lượng nhỏ và mạng còn lại sử dụng số lượng lớn hidden layer. Trái lại, trong deep neural network, số lượng hidden layer lớn hơn nhiều. Như đã nói ở trước, khi nói về số lớp của 1 mạng, ta sẽ bỏ qua input layer, do đó với hình dưới đây, logistic regression cũng có thể coi là một mạng neuron với chỉ 1 lớp.

Khi thực hiện tính toán forward propagation và back propagation trong Deep NN, ta cũng phải thực hiện tuần tự qua từng layer, ví dụ như với hình trên là 2 hidden layer, khi này ta sẽ phải lần lượt tính z1, a1, z2, a2 tương ứng với 2 hidden layer. 
Ta nên để ý và phân biệt rõ 2 khái niệm: hidden layer và layer của 1 mạng khi layer của 1 mạng được hiểu như là số lượng hidden layer cộng với 1 output layer.
Ngoài ta, ta sẽ có 1 vòng loop trong việc thực hiện FP và BP, ví dụ ta có n hidden layers, khi đó vòng loop của ta sẽ phải chạy qua n layer. Trái với việc tính toán trước đó ta có thể dùng vectorization, việc tính toán BP và FP không thể áp dụng vectorization và ta phải lặp qua từng layer để tính toán các giá trị W, b hay a, z.

Ngoài ra, ở layer input, ta nên chú ý rằng x1,x2,x3 chỉ là input feature của 1 sample, do đó khi có m samples, thì input vector sẽ là [mx3] với 3 là số feature của 1 input, mỗi hàng là 1 sample trong input vector.

Tiếp theo ta nói về size của các tham số trong 1 mạng Deep NN.
Giả sử ta có một Deep NN như hình dưới đây, khi đó, với mỗi layer, ta kí hiện n^[k] là số unit của layer đó, ví dụ với input layer, mỗi sample được biểu diễn bởi 2 feature, do đó n^[0] = 2, tương tự n^[1] = 3.
Các w và b của các layer có số chiều tổng quát là:
W[L] = n^[L]xn^[L-1].
Ví dụ W[2] = n^[2] x n^[1] = [5x3]
b là bias của các unit trong 1 layer, do đó nếu 1 layer có n^[L] units, thì chiều của b[L] = [n^[L] x 1]
Để tính BP, dw và db có cùng số chiều với w và b

Khi ta có 1 sample, chiều của z[L] hay a[L] là [n^[L] x 1]
Khi có m sample, chiều của z[L] hay a[L] là [n^[L] x m]

Thứ Ba, 25 tháng 12, 2018

[Machine Learning] Đạo hàm của các activation functions

Như ta đã nhắc đến lúc trước, đạo hàm của 1 hàm tại một điểm là độ dốc (slope) của hàm đó tại điểm đó. Ví dụ với hàm sigmoid.
Với giá trị lớn (z = 10) hoặc z nhỏ (-10), ta có thể thấy giá trị đạo hàm tính theo công thức = 0 ứng với các vùng bão hòa của sigmoid function.
Với giá trị z - 0, g(z) = 1/2 và g'(z) = 1/4 nghĩ là độ dốc của sigmoid tại điểm z = 0 là lớn.

Ngoài ra với hàm tanh, đạo hàm là tương đương với sigmoid ngoại trừ các điểm ở chính giữa đồ thị.



Cuối cùng là hàm RELU và Leaky RELU.

Thứ Ba, 4 tháng 12, 2018

[Natural Language Processing] Giới thiệu về RNN trong xử lý ngôn ngữ tự nhiên

RNN là một biến thể của mạng neuron (Neraul Network) trong đó ta có thể xử lý các chuỗi dữ liệu liên quan tới nhau ví dụ trong các ứng dụng như nhận dạng giọng nói, mô hình hóa ngôn ngữ, dịch ngôn ngữ hay viết tiêu đề cho ảnh tự động.

Ta có thể thấy tại mỗi bước của RNN, chúng đều sử dụng chung tham số U (ma trận trọng số cho input), W (ma trận chuyển trạng thái) và vocabulary V. Ta thấy rằng, mỗi state sẽ phụ thuộc vào kết quả của state trước đó, nhưng việc ta xử lý 1 chuỗi dữ liệu dài trong thực tế là rất khó.

Do đó, ta sẽ phải sử dụng các kiến trúc khác nhau là biến thể của RNN ví dụ như LSTM để giải quyết vấn đề này.

Để hiểu rõ hơn, ta có ví dụ như sau:



Trong ví dụ này, V là [h,e,l,o] gồm 4 phần tử mà training sequence của ta là từ "hello". Khi này, với một kí tự ví dụ như 'h', ta thu được đầu ra là từ 'e', từ 'e' này lại là đầu vào để dự đoán từ tiếp theo trong chuỗi. Quá trình này kết thúc, ta thu được từ 'hello'.

Hình dưới đây thể hiện rõ hơn quá trình hoạt động của RNN.


Trong hình trên, Lt-1, Lt và Lt+1 là thứ tự của các layer.
Output của trạng thái trước sẽ là input của trạng thái sau, ví dụ như Ot-1 sẽ tương ứng với xt.