Friday, February 7, 2025
Wednesday, March 13, 2024
Unleashing the Potential: Modern Techniques to Boost Large Language Model Performance
1. Retrieval-Augmented Generation (RAG):
Imagine an LLM that can not only generate text but also access and leverage relevant information from external sources. This is the core idea behind RAG models. RAG combines an LLM with a retrieval system that fetches information pertinent to the task at hand. The LLM then utilizes this retrieved information to enhance its generation process, leading to more factually accurate and informative outputs.
2. Chaining Transformers:
LLMs are often monolithic beasts, tackling entire tasks in one go. Chaining Transformers breaks down complex tasks into smaller, more manageable subtasks. Each subtask is handled by a specialized transformer model, and the outputs are sequentially chained together to achieve the final goal. This approach allows for more efficient training and potentially better performance on intricate tasks.
3. Prompt Engineering:
Think of prompts as instructions that guide an LLM towards the desired outcome. Prompt engineering focuses on crafting effective prompts that steer the LLM in the right direction. By carefully designing prompts that incorporate task-specific information and desired outcomes, researchers can significantly improve the quality and accuracy of LLM outputs.
4. Transfer Learning and Fine-tuning:
Pre-trained LLMs have learned a wealth of knowledge from massive datasets. Transfer learning and fine-tuning techniques leverage this pre-trained knowledge as a starting point for new tasks. By fine-tuning an LLM on a task-specific dataset, researchers can significantly reduce training time and improve performance compared to training from scratch.
This blog post has just scratched the surface of the exciting advancements in LLM technology. In future posts, we'll delve deeper into each of these techniques, exploring their specific applications and showcasing their potential to revolutionize various AI domains.
Wednesday, October 19, 2022
Easy setup Kibana Nginx reverse proxy with Ansible
Motivation
Amazon OpenSearch Service cluster instance run inside a virtual private cloud. If you want to access Kibana dedicated to this instance you have two options. One is tunneling to EC2 bastion host which is realitvely straightforward. One of the disadvantages of this approach is that you need to share your bastion host keys to clients. Another is reverse proxy on bastion host to private OpenSearch Kibana. In this example, we are going to show how you can setup access to Kibana using Nginx reverse proxy and provision it with Ansible.
This example represent basic setup which can serve as basis for future improvements. This basis don't include secure access configuration (certifications, authentication). It uses HTTP between client and proxy server, for production environment using HTTPS is recommended in this context. It's an easier setup, but for other hand it's also less secure setup.
Example
Inventory
First you need to have inventory defined with one variable (open_search_endpoint) which should point to Kibana instance. Notice, we have two ec2 instances in our inventory. One can be for production environment, second for staging for example.
Main playbook
Next we are going to define main Ansible playbook, which is pretty straight forward. For it to work, you need to have configuration files (default.config and ngnix.config) located in your path.
Default configuration
For default.config, we are using simple proxy pass. If you want more secure connection, this is where you would configure HTTPS.
Nginx configuration
Thursday, August 4, 2022
Serverless React, AWS Lambda and API Gateway example
Here is small terraform example how you can create serverless React app that will use AWS API Gateway which will call AWS Lambda.
API Gateway is proxying GET request to lambda. Lambda will simply return "Hello World".
Actual terraform infrastructure definition. This terraform definition include CORS configuration.
Lambda which that will return "Hello World".
Thursday, April 28, 2022
ALB rule based routing with terraform
Tuesday, January 28, 2020
React.js PDF export
Saturday, March 2, 2019
Python script to find structure of opportunities on Slovakia job market
Introduction
I will try to answer this simple question using google colab + python notebook + web crawling Slovak job ad site + simple NLP (mainly using regex and simple text transformations) and pandas with sklearn.
It's impossible to answer this question using something like TIOBE programming index. This index is composed using trend searches in popular search engines. It doesn't take into consideration what is actual demand for some programming language on job market, let alone niche market like Slovak.
How is this possible?
This is possible now due to change of law on Slovak job market, which basically force companies to publish lowest possible salary they are willing to pay for position. Companies tends to put higher figures in ads, to compete with each other. So real salaries are bit higher, but it should average itself out. There is one problem tough. There is no regulation what type of salary they should put on ad, so there are companies that put net salary and other put gross salary. But. there are not so many of those that put gross salaries.
Data
For correctness, jobs with salary lower than 900 and bigger than 5500 EUR will be ignored, because there is higher probability they are false positive.
We will crawl most popular Slovak job ad site. Crawler will crawl through roughly 1200 pages of IT jobs. Some of which are full programming jobs, others are something in between (Managers, Support, Testers)
We will use corpus of words that will represent most popular programming languages. There will be tree different strategies for parsing programming languages from ad text. You shouldn't worry to much about this. Main reason for this it's difficulty to parse words like "C" or "R" programming languages from ad text, so we must treat it as single word that have no word boundaries.
Python scripts
Here is link to read only google colab python notebook without crawl code (code that actually rip/downloads content from job ad site)Click here to see the scripts
Summary
As you can see there are some interesting surprises. Java is main language to learn if you want to make between 3000 and 4000 Euros.
Who knew bash is so important to learn? But on other hand is not so hard to learn it. :)
For lower paying positions PHP is main language, but you can also see there R at second spot (maybe some error in parsing?)
It no surprise that for higher salaries than 4000 EUR there is no clear winner. You must be generalist at these positions (Architects, Team Leads, Tech Leads). So answer to the question in title is: None, or there is not silver bullet, just be good at what you do and make sure to learn as much as you can.
Monday, August 13, 2018
Serverless Architectures
Serverless Architectures
SA are new approach to application designs. This is hot topic in the software architecture world right now. All "Big Three" (Amazon, Google, Microsoft) are heavily investing in "Serverlessnes" right now.
What is it?
Upsides and downsides
Upsides:
- No need for system administration (everything is handled by third party)
- Decreases complexity of your product
- Natively micro service architecture.
- Lesser cost to scale.
- Elasticity - native scaling
- Smaller development and operational costs
- Decrease time to market
Downsides:
- Debugging and monitoring is still and issue.
- Tooling is not there quite yet.
- Cold start issues.
Tuesday, March 27, 2018
Truffle execute external script call contract function
* Error: VM Exception while processing transaction: out of gas
* Error: Cannot create instance of YourContract; no code at address
* Error: sender account not recognized
* Error: invalid address
If you get some of these errors while trying to execute contract function from truffle script, here is proper way to do it:
Monday, March 26, 2018
Truffle external scripts working example
errors:
TypeError: Cannot read property 'apply' of undefined
exception at require.js:128:1
TypeError: fn is not a function
For some reason it was quite difficult to find solution how to run external script. After some time I finally have figure it out so I'm sharing it with world:
Thursday, March 22, 2018
Smart Contracts and Ethereum solidity
WHAT ARE SMART CONTRACTS?
Can laws be written on smart contacts. What world would that be? Programmers will become lawyers? Imagine code reviews and testing on that contracts.
HOW ARE THIS CONTRACT EXECUTED
Wednesday, December 9, 2015
Creating intentional memory leak in Java
Memory can become more fragmented which again force garbage collector to compact heap space and make long pauses or throw "Java.lang.OutOfMemoryError" exception. These long pause times are typically triggered when your Java program attempts to allocate large object, such as an array.
Nowadays, modern VM are very efficient and can deal efficiently with rapid small object creation, but if you hit limit you application will die or becomes unresponsive.
Concept of memory leak is very simple, you introduce memory leaks by maintaining obsolete references to Objects. An obsolete reference is simply a reference that will never be dereferenced again. This is so called "simple memory leak".
There are also "true memory leaks". You introduce this leaks when you create objects that are inaccessible by running code but still stored in memory.
This works because the ThreadLocal keeps a reference to the object, which keeps a reference to its Class, which in turn keeps a reference to its ClassLoader. The ClassLoader, in turn, keeps a reference to all the Classes it has loaded.
With multiple deploys you application will break with totally unexpected permanent generation memory leak exception.
There are many "out of memory" errors. Look here for description if interested: memory leaks
- Java.lang.OutOfMemoryError: Java heap space
- Heap is full
- Java.lang.OutOfMemoryError: PermGen space
- Permanent generation space is full.
- java.lang.OutOfMemoryError: GC Overhead limit exceeded
- GC is working way to hard with little or no result.
All examples are runnable, all you need to do is to clone https://github.com/spookysleeper/codingwithpassion/tree/master/leaks repository and run gradle script.
Byte leak
To run this example type: "gradlew runByteTest"
This is demonstration of pretty straight forward memory leak using array list and byte array. Array is growing and each element is holding references to one megabyte byte array. Arrays need be allocated as continuous chunks of memory within heap space, and if memory is fragmented GB is struggling and break in the end with Java.lang.OutOfMemoryError: Java heap space exception.
As you can see from this graph, CG didn't have a chance. It's a massacre!
List leak
To run this example type: "gradlew runListTest"
List leak is similar to previous example. It creates list of BigDecimal objects which are newer dereferenced. Simple and effective.
BigDecimal is chosen only because it is heavier than simple Integer or Float or something.
You can see that this time GC is trying really hard to clean heap, but fails eventually.
Map key leak
Next leak is bit more sophisticated, but at it's core no different than list leak. This is demonstration what will happen when your implementation of hashCode is bad.
Element will bee added indefinitely and every time reference will remain active.
You can run this example by typing: "gradlew runMapBadKeyTest" or you can type "gradlew runMapGoodKeyTest" to test it with good key.
This time CG is not even trying, maybe because StringBuilder with 100000 elements is so much heavier than BigDecimal and simply doesn't have time to do anything.
Class leak
Permanent generation hold internal representations of java classes among other things (names of classes, methods, Strings...). Simplest way of introducing memory leak in this memory area is to create too many classes. Other more sophisticated example is mentioned earlier in this post as "true memory leak".
To run example type: "gradlew runClassTest"
As you can see, it escalate pretty quickly. Because of this, you don't even get PermGen exception every time you run it, it just break on random thing.
Thanks for reading, hope you like it! :)
Saturday, July 25, 2015
Java 8 Streams
Introduction
Every application create and process collections. In Java until recently if you want to do some "finding" or "grouping" on collections you must code it yourself. It was not very exciting and it is repetitive job in nature. groovy for example offers great tools for transforming and managing collection. Check this link for some great examples. Java 8 borrows some concepts from groovy, but also go one step forward with multi core processing and stream concepts.In SQL you don't need to implement how to calculate grouping or something else, you just describe your expectation (what you want to have). Stream API in Java 8 is guided with same philosophy.
What is stream?
- Sequence of elements: Stream provides an interface to a sequenced set of values. Implementation of this interface don't store values, values are calculated on run-time.
- Source: This is where are values are stored. Collection, arrays, I/O.
- Aggregate operations: All common SQL-like (group, count, sum) and function programming languages constructions (filter, map, reduce, find, match, sorted).
- Pipelining: This allows operation on stream to be chained into large pipeline.
- Internal iteration: Collections are iterated externally (explicit iteration), stream do the iteration behind the scenes.
Listnumbers = Arrays.asList(1, 4, 1, 4, 2, 8, 5); List distinct = numbers.stream().map( i -> i*i). distinct().collect(Collectors.toList()); System.out.printf("integers: %s, squares : %s %n", numbers, distinct);
- Intermediate: can be connected together because their return type is a Stream.
- Terminal: this kind of operation produce a result from a pipeline such as a List, an Integer, or even void (any non-Stream type).
Tuesday, July 21, 2015
JavaScript Promises
What are promises?
Promises quickly become standard way we handle asynchronous operations in JavaScript. Everybody who code even little bit in JavaScript is familiar with callbacks. Essence of using callback functions in JavaScript passing a function as an argument in another function and later execute that passed-in function or even return it to be executed later.
There are several problems with callback. For example when you need to be sure that two callbacks finishes before you do something, you must introduce new variables to track state of each callback. Callbacks also lead to another problem, which you should be already familiar with: callback hell.
Callback hell
I think this all started with node.js and callback hell get a bad rap from the node.js community. This is because when you have your node application with express and mongoose then callbacks are all over the place.
When you need to perform number of actions in specific sequence in JavaScript, you must use nested functions. Something like this:
asyncCall(function(err, data1){
if(err) return callback(err);
anotherAsyncCall(function(err2, data2){
if(err2) return calllback(err2);
oneMoreAsyncCall(function(err3, data3){
if(err3) return callback(err3);
// are we done yet?
});
});
});
You can use promises to make this code prettier:
asyncCall()
.then(function(data1){
// do something...
return anotherAsyncCall();
})
.then(function(data2){
// do something...
return oneMoreAsyncCall();
})
.then(function(data3){
// the third and final async response
})
.fail(function(err) {
// handle any error resulting from any of the above calls
})
.done();
Lot nicer isn't it?You can see that instead of requiring a callback we are returning a Promise object. You can chain promises, so subsequent then() calls on the Promise object also return promises.
We don't need to check for error in every callback, but only at the end of promise chain. This is also feature of promises.
Promises are not only solution to callback hell. Some times callback hell is direct consequence of poor code organization. In some cases promises only hide underlying structural problems of code. I mean it you need 5 indention you're screwed anyway, and should fix your program. You can find here some of the hints how to resolve callback hell
Implementation
Promises have arrived natively in JavaScript, but for the end I want to provide half baked promise implementation with comments, so you have feeling how promises are (could be) impelmented:
function Promise(fn) {
var state = 'pending';
var value;
var deferred;
//When function we passed is done, this will be called.
//If then is called before resolve, then value for then is deffered to function outside promise.
//If then is called after resolve, then value is readed from internal state.
function resolve(newValue) {
value = newValue;
state = 'resolved';
if(deferred) {
handle(deferred);
}
}
function handle(onResolved) {
if(state === 'pending') {
deferred = onResolved;
return;
}
onResolved(value);
}
//This will be invoced when client calls it.
this.then = function(onResolved) {
handle(onResolved);
};
//Executing function that was passed into promise.
//We are waithing until this function is finished.
fn(resolve);
}
function testPromise() {
return new Promise(function(resolve) {
var value = readFromDatabase();
resolve(value);
});
}
testPromise().then(function(databaseValue) {
log(databaseValue);
});
Monday, September 15, 2014
SOLID object-oriented design
This acronym is coined by Robert Martin. According to him, these principles make a backbone of solid object oriented design. You can read more about these principles in his book "Agile Software Development: Principles, Patterns, and Practices". I will try to describe these principles in following posts, but in a timely manner off course. :)
For starters here are his views on bad object oriented design and what should be avoided:
- Rigidity - It is hard to change because every change affects too many other parts of the system.
- Fragility - When you make a change, unexpected parts of the system break.
- Immobility - It is hard to reuse in another application because it cannot be disentangled from the current application.
Sunday, September 14, 2014
Java built-in profiling and monitoring tools
Finding this kind of bugs is like art and you need lot of experience to be good at it. That's why some of programmers specialize in Java profiling. In some cases fining bug is impossible if you don't know how system works. Every Java programmer should know at least what are basic profiling tools, because you can't always pay some external specialist to fix memory leaks or deadlocks for you.
Java comes with built-in tools for profiling and monitoring. Some of these tools are:
jmap
This is internal Java tool and it is not profiling tool as such, but it is very useful. Oracle describes jmap as an application that “prints shared object memory maps or heap memory details of a given process or core file or remote debug server”. And it is exactly that. Most useful option is to print memory histogram report. The resulting report shows us a row for each class type currently on the heap, with their count of allocated instances and total bytes consumed. Using this report you can easily identify memory leaks if you have any.
jstack
JStack is also not profiling tool, but it can help you identify thread deadlocks. The output of "jstack" is very useful for debugging. It shows how many deadlocks exist in this JVM process and stack traces of waiting threads with source code line numbers, if source codes were compile with debug options.
jconsole
JConsole is a graphical monitoring tool to monitor Java Virtual Machine (JVM) and Java applications both on a local or remote machine. It is using for monitoring and not profiling, so you are better with using VisualVM described bellow.
VisualVM
Another tool currently built into the JVM is VisualVM, described by its creators as “a visual tool integrating several command line JDK tools and lightweight profiling capabilities”. This tool can generate memory graph that will show you how your application is consuming memory through time. VisualVM also provides a sampler and a lightweight profiler. Sampler lets you sample your application periodically for CPU and Memory usage. It’s possible to get statistics similar to those available through jmap, with the additional capability to sample your method calls’ CPU usage. The VisualVM Profiler will give you the same information as the sampler, but rather than sampling your application for information at regular intervals.
For me these built-in tools work quite well, but if you want more specialized and more powerful tools for profiling you can check: BTrace, EurekaJ and Eclipse Memory Analyzer (MAT).
Friday, September 12, 2014
Transform if else (conditional) with polymorphism
Sometimes when you refactor your code in this way, you actually learn something new about your data and make your code easier to follow.
Polymorphism also give you advantage when you have same conditional in through your code on several places and for example you want to introduce new branching, which in case of polymorphism will be just new type.
Let see it in example:
public class ConditionalPolymorphism {
//smelly approach
public int carSpeed(String car) {
if ("Hyundai".equals(car)) {
return 180;
} else if ("Mazda".equals(car)) {
return 160;
} else if ("Nissan".equals(car)) {
return 190;
} else {
throw new InvalidParameterException(
"Parameter not legal: " + car);
}
}
//polymorphic approach
public int carSpeed(Car car) {
return car.speed();
}
public static void main(String[] args) {
ConditionalPolymorphism conditionalPolymorphism =
new ConditionalPolymorphism();
System.out.println(
conditionalPolymorphism.carSpeed("Hyundai"));
System.out.println(
conditionalPolymorphism.carSpeed(new Hyundai()));
}
}
interface Car {
int speed();
}
class Hyundai implements Car {
public int speed() {
return 180;
}
}
class Mazda implements Car {
public int speed() {
return 160;
}
}
class Nissan implements Car {
public int speed() {
return 190;
}
}
Saturday, September 6, 2014
Type Erasure and Bridge Methods in Generics
-Alexander Stepanov
Generics programming concepts are nothing new. And it is not something Java introduced to the world (Ada, Eiffel and C++ supported generics even before Java did). In 1988 David Musser and Alexander Stepanov introduced and defined this concept.
Java introduced Generics in 2004 (Java 5) and implement it as type erasure. Type erasure consist of following steps:
- Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
- Insert type casts if necessary to preserve type safety.
- Generate bridge methods to preserve polymorphism in extended generic types.
public static <T> void array2Coll(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o);
}
}
After type erasure code will look like this:
public static void array2Coll(Object[] a, Collection c) {
for (Object o : a) {
c.add(o);
}
}
As you can see, generics type has been replaced with Object type (it's upper bound). If their bound would be something else (for example <T> extends Comparable), then generics would be replaced by Comparable.
Sometimes compiler create a synthetic method, called a bridge method, as part of the type erasure process. Next examples will explain why and when compiler create this methods.
public class Node<T> {
private T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node<Integer> {
public MyNode(Integer data) {
super(data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
After type erasure compiler will create one synthetic bridge method for second class:
public class Node {
private Object data;
public void setData(Object data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node {
public MyNode(Integer data) {
super(data);
}
// synthetic bridge method
public void setData(Object data) {
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println(Integer data);
super.setData(data);
}
}
In this example bridge method was created because MyNode class was missing setData method for Object parameter. Without this method we wouldn't have proper polymorphic behavior and next example would throw ClassCastException.
MyNode mn = new MyNode(5);
Node n = mn;
n.setData("Hello"); //throws ClassCastException
Friday, June 13, 2014
groovy Closures memoization
This is quite common technique to speed up recursive algorithms (Usually you will use maps for this).
Groovy support memoization through it's .memoize() method.
The first invocation is doing actual work and and subsequent invocation is pulling result from cache.
If you run this program, you will see something like this as output:
Test without memoization:
Adding 1 and 3 took 1540 msec with result 4.
Adding 1 and 3 took 1500 msec with result 4.
Adding 1 and 3 took 1501 msec with result 4.
Adding 1 and 3 took 1500 msec with result 4.
Adding 1 and 3 took 1500 msec with result 4.
Test with memoization:
Adding 1 and 3 took 1500 msec with result 4.
Adding 1 and 3 took 0 msec with result 4.
Adding 1 and 3 took 0 msec with result 4.
Adding 1 and 3 took 1 msec with result 4.
Adding 1 and 3 took 0 msec with result 4.
As you can see there is quite a difference between two test. It goes without saying that your closures should return same result for same parameters.
addTwoNumbers = {int a, b ->
//simulate some lengthy calculation
Thread.sleep(1500)
a + b
}
println("Test without memoization:")
def testItWithoutMemoization(a, b) {
long start = System.currentTimeMillis()
long result = addTwoNumbers(a, b)
println("Adding $a and $b took " +
"${System.currentTimeMillis() - start} " +
"msec with result $result.")
}
testItWithoutMemoization(1, 3)
testItWithoutMemoization(1, 3)
testItWithoutMemoization(1, 3)
testItWithoutMemoization(1, 3)
testItWithoutMemoization(1, 3)
addTwoNumbersWithMem = addTwoNumbers.memoize()
println("Test with memoization:")
def testItWithMemoization(a, b) {
long start = System.currentTimeMillis()
long result = addTwoNumbersWithMem(a, b)
println("Adding $a and $b took " +
"${System.currentTimeMillis() - start} " +
"msec with result $result.")
}
testItWithMemoization(1, 3)
testItWithMemoization(1, 3)
testItWithMemoization(1, 3)
testItWithMemoization(1, 3)
testItWithMemoization(1, 3)
Tuesday, June 10, 2014
Grails - dataBind in Service Layer
import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod
class DataBinder {
private static BindDynamicMethod bindDynamicMethod = new BindDynamicMethod()
/**
* make the controller bindData method statically available, e.g. for service layer use
* implemented as closure to allow static import emulating controller layer bindData usage 1:1
*/
static Closure bindData = { Object[] args ->
bindDynamicMethod.invoke(args ? args[0] : null, BindDynamicMethod.METHOD_SIGNATURE, args)
}
}
//usage
class TestBind {
public void intermediateNotification(Map params) {
Test test = new Test()
DataBinder.bindData(test, params)
test.save()
}
}



