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

Thứ Ba, 19 tháng 2, 2019

[Deep Learning] Cơ chế Attention trong Deep Learning

    Vào năm 2015, Attention mechanism xuất hiện và thu hút rất nhiều sự quan tâm, tuy nhiên số models sử dụng attention mechanism được công bố tới nay là rất ít. Bài viết này nhằm mục đích giải thích ở mức high-level về cơ chế Attention được sử dụng trong DL.

Attention  
    Trong thế giới tự nhiên, khi ta muốn nhận biết một vật, ta sẽ tập trung vào các đặc tính của vật đó thay vì tập trung vào toàn bộ hình dáng của vật. Ví dụ như để phân biệt con mèo và con vịt ta sẽ nghĩ ngay trong đầu sự khác biệt đó là vịt có cánh còn mèo thì không.

Ý tưởng tương tự cũng được áp dụng vào Deep Learning khi ta chỉ tập trung vào những phần nhất định của dữ liệu đầu vào tại 1 thời điểm nhất định cho các bài toán như nhận diện giọng nói, dịch máy hay phân loại vật thể.

 Attention trong mô tả ảnh
    Ta lấy một ví dụ để giải thích về cơ chế attetion đó là bài toán sinh ra mô tả cho 1 bức ảnh. Hệ thống sinh mô tả cho ảnh cổ điển sẽ mã hóa (encode) bức ảnh sử dụng một mô hình CNN có sẵn (pretrained) để sinh ra hidden state h. Sau đó, hệ thống sẽ giải mã (decode) hidden state này bằng một RNN và sinh ra các từ lần lượt cho đến một đoạn mô tả hoàn chỉnh. Mô hình như sau:
    

                Vấn đề của phương pháp này đó là trong khi hệ thống muốn sinh ra từ tiếp theo của caption thì từ tiếp theo này thường chỉ mô tả một phần nhất định của bức ảnh. Trong khi đó, ta lại sử dụng cả hidden state h chỉ để mô tả một phần nhỏ của bức ảnh và việc này sẽ không hiệu quả. Lúc này ta cần sử dụng attention.

                Trong cơ chế attention, bức ảnh đầu tiên được chia thành n phần và ta tính toán từng phần tử h1,...hn (h = hidden state) tương ứng với n phần bằng CNN. Khi RNN hoạt động, RNN sẽ chỉ tập trung vào phần tương ứng của bức ảnh. Trong ảnh dưới đây, ta có thể thấy mỗi từ sẽ tương ứng với phần có độ sáng lớn hơn những phần còn lại trong bức ảnh.

Ta cũng có thể hiểu như hệ thống sẽ học để attend một cách chính xác vào những phần của bức ảnh chứ không chỉ attend một cách tuần tự từ trái qua phải.
 Attention trong dịch máy
                Ta muốn dịch một câu từ tiếng Pháp qua Tiếng Anh, trong hình dưới đây, y là các từ được dịch bởi bộ giải mã, và x là câu ứng với input của ta.
Mô hình trên sử dụng bidirectional RNN nhưng quan trọng hơn ta thấy bộ giải mã không chỉ phụ thuộc vào state trước đó st-1 mà còn phụ thuộc vào trọng số là combination của tất cả các dữ trạng thái đầu vào. Các giá trị a là trọng số định nghĩa mức độ quan trọng của từng trạng thái đầu vào đến trạng thái đầu ra. Ví dụ a3,2 lớn, khi này bộ giải mã sẽ tập trung vào trạng thái số 2 trong câu tiếng Pháp, các giá trị a này thường được chuẩn hóa và có tổng là 1 (phân bố trên toàn dữ liệu đầu vào).

Ta cũng có thể visualize để thấy được attention hoạt động như thế nào
Ta thấy rằng khi dịch từ French qua English, hệ thống sẽ tập trung một cách tuần tự từ đầu tới cuối câu vào câu đầu vào, nhưng đôi khi sẽ tập trung vào 2 từ tại cùng 1 thời điểm để dịch ra 1 từ mới, ví dụ như dịch từ "la Syrie" thành "Syria".
 Mô hình Attention là gì?
                Trước tiên ta sẽ cần hiểu rõ hơn ý tưởng của cơ chế attention. Hầu hết phần dưới giải thích về attention được dịch từ đây (https://stackoverflow.com/questions/35549588/soft-attention-vs-hard-attention).
                Attention là gì? Để hiểu khái niệm này, ta sẽ thử trả lời 1 câu hỏi khác đó là Tại sao lại sử dụng attention? Giả sử bạn bị bịt mặt và dẫn đến một bữa tiệc sinh nhật, đây là thứ bạn sẽ nhìn thấy sau khi mở mắt ra.

                Đầu tiên ta sẽ nhìn khung cảnh mọi thứ xung quanh và thu thập thông tin tổng thể, tất nhiên ta chỉ nhìn lướt qua thôi chứ không để ý từng chi tiết bao giờ cả, và ta đã có câu trả lời cho mình. Ta nhìn thấy chú Bin hay dì Sâm và ta đặc biệt chú ý đến họ vì họ rất đỗi quen thuộc với ta và có lẽ là chi tiết quan trọng nhất sau khi mở mắt để biết đây là đâu và tôi là ai? Vậy tại sao lại như vậy, bởi vì bộ não chúng ta có khả năng tập trung vào những phần nhất định của một bức ảnh tại 1 thời gian và sau đó tổng hợp lại thông tin. Ta sẽ chú ý cao độ vào những chi tiết quan trọng nhất của bức ảnh và lờ đi những chi tiết còn lại.
                Giờ ta cũng muốn máy tính của ta có khả năng như vậy. Nếu giờ ta đã hiểu về attention, vậy còn tính differentiability(khác biệt) của cơ chế attetion là như thế nào. Ta sẽ tìm hiểu làm sao mà ta có thể biết mà nhìn vào những điểm đặc biệt của bức ảnh và lờ đi những điểm không đặc biệt. Ta có thể lựa chọn. Ví dụ như dựa vào cả bức ảnh và những phần của bức ảnh ta đã tập trung trước đó, ta sẽ chọn phần mà ta sẽ tập trung tiếp theo. Cũng như vậy, ta có thể có một train một mang neuron để có thể chỉ ra phần cần tập trung tiếp theo trong một bức ảnh, nhưng có muôn vàn kết quả, làm sao ta biết phần nào tập trung tiếp theo là chính xác hay không. Trong khi đó, việc train một mạng neuron sẽ phụ thuộc vào loss function, làm sao để ta xây dựng được loss function cho việc training? Ta có một số giải pháp, ta có thể sử dụng Reinforcement Learning (đọc thêm) hoặc còn cách khác đó là sử dụng soft hoặc hard attention.
                Để giải thích hai khái niệm này, ta giả sử đang làm bài toán sinh caption cho một bức ảnh, ta sẽ phải lựa chọn phần nào của bức ảnh quan trọng hơn phần còn lại. Để biết phần nào quan trọng hơn, ta có thể so sánh sự giống và khác nhau giữa query và các phần trong bức ảnh. Ví dụ bức ảnh có hình người đàn ông, khi này query mà hệ thống tự sinh ra có thể là: Người đàn ông này đang làm gì? Từ query này, ta ánh xạ để lấy được phần mà ta cần tập trung tiếp sau đó. Vậy tính differentiability ta nhắc đến ở trước nghĩa là gì? Đó nghĩa là hàm attention của ta không phụ thuộc vào ảnh đầu vào và gradient nữa.
                Sơ đồ tổng quát của 1 mô hình Attention như sau:
                Một mô hình attention sẽ nhận n đầu vào y1, y2 ... yn (chính là h1,h2...hn) và một context c, giá trị trả về là 1 vector z biểu diễn các đầu vào yi tương ứng với context c. Cụ thể, mô hình sẽ trả về một tập giá trị tương ứng yi và context c, giá trị weight này chỉ ra ta đang tập trung vào phần nào của ảnh. Ngoài ra, giá trị weight này có thể được visualize để ta có thể thấy bức ảnh đang được tập trung vào phần nào, một pixel sẽ trắng hơn nếu giá trị weight của pixel đó cao, nghĩa là ta đang tập trung vào pixel đó. Tiếp theo ta sẽ đi sâu hơn vào kiến trúc Attention.

                Đầu tiên ta nhận đầu với c là context và yi các phần của bức ảnh.

                Tiếp theo, mô hình tính toán m1, m2, ... mn bằng hàm tanh, hàm tanh này nhận đầu vào là context c và yi, và các giá trị mi này được tính toán một cách độc lập nghĩa là ta sẽ tính toán trên từng giá trị yi riêng rẽ.
                                                         m_i = \tanh\left(W_{cm}c + W_{ym}y_i\right)
                Với Wcm và Wym là các ma trận trọng số tương ứng của context c và đầu vào yi.
Sau đó ta tính toán từng weight sử dụng hàm softmax.
                                                         s_i \propto \exp\left(\left<w_m,m_i \right>\right)
                                                              \sum_i s_i = 1
wm là ma trận trọng số của mi.
                Ở đây ta thấy rằng giá trị weight của các phần sẽ thay đổi một cách tương ứng khi context c thay đổi, điều này phù hợp với việc ta dịch chuyển attention đến các phần khác nhau của ảnh.

Mô hình có thể được sửa đổi bằng cách thay hàm tanh bằng hàm khác miễn là giá trị đầu vào luôn giá context c và y, ví dụ ta có thể sử dụng dot product thay cho hàm tanh như sau:

 Soft Attention và Hard Attention
                Cơ chế được mô tả ở trên là soft-attention và có thể áp dụng vào bất kỳ một hệ thống nào, với giá trị gradient sẽ propagate qua attention mechanism. Hard attention là một quá trình ngẫy nhiên: Thay vì sử dụng tất cả hidden state yi là đầu vào cho việc giải mã, hệ thống lấy mẫu hidden state yi với một xác xuất là si. Để tính toán gradient, ta phải ước lượng bằng phương pháp lấy mẫu Monto Carlo.

Cả 2 cơ chế đều có ưu và nhược điểm riêng, nhưng ta thường tập trung vào soft attention do gradient có thể được tính toán trực tiếp thay vì phải ước lượng thông qua quá trình ngẫu nhiên như hard attention.

 Hệ thống mô tả ảnh sử dụng attention
                Cũng với hệ thống cổ điển, nhưng ta sẽ thêm 1 layer attention.

                Ở đây với context c là các hi và đầu vào là các phần của ảnh, attention model sẽ sinh ra đầu ra z1 là biểu diễn của ảnh mà chỉ 1 phần nhất định được focus vào, sau đó đưa biểu diễn này vào LSTM để ta có thể sinh từ.

 Attention cost
                Nếu ta nhìn vào công thức của attention mechanism, ta có thể thấy rằng ta cần tính toán một giá tri attention cho mỗi tổ hợp của dữ liệu đầu vào với một output. Nếu ta có 50 từ trong câu dữ liệu đầu vào và ta cần sinh ra 50 từ trong output, khi đó ta sẽ cần 50x50= 2500 giá trị attention. Đây là giá trị không quá lớn nhưng khi ta thực hiện ở mức kí tự (character-level), attention sẽ thực sự là một vấn đề. Ngoài ra, so với visual attention của con người hoặc động vật, attention trong DL là khá phản trực giác (counter-intuitive). Attention của con người sẽ chỉ tập trung vào 1 thứ và bỏ qua những thứ khác. Nhưng trong mô hình trên, ta cần xét tất cả đầu vào một cách chi tiết trước khi đưa ra quyết định nên tập trung vào phần nào. Rõ ràng vì ta đã xét tất cả dữ liệu đầu vào rồi mới quyết định, điều này giống với memory access hơn là attention. 
Intuitively that’s equivalent outputting a translated word, and then going back through all of your internal memory of the text in order to decide which word to produce next. That seems like a waste, and not at all what humans are doing. In fact, it’s more akin to memory access, not attention, which in my opinion is somewhat of a misnomer (more on that below). Still, that hasn’t stopped attention mechanisms from becoming quite popular and performing well on many tasks.


Thứ Bảy, 19 tháng 1, 2019

Semantic Segmentation

Đầu tiên ta nhắc lại về segmentation. Với segmentation, đầu vào là ảnh và đầu ra là các đường bao ứng với các vật thể và phân tách các vật thể trong ảnh.
Còn semantic segmentation, ta cần hiểu ảnh đầu vào ở mức ngữ nghĩa sâu hơn không chỉ là các đường bao vật thể.
Ví dụ với ứng dụng cho việc image captioning, với ảnh góc trên bên phải, ta có:
"Two men riding on a bike in front of a building on the road. And there is a car."
Rõ ràng việc ngữ nghĩa (semantic) là công việc khó hơn và đòi hỏi kỹ thuật phức tạp hơn việc chỉ segmentation đơn thuần. Nhưng tiềm năng của semantic segmentation lại lớn hơn nhiều, khi mà ta có thể hiểu được toàn bộ bức ảnh và áp dụng vào các mảng khác nhau như y tế, giao thông ...

Về cơ bản, semantic segmentation có thể hiểu như:
- Phụ thuộc vào CRF (Conditional Random Field)
- Thực hiện ở mức pixel hoặc superpixel
- Phân tích sự liên quan giữa các pixel gần nhau
- Sử dụng sự liên quan giữa các label gần nhau

Để hiểu 4 điều trên, ta hãy nhìn vào 1 ví dụ:
- Các pixels gần nhau thường có xác suất có cùng label
- Các pixels có cùng màu thường có xác suất có cùng label
- Pixels phía trên pixels "chair" thường có xác suất là pixel "person" thay vì "building" 

Vậy CRF là một mô hình dựa vào xác suất để có thể đưa ra các dự đoán về các pixels trên 1 ảnh.

Định nghĩa của superpixel là:
The concept of superpixel was first introduced by Xiaofeng Ren and Jitendra Malik in 2003. Superpixel is a group of connected pixels with similar colors or gray levels. Superpixel segmentation is dividing an image into hundreds of non-overlapping superpixels. Instead of working with just pixels, Ren and Malik use superpixels to do image segmentation.
There are two major advantages for using superpixels.
- you can compute features on more meaningful regions.
- you can reduce the input entities for the subsequnt algorithms.
Superpixel segmentation have been applied to many computer vision tasks, such as sematic segmentation, visual tracking, image classification, and so on.

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ứ Ba, 1 tháng 1, 2019

[Machine Learning][Deep Learning] Bidirectional RNN

Như ta đã đề  cập trước đó, trong các ứng dụng, ví dụ Name Entity Recognition, cho một đầu vào x(t) ở thời điểm t, để xác định x(t) có phải là 1 entiry cần tìm hay không, ta cần phải lấy thông tin không chỉ từ các dữ liệu trước thời điểm t mà còn phải sau thời điểm t. Ví dụ trong câu sau:
He said: "Teddy Roosevelt was a great president!"

Giả sử x(3) là Teddy, x(4) là Roosevelt, khi này ta sẽ cần xem xét cả các dữ liệu đằng sau để đưa ra quyết định x(3) và x(4) có phải entity cần tìm hay không.
Mô hình BRNN được cho bởi hình dưới đây:
Lúc này , thay vì chỉ có 1 đường forward, ta sẽ có thêm 1 đường backward, với mỗi giá trị ví dụ để tính toán output y3, tất cả các giá trị input xi đều sẽ tham gia. Các block trong mạng có thể là GRU block hoặc LSTM block.

Tuy nhiên, một nhược điểm của BRNN là ta chỉ có thể áp dụng mô hình này nếu toàn bộ tập dữ liệu đầu vafolaf biết trước, do đó các ứng dụng yêu cầu đáp ứng real-time có thể sẽ bị hạn chế.
Ví dụ như trong ứng dụng Speech Recognition, người dùng phải nói hết câu thì hệ thống mới có thể thực hiện.
Dù vậy, trong các ứng dụng về NLP, hầu hết các input là các corpus nên ta có thể sử dụng BRNN.

[Machine Learning][Deep Learning] Kiến trúc Long Short Term Memory (LSTM) trong RNN

Trong kiến trúc LSTM, c<t> và a<t> sẽ không tương đương nữa, lúc này LSTM sẽ gồm 3 gates Γu, Γf  và Γo.
Mỗi gate đều được tính toán từ a<t-1> và x<t>, sơ đồ của 1 unit được mô tả như hình dưới đây.
Khi này, dựa vào các giá trị của các gate, ta cũng có thể sử dụng những feature xa trong 1 sequence hoặc giải quyết được vanishing/exploding gradient. LSTM là một mô hình tổng quát hơn và ra đời trước GRU rất lâu. Ta có thể thấy GRU là mô hình đơn giản hơn LSTM nhiều do đó ta có thể xây dựng được các hệ thống lớn hơn, tuy nhiên LSTM lại có performance cao do nó có 3 gates thay vì 2 gates của GRU. 

Thứ Hai, 31 tháng 12, 2018

[Machine Learning][Deep Learning] Kiến trúc Gated Recurrent Unit (GRU) trong RNN

Kiến trúc của 1 unit trong 1 RNN như ta đã đề cập trước đó có mô hình như dưới đây:
Lúc này, a<t> sẽ phụ thuộc vào chuỗi dữ liệu trước đó bên cạnh tác động của exploding/vanishing gradient.
Ví dụ trong câu: The cat, which already ate two big fishes and three apples ..., was full.
Lúc này The cat là số ít sẽ đi kèm với động từ tobe was, tuy nhiên ở giữa lại là 1 chuỗi dài, và trong RNN thường, ta không thể sử dụng feature The cat do chủ ngữ The cat và động từ was cách xa nhau trong chuỗi.

Một kiến trúc mới của RNN là GRU sẽ giải quyết vấn đề này.
Trong GRU, ta định nghĩa c là 1 memory cell, và c<t> = a<t> (a<t> trong RNN thường, nhưng trong GRU, ta dùng c<t> thay vì a<t>). Γu là hàm gate được tính bởi sigmoid function sẽ có giá trị xấp xỉ 0 hoặc 1. Với mỗi thời điểm t, Γu sẽ quyết định việc update c<t> = č<t> bằng biểu thức sau đây:

Nghĩa là nếu Γu = 1, ta sẽ update, nếu Γu=0, giá trị c<t> = c<t-1>, không có sự biến đổi trong mạng RNN. Do vậy trong chuỗi đã cho ở phần đầu, ta sẽ xác định được những step nào nên có sự biến đổi và những step nào nên được giữ nguyên.
Ở đây ta thấy chỉ có cat và was sẽ được update, những step t giữa chúng sẽ có giá trị  Γu=0 ứng với việc giữ nguyên. Do đó, ta có thể coi như trong câu chỉ còn The cat was full vì các step t có giá trị Γu=0 sẽ không đóng vai trò trong việc tính toán output. Thực ra vai trò của chúng là rất nhỏ vì Γu là xấp xỉ bằng 0, nhưng do đi qua nhiều step t, nên giá trị này trở nên nhỏ vô cùng gần 0, do đó ta vừa có thể tính toán output từ 1 step t rất ra trước đó, vừa có thể khắc phục vanishing hoặc exploding gradient khi mà ta bỏ qua hầu hết những thành phần không quan trọng trong sequence.

Mô hình đơn giản của 1 GRU unit sẽ như sau:

Thực tế trong mô hình GRU, ta có thêm 1 gate nữa là Γr trong đó gate này thể hiện sự giống nhau giữa c<t-1> và č<t>.
Mô hình GRU lúc này sẽ gồm 2 gate được biểu diễn như sau: